Commit 8e676db6 authored by Max Kellermann's avatar Max Kellermann

Thread/Thread: replacement library for GThread

parent f6d74012
...@@ -274,6 +274,7 @@ libthread_a_SOURCES = \ ...@@ -274,6 +274,7 @@ libthread_a_SOURCES = \
src/thread/PosixCond.hxx \ src/thread/PosixCond.hxx \
src/thread/WindowsCond.hxx \ src/thread/WindowsCond.hxx \
src/thread/GLibCond.hxx \ src/thread/GLibCond.hxx \
src/thread/Thread.cxx src/thread/Thread.hxx \
src/thread/Id.hxx src/thread/Id.hxx
# System library # System library
...@@ -1120,6 +1121,7 @@ test_run_input_LDADD = \ ...@@ -1120,6 +1121,7 @@ test_run_input_LDADD = \
libconf.a \ libconf.a \
libutil.a \ libutil.a \
libevent.a \ libevent.a \
libthread.a \
libsystem.a \ libsystem.a \
libfs.a \ libfs.a \
$(GLIB_LIBS) $(GLIB_LIBS)
...@@ -1138,6 +1140,7 @@ test_visit_archive_LDADD = \ ...@@ -1138,6 +1140,7 @@ test_visit_archive_LDADD = \
libconf.a \ libconf.a \
libutil.a \ libutil.a \
libevent.a \ libevent.a \
libthread.a \
libsystem.a \ libsystem.a \
libfs.a \ libfs.a \
$(GLIB_LIBS) $(GLIB_LIBS)
...@@ -1160,6 +1163,7 @@ test_dump_text_file_LDADD = \ ...@@ -1160,6 +1163,7 @@ test_dump_text_file_LDADD = \
libevent.a \ libevent.a \
libfs.a \ libfs.a \
libsystem.a \ libsystem.a \
libthread.a \
libutil.a \ libutil.a \
$(GLIB_LIBS) $(GLIB_LIBS)
test_dump_text_file_SOURCES = test/dump_text_file.cxx \ test_dump_text_file_SOURCES = test/dump_text_file.cxx \
...@@ -1177,6 +1181,7 @@ test_dump_playlist_LDADD = \ ...@@ -1177,6 +1181,7 @@ test_dump_playlist_LDADD = \
$(TAG_LIBS) \ $(TAG_LIBS) \
libconf.a \ libconf.a \
libevent.a \ libevent.a \
libthread.a \
libsystem.a \ libsystem.a \
libfs.a \ libfs.a \
libutil.a \ libutil.a \
...@@ -1206,6 +1211,7 @@ test_run_decoder_LDADD = \ ...@@ -1206,6 +1211,7 @@ test_run_decoder_LDADD = \
$(TAG_LIBS) \ $(TAG_LIBS) \
libconf.a \ libconf.a \
libevent.a \ libevent.a \
libthread.a \
libsystem.a \ libsystem.a \
libfs.a \ libfs.a \
libutil.a \ libutil.a \
...@@ -1229,6 +1235,7 @@ test_read_tags_LDADD = \ ...@@ -1229,6 +1235,7 @@ test_read_tags_LDADD = \
$(TAG_LIBS) \ $(TAG_LIBS) \
libconf.a \ libconf.a \
libevent.a \ libevent.a \
libthread.a \
libsystem.a \ libsystem.a \
libfs.a \ libfs.a \
libutil.a \ libutil.a \
...@@ -1289,6 +1296,7 @@ test_run_encoder_LDADD = \ ...@@ -1289,6 +1296,7 @@ test_run_encoder_LDADD = \
$(TAG_LIBS) \ $(TAG_LIBS) \
libconf.a \ libconf.a \
libpcm.a \ libpcm.a \
libthread.a \
libsystem.a \ libsystem.a \
libfs.a \ libfs.a \
libutil.a \ libutil.a \
...@@ -1356,6 +1364,7 @@ test_run_output_LDADD = $(MPD_LIBS) \ ...@@ -1356,6 +1364,7 @@ test_run_output_LDADD = $(MPD_LIBS) \
libevent.a \ libevent.a \
libfs.a \ libfs.a \
libsystem.a \ libsystem.a \
libthread.a \
libutil.a \ libutil.a \
$(GLIB_LIBS) $(GLIB_LIBS)
test_run_output_SOURCES = test/run_output.cxx \ test_run_output_SOURCES = test/run_output.cxx \
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include "util/Error.hxx" #include "util/Error.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <glib.h>
#include <assert.h> #include <assert.h>
#include <sys/types.h> #include <sys/types.h>
#ifdef WIN32 #ifdef WIN32
......
...@@ -27,8 +27,7 @@ ...@@ -27,8 +27,7 @@
#include <assert.h> #include <assert.h>
decoder_control::decoder_control() decoder_control::decoder_control()
:thread(nullptr), :state(DecoderState::STOP),
state(DecoderState::STOP),
command(DecoderCommand::NONE), command(DecoderCommand::NONE),
song(nullptr), song(nullptr),
replay_gain_db(0), replay_gain_prev_db(0), replay_gain_db(0), replay_gain_prev_db(0),
...@@ -124,13 +123,12 @@ decoder_control::Seek(double where) ...@@ -124,13 +123,12 @@ decoder_control::Seek(double where)
void void
decoder_control::Quit() decoder_control::Quit()
{ {
assert(thread != nullptr); assert(thread.IsDefined());
quit = true; quit = true;
LockAsynchronousCommand(DecoderCommand::STOP); LockAsynchronousCommand(DecoderCommand::STOP);
g_thread_join(thread); thread.Join();
thread = nullptr;
} }
void void
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "thread/Thread.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include <assert.h> #include <assert.h>
...@@ -37,7 +38,6 @@ ...@@ -37,7 +38,6 @@
struct Song; struct Song;
class MusicBuffer; class MusicBuffer;
class MusicPipe; class MusicPipe;
typedef struct _GThread GThread;
enum class DecoderState : uint8_t { enum class DecoderState : uint8_t {
STOP = 0, STOP = 0,
...@@ -54,9 +54,10 @@ enum class DecoderState : uint8_t { ...@@ -54,9 +54,10 @@ enum class DecoderState : uint8_t {
}; };
struct decoder_control { struct decoder_control {
/** the handle of the decoder thread, or NULL if the decoder /**
thread isn't running */ * The handle of the decoder thread.
GThread *thread; */
Thread thread;
/** /**
* This lock protects #state and #command. * This lock protects #state and #command.
......
...@@ -440,8 +440,8 @@ decoder_run(struct decoder_control *dc) ...@@ -440,8 +440,8 @@ decoder_run(struct decoder_control *dc)
} }
static gpointer static void
decoder_task(gpointer arg) decoder_task(void *arg)
{ {
struct decoder_control *dc = (struct decoder_control *)arg; struct decoder_control *dc = (struct decoder_control *)arg;
...@@ -476,23 +476,16 @@ decoder_task(gpointer arg) ...@@ -476,23 +476,16 @@ decoder_task(gpointer arg)
} while (dc->command != DecoderCommand::NONE || !dc->quit); } while (dc->command != DecoderCommand::NONE || !dc->quit);
dc->Unlock(); dc->Unlock();
return NULL;
} }
void void
decoder_thread_start(struct decoder_control *dc) decoder_thread_start(struct decoder_control *dc)
{ {
assert(dc->thread == NULL); assert(!dc->thread.IsDefined());
dc->quit = false; dc->quit = false;
#if GLIB_CHECK_VERSION(2,32,0) Error error;
dc->thread = g_thread_new("thread", decoder_task, dc); if (!dc->thread.Start(decoder_task, dc, error))
#else FatalError(error);
GError *e = NULL;
dc->thread = g_thread_create(decoder_task, dc, true, &e);
if (dc->thread == NULL)
FatalError("Failed to spawn decoder task", e);
#endif
} }
...@@ -21,10 +21,10 @@ ...@@ -21,10 +21,10 @@
#include "IOThread.hxx" #include "IOThread.hxx"
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "thread/Thread.hxx"
#include "event/Loop.hxx" #include "event/Loop.hxx"
#include "system/FatalError.hxx" #include "system/FatalError.hxx"
#include "util/Error.hxx"
#include <glib.h>
#include <assert.h> #include <assert.h>
...@@ -33,7 +33,7 @@ static struct { ...@@ -33,7 +33,7 @@ static struct {
Cond cond; Cond cond;
EventLoop *loop; EventLoop *loop;
GThread *thread; Thread thread;
} io; } io;
void void
...@@ -45,8 +45,8 @@ io_thread_run(void) ...@@ -45,8 +45,8 @@ io_thread_run(void)
io.loop->Run(); io.loop->Run();
} }
static gpointer static void
io_thread_func(gcc_unused gpointer arg) io_thread_func(gcc_unused void *arg)
{ {
/* lock+unlock to synchronize with io_thread_start(), to be /* lock+unlock to synchronize with io_thread_start(), to be
sure that io.thread is set */ sure that io.thread is set */
...@@ -54,14 +54,13 @@ io_thread_func(gcc_unused gpointer arg) ...@@ -54,14 +54,13 @@ io_thread_func(gcc_unused gpointer arg)
io.mutex.unlock(); io.mutex.unlock();
io_thread_run(); io_thread_run();
return NULL;
} }
void void
io_thread_init(void) io_thread_init(void)
{ {
assert(io.loop == NULL); assert(io.loop == NULL);
assert(io.thread == NULL); assert(!io.thread.IsDefined());
io.loop = new EventLoop(); io.loop = new EventLoop();
} }
...@@ -70,18 +69,13 @@ void ...@@ -70,18 +69,13 @@ void
io_thread_start() io_thread_start()
{ {
assert(io.loop != NULL); assert(io.loop != NULL);
assert(io.thread == NULL); assert(!io.thread.IsDefined());
const ScopeLock protect(io.mutex); const ScopeLock protect(io.mutex);
#if GLIB_CHECK_VERSION(2,32,0) Error error;
io.thread = g_thread_new("io", io_thread_func, nullptr); if (!io.thread.Start(io_thread_func, nullptr, error))
#else
GError *error = nullptr;
io.thread = g_thread_create(io_thread_func, NULL, true, &error);
if (io.thread == NULL)
FatalError(error); FatalError(error);
#endif
} }
void void
...@@ -95,10 +89,9 @@ io_thread_quit(void) ...@@ -95,10 +89,9 @@ io_thread_quit(void)
void void
io_thread_deinit(void) io_thread_deinit(void)
{ {
if (io.thread != NULL) { if (io.thread.IsDefined()) {
io_thread_quit(); io_thread_quit();
io.thread.Join();
g_thread_join(io.thread);
} }
delete io.loop; delete io.loop;
...@@ -115,5 +108,5 @@ io_thread_get() ...@@ -115,5 +108,5 @@ io_thread_get()
bool bool
io_thread_inside(void) io_thread_inside(void)
{ {
return io.thread != NULL && g_thread_self() == io.thread; return io.thread.IsInside();
} }
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include "ConfigOption.hxx" #include "ConfigOption.hxx"
#include "notify.hxx" #include "notify.hxx"
#include <glib.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
......
...@@ -107,7 +107,7 @@ audio_output_set_replay_gain_mode(struct audio_output *ao, ...@@ -107,7 +107,7 @@ audio_output_set_replay_gain_mode(struct audio_output *ao,
void void
audio_output_enable(struct audio_output *ao) audio_output_enable(struct audio_output *ao)
{ {
if (ao->thread == NULL) { if (!ao->thread.IsDefined()) {
if (ao->plugin->enable == NULL) { if (ao->plugin->enable == NULL) {
/* don't bother to start the thread now if the /* don't bother to start the thread now if the
device doesn't even have a enable() method; device doesn't even have a enable() method;
...@@ -125,7 +125,7 @@ audio_output_enable(struct audio_output *ao) ...@@ -125,7 +125,7 @@ audio_output_enable(struct audio_output *ao)
void void
audio_output_disable(struct audio_output *ao) audio_output_disable(struct audio_output *ao)
{ {
if (ao->thread == NULL) { if (!ao->thread.IsDefined()) {
if (ao->plugin->disable == NULL) if (ao->plugin->disable == NULL)
ao->really_enabled = false; ao->really_enabled = false;
else else
...@@ -184,7 +184,7 @@ audio_output_open(struct audio_output *ao, ...@@ -184,7 +184,7 @@ audio_output_open(struct audio_output *ao,
ao->pipe = &mp; ao->pipe = &mp;
if (ao->thread == NULL) if (!ao->thread.IsDefined())
audio_output_thread_start(ao); audio_output_thread_start(ao);
ao_command(ao, ao->open ? AO_COMMAND_REOPEN : AO_COMMAND_OPEN); ao_command(ao, ao->open ? AO_COMMAND_REOPEN : AO_COMMAND_OPEN);
...@@ -322,11 +322,10 @@ void audio_output_finish(struct audio_output *ao) ...@@ -322,11 +322,10 @@ void audio_output_finish(struct audio_output *ao)
assert(ao->fail_timer == NULL); assert(ao->fail_timer == NULL);
if (ao->thread != NULL) { if (ao->thread.IsDefined()) {
assert(ao->allow_play); assert(ao->allow_play);
ao_lock_command(ao, AO_COMMAND_KILL); ao_lock_command(ao, AO_COMMAND_KILL);
g_thread_join(ao->thread); ao->thread.Join();
ao->thread = NULL;
} }
audio_output_free(ao); audio_output_free(ao);
......
...@@ -30,7 +30,7 @@ ao_base_finish(struct audio_output *ao) ...@@ -30,7 +30,7 @@ ao_base_finish(struct audio_output *ao)
{ {
assert(!ao->open); assert(!ao->open);
assert(ao->fail_timer == NULL); assert(ao->fail_timer == NULL);
assert(ao->thread == NULL); assert(!ao->thread.IsDefined());
if (ao->mixer != NULL) if (ao->mixer != NULL)
mixer_free(ao->mixer); mixer_free(ao->mixer);
...@@ -45,7 +45,7 @@ audio_output_free(struct audio_output *ao) ...@@ -45,7 +45,7 @@ audio_output_free(struct audio_output *ao)
{ {
assert(!ao->open); assert(!ao->open);
assert(ao->fail_timer == NULL); assert(ao->fail_timer == NULL);
assert(ao->thread == NULL); assert(!ao->thread.IsDefined());
ao_plugin_finish(ao); ao_plugin_finish(ao);
} }
...@@ -202,7 +202,6 @@ ao_base_init(struct audio_output *ao, ...@@ -202,7 +202,6 @@ ao_base_init(struct audio_output *ao,
"Failed to initialize filter chain for '%s'", "Failed to initialize filter chain for '%s'",
ao->name); ao->name);
ao->thread = NULL;
ao->command = AO_COMMAND_NONE; ao->command = AO_COMMAND_NONE;
ao->mixer = NULL; ao->mixer = NULL;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "pcm/PcmBuffer.hxx" #include "pcm/PcmBuffer.hxx"
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "thread/Thread.hxx"
#include <time.h> #include <time.h>
...@@ -31,7 +32,6 @@ class Error; ...@@ -31,7 +32,6 @@ class Error;
class Filter; class Filter;
class MusicPipe; class MusicPipe;
struct config_param; struct config_param;
typedef struct _GThread GThread;
typedef struct _GTimer GTimer; typedef struct _GTimer GTimer;
enum audio_output_command { enum audio_output_command {
...@@ -200,7 +200,7 @@ struct audio_output { ...@@ -200,7 +200,7 @@ struct audio_output {
* The thread handle, or NULL if the output thread isn't * The thread handle, or NULL if the output thread isn't
* running. * running.
*/ */
GThread *thread; Thread thread;
/** /**
* The next command to be performed by the output thread. * The next command to be performed by the output thread.
......
...@@ -562,7 +562,8 @@ static void ao_pause(struct audio_output *ao) ...@@ -562,7 +562,8 @@ static void ao_pause(struct audio_output *ao)
ao->pause = false; ao->pause = false;
} }
static gpointer audio_output_task(gpointer arg) static void
audio_output_task(void *arg)
{ {
struct audio_output *ao = (struct audio_output *)arg; struct audio_output *ao = (struct audio_output *)arg;
...@@ -647,7 +648,7 @@ static gpointer audio_output_task(gpointer arg) ...@@ -647,7 +648,7 @@ static gpointer audio_output_task(gpointer arg)
ao->chunk = NULL; ao->chunk = NULL;
ao_command_finished(ao); ao_command_finished(ao);
ao->mutex.unlock(); ao->mutex.unlock();
return NULL; return;
} }
if (ao->open && ao->allow_play && ao_play(ao)) if (ao->open && ao->allow_play && ao_play(ao))
...@@ -664,11 +665,7 @@ void audio_output_thread_start(struct audio_output *ao) ...@@ -664,11 +665,7 @@ void audio_output_thread_start(struct audio_output *ao)
{ {
assert(ao->command == AO_COMMAND_NONE); assert(ao->command == AO_COMMAND_NONE);
#if GLIB_CHECK_VERSION(2,32,0) Error error;
ao->thread = g_thread_new("output", audio_output_task, ao); if (!ao->thread.Start(audio_output_task, ao, error))
#else FatalError(error);
GError *e = nullptr;
if (!(ao->thread = g_thread_create(audio_output_task, ao, true, &e)))
FatalError("Failed to spawn output task", e);
#endif
} }
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "ReplayGainConfig.hxx" #include "ReplayGainConfig.hxx"
#include <glib.h>
#define COMMAND_STATUS_STATE "state" #define COMMAND_STATUS_STATE "state"
#define COMMAND_STATUS_REPEAT "repeat" #define COMMAND_STATUS_REPEAT "repeat"
#define COMMAND_STATUS_SINGLE "single" #define COMMAND_STATUS_SINGLE "single"
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include "Song.hxx" #include "Song.hxx"
#include "DecoderControl.hxx" #include "DecoderControl.hxx"
#include <glib.h>
#include <cmath> #include <cmath>
#include <assert.h> #include <assert.h>
...@@ -31,7 +33,6 @@ player_control::player_control(unsigned _buffer_chunks, ...@@ -31,7 +33,6 @@ player_control::player_control(unsigned _buffer_chunks,
unsigned _buffered_before_play) unsigned _buffered_before_play)
:buffer_chunks(_buffer_chunks), :buffer_chunks(_buffer_chunks),
buffered_before_play(_buffered_before_play), buffered_before_play(_buffered_before_play),
thread(nullptr),
command(PlayerCommand::NONE), command(PlayerCommand::NONE),
state(PlayerState::STOP), state(PlayerState::STOP),
error_type(PlayerError::NONE), error_type(PlayerError::NONE),
...@@ -100,11 +101,10 @@ player_control::UpdateAudio() ...@@ -100,11 +101,10 @@ player_control::UpdateAudio()
void void
player_control::Kill() player_control::Kill()
{ {
assert(thread != NULL); assert(thread.IsDefined());
LockSynchronousCommand(PlayerCommand::EXIT); LockSynchronousCommand(PlayerCommand::EXIT);
g_thread_join(thread); thread.Join();
thread = NULL;
idle_add(IDLE_PLAYER); idle_add(IDLE_PLAYER);
} }
......
...@@ -23,10 +23,9 @@ ...@@ -23,10 +23,9 @@
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "thread/Thread.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include <glib.h>
#include <stdint.h> #include <stdint.h>
struct Song; struct Song;
...@@ -95,9 +94,10 @@ struct player_control { ...@@ -95,9 +94,10 @@ struct player_control {
unsigned int buffered_before_play; unsigned int buffered_before_play;
/** the handle of the player thread, or NULL if the player /**
thread isn't running */ * The handle of the player thread.
GThread *thread; */
Thread thread;
/** /**
* This lock protects #command, #state, #error. * This lock protects #command, #state, #error.
...@@ -199,7 +199,7 @@ struct player_control { ...@@ -199,7 +199,7 @@ struct player_control {
* prior to calling this function. * prior to calling this function.
*/ */
void Wait() { void Wait() {
assert(thread == g_thread_self()); assert(thread.IsInside());
cond.wait(mutex); cond.wait(mutex);
} }
...@@ -210,7 +210,7 @@ struct player_control { ...@@ -210,7 +210,7 @@ struct player_control {
* Caller must lock the object. * Caller must lock the object.
*/ */
void ClientSignal() { void ClientSignal() {
assert(thread == g_thread_self()); assert(thread.IsInside());
client_cond.signal(); client_cond.signal();
} }
...@@ -222,7 +222,7 @@ struct player_control { ...@@ -222,7 +222,7 @@ struct player_control {
* Caller must lock the object. * Caller must lock the object.
*/ */
void ClientWait() { void ClientWait() {
assert(thread != g_thread_self()); assert(!thread.IsInside());
client_cond.wait(mutex); client_cond.wait(mutex);
} }
......
...@@ -1096,8 +1096,8 @@ do_play(player_control &pc, decoder_control &dc, ...@@ -1096,8 +1096,8 @@ do_play(player_control &pc, decoder_control &dc,
player.Run(); player.Run();
} }
static gpointer static void
player_task(gpointer arg) player_task(void *arg)
{ {
player_control &pc = *(player_control *)arg; player_control &pc = *(player_control *)arg;
...@@ -1163,7 +1163,7 @@ player_task(gpointer arg) ...@@ -1163,7 +1163,7 @@ player_task(gpointer arg)
audio_output_all_close(); audio_output_all_close();
player_command_finished(pc); player_command_finished(pc);
return nullptr; return;
case PlayerCommand::CANCEL: case PlayerCommand::CANCEL:
if (pc.next_song != nullptr) { if (pc.next_song != nullptr) {
...@@ -1189,14 +1189,9 @@ player_task(gpointer arg) ...@@ -1189,14 +1189,9 @@ player_task(gpointer arg)
void void
player_create(player_control &pc) player_create(player_control &pc)
{ {
assert(pc.thread == nullptr); assert(!pc.thread.IsDefined());
#if GLIB_CHECK_VERSION(2,32,0) Error error;
pc.thread = g_thread_new("player", player_task, &pc); if (!pc.thread.Start(player_task, &pc, error))
#else FatalError(error);
GError *e = nullptr;
pc.thread = g_thread_create(player_task, &pc, true, &e);
if (pc.thread == nullptr)
FatalError("Failed to spawn player task", e);
#endif
} }
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include "ConfigOption.hxx" #include "ConfigOption.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <glib.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include "util/Error.hxx" #include "util/Error.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include <glib.h>
#include <string.h> #include <string.h>
enum command_return enum command_return
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "Instance.hxx" #include "Instance.hxx"
#include "system/FatalError.hxx" #include "system/FatalError.hxx"
#include "thread/Id.hxx" #include "thread/Id.hxx"
#include "thread/Thread.hxx"
#include <glib.h> #include <glib.h>
...@@ -47,7 +48,7 @@ static enum update_progress { ...@@ -47,7 +48,7 @@ static enum update_progress {
static bool modified; static bool modified;
static GThread *update_thr; static Thread update_thread;
static const unsigned update_task_id_max = 1 << 15; static const unsigned update_task_id_max = 1 << 15;
...@@ -62,7 +63,8 @@ isUpdatingDB(void) ...@@ -62,7 +63,8 @@ isUpdatingDB(void)
return (progress != UPDATE_PROGRESS_IDLE) ? update_task_id : 0; return (progress != UPDATE_PROGRESS_IDLE) ? update_task_id : 0;
} }
static void * update_task(void *_path) static void
update_task(void *_path)
{ {
const char *path = (const char *)_path; const char *path = (const char *)_path;
...@@ -87,7 +89,6 @@ static void * update_task(void *_path) ...@@ -87,7 +89,6 @@ static void * update_task(void *_path)
progress = UPDATE_PROGRESS_DONE; progress = UPDATE_PROGRESS_DONE;
GlobalEvents::Emit(GlobalEvents::UPDATE); GlobalEvents::Emit(GlobalEvents::UPDATE);
return NULL;
} }
static void static void
...@@ -98,14 +99,9 @@ spawn_update_task(const char *path) ...@@ -98,14 +99,9 @@ spawn_update_task(const char *path)
progress = UPDATE_PROGRESS_RUNNING; progress = UPDATE_PROGRESS_RUNNING;
modified = false; modified = false;
#if GLIB_CHECK_VERSION(2,32,0) Error error;
update_thr = g_thread_new("update", update_task, g_strdup(path)); if (!update_thread.Start(update_task, g_strdup(path), error))
#else FatalError(error);
GError *e = NULL;
update_thr = g_thread_create(update_task, g_strdup(path), TRUE, &e);
if (update_thr == NULL)
FatalError("Failed to spawn update task", e);
#endif
if (++update_task_id > update_task_id_max) if (++update_task_id > update_task_id_max)
update_task_id = 1; update_task_id = 1;
...@@ -147,7 +143,7 @@ static void update_finished_event(void) ...@@ -147,7 +143,7 @@ static void update_finished_event(void)
assert(progress == UPDATE_PROGRESS_DONE); assert(progress == UPDATE_PROGRESS_DONE);
g_thread_join(update_thr); update_thread.Join();
idle_add(IDLE_UPDATE); idle_add(IDLE_UPDATE);
......
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "Thread.hxx"
#include "util/Error.hxx"
bool
Thread::Start(void (*_f)(void *ctx), void *_ctx, Error &error)
{
assert(!IsDefined());
f = _f;
ctx = _ctx;
#ifdef WIN32
handle = ::CreateThread(nullptr, 0, ThreadProc, this, 0, &id);
if (handle == nullptr) {
error.SetLastError("Failed to create thread");
return false;
}
#else
#ifndef NDEBUG
creating = true;
#endif
int e = pthread_create(&handle, nullptr, ThreadProc, this);
if (e != 0) {
#ifndef NDEBUG
creating = false;
#endif
error.SetErrno(e, "Failed to create thread");
return false;
}
defined = true;
#ifndef NDEBUG
creating = false;
#endif
#endif
return true;
}
void
Thread::Join()
{
assert(IsDefined());
assert(!IsInside());
#ifdef WIN32
::WaitForSingleObject(handle, INFINITE);
::CloseHandle(handle);
handle = nullptr;
#else
pthread_join(handle, nullptr);
defined = false;
#endif
}
#ifdef WIN32
DWORD WINAPI
Thread::ThreadProc(LPVOID ctx)
{
Thread &thread = *(Thread *)ctx;
thread.f(thread.ctx);
return 0;
}
#else
void *
Thread::ThreadProc(void *ctx)
{
Thread &thread = *(Thread *)ctx;
#ifndef NDEBUG
/* this works around a race condition that causes an assertion
failure due to IsInside() spuriously returning false right
after the thread has been created, and the calling thread
hasn't initialised "defined" yet */
thread.defined = true;
#endif
thread.f(thread.ctx);
return nullptr;
}
#endif
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_THREAD_HXX
#define MPD_THREAD_HXX
#include "check.h"
#include "Compiler.h"
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include <assert.h>
class Error;
class Thread {
#ifdef WIN32
HANDLE handle;
DWORD id;
#else
pthread_t handle;
bool defined;
#ifndef NDEBUG
/**
* The thread is currently being created. This is a workaround for
* IsInside(), which may return false until pthread_create() has
* initialised the #handle.
*/
bool creating;
#endif
#endif
void (*f)(void *ctx);
void *ctx;
public:
#ifdef WIN32
Thread():handle(nullptr) {}
#else
Thread():defined(false) {
#ifndef NDEBUG
creating = false;
#endif
}
#endif
Thread(const Thread &) = delete;
#ifndef NDEBUG
virtual ~Thread() {
/* all Thread objects must be destructed manually by calling
Join(), to clean up */
assert(!IsDefined());
}
#endif
bool IsDefined() const {
#ifdef WIN32
return handle != nullptr;
#else
return defined;
#endif
}
/**
* Check if this thread is the current thread.
*/
gcc_pure
bool IsInside() const {
#ifdef WIN32
return GetCurrentThreadId() == id;
#else
#ifdef NDEBUG
constexpr bool creating = false;
#endif
return IsDefined() && (creating ||
pthread_equal(pthread_self(), handle));
#endif
}
bool Start(void (*f)(void *ctx), void *ctx, Error &error);
void Join();
private:
#ifdef WIN32
static DWORD WINAPI ThreadProc(LPVOID ctx);
#else
static void *ThreadProc(void *ctx);
#endif
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment