gmain: Avoid some lock/unlock dance during g_main_context_iterate

A context iteration we're doing lots of lock/unlocks and that's fine to give
other threads contexts a chance to run, but we're doing it also just to call
other functions that require locking, and this can be avoided.

Other threads can still have a chance to run while releasing the ownership
of the context.
This commit is contained in:
Marco Trevisan (Treviño) 2023-01-25 19:46:10 +01:00
parent fe2de360de
commit e7c2ead41b

View File

@ -446,11 +446,25 @@ static void g_source_set_priority_unlocked (GSource *source,
static void g_child_source_remove_internal (GSource *child_source, static void g_child_source_remove_internal (GSource *child_source,
GMainContext *context); GMainContext *context);
static void g_main_context_poll (GMainContext *context, static gboolean g_main_context_acquire_unlocked (GMainContext *context);
gint timeout, static void g_main_context_release_unlocked (GMainContext *context);
gint priority, static gboolean g_main_context_prepare_unlocked (GMainContext *context,
GPollFD *fds, gint *priority);
gint n_fds); static gint g_main_context_query_unlocked (GMainContext *context,
gint max_priority,
gint *timeout,
GPollFD *fds,
gint n_fds);
static gboolean g_main_context_check_unlocked (GMainContext *context,
gint max_priority,
GPollFD *fds,
gint n_fds);
static void g_main_context_dispatch_unlocked (GMainContext *context);
static void g_main_context_poll_unlocked (GMainContext *context,
int timeout,
int priority,
GPollFD *fds,
int n_fds);
static void g_main_context_add_poll_unlocked (GMainContext *context, static void g_main_context_add_poll_unlocked (GMainContext *context,
gint priority, gint priority,
GPollFD *fd); GPollFD *fd);
@ -3523,13 +3537,24 @@ gboolean
g_main_context_acquire (GMainContext *context) g_main_context_acquire (GMainContext *context)
{ {
gboolean result = FALSE; gboolean result = FALSE;
GThread *self = G_THREAD_SELF;
if (context == NULL) if (context == NULL)
context = g_main_context_default (); context = g_main_context_default ();
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
result = g_main_context_acquire_unlocked (context);
UNLOCK_CONTEXT (context);
return result;
}
static gboolean
g_main_context_acquire_unlocked (GMainContext *context)
{
GThread *self = G_THREAD_SELF;
if (!context->owner) if (!context->owner)
{ {
context->owner = self; context->owner = self;
@ -3540,16 +3565,13 @@ g_main_context_acquire (GMainContext *context)
if (context->owner == self) if (context->owner == self)
{ {
context->owner_count++; context->owner_count++;
result = TRUE; return TRUE;
} }
else else
{ {
TRACE (GLIB_MAIN_CONTEXT_ACQUIRE (context, FALSE /* failure */)); TRACE (GLIB_MAIN_CONTEXT_ACQUIRE (context, FALSE /* failure */));
return FALSE;
} }
UNLOCK_CONTEXT (context);
return result;
} }
/** /**
@ -3570,6 +3592,14 @@ g_main_context_release (GMainContext *context)
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
g_main_context_release_unlocked (context);
UNLOCK_CONTEXT (context);
}
static void
g_main_context_release_unlocked (GMainContext *context)
{
context->owner_count--; context->owner_count--;
if (context->owner_count == 0) if (context->owner_count == 0)
{ {
@ -3592,8 +3622,6 @@ g_main_context_release (GMainContext *context)
g_mutex_unlock (waiter->mutex); g_mutex_unlock (waiter->mutex);
} }
} }
UNLOCK_CONTEXT (context);
} }
static gboolean static gboolean
@ -3706,24 +3734,36 @@ gboolean
g_main_context_prepare (GMainContext *context, g_main_context_prepare (GMainContext *context,
gint *priority) gint *priority)
{ {
guint i; gboolean ready;
gint n_ready = 0;
gint current_priority = G_MAXINT;
GSource *source;
GSourceIter iter;
if (context == NULL) if (context == NULL)
context = g_main_context_default (); context = g_main_context_default ();
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
ready = g_main_context_prepare_unlocked (context, priority);
UNLOCK_CONTEXT (context);
return ready;
}
static gboolean
g_main_context_prepare_unlocked (GMainContext *context,
gint *priority)
{
guint i;
gint n_ready = 0;
gint current_priority = G_MAXINT;
GSource *source;
GSourceIter iter;
context->time_is_fresh = FALSE; context->time_is_fresh = FALSE;
if (context->in_check_or_prepare) if (context->in_check_or_prepare)
{ {
g_warning ("g_main_context_prepare() called recursively from within a source's check() or " g_warning ("g_main_context_prepare() called recursively from within a source's check() or "
"prepare() member."); "prepare() member.");
UNLOCK_CONTEXT (context);
return FALSE; return FALSE;
} }
@ -3736,7 +3776,6 @@ g_main_context_prepare (GMainContext *context,
if (dispatch) if (dispatch)
g_main_dispatch (context, &current_time); g_main_dispatch (context, &current_time);
UNLOCK_CONTEXT (context);
return TRUE; return TRUE;
} }
#endif #endif
@ -3854,8 +3893,6 @@ g_main_context_prepare (GMainContext *context,
g_source_iter_clear (&iter); g_source_iter_clear (&iter);
TRACE (GLIB_MAIN_CONTEXT_AFTER_PREPARE (context, current_priority, n_ready)); TRACE (GLIB_MAIN_CONTEXT_AFTER_PREPARE (context, current_priority, n_ready));
UNLOCK_CONTEXT (context);
if (priority) if (priority)
*priority = current_priority; *priority = current_priority;
@ -3893,14 +3930,30 @@ g_main_context_query (GMainContext *context,
gint n_fds) gint n_fds)
{ {
gint n_poll; gint n_poll;
GPollRec *pollrec, *lastpollrec;
gushort events;
if (context == NULL) if (context == NULL)
context = g_main_context_default (); context = g_main_context_default ();
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
n_poll = g_main_context_query_unlocked (context, max_priority, timeout, fds, n_fds);
UNLOCK_CONTEXT (context);
return n_poll;
}
static gint
g_main_context_query_unlocked (GMainContext *context,
gint max_priority,
gint *timeout,
GPollFD *fds,
gint n_fds)
{
gint n_poll;
GPollRec *pollrec, *lastpollrec;
gushort events;
TRACE (GLIB_MAIN_CONTEXT_BEFORE_QUERY (context, max_priority)); TRACE (GLIB_MAIN_CONTEXT_BEFORE_QUERY (context, max_priority));
/* fds is filled sequentially from poll_records. Since poll_records /* fds is filled sequentially from poll_records. Since poll_records
@ -3957,8 +4010,6 @@ g_main_context_query (GMainContext *context,
TRACE (GLIB_MAIN_CONTEXT_AFTER_QUERY (context, context->timeout, TRACE (GLIB_MAIN_CONTEXT_AFTER_QUERY (context, context->timeout,
fds, n_poll)); fds, n_poll));
UNLOCK_CONTEXT (context);
return n_poll; return n_poll;
} }
@ -3989,6 +4040,23 @@ g_main_context_check (GMainContext *context,
gint max_priority, gint max_priority,
GPollFD *fds, GPollFD *fds,
gint n_fds) gint n_fds)
{
gboolean ready;
LOCK_CONTEXT (context);
ready = g_main_context_check_unlocked (context, max_priority, fds, n_fds);
UNLOCK_CONTEXT (context);
return ready;
}
static gboolean
g_main_context_check_unlocked (GMainContext *context,
gint max_priority,
GPollFD *fds,
gint n_fds)
{ {
GSource *source; GSource *source;
GSourceIter iter; GSourceIter iter;
@ -3999,13 +4067,10 @@ g_main_context_check (GMainContext *context,
if (context == NULL) if (context == NULL)
context = g_main_context_default (); context = g_main_context_default ();
LOCK_CONTEXT (context);
if (context->in_check_or_prepare) if (context->in_check_or_prepare)
{ {
g_warning ("g_main_context_check() called recursively from within a source's check() or " g_warning ("g_main_context_check() called recursively from within a source's check() or "
"prepare() member."); "prepare() member.");
UNLOCK_CONTEXT (context);
return FALSE; return FALSE;
} }
@ -4031,7 +4096,6 @@ g_main_context_check (GMainContext *context,
{ {
TRACE (GLIB_MAIN_CONTEXT_AFTER_CHECK (context, 0)); TRACE (GLIB_MAIN_CONTEXT_AFTER_CHECK (context, 0));
UNLOCK_CONTEXT (context);
return FALSE; return FALSE;
} }
@ -4167,8 +4231,6 @@ g_main_context_check (GMainContext *context,
TRACE (GLIB_MAIN_CONTEXT_AFTER_CHECK (context, n_ready)); TRACE (GLIB_MAIN_CONTEXT_AFTER_CHECK (context, n_ready));
UNLOCK_CONTEXT (context);
return n_ready > 0; return n_ready > 0;
} }
@ -4193,6 +4255,14 @@ g_main_context_dispatch (GMainContext *context)
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
g_main_context_dispatch_unlocked (context);
UNLOCK_CONTEXT (context);
}
static void
g_main_context_dispatch_unlocked (GMainContext *context)
{
TRACE (GLIB_MAIN_CONTEXT_BEFORE_DISPATCH (context)); TRACE (GLIB_MAIN_CONTEXT_BEFORE_DISPATCH (context));
if (context->pending_dispatches->len > 0) if (context->pending_dispatches->len > 0)
@ -4201,16 +4271,14 @@ g_main_context_dispatch (GMainContext *context)
} }
TRACE (GLIB_MAIN_CONTEXT_AFTER_DISPATCH (context)); TRACE (GLIB_MAIN_CONTEXT_AFTER_DISPATCH (context));
UNLOCK_CONTEXT (context);
} }
/* HOLDS context lock */ /* HOLDS context lock */
static gboolean static gboolean
g_main_context_iterate (GMainContext *context, g_main_context_iterate_unlocked (GMainContext *context,
gboolean block, gboolean block,
gboolean dispatch, gboolean dispatch,
GThread *self) GThread *self)
{ {
gint max_priority = 0; gint max_priority = 0;
gint timeout; gint timeout;
@ -4219,16 +4287,12 @@ g_main_context_iterate (GMainContext *context,
GPollFD *fds = NULL; GPollFD *fds = NULL;
gint64 begin_time_nsec G_GNUC_UNUSED; gint64 begin_time_nsec G_GNUC_UNUSED;
UNLOCK_CONTEXT (context);
begin_time_nsec = G_TRACE_CURRENT_TIME; begin_time_nsec = G_TRACE_CURRENT_TIME;
if (!g_main_context_acquire (context)) if (!g_main_context_acquire_unlocked (context))
{ {
gboolean got_ownership; gboolean got_ownership;
LOCK_CONTEXT (context);
if (!block) if (!block)
return FALSE; return FALSE;
@ -4239,8 +4303,6 @@ g_main_context_iterate (GMainContext *context,
if (!got_ownership) if (!got_ownership)
return FALSE; return FALSE;
} }
else
LOCK_CONTEXT (context);
if (!context->cached_poll_array) if (!context->cached_poll_array)
{ {
@ -4251,38 +4313,33 @@ g_main_context_iterate (GMainContext *context,
allocated_nfds = context->cached_poll_array_size; allocated_nfds = context->cached_poll_array_size;
fds = context->cached_poll_array; fds = context->cached_poll_array;
UNLOCK_CONTEXT (context); g_main_context_prepare_unlocked (context, &max_priority);
g_main_context_prepare (context, &max_priority);
while ((nfds = g_main_context_query (context, max_priority, &timeout, fds, while ((nfds = g_main_context_query_unlocked (
allocated_nfds)) > allocated_nfds) context, max_priority, &timeout, fds,
allocated_nfds)) > allocated_nfds)
{ {
LOCK_CONTEXT (context);
g_free (fds); g_free (fds);
context->cached_poll_array_size = allocated_nfds = nfds; context->cached_poll_array_size = allocated_nfds = nfds;
context->cached_poll_array = fds = g_new (GPollFD, nfds); context->cached_poll_array = fds = g_new (GPollFD, nfds);
UNLOCK_CONTEXT (context);
} }
if (!block) if (!block)
timeout = 0; timeout = 0;
g_main_context_poll (context, timeout, max_priority, fds, nfds); g_main_context_poll_unlocked (context, timeout, max_priority, fds, nfds);
some_ready = g_main_context_check (context, max_priority, fds, nfds); some_ready = g_main_context_check_unlocked (context, max_priority, fds, nfds);
if (dispatch) if (dispatch)
g_main_context_dispatch (context); g_main_context_dispatch_unlocked (context);
g_main_context_release (context); g_main_context_release_unlocked (context);
g_trace_mark (begin_time_nsec, G_TRACE_CURRENT_TIME - begin_time_nsec, g_trace_mark (begin_time_nsec, G_TRACE_CURRENT_TIME - begin_time_nsec,
"GLib", "g_main_context_iterate", "GLib", "g_main_context_iterate",
"Context %p, %s ⇒ %s", context, block ? "blocking" : "non-blocking", some_ready ? "dispatched" : "nothing"); "Context %p, %s ⇒ %s", context, block ? "blocking" : "non-blocking", some_ready ? "dispatched" : "nothing");
LOCK_CONTEXT (context);
return some_ready; return some_ready;
} }
@ -4304,7 +4361,7 @@ g_main_context_pending (GMainContext *context)
context = g_main_context_default(); context = g_main_context_default();
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
retval = g_main_context_iterate (context, FALSE, FALSE, G_THREAD_SELF); retval = g_main_context_iterate_unlocked (context, FALSE, FALSE, G_THREAD_SELF);
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);
return retval; return retval;
@ -4340,7 +4397,7 @@ g_main_context_iteration (GMainContext *context, gboolean may_block)
context = g_main_context_default(); context = g_main_context_default();
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
retval = g_main_context_iterate (context, may_block, TRUE, G_THREAD_SELF); retval = g_main_context_iterate_unlocked (context, may_block, TRUE, G_THREAD_SELF);
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);
return retval; return retval;
@ -4476,7 +4533,7 @@ g_main_loop_run (GMainLoop *loop)
g_atomic_int_set (&loop->is_running, TRUE); g_atomic_int_set (&loop->is_running, TRUE);
while (g_atomic_int_get (&loop->is_running)) while (g_atomic_int_get (&loop->is_running))
g_main_context_iterate (loop->context, TRUE, TRUE, self); g_main_context_iterate_unlocked (loop->context, TRUE, TRUE, self);
UNLOCK_CONTEXT (loop->context); UNLOCK_CONTEXT (loop->context);
@ -4548,11 +4605,11 @@ g_main_loop_get_context (GMainLoop *loop)
/* HOLDS: context's lock */ /* HOLDS: context's lock */
static void static void
g_main_context_poll (GMainContext *context, g_main_context_poll_unlocked (GMainContext *context,
gint timeout, int timeout,
gint priority, int priority,
GPollFD *fds, GPollFD *fds,
gint n_fds) int n_fds)
{ {
#ifdef G_MAIN_POLL_DEBUG #ifdef G_MAIN_POLL_DEBUG
GTimer *poll_timer; GTimer *poll_timer;
@ -4575,13 +4632,12 @@ g_main_context_poll (GMainContext *context,
poll_timer = g_timer_new (); poll_timer = g_timer_new ();
} }
#endif #endif
LOCK_CONTEXT (context);
poll_func = context->poll_func; poll_func = context->poll_func;
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);
ret = (*poll_func) (fds, n_fds, timeout); ret = (*poll_func) (fds, n_fds, timeout);
LOCK_CONTEXT (context);
errsv = errno; errsv = errno;
if (ret < 0 && errsv != EINTR) if (ret < 0 && errsv != EINTR)
{ {
@ -4596,8 +4652,6 @@ g_main_context_poll (GMainContext *context,
#ifdef G_MAIN_POLL_DEBUG #ifdef G_MAIN_POLL_DEBUG
if (_g_main_poll_debug) if (_g_main_poll_debug)
{ {
LOCK_CONTEXT (context);
g_print ("g_main_poll(%d) timeout: %d - elapsed %12.10f seconds", g_print ("g_main_poll(%d) timeout: %d - elapsed %12.10f seconds",
n_fds, n_fds,
timeout, timeout,
@ -4634,8 +4688,6 @@ g_main_context_poll (GMainContext *context,
pollrec = pollrec->next; pollrec = pollrec->next;
} }
g_print ("\n"); g_print ("\n");
UNLOCK_CONTEXT (context);
} }
#endif #endif
} /* if (n_fds || timeout != 0) */ } /* if (n_fds || timeout != 0) */