This was prompted by the interactions between GL::ResourceManager and
some upcoming changes to DataFile::PackSource. If a new Slice object is
created and tries to connect to signal_flush_required at the exact moment
another Slice is seeking and causing the signal to be emitted, the emit
and connect calls step on each others' toes and corrupt the heap.
Base::Base():
mode(M_READ),
Base::Base():
mode(M_READ),
+ eof_flag(false),
+ mutex(0)
{ }
Base::~Base()
{
signal_deleted.emit();
{ }
Base::~Base()
{
signal_deleted.emit();
}
void Base::check_access(Mode m) const
}
void Base::check_access(Mode m) const
throw logic_error("Base::get_handle");
}
throw logic_error("Base::get_handle");
}
+
+Base::Synchronize::Synchronize(Base &i):
+ io(i)
+{
+ if(!io.mutex)
+ io.mutex = new Mutex;
+ io.mutex->lock();
+}
+
+Base::Synchronize::~Synchronize()
+{
+ io.mutex->unlock();
+}
+
} // namespace IO
} // namespace Msp
} // namespace IO
} // namespace Msp
#define MSP_IO_BASE_H_
#include <sigc++/sigc++.h>
#define MSP_IO_BASE_H_
#include <sigc++/sigc++.h>
+#include <msp/core/mutex.h>
#include "handle.h"
#include "mode.h"
#include "poll.h"
#include "handle.h"
#include "mode.h"
#include "poll.h"
+ /** RAII synchronization primitive. Prevents concurrent access to the
+ target object during the lifetime of the Synchronize object. */
+ class Synchronize
+ {
+ private:
+ Base &io;
+
+ public:
+ Synchronize(Base &);
+ ~Synchronize();
+ };
+
/** Emitted when there is no more data to be read. */
sigc::signal<void> signal_end_of_file;
/** Emitted when there is no more data to be read. */
sigc::signal<void> signal_end_of_file;
protected:
Mode mode;
bool eof_flag;
protected:
Mode mode;
bool eof_flag;
if(s<0 || l<0)
throw invalid_argument("Slice");
if(s<0 || l<0)
throw invalid_argument("Slice");
+ Base::Synchronize sync(below);
mode = below.get_mode()&M_RDWR;
below.signal_flush_required.connect(sigc::mem_fun(this, &Slice::flush));
}
mode = below.get_mode()&M_RDWR;
below.signal_flush_required.connect(sigc::mem_fun(this, &Slice::flush));
}
check_access(m);
if(sync_position)
check_access(m);
if(sync_position)
+ {
+ SeekOffset pos = below.seek(start_offset+position, S_BEG)-start_offset;
+ if(pos!=position)
+ throw runtime_error("failed to restore position");
+ sync_position = false;
+ }
SeekOffset remaining = start_offset+length-position;
if(size>remaining)
SeekOffset remaining = start_offset+length-position;
if(size>remaining)
unsigned Slice::do_write(const char *data, unsigned size)
{
unsigned Slice::do_write(const char *data, unsigned size)
{
+ Base::Synchronize sync(below);
size = prepare_op(size, M_WRITE);
if(!size)
return 0;
size = prepare_op(size, M_WRITE);
if(!size)
return 0;
unsigned Slice::do_read(char *data, unsigned size)
{
unsigned Slice::do_read(char *data, unsigned size)
{
+ Base::Synchronize sync(below);
size = prepare_op(size, M_READ);
if(!size)
return 0;
size = prepare_op(size, M_READ);
if(!size)
return 0;
unsigned Slice::put(char c)
{
unsigned Slice::put(char c)
{
+ Base::Synchronize sync(below);
if(!prepare_op(1, M_WRITE))
return 0;
if(!prepare_op(1, M_WRITE))
return 0;
+ Base::Synchronize sync(below);
if(!prepare_op(1, M_READ))
return 0;
if(!prepare_op(1, M_READ))
return 0;
SeekOffset Slice::seek(SeekOffset off, SeekType type)
{
SeekOffset Slice::seek(SeekOffset off, SeekType type)
{
+ Base::Synchronize sync(below);
off += start_offset;
if(type==S_CUR)
off += position;
off += start_offset;
if(type==S_CUR)
off += position;