diff --git a/lib/wp/event-dispatcher.c b/lib/wp/event-dispatcher.c index a069b090..6a290512 100644 --- a/lib/wp/event-dispatcher.c +++ b/lib/wp/event-dispatcher.c @@ -200,6 +200,7 @@ void wp_event_stop_processing (WpEvent * self) { g_return_if_fail (self != NULL); + wp_debug ("stopping event(%s)", self->name); g_cancellable_cancel (self->cancellable); } @@ -250,6 +251,9 @@ on_event_hook_done (WpEventHook * hook, GAsyncResult * res, WpEvent * event) error->domain != G_IO_ERROR && error->code != G_IO_ERROR_CANCELLED) wp_message_object (hook, "failed: %s", error->message); + if (dispatcher->rescan_event == event) + wp_event_hook_set_event (event->current_hook_in_async, NULL); + g_clear_object (&event->current_hook_in_async); spa_system_eventfd_write (dispatcher->system, dispatcher->eventfd, 1); } @@ -284,8 +288,10 @@ wp_event_source_dispatch (GSource * s, GSourceFunc callback, gpointer user_data) return G_SOURCE_CONTINUE; /* remove the remaining hooks if the event was cancelled */ - if (g_cancellable_is_cancelled (event->cancellable) && event->hooks) + if (g_cancellable_is_cancelled (event->cancellable) && event->hooks) { + wp_debug_object (d, "event(%s) cancelled remove it", event->name); g_list_free_full (g_steal_pointer (&event->hooks), g_object_unref); + } /* avoid duplicate entries in chain */ if (!d->events_chain || !strstr (d->events_chain, event->name)) { @@ -300,6 +306,7 @@ wp_event_source_dispatch (GSource * s, GSourceFunc callback, gpointer user_data) if (lhook) { gchar *name = NULL; gint priority; + event->current_hook_in_async = WP_EVENT_HOOK (lhook->data); event->hooks = g_list_delete_link (event->hooks, g_steal_pointer (&lhook)); name = wp_event_hook_get_name (event->current_hook_in_async); @@ -309,8 +316,22 @@ wp_event_source_dispatch (GSource * s, GSourceFunc callback, gpointer user_data) wp_debug_object (d, "running hook <%p>(%s) and hooks chain (%s)", event->current_hook_in_async, name, event->hooks_chain); - /* execute the hook, possibly async */ - wp_event_hook_run (event->current_hook_in_async, event, + if (event == d->rescan_event) { + WpEvent *hook_event = + wp_event_hook_get_event (event->current_hook_in_async); + + /* for after-events, check if the corresponding event is cancelled */ + if (g_cancellable_is_cancelled (hook_event->cancellable)) + wp_debug_object (d, "remove hook(%s) as its trigger event(%s)" + " is cancelled", name, hook_event->name); + else + wp_event_hook_run (event->current_hook_in_async, hook_event, + event->cancellable, (GAsyncReadyCallback) on_event_hook_done, + event); + } + else + /* execute the hook, possibly async */ + wp_event_hook_run (event->current_hook_in_async, event, event->cancellable, (GAsyncReadyCallback) on_event_hook_done, event); } @@ -480,7 +501,9 @@ wp_event_dispatcher_push_event (WpEventDispatcher * self, WpEvent * event) self->rescan_event->hooks, g_object_ref (hook), (GCompareFunc) hook_cmp_func); wp_debug_object (self, "added rescan hook <%p>(%s(%d))", hook, - wp_event_hook_get_name (hook), wp_event_hook_get_priority (hook)); + wp_event_hook_get_name (hook), wp_event_hook_get_priority (hook)); + + wp_event_hook_set_event (hook, event); rescan_hooks_added = true; } } diff --git a/lib/wp/event-hook.c b/lib/wp/event-hook.c index cb17f5e6..9859f5e3 100644 --- a/lib/wp/event-hook.c +++ b/lib/wp/event-hook.c @@ -21,6 +21,8 @@ struct _WpEventHookPrivate WpEventHookExecType exec_type; GWeakRef dispatcher; gchar *name; + /* event triggering the hook, useful for after-events. */ + WpEvent *event_trigger; }; enum { @@ -47,6 +49,7 @@ wp_event_hook_finalize (GObject * object) WpEventHookPrivate *priv = wp_event_hook_get_instance_private (self); g_weak_ref_clear (&priv->dispatcher); + g_clear_pointer (&priv->event_trigger, wp_event_unref); g_free (priv->name); G_OBJECT_CLASS (wp_event_hook_parent_class)->finalize (object); @@ -130,6 +133,38 @@ wp_event_hook_class_init (WpEventHookClass * klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } +/*! + * \brief Returns the event triggering the hook, this data is useful for + * after-events. + * + * \ingroup wpeventhook + * \param self the event hook + * \returns (transfer none) (nullable): the event + */ +WpEvent * +wp_event_hook_get_event (WpEventHook *self) +{ + g_return_val_if_fail (WP_IS_EVENT_HOOK (self), 0); + WpEventHookPrivate *priv = wp_event_hook_get_instance_private (self); + return priv->event_trigger; +} + +/*! + * \brief Sets the event triggering the hook + * + * \ingroup wpeventhook + * \param self the event hook + * \param event (transfer none) (nullable):the event associated with the hook + */ +void +wp_event_hook_set_event (WpEventHook *self, WpEvent *event) +{ + WpEventHookPrivate *priv = wp_event_hook_get_instance_private (self); + g_clear_pointer (&priv->event_trigger, wp_event_unref); + if (event) + priv->event_trigger = wp_event_ref (event); +} + /*! * \brief Returns the priority of the hook * @@ -191,6 +226,14 @@ wp_event_hook_get_dispatcher (WpEventHook * self) return g_weak_ref_get (&priv->dispatcher); } +/*! + * \brief Sets the dispatcher to the hook + * + * \ingroup wpeventhook + * \param self the event hook + * \param dispatcher (transfer none) (nullable) dispatcher to which the hook is + * to be registered. + */ void wp_event_hook_set_dispatcher (WpEventHook * self, WpEventDispatcher * dispatcher) { diff --git a/lib/wp/event-hook.h b/lib/wp/event-hook.h index 9f963fd4..2d8b925f 100644 --- a/lib/wp/event-hook.h +++ b/lib/wp/event-hook.h @@ -29,8 +29,15 @@ typedef enum { WP_EVENT_HOOK_DEFAULT_PRIORITY_BASE = 0, - WP_EVENT_HOOK_DEFAULT_PRIORITY_RESCAN_POLICY = WP_EVENT_HOOK_DEFAULT_PRIORITY_BASE, - WP_EVENT_HOOK_DEFAULT_PRIORITY_AFTER_EVENTS_DEFAULT_NODES_STATE_SAVE = WP_EVENT_HOOK_DEFAULT_PRIORITY_RESCAN_POLICY + PRIORITY_STEP, WP_EVENT_HOOK_DEFAULT_PRIORITY_RESCAN_DEFAULT_NODES = WP_EVENT_HOOK_DEFAULT_PRIORITY_AFTER_EVENTS_DEFAULT_NODES_STATE_SAVE + PRIORITY_STEP, + WP_EVENT_HOOK_DEFAULT_PRIORITY_FIND_DEFINED_TARGET = WP_EVENT_HOOK_DEFAULT_PRIORITY_BASE, + WP_EVENT_HOOK_DEFAULT_PRIORITY_FIND_UNDEFINED_TARGET = WP_EVENT_HOOK_DEFAULT_PRIORITY_FIND_DEFINED_TARGET + PRIORITY_STEP, + WP_EVENT_HOOK_DEFAULT_PRIORITY_FIND_BEST_TARGET = WP_EVENT_HOOK_DEFAULT_PRIORITY_FIND_UNDEFINED_TARGET + PRIORITY_STEP, + WP_EVENT_HOOK_DEFAULT_PRIORITY_PREPARE_LINK = WP_EVENT_HOOK_DEFAULT_PRIORITY_FIND_BEST_TARGET + PRIORITY_STEP, + WP_EVENT_HOOK_DEFAULT_PRIORITY_CREATE_LINK = WP_EVENT_HOOK_DEFAULT_PRIORITY_PREPARE_LINK + PRIORITY_STEP, + + WP_EVENT_HOOK_DEFAULT_PRIORITY_RESCAN_POLICY = WP_EVENT_HOOK_DEFAULT_PRIORITY_CREATE_LINK + PRIORITY_STEP, + WP_EVENT_HOOK_DEFAULT_PRIORITY_AFTER_EVENTS_DEFAULT_NODES_STATE_SAVE = WP_EVENT_HOOK_DEFAULT_PRIORITY_RESCAN_POLICY + PRIORITY_STEP, + WP_EVENT_HOOK_DEFAULT_PRIORITY_RESCAN_DEFAULT_NODES = WP_EVENT_HOOK_DEFAULT_PRIORITY_AFTER_EVENTS_DEFAULT_NODES_STATE_SAVE + PRIORITY_STEP, WP_EVENT_HOOK_DEFAULT_PRIORITY_NODE_ADDED = WP_EVENT_HOOK_DEFAULT_PRIORITY_RESCAN_POLICY + PRIORITY_JUMP, WP_EVENT_HOOK_DEFAULT_PRIORITY_NODE_ADDED_RESTORE_STREAM = WP_EVENT_HOOK_DEFAULT_PRIORITY_NODE_ADDED, @@ -120,6 +127,12 @@ WP_PRIVATE_API void wp_event_hook_set_dispatcher (WpEventHook * self, WpEventDispatcher * dispatcher); +WP_API +void wp_event_hook_set_event (WpEventHook *self, WpEvent *event); + +WP_API +WpEvent *wp_event_hook_get_event (WpEventHook *self); + WP_API gboolean wp_event_hook_runs_for_event (WpEventHook * self, WpEvent * event); diff --git a/tests/wp/events.c b/tests/wp/events.c index 1e04b4cd..6ae420b9 100644 --- a/tests/wp/events.c +++ b/tests/wp/events.c @@ -12,6 +12,7 @@ typedef struct { WpBaseTestFixture base; WpObjectManager *om; GPtrArray *hooks_executed; + GPtrArray *events; WpTransition *transition; } TestFixture; @@ -20,6 +21,7 @@ test_events_setup (TestFixture *self, gconstpointer user_data) { wp_base_test_fixture_setup (&self->base, 0); self->hooks_executed = g_ptr_array_new (); + self->events = g_ptr_array_new (); } static void @@ -35,6 +37,7 @@ test_events_teardown (TestFixture *self, gconstpointer user_data) { \ g_debug ("in hook_" #x); \ g_ptr_array_add (self->hooks_executed, hook_##x); \ + g_ptr_array_add (self->events, event); \ } HOOK_FUNC(a) @@ -47,6 +50,7 @@ hook_quit (WpEvent * event, TestFixture * self) { g_debug ("in hook_quit"); g_ptr_array_add (self->hooks_executed, hook_quit); + g_ptr_array_add (self->events, event); g_main_loop_quit (self->base.loop); } @@ -55,6 +59,7 @@ test_events_basic (TestFixture * self, gconstpointer user_data) { g_autoptr (WpEventDispatcher) dispatcher = NULL; g_autoptr (WpEventHook) hook = NULL; + WpEvent *event1 = NULL, *event2 = NULL; dispatcher = wp_event_dispatcher_get_instance (self->base.core); g_assert_nonnull (dispatcher); @@ -101,37 +106,73 @@ test_events_basic (TestFixture * self, gconstpointer user_data) wp_event_dispatcher_register_hook (dispatcher, hook); g_clear_object (&hook); - /* first event */ - wp_event_dispatcher_push_event (dispatcher, - wp_event_new ("type1", 10, NULL, NULL, NULL)); + /* first event run */ + event1 = wp_event_new ("type1", 10, NULL, NULL, NULL); + wp_event_dispatcher_push_event (dispatcher, event1); g_assert_cmpint (self->hooks_executed->len, ==, 0); g_main_loop_run (self->base.loop); g_assert_cmpint (self->hooks_executed->len, ==, 4); g_assert (hook_c == self->hooks_executed->pdata[0]); + g_assert (event1 == self->events->pdata[0]); g_assert (hook_a == self->hooks_executed->pdata[1]); - g_assert (hook_b == self->hooks_executed->pdata[2]); - g_assert (hook_quit == self->hooks_executed->pdata[3]); + g_assert (event1 == self->events->pdata [1]); + g_assert (hook_b == self->hooks_executed->pdata [2]); + g_assert (event1 == self->events->pdata [2]); + g_assert (hook_quit == self->hooks_executed->pdata [3]); + g_assert (event1 == self->events->pdata [3]); g_ptr_array_remove_range (self->hooks_executed, 0, self->hooks_executed->len); g_assert_cmpint (self->hooks_executed->len, ==, 0); + g_ptr_array_remove_range (self->events, 0, self->events->len); + g_assert_cmpint (self->events->len, == , 0); - /* second event */ - wp_event_dispatcher_push_event (dispatcher, - wp_event_new ("type1", 10, - wp_properties_new ("test.prop", "some-val", NULL), NULL, NULL)); - wp_event_dispatcher_push_event (dispatcher, - wp_event_new ("type2", 100, - wp_properties_new ("test.prop", "some-val", NULL), NULL, NULL)); + /* second event run */ + event1 = wp_event_new ("type1", 10, + wp_properties_new ("test.prop", "some-val", NULL), NULL, NULL); + event2 = wp_event_new ("type2", 100, + wp_properties_new ("test.prop", "some-val", NULL), NULL, NULL); + + wp_event_dispatcher_push_event (dispatcher, event1); + wp_event_dispatcher_push_event (dispatcher, event2); g_assert_cmpint (self->hooks_executed->len, ==, 0); g_main_loop_run (self->base.loop); g_assert_cmpint (self->hooks_executed->len, ==, 5); - g_assert (hook_d == self->hooks_executed->pdata[0]); - g_assert (hook_c == self->hooks_executed->pdata[1]); - g_assert (hook_a == self->hooks_executed->pdata[2]); - g_assert (hook_b == self->hooks_executed->pdata[3]); - g_assert (hook_quit == self->hooks_executed->pdata[4]); + g_assert (hook_d == self->hooks_executed->pdata [0]); + g_assert (event2 == self->events->pdata [0]); + g_assert (hook_c == self->hooks_executed->pdata [1]); + g_assert (event1 == self->events->pdata [1]); + g_assert (hook_a == self->hooks_executed->pdata [2]); + g_assert (event1 == self->events->pdata [2]); + g_assert (hook_b == self->hooks_executed->pdata [3]); + g_assert (event1 == self->events->pdata [3]); + g_assert (hook_quit == self->hooks_executed->pdata [4]); + g_assert (event1 == self->events->pdata [4]); + + g_ptr_array_remove_range (self->hooks_executed, 0, self->hooks_executed->len); + g_assert_cmpint (self->hooks_executed->len, == , 0); + g_ptr_array_remove_range (self->events, 0, self->events->len); + g_assert_cmpint (self->events->len, == , 0); + + + /* thrid event run to test event cancellation */ + event1 = wp_event_new ("type1", 10, + wp_properties_new ("test.prop", "some-val", NULL), NULL, NULL); + event2 = wp_event_new ("type2", 100, + wp_properties_new ("test.prop", "some-val", NULL), NULL, NULL); + + wp_event_dispatcher_push_event (dispatcher, event2); + wp_event_dispatcher_push_event (dispatcher, event1); + wp_event_stop_processing (event1); + + g_assert_cmpint (self->hooks_executed->len, == , 0); + g_main_loop_run (self->base.loop); + g_assert_cmpint (self->hooks_executed->len, == , 2); + g_assert (hook_d == self->hooks_executed->pdata [0]); + g_assert (event2 == self->events->pdata [0]); + g_assert (hook_quit == self->hooks_executed->pdata [1]); + g_assert (event2 == self->events->pdata [1]); } enum {