};
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);
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;
+}