Fix race conditions and deadlocks in Channels (hopefully) (issue #554)

Also, this is a giant commit because of the official Code Style (tm) was applied.

--HG--
branch : minor
This commit is contained in:
Bart van Strien
2013-01-30 17:15:12 +01:00
parent be2363fc00
commit c7c5d0ed6b
15 changed files with 414 additions and 367 deletions
+56 -54
View File
@@ -26,65 +26,67 @@ namespace thread
{
namespace sdl
{
Thread::Thread(Threadable *t)
: t(t), running(false), thread(0)
{
}
Thread::Thread(Threadable *t)
: t(t)
, running(false)
, thread(0)
{
}
Thread::~Thread()
{
if (!running) // Clean up handle
wait();
/*
if (running)
wait();
FIXME: Needed for proper thread cleanup
*/
}
Thread::~Thread()
{
if (!running) // Clean up handle
wait();
/*
if (running)
wait();
FIXME: Needed for proper thread cleanup
*/
}
bool Thread::start()
{
Lock l(mutex);
if (running)
return false;
if (thread) // Clean old handle up
SDL_WaitThread(thread, 0);
thread = SDL_CreateThread(thread_runner, this);
running = (thread != 0);
return running;
}
void Thread::wait()
{
mutex.lock();
if (!thread)
return;
mutex.unlock();
bool Thread::start()
{
Lock l(mutex);
if (running)
return false;
if (thread) // Clean old handle up
SDL_WaitThread(thread, 0);
Lock l(mutex);
running = false;
thread = 0;
}
thread = SDL_CreateThread(thread_runner, this);
running = (thread != 0);
return running;
}
void Thread::kill()
{
Lock l(mutex);
if (!running)
return;
SDL_KillThread(thread);
SDL_WaitThread(thread, 0);
running = false;
thread = 0;
}
void Thread::wait()
{
mutex.lock();
if (!thread)
return;
mutex.unlock();
SDL_WaitThread(thread, 0);
Lock l(mutex);
running = false;
thread = 0;
}
int Thread::thread_runner(void *data)
{
Thread *self = (Thread*) data; // some compilers don't like 'this'
self->t->threadFunction();
Lock l(self->mutex);
self->running = false;
return 0;
}
void Thread::kill()
{
Lock l(mutex);
if (!running)
return;
SDL_KillThread(thread);
SDL_WaitThread(thread, 0);
running = false;
thread = 0;
}
int Thread::thread_runner(void *data)
{
Thread *self = (Thread *) data; // some compilers don't like 'this'
self->t->threadFunction();
Lock l(self->mutex);
self->running = false;
return 0;
}
} // sdl
} // thread
} // love
+15 -15
View File
@@ -34,22 +34,22 @@ namespace thread
{
namespace sdl
{
class Thread : public thread::Thread
{
private:
Threadable *t;
bool running;
SDL_Thread *thread;
static int thread_runner(void *data);
Mutex mutex;
class Thread : public thread::Thread
{
private:
Threadable *t;
bool running;
SDL_Thread *thread;
static int thread_runner(void *data);
Mutex mutex;
public:
Thread(Threadable *t);
~Thread();
bool start();
void kill();
void wait();
}; // Thread
public:
Thread(Threadable *t);
~Thread();
bool start();
void kill();
void wait();
}; // Thread
} // sdl
} // thread
} // love
+1 -1
View File
@@ -72,7 +72,7 @@ bool Conditional::wait(thread::Mutex *_mutex, int timeout)
// Yes, I realise this can be dangerous,
// however, you're asking for it if you're
// mixing thread implementations.
Mutex *mutex = (Mutex*) _mutex;
Mutex *mutex = (Mutex *) _mutex;
if (timeout < 0)
return !SDL_CondWait(cond, mutex->mutex);
else
+24 -24
View File
@@ -32,37 +32,37 @@ namespace thread
{
namespace sdl
{
class Conditional;
class Conditional;
class Mutex : public thread::Mutex
{
public:
Mutex();
~Mutex();
class Mutex : public thread::Mutex
{
public:
Mutex();
~Mutex();
void lock();
void unlock();
void lock();
void unlock();
private:
SDL_mutex* mutex;
Mutex(const Mutex&/* mutex*/) {}
private:
SDL_mutex *mutex;
Mutex(const Mutex&/* mutex*/) {}
friend class Conditional;
};
friend class Conditional;
};
class Conditional : public thread::Conditional
{
public:
Conditional();
~Conditional();
class Conditional : public thread::Conditional
{
public:
Conditional();
~Conditional();
void signal();
void broadcast();
bool wait(thread::Mutex* mutex, int timeout=-1);
void signal();
void broadcast();
bool wait(thread::Mutex *mutex, int timeout=-1);
private:
SDL_cond* cond;
};
private:
SDL_cond *cond;
};
} // sdl
} // thread