Commit 781487c4 authored by Max Kellermann's avatar Max Kellermann

thread/Thread: use BoundMethod

parent 5ba5bc8b
......@@ -43,6 +43,7 @@ UpdateService::UpdateService(EventLoop &_loop, SimpleDatabase &_db,
:DeferredMonitor(_loop),
db(_db), storage(_storage),
listener(_listener),
update_thread(BIND_THIS_METHOD(Task)),
update_task_id(0),
walk(nullptr)
{
......@@ -141,13 +142,6 @@ UpdateService::Task()
}
void
UpdateService::Task(void *ctx)
{
UpdateService &service = *(UpdateService *)ctx;
return service.Task();
}
void
UpdateService::StartThread(UpdateQueueItem &&i)
{
assert(GetEventLoop().IsInsideOrNull());
......@@ -158,7 +152,7 @@ UpdateService::StartThread(UpdateQueueItem &&i)
next = std::move(i);
walk = new UpdateWalk(GetEventLoop(), listener, *next.storage);
update_thread.Start(Task, this);
update_thread.Start();
FormatDebug(update_domain,
"spawned thread for update job id %i", next.id);
......
......@@ -98,7 +98,6 @@ private:
/* the update thread */
void Task();
static void Task(void *ctx);
void StartThread(UpdateQueueItem &&i);
......
......@@ -30,7 +30,8 @@
DecoderControl::DecoderControl(Mutex &_mutex, Cond &_client_cond,
const AudioFormat _configured_audio_format,
const ReplayGainConfig &_replay_gain_config)
:mutex(_mutex), client_cond(_client_cond),
:thread(BIND_THIS_METHOD(RunThread)),
mutex(_mutex), client_cond(_client_cond),
configured_audio_format(_configured_audio_format),
replay_gain_config(_replay_gain_config) {}
......
......@@ -415,6 +415,9 @@ public:
* mixramp_start/mixramp_end.
*/
void CycleMixRamp();
private:
void RunThread();
};
#endif
......@@ -510,30 +510,28 @@ try {
dc.client_cond.signal();
}
static void
decoder_task(void *arg)
void
DecoderControl::RunThread()
{
DecoderControl &dc = *(DecoderControl *)arg;
SetThreadName("decoder");
const std::lock_guard<Mutex> protect(dc.mutex);
const std::lock_guard<Mutex> protect(mutex);
do {
assert(dc.state == DecoderState::STOP ||
dc.state == DecoderState::ERROR);
assert(state == DecoderState::STOP ||
state == DecoderState::ERROR);
switch (dc.command) {
switch (command) {
case DecoderCommand::START:
dc.CycleMixRamp();
dc.replay_gain_prev_db = dc.replay_gain_db;
dc.replay_gain_db = 0;
CycleMixRamp();
replay_gain_prev_db = replay_gain_db;
replay_gain_db = 0;
decoder_run(dc);
decoder_run(*this);
if (dc.state == DecoderState::ERROR) {
if (state == DecoderState::ERROR) {
try {
std::rethrow_exception(dc.error);
std::rethrow_exception(error);
} catch (const std::exception &e) {
LogError(e);
} catch (...) {
......@@ -549,20 +547,20 @@ decoder_task(void *arg)
/* we need to clear the pipe here; usually the
PlayerThread is responsible, but it is not
aware that the decoder has finished */
dc.pipe->Clear(*dc.buffer);
pipe->Clear(*buffer);
decoder_run(dc);
decoder_run(*this);
break;
case DecoderCommand::STOP:
dc.CommandFinishedLocked();
CommandFinishedLocked();
break;
case DecoderCommand::NONE:
dc.Wait();
Wait();
break;
}
} while (dc.command != DecoderCommand::NONE || !dc.quit);
} while (command != DecoderCommand::NONE || !quit);
}
void
......@@ -571,5 +569,5 @@ decoder_thread_start(DecoderControl &dc)
assert(!dc.thread.IsDefined());
dc.quit = false;
dc.thread.Start(decoder_task, &dc);
dc.thread.Start();
}
......@@ -26,7 +26,7 @@ EventThread::Start()
{
assert(!thread.IsDefined());
thread.Start(ThreadFunc, this);
thread.Start();
}
void
......@@ -39,17 +39,9 @@ EventThread::Stop()
}
void
EventThread::ThreadFunc()
EventThread::Run()
{
SetThreadName("io");
event_loop.Run();
};
void
EventThread::ThreadFunc(void *arg)
{
auto &et = *(EventThread *)arg;
et.ThreadFunc();
};
}
......@@ -33,6 +33,9 @@ class EventThread final {
Thread thread;
public:
EventThread()
:thread(BIND_THIS_METHOD(Run)) {}
~EventThread() {
Stop();
}
......@@ -55,8 +58,7 @@ public:
void Stop();
private:
void ThreadFunc();
static void ThreadFunc(void *arg);
void Run();
};
#endif /* MAIN_NOTIFY_H */
......@@ -54,10 +54,10 @@ ThreadInputStream::Start()
assert(p != nullptr);
buffer = new CircularBuffer<uint8_t>((uint8_t *)p, buffer_size);
thread.Start(ThreadFunc, this);
thread.Start();
}
inline void
void
ThreadInputStream::ThreadFunc()
{
FormatThreadName("input:%s", plugin);
......@@ -108,13 +108,6 @@ ThreadInputStream::ThreadFunc()
}
void
ThreadInputStream::ThreadFunc(void *ctx)
{
ThreadInputStream &tis = *(ThreadInputStream *)ctx;
tis.ThreadFunc();
}
void
ThreadInputStream::Check()
{
assert(!thread.IsInside());
......
......@@ -73,6 +73,7 @@ public:
size_t _buffer_size)
:InputStream(_uri, _mutex, _cond),
plugin(_plugin),
thread(BIND_THIS_METHOD(ThreadFunc)),
buffer_size(_buffer_size) {}
virtual ~ThreadInputStream();
......@@ -138,7 +139,6 @@ protected:
private:
void ThreadFunc();
static void ThreadFunc(void *ctx);
};
#endif
......@@ -69,7 +69,8 @@ class SmbclientNeighborExplorer final : public NeighborExplorer {
public:
SmbclientNeighborExplorer(NeighborListener &_listener)
:NeighborExplorer(_listener) {}
:NeighborExplorer(_listener),
thread(BIND_THIS_METHOD(ThreadFunc)) {}
/* virtual methods from class NeighborExplorer */
void Open() override;
......@@ -79,14 +80,13 @@ public:
private:
void Run();
void ThreadFunc();
static void ThreadFunc(void *ctx);
};
void
SmbclientNeighborExplorer::Open()
{
quit = false;
thread.Start(ThreadFunc, this);
thread.Start();
}
void
......@@ -239,6 +239,8 @@ SmbclientNeighborExplorer::Run()
inline void
SmbclientNeighborExplorer::ThreadFunc()
{
SetThreadName("smbclient");
mutex.lock();
while (!quit) {
......@@ -257,15 +259,6 @@ SmbclientNeighborExplorer::ThreadFunc()
mutex.unlock();
}
void
SmbclientNeighborExplorer::ThreadFunc(void *ctx)
{
SetThreadName("smbclient");
SmbclientNeighborExplorer &e = *(SmbclientNeighborExplorer *)ctx;
e.ThreadFunc();
}
static NeighborExplorer *
smbclient_neighbor_create(gcc_unused EventLoop &loop,
NeighborListener &listener,
......
......@@ -51,7 +51,8 @@
AudioOutput::AudioOutput(const AudioOutputPlugin &_plugin,
const ConfigBlock &block)
:plugin(_plugin)
:plugin(_plugin),
thread(BIND_THIS_METHOD(Task))
{
assert(plugin.finish != nullptr);
assert(plugin.open != nullptr);
......
......@@ -515,7 +515,6 @@ private:
* The OutputThread.
*/
void Task();
static void Task(void *arg);
};
/**
......
......@@ -398,7 +398,7 @@ AudioOutput::Pause()
pause = false;
}
inline void
void
AudioOutput::Task()
{
FormatThreadName("output:%s", name);
......@@ -515,16 +515,9 @@ AudioOutput::Task()
}
void
AudioOutput::Task(void *arg)
{
AudioOutput *ao = (AudioOutput *)arg;
ao->Task();
}
void
AudioOutput::StartThread()
{
assert(command == Command::NONE);
thread.Start(Task, this);
thread.Start();
}
......@@ -37,6 +37,7 @@ PlayerControl::PlayerControl(PlayerListener &_listener,
buffer_chunks(_buffer_chunks),
buffered_before_play(_buffered_before_play),
configured_audio_format(_configured_audio_format),
thread(BIND_THIS_METHOD(RunThread)),
replay_gain_config(_replay_gain_config)
{
}
......
......@@ -537,6 +537,9 @@ public:
void ApplyEnabled() override {
LockUpdateAudio();
}
private:
void RunThread();
};
#endif
......@@ -1136,91 +1136,89 @@ do_play(PlayerControl &pc, DecoderControl &dc,
player.Run();
}
static void
player_task(void *arg)
void
PlayerControl::RunThread()
{
PlayerControl &pc = *(PlayerControl *)arg;
SetThreadName("player");
DecoderControl dc(pc.mutex, pc.cond,
pc.configured_audio_format,
pc.replay_gain_config);
DecoderControl dc(mutex, cond,
configured_audio_format,
replay_gain_config);
decoder_thread_start(dc);
MusicBuffer buffer(pc.buffer_chunks);
MusicBuffer buffer(buffer_chunks);
pc.Lock();
Lock();
while (1) {
switch (pc.command) {
switch (command) {
case PlayerCommand::SEEK:
case PlayerCommand::QUEUE:
assert(pc.next_song != nullptr);
assert(next_song != nullptr);
pc.Unlock();
do_play(pc, dc, buffer);
pc.listener.OnPlayerSync();
pc.Lock();
Unlock();
do_play(*this, dc, buffer);
listener.OnPlayerSync();
Lock();
break;
case PlayerCommand::STOP:
pc.Unlock();
pc.outputs.Cancel();
pc.Lock();
Unlock();
outputs.Cancel();
Lock();
/* fall through */
case PlayerCommand::PAUSE:
delete pc.next_song;
pc.next_song = nullptr;
delete next_song;
next_song = nullptr;
pc.CommandFinished();
CommandFinished();
break;
case PlayerCommand::CLOSE_AUDIO:
pc.Unlock();
Unlock();
pc.outputs.Release();
outputs.Release();
pc.Lock();
pc.CommandFinished();
Lock();
CommandFinished();
assert(buffer.IsEmptyUnsafe());
break;
case PlayerCommand::UPDATE_AUDIO:
pc.Unlock();
pc.outputs.EnableDisable();
pc.Lock();
pc.CommandFinished();
Unlock();
outputs.EnableDisable();
Lock();
CommandFinished();
break;
case PlayerCommand::EXIT:
pc.Unlock();
Unlock();
dc.Quit();
pc.outputs.Close();
outputs.Close();
pc.LockCommandFinished();
LockCommandFinished();
return;
case PlayerCommand::CANCEL:
delete pc.next_song;
pc.next_song = nullptr;
delete next_song;
next_song = nullptr;
pc.CommandFinished();
CommandFinished();
break;
case PlayerCommand::REFRESH:
/* no-op when not playing */
pc.CommandFinished();
CommandFinished();
break;
case PlayerCommand::NONE:
pc.Wait();
Wait();
break;
}
}
......@@ -1231,5 +1229,5 @@ StartPlayerThread(PlayerControl &pc)
{
assert(!pc.thread.IsDefined());
pc.thread.Start(player_task, &pc);
pc.thread.Start();
}
......@@ -26,13 +26,10 @@
#endif
void
Thread::Start(void (*_f)(void *ctx), void *_ctx)
Thread::Start()
{
assert(!IsDefined());
f = _f;
ctx = _ctx;
#ifdef WIN32
handle = ::CreateThread(nullptr, 0, ThreadProc, this, 0, &id);
if (handle == nullptr)
......@@ -87,7 +84,7 @@ Thread::Run()
#endif
#endif
f(ctx);
f();
#ifdef ANDROID
Java::DetachCurrentThread();
......
......@@ -21,6 +21,7 @@
#define MPD_THREAD_HXX
#include "check.h"
#include "util/BindMethod.hxx"
#include "Compiler.h"
#ifdef WIN32
......@@ -32,6 +33,9 @@
#include <assert.h>
class Thread {
typedef BoundMethod<void()> Function;
const Function f;
#ifdef WIN32
HANDLE handle = nullptr;
DWORD id;
......@@ -49,11 +53,8 @@ class Thread {
#endif
#endif
void (*f)(void *ctx);
void *ctx;
public:
Thread() = default;
explicit Thread(Function _f):f(_f) {}
Thread(const Thread &) = delete;
......@@ -89,7 +90,7 @@ public:
#endif
}
void Start(void (*f)(void *ctx), void *ctx);
void Start();
void Join();
private:
......
......@@ -43,6 +43,8 @@
#include <stdlib.h>
#include <stdio.h>
void AudioOutput::Task() {}
class DummyAudioOutputClient final : public AudioOutputClient {
public:
/* virtual methods from AudioOutputClient */
......
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