core/calendar-monitor: Replace signals by callbacks

This should save quite some resources when manipulating events.
Signals are relatively expensive, and 2 pointer chases are
definitely better than a global lock + FFI stashing + signal
manipulation.
This commit is contained in:
Georges Basile Stavracas Neto
2023-08-18 10:41:18 -03:00
parent ec840fbab9
commit 60223adc5c
3 changed files with 207 additions and 156 deletions
+64 -65
View File
@@ -59,6 +59,9 @@ struct _GcalCalendarMonitor
GcalCalendar *calendar;
gboolean complete;
const GcalCalendarMonitorListener *listener;
gpointer listener_user_data;
/*
* These fields are only accessed on the monitor thread, and
* never on the main thread.
@@ -88,14 +91,6 @@ static gboolean complete_in_idle_cb (gpointer
G_DEFINE_TYPE (GcalCalendarMonitor, gcal_calendar_monitor, G_TYPE_OBJECT)
enum
{
EVENT_ADDED,
EVENT_UPDATED,
EVENT_REMOVED,
N_SIGNALS,
};
enum
{
PROP_0,
@@ -104,7 +99,6 @@ enum
N_PROPS
};
static gulong signals[N_SIGNALS] = { 0, };
static GParamSpec *properties [N_PROPS] = { NULL, };
/*
@@ -957,6 +951,7 @@ remove_events_outside_range (GcalCalendarMonitor *self,
GcalRange *range)
{
g_autoptr (GRWLockWriterLocker) writer_locker = NULL;
g_autoptr (GPtrArray) events_to_remove = NULL;
GHashTableIter iter;
GcalEvent *event;
@@ -964,6 +959,9 @@ remove_events_outside_range (GcalCalendarMonitor *self,
writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock);
events_to_remove = g_ptr_array_new_full (g_hash_table_size (self->shared.events),
g_object_unref);
g_hash_table_iter_init (&iter, self->shared.events);
while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &event))
{
@@ -972,36 +970,28 @@ remove_events_outside_range (GcalCalendarMonitor *self,
if (gcal_range_calculate_overlap (range, event_range, NULL) != GCAL_RANGE_NO_OVERLAP)
continue;
g_object_ref (event);
g_hash_table_iter_remove (&iter);
g_signal_emit (self, signals[EVENT_REMOVED], 0, event);
g_object_unref (event);
g_ptr_array_add (events_to_remove, event);
g_hash_table_iter_steal (&iter);
}
if (events_to_remove->len > 0)
self->listener->remove_events (self, events_to_remove, self->listener_user_data);
}
static void
remove_all_events (GcalCalendarMonitor *self)
{
g_autoptr (GRWLockWriterLocker) writer_locker = NULL;
GHashTableIter iter;
GcalEvent *event;
g_autoptr (GPtrArray) events_to_remove = NULL;
GCAL_TRACE_MSG ("Removing all events from view");
writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock);
g_hash_table_iter_init (&iter, self->shared.events);
while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &event))
{
g_object_ref (event);
events_to_remove = g_hash_table_steal_all_values (self->shared.events);
g_hash_table_iter_remove (&iter);
g_signal_emit (self, signals[EVENT_REMOVED], 0, event);
g_object_unref (event);
}
if (events_to_remove->len > 0)
self->listener->remove_events (self, events_to_remove, self->listener_user_data);
}
static void
@@ -1026,6 +1016,7 @@ static gboolean
add_events_to_timeline_in_idle_cb (gpointer user_data)
{
g_autoptr (GRWLockWriterLocker) writer_locker = NULL;
g_autoptr (GPtrArray) events_to_add = NULL;
GcalCalendarMonitor *self;
GPtrArray *events;
IdleData *idle_data;
@@ -1037,6 +1028,8 @@ add_events_to_timeline_in_idle_cb (gpointer user_data)
events = idle_data->events;
g_assert (idle_data->event_ids == NULL);
events_to_add = g_ptr_array_sized_new (events->len);
writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock);
for (guint i = 0; i < events->len; i++)
{
@@ -1049,10 +1042,13 @@ add_events_to_timeline_in_idle_cb (gpointer user_data)
if (!g_hash_table_contains (self->shared.events, uid))
{
g_hash_table_insert (self->shared.events, g_strdup (uid), g_object_ref (event));
g_signal_emit (self, signals[EVENT_ADDED], 0, event);
g_ptr_array_add (events_to_add, event);
}
}
if (events_to_add->len > 0)
self->listener->add_events (self, events_to_add, self->listener_user_data);
GCAL_RETURN (G_SOURCE_REMOVE);
}
@@ -1060,6 +1056,8 @@ static gboolean
update_events_in_idle_cb (gpointer user_data)
{
g_autoptr (GRWLockWriterLocker) writer_locker = NULL;
g_autoptr (GPtrArray) old_events = NULL;
g_autoptr (GPtrArray) new_events = NULL;
g_autoptr (GPtrArray) events = NULL;
GcalCalendarMonitor *self;
IdleData *idle_data;
@@ -1071,26 +1069,36 @@ update_events_in_idle_cb (gpointer user_data)
events = g_steal_pointer (&idle_data->events);
g_assert (idle_data->event_ids == NULL);
old_events = g_ptr_array_new_full (events->len, g_object_unref);
new_events = g_ptr_array_sized_new (events->len);
writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock);
for (guint i = 0; i < events->len; i++)
{
g_autoptr (GcalEvent) old_event = NULL;
g_autofree gchar *old_event_id = NULL;
GcalEvent *event;
const gchar *event_id;
event = g_ptr_array_index (events, i);
event_id = gcal_event_get_uid (event);
old_event = g_hash_table_lookup (self->shared.events, event_id);
if (old_event)
if (g_hash_table_steal_extended (self->shared.events,
event_id,
(gpointer*) &old_event_id,
(gpointer*) &old_event))
{
g_object_ref (old_event);
g_hash_table_insert (self->shared.events, g_strdup (event_id), g_object_ref (event));
g_signal_emit (self, signals[EVENT_UPDATED], 0, old_event, event);
g_ptr_array_add (old_events, g_steal_pointer (&old_event));
g_ptr_array_add (new_events, event);
}
}
g_assert (old_events->len == new_events->len);
if (new_events->len > 0)
self->listener->update_events (self, old_events, new_events, self->listener_user_data);
GCAL_RETURN (G_SOURCE_REMOVE);
}
@@ -1098,6 +1106,7 @@ static gboolean
remove_events_from_timeline_in_idle_cb (gpointer user_data)
{
g_autoptr (GRWLockWriterLocker) writer_locker = NULL;
g_autoptr (GPtrArray) events_to_remove = NULL;
g_autoptr (GPtrArray) event_ids = NULL;
GcalCalendarMonitor *self;
IdleData *idle_data;
@@ -1109,6 +1118,8 @@ remove_events_from_timeline_in_idle_cb (gpointer user_data)
event_ids = g_steal_pointer (&idle_data->event_ids);
g_assert (idle_data->events == NULL);
events_to_remove = g_ptr_array_new_full (event_ids->len, g_object_unref);
writer_locker = g_rw_lock_writer_locker_new (&self->shared.lock);
for (guint i = 0; i < event_ids->len; i++)
@@ -1121,14 +1132,15 @@ remove_events_from_timeline_in_idle_cb (gpointer user_data)
if (event)
{
/* Keep the event alive until the signal is emitted */
g_object_ref (event);
/* Keep the event alive until the listener process it*/
g_ptr_array_add (events_to_remove, g_object_ref (event));
g_hash_table_remove (self->shared.events, event_id);
g_signal_emit (self, signals[EVENT_REMOVED], 0, event);
}
}
if (events_to_remove->len > 0)
self->listener->remove_events (self, events_to_remove, self->listener_user_data);
GCAL_RETURN (G_SOURCE_REMOVE);
}
@@ -1250,31 +1262,6 @@ gcal_calendar_monitor_class_init (GcalCalendarMonitorClass *klass)
object_class->get_property = gcal_calendar_monitor_get_property;
object_class->set_property = gcal_calendar_monitor_set_property;
signals[EVENT_ADDED] = g_signal_new ("event-added",
GCAL_TYPE_CALENDAR_MONITOR,
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE,
1,
GCAL_TYPE_EVENT);
signals[EVENT_UPDATED] = g_signal_new ("event-updated",
GCAL_TYPE_CALENDAR_MONITOR,
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE,
2,
GCAL_TYPE_EVENT,
GCAL_TYPE_EVENT);
signals[EVENT_REMOVED] = g_signal_new ("event-removed",
GCAL_TYPE_CALENDAR_MONITOR,
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE,
1,
GCAL_TYPE_EVENT);
properties[PROP_CALENDAR] = g_param_spec_object ("calendar",
"Calendar",
"Calendar to be monitored",
@@ -1304,11 +1291,23 @@ gcal_calendar_monitor_init (GcalCalendarMonitor *self)
}
GcalCalendarMonitor*
gcal_calendar_monitor_new (GcalCalendar *calendar)
gcal_calendar_monitor_new (GcalCalendar *calendar,
const GcalCalendarMonitorListener *listener,
gpointer user_data)
{
return g_object_new (GCAL_TYPE_CALENDAR_MONITOR,
"calendar", calendar,
NULL);
g_autoptr (GcalCalendarMonitor) monitor = NULL;
g_assert (calendar != NULL && GCAL_IS_CALENDAR (calendar));
g_assert (listener != NULL);
monitor = g_object_new (GCAL_TYPE_CALENDAR_MONITOR,
"calendar", calendar,
NULL);
monitor->listener = listener;
monitor->listener_user_data = user_data;
return g_steal_pointer (&monitor);
}
/**
+18 -1
View File
@@ -30,7 +30,24 @@ G_BEGIN_DECLS
#define GCAL_TYPE_CALENDAR_MONITOR (gcal_calendar_monitor_get_type())
G_DECLARE_FINAL_TYPE (GcalCalendarMonitor, gcal_calendar_monitor, GCAL, CALENDAR_MONITOR, GObject)
GcalCalendarMonitor* gcal_calendar_monitor_new (GcalCalendar *calendar);
typedef struct {
void (*add_events) (GcalCalendarMonitor *self,
GPtrArray *events,
gpointer user_data);
void (*update_events) (GcalCalendarMonitor *self,
GPtrArray *old_events,
GPtrArray *events,
gpointer user_data);
void (*remove_events) (GcalCalendarMonitor *self,
GPtrArray *events,
gpointer user_data);
} GcalCalendarMonitorListener;
GcalCalendarMonitor* gcal_calendar_monitor_new (GcalCalendar *calendar,
const GcalCalendarMonitorListener *listener,
gpointer user_data);
void gcal_calendar_monitor_set_range (GcalCalendarMonitor *self,
GcalRange *range);
+125 -90
View File
@@ -473,97 +473,135 @@ update_calendar_monitor_filters (GcalTimeline *self)
gcal_calendar_monitor_set_filter (monitor, self->filter);
}
/*
* GcalCalendarMonitorListener events
*/
static void
calendar_monitor_add_events_cb (GcalCalendarMonitor *monitor,
GPtrArray *events,
gpointer user_data)
{
GcalTimeline *self;
GCAL_ENTRY;
self = GCAL_TIMELINE (user_data);
for (guint i = 0; i < events->len; i++)
{
g_autoptr (GPtrArray) subscribers_at_range = NULL;
GcalRange *event_range;
GcalEvent *event;
event = g_ptr_array_index (events, i);
event_range = gcal_event_get_range (event);
/* Add to all subscribers within the event range */
subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range);
queue_event_data (self, ADD_EVENT, NULL, event, NULL, TRUE);
for (guint j = 0; subscribers_at_range && j < subscribers_at_range->len; j++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, j);
queue_event_data (self, ADD_EVENT, subscriber, event, NULL, FALSE);
}
}
GCAL_EXIT;
}
static void
calendar_monitor_update_events_cb (GcalCalendarMonitor *monitor,
GPtrArray *old_events,
GPtrArray *events,
gpointer user_data)
{
GcalTimeline *self;
GCAL_ENTRY;
g_assert (old_events->len == events->len);
self = GCAL_TIMELINE (user_data);
for (guint i = 0; i < events->len; i++)
{
g_autoptr (GPtrArray) subscribers_at_range = NULL;
GcalRange *event_range;
GcalEvent *old_event;
GcalEvent *event;
event = g_ptr_array_index (events, i);
old_event = g_ptr_array_index (old_events, i);
event_range = gcal_event_get_range (event);
/* Add to all subscribers within the event range */
subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range);
queue_event_data (self, UPDATE_EVENT, NULL, event, old_event, TRUE);
for (guint j = 0; subscribers_at_range && j < subscribers_at_range->len; j++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, j);
queue_event_data (self, UPDATE_EVENT, subscriber, event, old_event, FALSE);
}
}
GCAL_EXIT;
}
static void
calendar_monitor_remove_events_cb (GcalCalendarMonitor *monitor,
GPtrArray *events,
gpointer user_data)
{
GcalTimeline *self;
GCAL_ENTRY;
self = GCAL_TIMELINE (user_data);
for (guint i = 0; i < events->len; i++)
{
g_autoptr (GPtrArray) subscribers_at_range = NULL;
GcalRange *event_range;
GcalEvent *event;
event = g_ptr_array_index (events, i);
event_range = gcal_event_get_range (event);
/* Add to all subscribers within the event range */
subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range);
for (guint j = 0; subscribers_at_range && j < subscribers_at_range->len; j++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, j);
queue_event_data (self, REMOVE_EVENT, subscriber, event, NULL, FALSE);
}
queue_event_data (self, REMOVE_EVENT, NULL, event, NULL, TRUE);
}
GCAL_EXIT;
}
static const GcalCalendarMonitorListener monitor_listener = {
calendar_monitor_add_events_cb,
calendar_monitor_update_events_cb,
calendar_monitor_remove_events_cb,
};
/*
* Callbacks
*/
static void
on_calendar_monitor_event_added_cb (GcalCalendarMonitor *monitor,
GcalEvent *event,
GcalTimeline *self)
{
g_autoptr (GPtrArray) subscribers_at_range = NULL;
GcalRange *event_range;
gint i;
GCAL_ENTRY;
event_range = gcal_event_get_range (event);
/* Add to all subscribers within the event range */
subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range);
queue_event_data (self, ADD_EVENT, NULL, event, NULL, TRUE);
for (i = 0; subscribers_at_range && i < subscribers_at_range->len; i++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, i);
queue_event_data (self, ADD_EVENT, subscriber, event, NULL, FALSE);
}
GCAL_EXIT;
}
static void
on_calendar_monitor_event_updated_cb (GcalCalendarMonitor *monitor,
GcalEvent *old_event,
GcalEvent *event,
GcalTimeline *self)
{
g_autoptr (GPtrArray) subscribers_at_range = NULL;
GcalRange *event_range;
gint i;
GCAL_ENTRY;
/* Add the updated event to the (potentially new) range */
event_range = gcal_event_get_range (event);
/* Add to all subscribers within the event range */
subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range);
queue_event_data (self, UPDATE_EVENT, NULL, event, old_event, TRUE);
for (i = 0; subscribers_at_range && i < subscribers_at_range->len; i++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, i);
queue_event_data (self, UPDATE_EVENT, subscriber, event, old_event, FALSE);
}
GCAL_EXIT;
}
static void
on_calendar_monitor_event_removed_cb (GcalCalendarMonitor *monitor,
GcalEvent *event,
GcalTimeline *self)
{
g_autoptr (GPtrArray) subscribers_at_range = NULL;
GcalRange *event_range;
gint i;
GCAL_ENTRY;
event_range = gcal_event_get_range (event);
/* Add to all subscribers within the event range */
subscribers_at_range = gcal_range_tree_get_data_at_range (self->subscriber_ranges, event_range);
for (i = 0; subscribers_at_range && i < subscribers_at_range->len; i++)
{
GcalTimelineSubscriber *subscriber = g_ptr_array_index (subscribers_at_range, i);
queue_event_data (self, REMOVE_EVENT, subscriber, event, NULL, FALSE);
}
queue_event_data (self, REMOVE_EVENT, NULL, event, NULL, TRUE);
GCAL_EXIT;
}
static void
on_calendar_monitor_completed_cb (GcalCalendarMonitor *monitor,
GParamSpec *pspec,
@@ -933,10 +971,7 @@ gcal_timeline_add_calendar (GcalTimeline *self,
GCAL_TRACE_MSG ("Adding calendar '%s' to timeline %p", gcal_calendar_get_name (calendar), self);
monitor = gcal_calendar_monitor_new (calendar);
g_signal_connect (monitor, "event-added", G_CALLBACK (on_calendar_monitor_event_added_cb), self);
g_signal_connect (monitor, "event-updated", G_CALLBACK (on_calendar_monitor_event_updated_cb), self);
g_signal_connect (monitor, "event-removed", G_CALLBACK (on_calendar_monitor_event_removed_cb), self);
monitor = gcal_calendar_monitor_new (calendar, &monitor_listener, self);
g_signal_connect (monitor, "notify::complete", G_CALLBACK (on_calendar_monitor_completed_cb), self);
g_hash_table_insert (self->calendars, calendar, g_object_ref (monitor));