From: Takashi Sakamoto Date: Sun, 9 Feb 2020 03:20:53 +0000 (+0900) Subject: timer: user_instance: add an API to create GSource to dispatch event X-Git-Tag: v0.1.0~337 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=eaab98259d824933a84548c5e3331730dc33b3bb;p=alsa-gobject.git timer: user_instance: add an API to create GSource to dispatch event Signed-off-by: Takashi Sakamoto --- diff --git a/src/timer/alsatimer.map b/src/timer/alsatimer.map index c02c809..030945a 100644 --- a/src/timer/alsatimer.map +++ b/src/timer/alsatimer.map @@ -35,6 +35,7 @@ ALSA_GOBJECT_0_0_0 { "alsatimer_user_instance_get_info"; "alsatimer_user_instance_set_params"; "alsatimer_user_instance_get_status"; + "alsatimer_user_instance_create_source"; "alsatimer_instance_info_get_type"; diff --git a/src/timer/user-instance.c b/src/timer/user-instance.c index f5ff2c1..daf30f5 100644 --- a/src/timer/user-instance.c +++ b/src/timer/user-instance.c @@ -15,6 +15,14 @@ struct _ALSATimerUserInstancePrivate { }; G_DEFINE_TYPE_WITH_PRIVATE(ALSATimerUserInstance, alsatimer_user_instance, G_TYPE_OBJECT) +typedef struct { + GSource src; + ALSATimerUserInstance *self; + gpointer tag; + void *buf; + unsigned int buf_len; +} TimerUserInstanceSource; + static void timer_user_instance_finalize(GObject *obj) { ALSATimerUserInstance *self = ALSATIMER_USER_INSTANCE(obj); @@ -207,3 +215,109 @@ void alsatimer_user_instance_get_status(ALSATimerUserInstance *self, g_object_unref(*instance_status); } } + +static gboolean timer_user_instance_prepare_src(GSource *src, gint *timeout) +{ + *timeout = 500; + + // This source is not ready, let's poll(2). + return FALSE; +} + +static gboolean timer_user_instance_check_src(GSource *gsrc) +{ + TimerUserInstanceSource *src = (TimerUserInstanceSource *)gsrc; + GIOCondition condition; + + // Don't go to dispatch if nothing available. As an exception, return TRUE + // for POLLERR to call .dispatch for internal destruction. + condition = g_source_query_unix_fd(gsrc, src->tag); + return !!(condition & (G_IO_IN | G_IO_ERR)); +} + +static gboolean timer_user_instance_dispatch_src(GSource *gsrc, GSourceFunc cb, + gpointer user_data) +{ + TimerUserInstanceSource *src = (TimerUserInstanceSource *)gsrc; + ALSATimerUserInstance *self = src->self; + ALSATimerUserInstancePrivate *priv; + GIOCondition condition; + int len; + + priv = alsatimer_user_instance_get_instance_private(self); + if (priv->fd < 0) + return G_SOURCE_REMOVE; + + condition = g_source_query_unix_fd(gsrc, src->tag); + if (condition & G_IO_ERR) + return G_SOURCE_REMOVE; + + len = read(priv->fd, src->buf, src->buf_len); + if (len < 0) { + if (errno == EAGAIN) + return G_SOURCE_CONTINUE; + + return G_SOURCE_REMOVE; + } + + // Just be sure to continue to process this source. + return G_SOURCE_CONTINUE; +} + +static void timer_user_instance_finalize_src(GSource *gsrc) +{ + TimerUserInstanceSource *src = (TimerUserInstanceSource *)gsrc; + + g_free(src->buf); + g_object_unref(src->self); +} + +/** + * alsatimer_user_instance_create_source: + * @self: A #ALSATimerUserInstance. + * @gsrc: (out): A #GSource to handle events from ALSA timer character device. + * @error: A #GError. + * + * Allocate GSource structure to handle events from ALSA timer character + * device. + */ +void alsatimer_user_instance_create_source(ALSATimerUserInstance *self, + GSource **gsrc, GError **error) +{ + static GSourceFuncs funcs = { + .prepare = timer_user_instance_prepare_src, + .check = timer_user_instance_check_src, + .dispatch = timer_user_instance_dispatch_src, + .finalize = timer_user_instance_finalize_src, + }; + ALSATimerUserInstancePrivate *priv; + TimerUserInstanceSource *src; + long page_size = sysconf(_SC_PAGESIZE); + void *buf; + + g_return_if_fail(ALSATIMER_IS_USER_INSTANCE(self)); + priv = alsatimer_user_instance_get_instance_private(self); + + if (priv->fd < 0) { + generate_error(error, ENXIO); + return; + } + + buf = g_try_malloc0(page_size); + if (buf == NULL) { + generate_error(error, ENOMEM); + return; + } + + *gsrc = g_source_new(&funcs, sizeof(TimerUserInstanceSource)); + src = (TimerUserInstanceSource *)(*gsrc); + + g_source_set_name(*gsrc, "ALSATimerUserInstance"); + g_source_set_priority(*gsrc, G_PRIORITY_HIGH_IDLE); + g_source_set_can_recurse(*gsrc, TRUE); + + src->self = g_object_ref(self); + src->tag = g_source_add_unix_fd(*gsrc, priv->fd, G_IO_IN); + src->buf = buf; + src->buf_len = page_size; +} diff --git a/src/timer/user-instance.h b/src/timer/user-instance.h index 62fb659..3a21a0e 100644 --- a/src/timer/user-instance.h +++ b/src/timer/user-instance.h @@ -75,6 +75,9 @@ void alsatimer_user_instance_get_status(ALSATimerUserInstance *self, ALSATimerInstanceStatus **instance_status, GError **error); +void alsatimer_user_instance_create_source(ALSATimerUserInstance *self, + GSource **gsrc, GError **error); + G_END_DECLS #endif diff --git a/tests/alsatimer-user-instance b/tests/alsatimer-user-instance index 86a9a39..5f189e9 100644 --- a/tests/alsatimer-user-instance +++ b/tests/alsatimer-user-instance @@ -19,6 +19,7 @@ methods = ( 'get_info', 'set_params', 'get_status', + 'create_source', ) signals = ()