]> git.alsa-project.org Git - alsa-gobject.git/commitdiff
timer: user_instance: add an API to create GSource to dispatch event
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Sun, 9 Feb 2020 03:20:53 +0000 (12:20 +0900)
committer坂本 貴史 <o-takashi@sakamocchi.jp>
Tue, 11 Feb 2020 04:28:18 +0000 (13:28 +0900)
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
src/timer/alsatimer.map
src/timer/user-instance.c
src/timer/user-instance.h
tests/alsatimer-user-instance

index c02c8092c1a7ca2cc97b4d74c6a1477e8b545cfb..030945a0e5309a3d25351a33f9fd045cee0c5172 100644 (file)
@@ -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";
 
index f5ff2c1d3ccaa6a25cf33a4f7df9a8c7e7ae187d..daf30f5e68e9d487e2a1c3e1a40cd60a821528c4 100644 (file)
@@ -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;
+}
index 62fb6596d9cf6d8ca603103250e79d89dcff9f08..3a21a0eaceaca0fc95ac0a73c049f333deb161bc 100644 (file)
@@ -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
index 86a9a399946874981d43aa52c470da1d9269eab3..5f189e94ef22aa7aa70ce7c967243c9e9b8f42c2 100644 (file)
@@ -19,6 +19,7 @@ methods = (
     'get_info',
     'set_params',
     'get_status',
+    'create_source',
 )
 signals = ()