1 /* GObject - GLib Type, Object, Parameter and Signal Library
2 * Copyright (C) 2000-2001 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include "gobjectalias.h"
26 /* FIXME: need caching allocators
29 #define CLOSURE_MAX_REF_COUNT ((1 << 15) - 1)
30 #define CLOSURE_MAX_N_GUARDS ((1 << 1) - 1)
31 #define CLOSURE_MAX_N_FNOTIFIERS ((1 << 2) - 1)
32 #define CLOSURE_MAX_N_INOTIFIERS ((1 << 8) - 1)
33 #define CLOSURE_N_MFUNCS(cl) ((cl)->meta_marshal + \
34 ((cl)->n_guards << 1L))
35 /* same as G_CLOSURE_N_NOTIFIERS() (keep in sync) */
36 #define CLOSURE_N_NOTIFIERS(cl) (CLOSURE_N_MFUNCS (cl) + \
37 (cl)->n_fnotifiers + \
40 /* union of first int we need to make atomic */
46 #define BITS_AS_INT(b) (((GAtomicClosureBits*)(b))->atomic)
48 #define CLOSURE_READ_BITS(cl,bits) (BITS_AS_INT(bits) = g_atomic_int_get ((gint*)(cl)))
49 #define CLOSURE_READ_BITS2(cl,old,new) (BITS_AS_INT(old) = CLOSURE_READ_BITS (cl, new))
50 #define CLOSURE_SWAP_BITS(cl,old,new) (g_atomic_int_compare_and_exchange ((gint*)(cl), \
51 BITS_AS_INT(old),BITS_AS_INT(new)))
53 #define CLOSURE_REF(closure) \
57 CLOSURE_READ_BITS2 (closure, &old, &new); \
60 while (!CLOSURE_SWAP_BITS (closure, &old, &new)); \
64 #define CLOSURE_UNREF(closure, is_zero) \
68 CLOSURE_READ_BITS2 (closure, &old, &new); \
69 if (old.ref_count == 1) /* last unref, invalidate first */ \
70 g_closure_invalidate ((closure)); \
72 is_zero = (new.ref_count == 0); \
74 while (!CLOSURE_SWAP_BITS (closure, &old, &new)); \
85 /* --- functions --- */
87 g_closure_new_simple (guint sizeof_closure,
92 g_return_val_if_fail (sizeof_closure >= sizeof (GClosure), NULL);
94 closure = g_malloc (sizeof_closure);
95 closure->ref_count = 1;
96 closure->meta_marshal = 0;
97 closure->n_guards = 0;
98 closure->n_fnotifiers = 0;
99 closure->n_inotifiers = 0;
100 closure->in_inotify = FALSE;
101 closure->floating = TRUE;
102 closure->derivative_flag = 0;
103 closure->in_marshal = FALSE;
104 closure->is_invalid = FALSE;
105 closure->marshal = NULL;
106 closure->data = data;
107 closure->notifiers = NULL;
108 memset (G_STRUCT_MEMBER_P (closure, sizeof (*closure)), 0, sizeof_closure - sizeof (*closure));
114 closure_invoke_notifiers (GClosure *closure,
120 * meta_marshal n_guards n_guards n_fnotif. n_inotifiers
121 * ->[[meta_marshal][pre_guards][post_guards][fnotifiers][inotifiers]]
123 * CLOSURE_N_MFUNCS(cl) = meta_marshal + n_guards + n_guards;
124 * CLOSURE_N_NOTIFIERS(cl) = CLOSURE_N_MFUNCS(cl) + n_fnotifiers + n_inotifiers
126 * constrains/catches:
127 * - closure->notifiers may be reloacted during callback
128 * - closure->n_fnotifiers and closure->n_inotifiers may change during callback
129 * - i.e. callbacks can be removed/added during invocation
130 * - have to prepare for callback removal during invocation (->marshal & ->data)
131 * - have to distinguish (->marshal & ->data) for INOTIFY/FNOTIFY (->in_inotify)
132 * + closure->n_guards is const during PRE_NOTIFY & POST_NOTIFY
133 * + closure->meta_marshal is const for all cases
134 * + none of the callbacks can cause recursion
135 * + closure->n_inotifiers is const 0 during FNOTIFY
139 GClosureNotifyData *ndata;
142 CLOSURE_READ_BITS (closure, &bits);
143 while (bits.n_fnotifiers)
145 register guint n = --bits.n_fnotifiers;
147 ndata = closure->notifiers + CLOSURE_N_MFUNCS (&bits) + n;
148 closure->marshal = (GClosureMarshal) ndata->notify;
149 closure->data = ndata->data;
150 ndata->notify (ndata->data, closure);
152 closure->marshal = NULL;
153 closure->data = NULL;
157 CLOSURE_READ_BITS2 (closure, &bits, &new);
158 new.in_inotify = TRUE;
160 while (!CLOSURE_SWAP_BITS (closure, &bits, &new));
162 while (bits.n_inotifiers)
164 register guint n = --bits.n_inotifiers;
166 ndata = closure->notifiers + CLOSURE_N_MFUNCS (&bits) + bits.n_fnotifiers + n;
167 closure->marshal = (GClosureMarshal) ndata->notify;
168 closure->data = ndata->data;
169 ndata->notify (ndata->data, closure);
171 closure->marshal = NULL;
172 closure->data = NULL;
174 CLOSURE_READ_BITS2 (closure, &bits, &new);
175 new.n_inotifiers = 0;
176 new.in_inotify = FALSE;
178 while (!CLOSURE_SWAP_BITS (closure, &bits, &new));
181 CLOSURE_READ_BITS (closure, &bits);
183 offs = bits.meta_marshal;
186 ndata = closure->notifiers + offs + i;
187 ndata->notify (ndata->data, closure);
191 CLOSURE_READ_BITS (closure, &bits);
193 offs = bits.meta_marshal + i;
196 ndata = closure->notifiers + offs + i;
197 ndata->notify (ndata->data, closure);
204 g_closure_set_meta_marshal (GClosure *closure,
205 gpointer marshal_data,
206 GClosureMarshal meta_marshal)
208 GClosureNotifyData *old_notifiers, *new_notifiers;
212 g_return_if_fail (closure != NULL);
213 g_return_if_fail (meta_marshal != NULL);
216 CLOSURE_READ_BITS2 (closure, &old, &new);
218 g_return_if_fail (old.is_invalid == FALSE);
219 g_return_if_fail (old.in_marshal == FALSE);
220 g_return_if_fail (old.meta_marshal == 0);
222 n = CLOSURE_N_NOTIFIERS (&old);
224 old_notifiers = closure->notifiers;
225 new_notifiers = g_renew (GClosureNotifyData, NULL, n + 1);
228 /* usually the meta marshal will be setup right after creation, so the
229 * g_memmove() should be rare-case scenario
231 g_memmove (new_notifiers + 1, old_notifiers, n * sizeof (old_notifiers[0]));
233 new_notifiers[0].data = marshal_data;
234 new_notifiers[0].notify = (GClosureNotify) meta_marshal;
236 new.meta_marshal = 1;
238 /* this cannot be made atomic, as soon as we switch on the meta_marshal
239 * bit, another thread could use the notifier while we have not yet
240 * copied it. the safest is to install the new_notifiers first and then
241 * switch on the meta_marshal flag. */
242 closure->notifiers = new_notifiers;
244 if (!CLOSURE_SWAP_BITS (closure, &old, &new)) {
245 g_free (new_notifiers);
249 g_free (old_notifiers);
253 g_closure_add_marshal_guards (GClosure *closure,
254 gpointer pre_marshal_data,
255 GClosureNotify pre_marshal_notify,
256 gpointer post_marshal_data,
257 GClosureNotify post_marshal_notify)
261 GClosureNotifyData *old_notifiers, *new_notifiers;
263 g_return_if_fail (closure != NULL);
264 g_return_if_fail (pre_marshal_notify != NULL);
265 g_return_if_fail (post_marshal_notify != NULL);
268 CLOSURE_READ_BITS2 (closure, &old, &new);
270 g_return_if_fail (old.is_invalid == FALSE);
271 g_return_if_fail (old.in_marshal == FALSE);
272 g_return_if_fail (old.n_guards < CLOSURE_MAX_N_GUARDS);
274 old_notifiers = closure->notifiers;
275 new_notifiers = g_renew (GClosureNotifyData, old_notifiers, CLOSURE_N_NOTIFIERS (&old) + 2);
276 if (old.n_inotifiers)
277 new_notifiers[(CLOSURE_N_MFUNCS (&old) +
279 old.n_inotifiers + 1)] = new_notifiers[(CLOSURE_N_MFUNCS (&old) +
280 old.n_fnotifiers + 0)];
281 if (old.n_inotifiers > 1)
282 new_notifiers[(CLOSURE_N_MFUNCS (&old) +
284 old.n_inotifiers)] = new_notifiers[(CLOSURE_N_MFUNCS (&old) +
285 old.n_fnotifiers + 1)];
286 if (old.n_fnotifiers)
287 new_notifiers[(CLOSURE_N_MFUNCS (&old) +
288 old.n_fnotifiers + 1)] = new_notifiers[CLOSURE_N_MFUNCS (&old) + 0];
289 if (old.n_fnotifiers > 1)
290 new_notifiers[(CLOSURE_N_MFUNCS (&old) +
291 old.n_fnotifiers)] = new_notifiers[CLOSURE_N_MFUNCS (&old) + 1];
293 new_notifiers[(old.meta_marshal +
295 old.n_guards + 1)] = new_notifiers[old.meta_marshal + old.n_guards];
300 new_notifiers[old.meta_marshal + i].data = pre_marshal_data;
301 new_notifiers[old.meta_marshal + i].notify = pre_marshal_notify;
302 new_notifiers[old.meta_marshal + i + 1].data = post_marshal_data;
303 new_notifiers[old.meta_marshal + i + 1].notify = post_marshal_notify;
305 /* not really atomic */
306 closure->notifiers = new_notifiers;
308 if (!CLOSURE_SWAP_BITS (closure, &old, &new))
313 g_closure_add_finalize_notifier (GClosure *closure,
314 gpointer notify_data,
315 GClosureNotify notify_func)
319 GClosureNotifyData *old_notifiers, *new_notifiers;
321 g_return_if_fail (closure != NULL);
322 g_return_if_fail (notify_func != NULL);
325 CLOSURE_READ_BITS2 (closure, &old, &new);
327 g_return_if_fail (old.n_fnotifiers < CLOSURE_MAX_N_FNOTIFIERS);
329 old_notifiers = closure->notifiers;
330 new_notifiers = g_renew (GClosureNotifyData, old_notifiers, CLOSURE_N_NOTIFIERS (&old) + 1);
331 if (old.n_inotifiers)
332 new_notifiers[(CLOSURE_N_MFUNCS (&old) +
334 old.n_inotifiers)] = new_notifiers[(CLOSURE_N_MFUNCS (&old) +
335 old.n_fnotifiers + 0)];
336 i = CLOSURE_N_MFUNCS (&old) + old.n_fnotifiers;
339 new_notifiers[i].data = notify_data;
340 new_notifiers[i].notify = notify_func;
342 /* not really atomic */
343 closure->notifiers = new_notifiers;
345 while (!CLOSURE_SWAP_BITS (closure, &old, &new))
350 g_closure_add_invalidate_notifier (GClosure *closure,
351 gpointer notify_data,
352 GClosureNotify notify_func)
356 GClosureNotifyData *old_notifiers, *new_notifiers;
358 g_return_if_fail (closure != NULL);
359 g_return_if_fail (notify_func != NULL);
362 CLOSURE_READ_BITS2 (closure, &old, &new);
364 g_return_if_fail (old.is_invalid == FALSE);
365 g_return_if_fail (old.n_inotifiers < CLOSURE_MAX_N_INOTIFIERS);
367 old_notifiers = closure->notifiers;
368 new_notifiers = g_renew (GClosureNotifyData, old_notifiers, CLOSURE_N_NOTIFIERS (&old) + 1);
369 i = CLOSURE_N_MFUNCS (&old) + old.n_fnotifiers + old.n_inotifiers;
372 new_notifiers[i].data = notify_data;
373 new_notifiers[i].notify = notify_func;
375 /* not really atomic */
376 closure->notifiers = new_notifiers;
378 while (!CLOSURE_SWAP_BITS (closure, &old, &new))
382 static inline gboolean
383 closure_try_remove_inotify (GClosure *closure,
384 gpointer notify_data,
385 GClosureNotify notify_func)
387 GClosureNotifyData *ndata, *nlast;
391 CLOSURE_READ_BITS2 (closure, &old, &new);
393 nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (&old) - 1;
394 for (ndata = nlast + 1 - old.n_inotifiers; ndata <= nlast; ndata++)
395 if (ndata->notify == notify_func && ndata->data == notify_data)
397 new.n_inotifiers -= 1;
398 if (!CLOSURE_SWAP_BITS (closure, &old, &new))
409 static inline gboolean
410 closure_try_remove_fnotify (GClosure *closure,
411 gpointer notify_data,
412 GClosureNotify notify_func)
414 GClosureNotifyData *ndata, *nlast;
418 CLOSURE_READ_BITS2 (closure, &old, &new);
420 nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (&old) - old.n_inotifiers - 1;
421 for (ndata = nlast + 1 - old.n_fnotifiers; ndata <= nlast; ndata++)
422 if (ndata->notify == notify_func && ndata->data == notify_data)
424 new.n_fnotifiers -= 1;
425 if (!CLOSURE_SWAP_BITS (closure, &old, &new))
431 if (new.n_inotifiers)
432 closure->notifiers[(CLOSURE_N_MFUNCS (&new) +
433 new.n_fnotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (&new) +
442 g_closure_ref (GClosure *closure)
444 g_return_val_if_fail (closure != NULL, NULL);
445 g_return_val_if_fail (closure->ref_count > 0, NULL);
446 g_return_val_if_fail (closure->ref_count < CLOSURE_MAX_REF_COUNT, NULL);
448 CLOSURE_REF (closure);
454 g_closure_invalidate (GClosure *closure)
458 g_return_if_fail (closure != NULL);
461 CLOSURE_READ_BITS2 (closure, &old, &new);
466 new.is_invalid = TRUE;
468 if (!CLOSURE_SWAP_BITS (closure, &old, &new))
471 closure_invoke_notifiers (closure, INOTIFY);
472 g_closure_unref (closure);
477 g_closure_unref (GClosure *closure)
481 g_return_if_fail (closure != NULL);
482 g_return_if_fail (closure->ref_count > 0);
484 CLOSURE_UNREF (closure, is_zero);
486 if (G_UNLIKELY (is_zero))
488 closure_invoke_notifiers (closure, FNOTIFY);
489 g_free (closure->notifiers);
495 g_closure_sink (GClosure *closure)
499 g_return_if_fail (closure != NULL);
500 g_return_if_fail (closure->ref_count > 0);
502 /* floating is basically a kludge to avoid creating closures
503 * with a ref_count of 0. so the intial ref_count a closure has
504 * is unowned. with invoking g_closure_sink() code may
505 * indicate that it takes over that intiial ref_count.
508 CLOSURE_READ_BITS2 (closure, &old, &new);
512 new.floating = FALSE;
514 if (!CLOSURE_SWAP_BITS (closure, &old, &new))
517 g_closure_unref (closure);
522 g_closure_remove_invalidate_notifier (GClosure *closure,
523 gpointer notify_data,
524 GClosureNotify notify_func)
528 g_return_if_fail (closure != NULL);
529 g_return_if_fail (notify_func != NULL);
531 CLOSURE_READ_BITS (closure, &bits);
533 if (bits.is_invalid && bits.in_inotify && /* account removal of notify_func() while its called */
534 ((gpointer) closure->marshal) == ((gpointer) notify_func) && closure->data == notify_data)
535 closure->marshal = NULL;
536 else if (!closure_try_remove_inotify (closure, notify_data, notify_func))
537 g_warning (G_STRLOC ": unable to remove uninstalled invalidation notifier: %p (%p)",
538 notify_func, notify_data);
542 g_closure_remove_finalize_notifier (GClosure *closure,
543 gpointer notify_data,
544 GClosureNotify notify_func)
548 g_return_if_fail (closure != NULL);
549 g_return_if_fail (notify_func != NULL);
551 CLOSURE_READ_BITS (closure, &bits);
553 if (bits.is_invalid && !bits.in_inotify && /* account removal of notify_func() while its called */
554 ((gpointer) closure->marshal) == ((gpointer) notify_func) && closure->data == notify_data)
555 closure->marshal = NULL;
556 else if (!closure_try_remove_fnotify (closure, notify_data, notify_func))
557 g_warning (G_STRLOC ": unable to remove uninstalled finalization notifier: %p (%p)",
558 notify_func, notify_data);
562 g_closure_invoke (GClosure *closure,
563 GValue /*out*/ *return_value,
564 guint n_param_values,
565 const GValue *param_values,
566 gpointer invocation_hint)
570 g_return_if_fail (closure != NULL);
573 CLOSURE_READ_BITS2 (closure, &old, &new);
577 GClosureMarshal marshal;
578 gpointer marshal_data;
579 gboolean in_marshal = old.in_marshal;
580 gboolean meta_marshal = old.meta_marshal;
582 g_return_if_fail (closure->marshal || meta_marshal);
585 new.in_marshal = TRUE;
587 if (!CLOSURE_SWAP_BITS (closure, &old, &new))
592 marshal_data = closure->notifiers[0].data;
593 marshal = (GClosureMarshal) closure->notifiers[0].notify;
598 marshal = closure->marshal;
601 closure_invoke_notifiers (closure, PRE_NOTIFY);
605 n_param_values, param_values,
610 closure_invoke_notifiers (closure, POST_NOTIFY);
613 CLOSURE_READ_BITS2 (closure, &old, &new);
614 new.in_marshal = in_marshal;
617 while (!CLOSURE_SWAP_BITS (closure, &old, &new));
622 g_closure_set_marshal (GClosure *closure,
623 GClosureMarshal marshal)
625 g_return_if_fail (closure != NULL);
626 g_return_if_fail (marshal != NULL);
628 if (closure->marshal && closure->marshal != marshal)
629 g_warning ("attempt to override closure->marshal (%p) with new marshal (%p)",
630 closure->marshal, marshal);
632 closure->marshal = marshal;
636 g_cclosure_new (GCallback callback_func,
638 GClosureNotify destroy_data)
642 g_return_val_if_fail (callback_func != NULL, NULL);
644 closure = g_closure_new_simple (sizeof (GCClosure), user_data);
646 g_closure_add_finalize_notifier (closure, user_data, destroy_data);
647 ((GCClosure*) closure)->callback = (gpointer) callback_func;
653 g_cclosure_new_swap (GCallback callback_func,
655 GClosureNotify destroy_data)
659 g_return_val_if_fail (callback_func != NULL, NULL);
661 closure = g_closure_new_simple (sizeof (GCClosure), user_data);
663 g_closure_add_finalize_notifier (closure, user_data, destroy_data);
664 ((GCClosure*) closure)->callback = (gpointer) callback_func;
665 closure->derivative_flag = TRUE;
671 g_type_class_meta_marshal (GClosure *closure,
672 GValue /*out*/ *return_value,
673 guint n_param_values,
674 const GValue *param_values,
675 gpointer invocation_hint,
676 gpointer marshal_data)
680 /* GType itype = (GType) closure->data; */
681 guint offset = GPOINTER_TO_UINT (marshal_data);
683 class = G_TYPE_INSTANCE_GET_CLASS (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
684 callback = G_STRUCT_MEMBER (gpointer, class, offset);
686 closure->marshal (closure,
688 n_param_values, param_values,
694 g_type_iface_meta_marshal (GClosure *closure,
695 GValue /*out*/ *return_value,
696 guint n_param_values,
697 const GValue *param_values,
698 gpointer invocation_hint,
699 gpointer marshal_data)
703 GType itype = (GType) closure->data;
704 guint offset = GPOINTER_TO_UINT (marshal_data);
706 class = G_TYPE_INSTANCE_GET_INTERFACE (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
707 callback = G_STRUCT_MEMBER (gpointer, class, offset);
709 closure->marshal (closure,
711 n_param_values, param_values,
717 g_signal_type_cclosure_new (GType itype,
722 g_return_val_if_fail (G_TYPE_IS_CLASSED (itype) || G_TYPE_IS_INTERFACE (itype), NULL);
723 g_return_val_if_fail (struct_offset >= sizeof (GTypeClass), NULL);
725 closure = g_closure_new_simple (sizeof (GClosure), (gpointer) itype);
726 if (G_TYPE_IS_INTERFACE (itype))
727 g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal);
729 g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
734 #define __G_CLOSURE_C__
735 #include "gobjectaliasdef.c"