diff --git a/dtool/src/prc/streamWrapper.I b/dtool/src/prc/streamWrapper.I index 0f9d65d414..6d2578262c 100644 --- a/dtool/src/prc/streamWrapper.I +++ b/dtool/src/prc/streamWrapper.I @@ -58,6 +58,24 @@ release() { _lock.unlock(); } +/** + * Increments the reference count. Only has impact if the class that manages + * this StreamWrapper's lifetime (eg. Multifile) respects it. + */ +INLINE void StreamWrapperBase:: +ref() const { + AtomicAdjust::inc(_ref_count); +} + +/** + * Decrements the reference count. Only has impact if the class that manages + * this StreamWrapper's lifetime (eg. Multifile) respects it. + */ +INLINE bool StreamWrapperBase:: +unref() const { + return AtomicAdjust::dec(_ref_count); +} + /** * */ diff --git a/dtool/src/prc/streamWrapper.h b/dtool/src/prc/streamWrapper.h index b5a4d5bf72..a837540129 100644 --- a/dtool/src/prc/streamWrapper.h +++ b/dtool/src/prc/streamWrapper.h @@ -16,6 +16,7 @@ #include "dtoolbase.h" #include "mutexImpl.h" +#include "atomicAdjust.h" /** * The base class for both IStreamWrapper and OStreamWrapper, this provides @@ -30,8 +31,17 @@ PUBLISHED: INLINE void acquire(); INLINE void release(); +public: + INLINE void ref() const; + INLINE bool unref() const; + private: MutexImpl _lock; + + // This isn't really designed as a reference counted class, but it is useful + // to treat it as one when dealing with substreams created by Multifile. + mutable AtomicAdjust::Integer _ref_count = 1; + #ifdef SIMPLE_THREADS // In the SIMPLE_THREADS case, we need to use a bool flag, because MutexImpl // defines to nothing in this case--but we still need to achieve a form of diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index e625861f87..cdb1c56ec8 100644 --- a/panda/src/express/multifile.cxx +++ b/panda/src/express/multifile.cxx @@ -333,7 +333,10 @@ close() { if (_owns_stream) { // We prefer to delete the IStreamWrapper over the ostream, if possible. if (_read != nullptr) { - delete _read; + // Only delete it if no SubStream is still referencing it. + if (!_read->unref()) { + delete _read; + } } else if (_write != nullptr) { delete _write; } diff --git a/panda/src/express/subStreamBuf.cxx b/panda/src/express/subStreamBuf.cxx index 4d773e359f..14a05f1bfb 100644 --- a/panda/src/express/subStreamBuf.cxx +++ b/panda/src/express/subStreamBuf.cxx @@ -88,6 +88,13 @@ open(IStreamWrapper *source, OStreamWrapper *dest, streampos start, streampos en _append = append; _gpos = _start; _ppos = _start; + + if (source != nullptr) { + source->ref(); + } + if (dest != nullptr) { + dest->ref(); + } } /** @@ -98,6 +105,12 @@ close() { // Make sure the write buffer is flushed. sync(); + if (_source != nullptr && !_source->unref()) { + delete _source; + } + if (_dest != nullptr && !_dest->unref()) { + delete _dest; + } _source = nullptr; _dest = nullptr; _start = 0; diff --git a/panda/src/express/subStreamBuf.h b/panda/src/express/subStreamBuf.h index 779f43d94c..1f0c511e51 100644 --- a/panda/src/express/subStreamBuf.h +++ b/panda/src/express/subStreamBuf.h @@ -23,6 +23,7 @@ class EXPCL_PANDA_EXPRESS SubStreamBuf : public std::streambuf { public: SubStreamBuf(); + SubStreamBuf(const SubStreamBuf ©) = delete; virtual ~SubStreamBuf(); void open(IStreamWrapper *source, OStreamWrapper *dest, std::streampos start, std::streampos end, bool append);