event_pipe: added pipe_event enum and callbacks
Make the event_pipe (formerly main_notify) send/receive a set of events, with a callback for each one. The default event PIPE_EVENT_SIGNAL does not have a callback. It is still there for waking up the main thread, when it is waiting for the player thread.
This commit is contained in:
parent
22bb5a5856
commit
b3e2635ac1
@ -59,7 +59,6 @@ db_init(void)
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
event_pipe_wait();
|
event_pipe_wait();
|
||||||
reap_update_task();
|
|
||||||
} while (isUpdatingDB());
|
} while (isUpdatingDB());
|
||||||
|
|
||||||
stats.numberOfSongs = countSongsIn(NULL);
|
stats.numberOfSongs = countSongsIn(NULL);
|
||||||
|
@ -28,14 +28,45 @@
|
|||||||
|
|
||||||
GThread *main_task;
|
GThread *main_task;
|
||||||
static int event_pipe[2];
|
static int event_pipe[2];
|
||||||
|
static GMutex *event_pipe_mutex;
|
||||||
|
static bool pipe_events[PIPE_EVENT_MAX];
|
||||||
|
static event_pipe_callback_t event_pipe_callbacks[PIPE_EVENT_MAX];
|
||||||
|
|
||||||
static void consume_pipe(void)
|
/**
|
||||||
|
* Invoke the callback for a certain event.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
event_pipe_invoke(enum pipe_event event)
|
||||||
|
{
|
||||||
|
assert((unsigned)event < PIPE_EVENT_MAX);
|
||||||
|
assert(event != PIPE_EVENT_SIGNAL);
|
||||||
|
assert(event_pipe_callbacks[event] != NULL);
|
||||||
|
|
||||||
|
event_pipe_callbacks[event]();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool consume_pipe(void)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
ssize_t r = read(event_pipe[0], buffer, sizeof(buffer));
|
ssize_t r = read(event_pipe[0], buffer, sizeof(buffer));
|
||||||
|
bool events[PIPE_EVENT_MAX];
|
||||||
|
|
||||||
if (r < 0 && errno != EAGAIN && errno != EINTR)
|
if (r < 0 && errno != EAGAIN && errno != EINTR)
|
||||||
FATAL("error reading from pipe: %s\n", strerror(errno));
|
FATAL("error reading from pipe: %s\n", strerror(errno));
|
||||||
|
|
||||||
|
g_mutex_lock(event_pipe_mutex);
|
||||||
|
memcpy(events, pipe_events, sizeof(events));
|
||||||
|
memset(pipe_events, 0, sizeof(pipe_events));
|
||||||
|
g_mutex_unlock(event_pipe_mutex);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < PIPE_EVENT_MAX; ++i)
|
||||||
|
if (i != PIPE_EVENT_SIGNAL && events[i])
|
||||||
|
/* invoke the event handler; the SIGNAL event
|
||||||
|
has no handler, because it is handled by
|
||||||
|
the event_pipe_wait() caller */
|
||||||
|
event_pipe_invoke(i);
|
||||||
|
|
||||||
|
return events[PIPE_EVENT_SIGNAL];
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -44,7 +75,6 @@ main_notify_event(G_GNUC_UNUSED GIOChannel *source,
|
|||||||
G_GNUC_UNUSED gpointer data)
|
G_GNUC_UNUSED gpointer data)
|
||||||
{
|
{
|
||||||
consume_pipe();
|
consume_pipe();
|
||||||
main_notify_triggered();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,22 +93,55 @@ void event_pipe_init(void)
|
|||||||
g_io_add_watch(channel, G_IO_IN, main_notify_event, NULL);
|
g_io_add_watch(channel, G_IO_IN, main_notify_event, NULL);
|
||||||
g_io_channel_unref(channel);
|
g_io_channel_unref(channel);
|
||||||
|
|
||||||
|
event_pipe_mutex = g_mutex_new();
|
||||||
|
|
||||||
main_task = g_thread_self();
|
main_task = g_thread_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
void event_pipe_deinit(void)
|
void event_pipe_deinit(void)
|
||||||
{
|
{
|
||||||
|
g_mutex_free(event_pipe_mutex);
|
||||||
|
|
||||||
xclose(event_pipe[0]);
|
xclose(event_pipe[0]);
|
||||||
xclose(event_pipe[1]);
|
xclose(event_pipe[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void event_pipe_signal(void)
|
void
|
||||||
|
event_pipe_register(enum pipe_event event, event_pipe_callback_t callback)
|
||||||
{
|
{
|
||||||
ssize_t w = write(event_pipe[1], "", 1);
|
assert(event != PIPE_EVENT_SIGNAL);
|
||||||
|
assert((unsigned)event < PIPE_EVENT_MAX);
|
||||||
|
assert(event_pipe_callbacks[event] == NULL);
|
||||||
|
|
||||||
|
event_pipe_callbacks[event] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void event_pipe_emit(enum pipe_event event)
|
||||||
|
{
|
||||||
|
ssize_t w;
|
||||||
|
|
||||||
|
assert((unsigned)event < PIPE_EVENT_MAX);
|
||||||
|
|
||||||
|
g_mutex_lock(event_pipe_mutex);
|
||||||
|
if (pipe_events[event]) {
|
||||||
|
/* already set: don't write */
|
||||||
|
g_mutex_unlock(event_pipe_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe_events[event] = true;
|
||||||
|
g_mutex_unlock(event_pipe_mutex);
|
||||||
|
|
||||||
|
w = write(event_pipe[1], "", 1);
|
||||||
if (w < 0 && errno != EAGAIN && errno != EINTR)
|
if (w < 0 && errno != EAGAIN && errno != EINTR)
|
||||||
g_error("error writing to pipe: %s", strerror(errno));
|
g_error("error writing to pipe: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void event_pipe_signal(void)
|
||||||
|
{
|
||||||
|
event_pipe_emit(PIPE_EVENT_SIGNAL);
|
||||||
|
}
|
||||||
|
|
||||||
void event_pipe_wait(void)
|
void event_pipe_wait(void)
|
||||||
{
|
{
|
||||||
consume_pipe();
|
consume_pipe();
|
||||||
|
@ -23,17 +23,41 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
enum pipe_event {
|
||||||
|
/** the default event: the main thread is waiting for somebody,
|
||||||
|
and this event wakes up the main thread */
|
||||||
|
PIPE_EVENT_SIGNAL = 0,
|
||||||
|
|
||||||
|
/** database update was finished */
|
||||||
|
PIPE_EVENT_UPDATE,
|
||||||
|
|
||||||
|
/** during database update, a song was deleted */
|
||||||
|
PIPE_EVENT_DELETE,
|
||||||
|
|
||||||
|
/** an idle event was emitted */
|
||||||
|
PIPE_EVENT_IDLE,
|
||||||
|
|
||||||
|
/** must call syncPlayerAndPlaylist() */
|
||||||
|
PIPE_EVENT_PLAYLIST,
|
||||||
|
|
||||||
|
PIPE_EVENT_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*event_pipe_callback_t)(void);
|
||||||
|
|
||||||
extern GThread *main_task;
|
extern GThread *main_task;
|
||||||
|
|
||||||
void event_pipe_init(void);
|
void event_pipe_init(void);
|
||||||
|
|
||||||
void event_pipe_deinit(void);
|
void event_pipe_deinit(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
event_pipe_register(enum pipe_event event, event_pipe_callback_t callback);
|
||||||
|
|
||||||
|
void event_pipe_emit(enum pipe_event event);
|
||||||
|
|
||||||
void event_pipe_signal(void);
|
void event_pipe_signal(void);
|
||||||
|
|
||||||
void event_pipe_wait(void);
|
void event_pipe_wait(void);
|
||||||
|
|
||||||
void
|
|
||||||
main_notify_triggered(void);
|
|
||||||
|
|
||||||
#endif /* MAIN_NOTIFY_H */
|
#endif /* MAIN_NOTIFY_H */
|
||||||
|
@ -66,7 +66,7 @@ idle_add(unsigned flags)
|
|||||||
idle_flags |= flags;
|
idle_flags |= flags;
|
||||||
g_mutex_unlock(idle_mutex);
|
g_mutex_unlock(idle_mutex);
|
||||||
|
|
||||||
event_pipe_signal();
|
event_pipe_emit(PIPE_EVENT_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
|
20
src/main.c
20
src/main.c
@ -190,17 +190,15 @@ timer_save_state_file(G_GNUC_UNUSED gpointer data)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/**
|
||||||
main_notify_triggered(void)
|
* event_pipe callback function for PIPE_EVENT_IDLE
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
idle_event_emitted(void)
|
||||||
{
|
{
|
||||||
unsigned flags;
|
|
||||||
|
|
||||||
syncPlayerAndPlaylist();
|
|
||||||
reap_update_task();
|
|
||||||
|
|
||||||
/* send "idle" notificaions to all subscribed
|
/* send "idle" notificaions to all subscribed
|
||||||
clients */
|
clients */
|
||||||
flags = idle_get();
|
unsigned flags = idle_get();
|
||||||
if (flags != 0)
|
if (flags != 0)
|
||||||
client_manager_idle_add(flags);
|
client_manager_idle_add(flags);
|
||||||
}
|
}
|
||||||
@ -243,6 +241,10 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
main_loop = g_main_loop_new(NULL, FALSE);
|
main_loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
|
||||||
|
event_pipe_init();
|
||||||
|
event_pipe_register(PIPE_EVENT_IDLE, idle_event_emitted);
|
||||||
|
event_pipe_register(PIPE_EVENT_PLAYLIST, syncPlayerAndPlaylist);
|
||||||
|
|
||||||
path_global_init();
|
path_global_init();
|
||||||
mapper_init();
|
mapper_init();
|
||||||
initPermissions();
|
initPermissions();
|
||||||
@ -253,8 +255,6 @@ int main(int argc, char *argv[])
|
|||||||
decoder_plugin_init_all();
|
decoder_plugin_init_all();
|
||||||
update_global_init();
|
update_global_init();
|
||||||
|
|
||||||
event_pipe_init();
|
|
||||||
|
|
||||||
openDB(&options, argv[0]);
|
openDB(&options, argv[0]);
|
||||||
|
|
||||||
command_init();
|
command_init();
|
||||||
|
@ -90,7 +90,7 @@ static void player_stop_decoder(void)
|
|||||||
{
|
{
|
||||||
dc_stop(&pc.notify);
|
dc_stop(&pc.notify);
|
||||||
pc.state = PLAYER_STATE_STOP;
|
pc.state = PLAYER_STATE_STOP;
|
||||||
event_pipe_signal();
|
event_pipe_emit(PIPE_EVENT_PLAYLIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int player_wait_for_decoder(struct player *player)
|
static int player_wait_for_decoder(struct player *player)
|
||||||
@ -369,7 +369,7 @@ static void do_play(void)
|
|||||||
request the next song from the playlist */
|
request the next song from the playlist */
|
||||||
|
|
||||||
pc.next_song = NULL;
|
pc.next_song = NULL;
|
||||||
event_pipe_signal();
|
event_pipe_emit(PIPE_EVENT_PLAYLIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decoder_is_idle() && player.queued) {
|
if (decoder_is_idle() && player.queued) {
|
||||||
@ -476,7 +476,7 @@ static void do_play(void)
|
|||||||
if (player_wait_for_decoder(&player) < 0)
|
if (player_wait_for_decoder(&player) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
event_pipe_signal();
|
event_pipe_emit(PIPE_EVENT_PLAYLIST);
|
||||||
} else if (decoder_is_idle()) {
|
} else if (decoder_is_idle()) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -98,7 +98,7 @@ delete_song(struct directory *dir, struct song *del)
|
|||||||
cond_enter(&delete_cond);
|
cond_enter(&delete_cond);
|
||||||
assert(!delete);
|
assert(!delete);
|
||||||
delete = del;
|
delete = del;
|
||||||
event_pipe_signal();
|
event_pipe_emit(PIPE_EVENT_DELETE);
|
||||||
do { cond_wait(&delete_cond); } while (delete);
|
do { cond_wait(&delete_cond); } while (delete);
|
||||||
cond_leave(&delete_cond);
|
cond_leave(&delete_cond);
|
||||||
|
|
||||||
@ -603,7 +603,7 @@ static void * update_task(void *_path)
|
|||||||
if (modified)
|
if (modified)
|
||||||
db_save();
|
db_save();
|
||||||
progress = UPDATE_PROGRESS_DONE;
|
progress = UPDATE_PROGRESS_DONE;
|
||||||
event_pipe_signal();
|
event_pipe_emit(PIPE_EVENT_UPDATE);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,7 +646,7 @@ directory_update_init(char *path)
|
|||||||
return update_task_id;
|
return update_task_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reap_update_task(void)
|
static void reap_update_task(void)
|
||||||
{
|
{
|
||||||
assert(g_thread_self() == main_task);
|
assert(g_thread_self() == main_task);
|
||||||
|
|
||||||
@ -693,6 +693,9 @@ void update_global_init(void)
|
|||||||
DEFAULT_FOLLOW_OUTSIDE_SYMLINKS);
|
DEFAULT_FOLLOW_OUTSIDE_SYMLINKS);
|
||||||
|
|
||||||
cond_init(&delete_cond);
|
cond_init(&delete_cond);
|
||||||
|
|
||||||
|
event_pipe_register(PIPE_EVENT_DELETE, reap_update_task);
|
||||||
|
event_pipe_register(PIPE_EVENT_UPDATE, reap_update_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_global_finish(void)
|
void update_global_finish(void)
|
||||||
|
@ -35,6 +35,4 @@ isUpdatingDB(void);
|
|||||||
unsigned
|
unsigned
|
||||||
directory_update_init(char *path);
|
directory_update_init(char *path);
|
||||||
|
|
||||||
void reap_update_task(void);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user