gsignal: Use static allocation if we've just few emission hooks

Normally we don't really have emission hooks around, so try to allocate
only tiny array to contain a few of them and in case we exceed that limit,
we go back to use allocated ones.
This commit is contained in:
Marco Trevisan (Treviño) 2022-12-21 03:52:59 +01:00 committed by Philip Withnall
parent bfc599b8a2
commit 76ed55f3a7

View File

@ -3833,8 +3833,7 @@ signal_emit_unlocked_R (SignalNode *node,
if (node->emission_hooks)
{
GHook *hook;
GHook **emission_hooks = NULL;
guint8 *hook_returns = NULL;
GHook *static_emission_hooks[3];
size_t n_emission_hooks = 0;
const gboolean may_recurse = TRUE;
guint i;
@ -3843,6 +3842,8 @@ signal_emit_unlocked_R (SignalNode *node,
/* Quick check to determine whether any hooks match this emission,
* before committing to the more complex work of calling those hooks.
* We save a few of them into a static array, to try to avoid further
* allocations.
*/
hook = g_hook_first_valid (node->emission_hooks, may_recurse);
while (hook)
@ -3850,34 +3851,70 @@ signal_emit_unlocked_R (SignalNode *node,
SignalHook *signal_hook = SIGNAL_HOOK (hook);
if (!signal_hook->detail || signal_hook->detail == detail)
n_emission_hooks += 1;
{
if (n_emission_hooks < G_N_ELEMENTS (static_emission_hooks))
{
static_emission_hooks[n_emission_hooks] =
g_hook_ref (node->emission_hooks, hook);
}
n_emission_hooks += 1;
}
hook = g_hook_next_valid (node->emission_hooks, hook, may_recurse);
}
/* Re-iterate back through the matching hooks and copy them into
* an array which wont change when we unlock to call the
* user-provided hook functions.
* These functions may change hook configuration for this signal,
* add / remove signal handlers, etc.
*/
if G_UNLIKELY (n_emission_hooks > 0)
{
emission_hooks = g_newa (GHook *, n_emission_hooks);
hook_returns = g_newa (guint8, n_emission_hooks);
guint8 static_hook_returns[G_N_ELEMENTS (static_emission_hooks)];
GHook **emission_hooks = NULL;
guint8 *hook_returns = NULL;
/* Re-iterate back through the matching hooks and copy them into
* an array which wont change when we unlock to call the
* user-provided hook functions.
* These functions may change hook configuration for this signal,
* add / remove signal handlers, etc.
*/
hook = g_hook_first_valid (node->emission_hooks, may_recurse);
for (i = 0; hook; )
if G_LIKELY (n_emission_hooks <= G_N_ELEMENTS (static_emission_hooks))
{
SignalHook *signal_hook = SIGNAL_HOOK (hook);
if (!signal_hook->detail || signal_hook->detail == detail)
emission_hooks[i++] = g_hook_ref (node->emission_hooks, hook);
hook = g_hook_next_valid (node->emission_hooks, hook, may_recurse);
emission_hooks = static_emission_hooks;
hook_returns = static_hook_returns;
}
else
{
emission_hooks = g_newa (GHook *, n_emission_hooks);
hook_returns = g_newa (guint8, n_emission_hooks);
g_assert (i == n_emission_hooks);
/* We can't just memcpy the ones we have in the static array,
* to the alloca()'d one because otherwise we'd get an invalid
* ID assertion during unref
*/
i = 0;
for (hook = g_hook_first_valid (node->emission_hooks, may_recurse);
hook != NULL;
hook = g_hook_next_valid (node->emission_hooks, hook, may_recurse))
{
SignalHook *signal_hook = SIGNAL_HOOK (hook);
if (!signal_hook->detail || signal_hook->detail == detail)
{
if (i < G_N_ELEMENTS (static_emission_hooks))
{
emission_hooks[i] = g_steal_pointer (&static_emission_hooks[i]);
g_assert (emission_hooks[i] == hook);
}
else
{
emission_hooks[i] = g_hook_ref (node->emission_hooks, hook);
}
i += 1;
}
}
g_assert (i == n_emission_hooks);
}
SIGNAL_UNLOCK ();