Make refcounting threadsafe by using atomic operations. (#166020, Wim
[platform/upstream/glib.git] / gobject / gclosure.c
1 /* GObject - GLib Type, Object, Parameter and Signal Library
2  * Copyright (C) 2000-2001 Red Hat, Inc.
3  *
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.
8  *
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.
13  *
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.
18  */
19 #include        "gclosure.h"
20
21 #include        "gvalue.h"
22 #include        "gobjectalias.h"
23 #include        <string.h>
24
25
26 /* FIXME: need caching allocators
27  */
28
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 + \
38                                          (cl)->n_inotifiers)
39
40 /* union of first int we need to make atomic */
41 typedef union {
42   GClosure bits;
43   gint atomic;
44 } GAtomicClosureBits;
45
46 #define BITS_AS_INT(b)  (((GAtomicClosureBits*)(b))->atomic)
47
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)))
52
53 #define CLOSURE_REF(closure)                                                    \
54 G_STMT_START {                                                                  \
55   GClosure old, new;                                                            \
56   do {                                                                          \
57     CLOSURE_READ_BITS2 (closure, &old, &new);                                   \
58     new.ref_count++;                                                            \
59   }                                                                             \
60   while (!CLOSURE_SWAP_BITS (closure, &old, &new));                             \
61 } G_STMT_END
62
63
64 #define CLOSURE_UNREF(closure, is_zero)                                         \
65 G_STMT_START {                                                                  \
66   GClosure old, new;                                                            \
67   do {                                                                          \
68     CLOSURE_READ_BITS2 (closure, &old, &new);                                   \
69     if (old.ref_count == 1)     /* last unref, invalidate first */              \
70       g_closure_invalidate ((closure));                                         \
71     new.ref_count--;                                                            \
72     is_zero = (new.ref_count == 0);                                             \
73   }                                                                             \
74   while (!CLOSURE_SWAP_BITS (closure, &old, &new));                             \
75 } G_STMT_END
76
77 enum {
78   FNOTIFY,
79   INOTIFY,
80   PRE_NOTIFY,
81   POST_NOTIFY
82 };
83
84
85 /* --- functions --- */
86 GClosure*
87 g_closure_new_simple (guint           sizeof_closure,
88                       gpointer        data)
89 {
90   GClosure *closure;
91
92   g_return_val_if_fail (sizeof_closure >= sizeof (GClosure), NULL);
93
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));
109
110   return closure;
111 }
112
113 static inline void
114 closure_invoke_notifiers (GClosure *closure,
115                           guint     notify_type)
116 {
117   GClosure bits, new;
118
119   /* notifier layout:
120    *     meta_marshal  n_guards    n_guards     n_fnotif.  n_inotifiers
121    * ->[[meta_marshal][pre_guards][post_guards][fnotifiers][inotifiers]]
122    *
123    * CLOSURE_N_MFUNCS(cl)    = meta_marshal + n_guards + n_guards;
124    * CLOSURE_N_NOTIFIERS(cl) = CLOSURE_N_MFUNCS(cl) + n_fnotifiers + n_inotifiers
125    *
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
136    */
137   switch (notify_type)
138     {
139       GClosureNotifyData *ndata;
140       guint i, offs;
141     case FNOTIFY:
142       CLOSURE_READ_BITS (closure, &bits);
143       while (bits.n_fnotifiers)
144         {
145           register guint n = --bits.n_fnotifiers;
146
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);
151         }
152       closure->marshal = NULL;
153       closure->data = NULL;
154       break;
155     case INOTIFY:
156       do {
157         CLOSURE_READ_BITS2 (closure, &bits, &new);
158         new.in_inotify = TRUE;
159       }
160       while (!CLOSURE_SWAP_BITS (closure, &bits,  &new));
161
162       while (bits.n_inotifiers)
163         {
164           register guint n = --bits.n_inotifiers;
165
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);
170         }
171       closure->marshal = NULL;
172       closure->data = NULL;
173       do {
174         CLOSURE_READ_BITS2 (closure, &bits, &new);
175         new.n_inotifiers = 0;
176         new.in_inotify = FALSE;
177       }
178       while (!CLOSURE_SWAP_BITS (closure, &bits, &new));
179       break;
180     case PRE_NOTIFY:
181       CLOSURE_READ_BITS (closure, &bits);
182       i = bits.n_guards;
183       offs = bits.meta_marshal;
184       while (i--)
185         {
186           ndata = closure->notifiers + offs + i;
187           ndata->notify (ndata->data, closure);
188         }
189       break;
190     case POST_NOTIFY:
191       CLOSURE_READ_BITS (closure, &bits);
192       i = bits.n_guards;
193       offs = bits.meta_marshal + i;
194       while (i--)
195         {
196           ndata = closure->notifiers + offs + i;
197           ndata->notify (ndata->data, closure);
198         }
199       break;
200     }
201 }
202
203 void
204 g_closure_set_meta_marshal (GClosure       *closure,
205                             gpointer        marshal_data,
206                             GClosureMarshal meta_marshal)
207 {
208   GClosureNotifyData *old_notifiers, *new_notifiers;
209   guint n;
210   GClosure old, new;
211
212   g_return_if_fail (closure != NULL);
213   g_return_if_fail (meta_marshal != NULL);
214
215 retry:
216   CLOSURE_READ_BITS2 (closure, &old, &new);
217
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);
221
222   n = CLOSURE_N_NOTIFIERS (&old);
223
224   old_notifiers = closure->notifiers;
225   new_notifiers = g_renew (GClosureNotifyData, NULL, n + 1);
226   if (old_notifiers)
227     {
228       /* usually the meta marshal will be setup right after creation, so the
229        * g_memmove() should be rare-case scenario
230        */
231       g_memmove (new_notifiers + 1, old_notifiers, n * sizeof (old_notifiers[0]));
232     }
233   new_notifiers[0].data = marshal_data;
234   new_notifiers[0].notify = (GClosureNotify) meta_marshal;
235
236   new.meta_marshal = 1;
237
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;
243
244   if (!CLOSURE_SWAP_BITS (closure, &old, &new)) {
245     g_free (new_notifiers);
246     goto retry;
247   }
248
249   g_free (old_notifiers);
250 }
251
252 void
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)
258 {
259   guint i;
260   GClosure old, new;
261   GClosureNotifyData *old_notifiers, *new_notifiers;
262
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);
266
267 retry:
268   CLOSURE_READ_BITS2 (closure,  &old,  &new);
269
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);
273
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) +
278                         old.n_fnotifiers +
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) +
283                         old.n_fnotifiers +
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];
292   if (old.n_guards)
293     new_notifiers[(old.meta_marshal +
294                         old.n_guards +
295                         old.n_guards + 1)] = new_notifiers[old.meta_marshal + old.n_guards];
296   i = old.n_guards;
297
298   new.n_guards = i+1;
299
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;
304
305   /* not really atomic */
306   closure->notifiers = new_notifiers;
307
308   if (!CLOSURE_SWAP_BITS (closure, &old, &new))
309     goto retry;
310 }
311
312 void
313 g_closure_add_finalize_notifier (GClosure      *closure,
314                                  gpointer       notify_data,
315                                  GClosureNotify notify_func)
316 {
317   guint i;
318   GClosure old, new;
319   GClosureNotifyData *old_notifiers, *new_notifiers;
320
321   g_return_if_fail (closure != NULL);
322   g_return_if_fail (notify_func != NULL);
323
324 retry:
325   CLOSURE_READ_BITS2 (closure, &old, &new);
326
327   g_return_if_fail (old.n_fnotifiers < CLOSURE_MAX_N_FNOTIFIERS);
328
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) +
333                         old.n_fnotifiers +
334                         old.n_inotifiers)] = new_notifiers[(CLOSURE_N_MFUNCS (&old) +
335                                                                       old.n_fnotifiers + 0)];
336   i = CLOSURE_N_MFUNCS (&old) + old.n_fnotifiers;
337   new.n_fnotifiers++;
338
339   new_notifiers[i].data = notify_data;
340   new_notifiers[i].notify = notify_func;
341
342   /* not really atomic */
343   closure->notifiers = new_notifiers;
344
345   while (!CLOSURE_SWAP_BITS (closure, &old, &new))
346     goto retry;
347 }
348
349 void
350 g_closure_add_invalidate_notifier (GClosure      *closure,
351                                    gpointer       notify_data,
352                                    GClosureNotify notify_func)
353 {
354   guint i;
355   GClosure old, new;
356   GClosureNotifyData *old_notifiers, *new_notifiers;
357
358   g_return_if_fail (closure != NULL);
359   g_return_if_fail (notify_func != NULL);
360
361 retry:
362   CLOSURE_READ_BITS2 (closure, &old, &new);
363
364   g_return_if_fail (old.is_invalid == FALSE);
365   g_return_if_fail (old.n_inotifiers < CLOSURE_MAX_N_INOTIFIERS);
366
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;
370   new.n_inotifiers++;
371
372   new_notifiers[i].data = notify_data;
373   new_notifiers[i].notify = notify_func;
374
375   /* not really atomic */
376   closure->notifiers = new_notifiers;
377
378   while (!CLOSURE_SWAP_BITS (closure, &old, &new))
379     goto retry;
380 }
381
382 static inline gboolean
383 closure_try_remove_inotify (GClosure       *closure,
384                             gpointer       notify_data,
385                             GClosureNotify notify_func)
386 {
387   GClosureNotifyData *ndata, *nlast;
388   GClosure old, new;
389
390 retry:
391   CLOSURE_READ_BITS2 (closure, &old, &new);
392
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)
396       {
397         new.n_inotifiers -= 1;
398         if (!CLOSURE_SWAP_BITS (closure, &old, &new))
399           goto retry;
400         
401         if (ndata < nlast)
402           *ndata = *nlast;
403
404         return TRUE;
405       }
406   return FALSE;
407 }
408
409 static inline gboolean
410 closure_try_remove_fnotify (GClosure       *closure,
411                             gpointer       notify_data,
412                             GClosureNotify notify_func)
413 {
414   GClosureNotifyData *ndata, *nlast;
415   GClosure old, new;
416
417 retry:
418   CLOSURE_READ_BITS2 (closure, &old, &new);
419
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)
423       {
424         new.n_fnotifiers -= 1;
425         if (!CLOSURE_SWAP_BITS (closure, &old, &new))
426           goto retry;
427         
428         if (ndata < nlast)
429           *ndata = *nlast;
430
431         if (new.n_inotifiers)
432           closure->notifiers[(CLOSURE_N_MFUNCS (&new) +
433                               new.n_fnotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (&new) +
434                                                                             new.n_fnotifiers +
435                                                                             new.n_inotifiers)];
436         return TRUE;
437       }
438   return FALSE;
439 }
440
441 GClosure*
442 g_closure_ref (GClosure *closure)
443 {
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);
447
448   CLOSURE_REF (closure);
449
450   return closure;
451 }
452
453 void
454 g_closure_invalidate (GClosure *closure)
455 {
456   GClosure old, new;
457
458   g_return_if_fail (closure != NULL);
459
460 retry:
461   CLOSURE_READ_BITS2 (closure, &old, &new);
462
463   if (!old.is_invalid)
464     {
465       new.ref_count++;
466       new.is_invalid = TRUE;
467
468       if (!CLOSURE_SWAP_BITS (closure, &old, &new))
469         goto retry;
470
471       closure_invoke_notifiers (closure, INOTIFY);
472       g_closure_unref (closure);
473     }
474 }
475
476 void
477 g_closure_unref (GClosure *closure)
478 {
479   gboolean is_zero;
480
481   g_return_if_fail (closure != NULL);
482   g_return_if_fail (closure->ref_count > 0);
483
484   CLOSURE_UNREF (closure, is_zero);
485
486   if (G_UNLIKELY (is_zero))
487     {
488       closure_invoke_notifiers (closure, FNOTIFY);
489       g_free (closure->notifiers);
490       g_free (closure);
491     }
492 }
493
494 void
495 g_closure_sink (GClosure *closure)
496 {
497   GClosure old, new;
498
499   g_return_if_fail (closure != NULL);
500   g_return_if_fail (closure->ref_count > 0);
501
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.
506    */
507 retry:
508   CLOSURE_READ_BITS2 (closure, &old, &new);
509
510   if (old.floating)
511     {
512       new.floating = FALSE;
513
514       if (!CLOSURE_SWAP_BITS (closure, &old, &new))
515         goto retry;
516
517       g_closure_unref (closure);
518     }
519 }
520
521 void
522 g_closure_remove_invalidate_notifier (GClosure      *closure,
523                                       gpointer       notify_data,
524                                       GClosureNotify notify_func)
525 {
526   GClosure bits;
527
528   g_return_if_fail (closure != NULL);
529   g_return_if_fail (notify_func != NULL);
530
531   CLOSURE_READ_BITS (closure, &bits);
532
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);
539 }
540
541 void
542 g_closure_remove_finalize_notifier (GClosure      *closure,
543                                     gpointer       notify_data,
544                                     GClosureNotify notify_func)
545 {
546   GClosure bits;
547         
548   g_return_if_fail (closure != NULL);
549   g_return_if_fail (notify_func != NULL);
550
551   CLOSURE_READ_BITS (closure, &bits);
552
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);
559 }
560
561 void
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)
567 {
568   GClosure old, new;
569
570   g_return_if_fail (closure != NULL);
571
572 retry:
573   CLOSURE_READ_BITS2 (closure, &old, &new);
574
575   if (!old.is_invalid)
576    {
577       GClosureMarshal marshal;
578       gpointer marshal_data;
579       gboolean in_marshal = old.in_marshal;
580       gboolean meta_marshal = old.meta_marshal;
581
582       g_return_if_fail (closure->marshal || meta_marshal);
583
584       new.ref_count++;
585       new.in_marshal = TRUE;
586
587       if (!CLOSURE_SWAP_BITS (closure, &old, &new))
588         goto retry;
589
590       if (meta_marshal)
591         {
592           marshal_data = closure->notifiers[0].data;
593           marshal = (GClosureMarshal) closure->notifiers[0].notify;
594         }
595       else
596         {
597           marshal_data = NULL;
598           marshal = closure->marshal;
599         }
600       if (!in_marshal)
601         closure_invoke_notifiers (closure, PRE_NOTIFY);
602
603       marshal (closure,
604                return_value,
605                n_param_values, param_values,
606                invocation_hint,
607                marshal_data);
608
609       if (!in_marshal)
610         closure_invoke_notifiers (closure, POST_NOTIFY);
611
612       do {
613         CLOSURE_READ_BITS2 (closure, &old, &new);
614         new.in_marshal = in_marshal;
615         new.ref_count--;
616       }
617       while (!CLOSURE_SWAP_BITS (closure, &old, &new));
618     }
619 }
620
621 void
622 g_closure_set_marshal (GClosure       *closure,
623                        GClosureMarshal marshal)
624 {
625   g_return_if_fail (closure != NULL);
626   g_return_if_fail (marshal != NULL);
627
628   if (closure->marshal && closure->marshal != marshal)
629     g_warning ("attempt to override closure->marshal (%p) with new marshal (%p)",
630                closure->marshal, marshal);
631   else
632     closure->marshal = marshal;
633 }
634
635 GClosure*
636 g_cclosure_new (GCallback      callback_func,
637                 gpointer       user_data,
638                 GClosureNotify destroy_data)
639 {
640   GClosure *closure;
641   
642   g_return_val_if_fail (callback_func != NULL, NULL);
643   
644   closure = g_closure_new_simple (sizeof (GCClosure), user_data);
645   if (destroy_data)
646     g_closure_add_finalize_notifier (closure, user_data, destroy_data);
647   ((GCClosure*) closure)->callback = (gpointer) callback_func;
648   
649   return closure;
650 }
651
652 GClosure*
653 g_cclosure_new_swap (GCallback      callback_func,
654                      gpointer       user_data,
655                      GClosureNotify destroy_data)
656 {
657   GClosure *closure;
658   
659   g_return_val_if_fail (callback_func != NULL, NULL);
660   
661   closure = g_closure_new_simple (sizeof (GCClosure), user_data);
662   if (destroy_data)
663     g_closure_add_finalize_notifier (closure, user_data, destroy_data);
664   ((GCClosure*) closure)->callback = (gpointer) callback_func;
665   closure->derivative_flag = TRUE;
666   
667   return closure;
668 }
669
670 static void
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)
677 {
678   GTypeClass *class;
679   gpointer callback;
680   /* GType itype = (GType) closure->data; */
681   guint offset = GPOINTER_TO_UINT (marshal_data);
682   
683   class = G_TYPE_INSTANCE_GET_CLASS (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
684   callback = G_STRUCT_MEMBER (gpointer, class, offset);
685   if (callback)
686     closure->marshal (closure,
687                       return_value,
688                       n_param_values, param_values,
689                       invocation_hint,
690                       callback);
691 }
692
693 static void
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)
700 {
701   GTypeClass *class;
702   gpointer callback;
703   GType itype = (GType) closure->data;
704   guint offset = GPOINTER_TO_UINT (marshal_data);
705   
706   class = G_TYPE_INSTANCE_GET_INTERFACE (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
707   callback = G_STRUCT_MEMBER (gpointer, class, offset);
708   if (callback)
709     closure->marshal (closure,
710                       return_value,
711                       n_param_values, param_values,
712                       invocation_hint,
713                       callback);
714 }
715
716 GClosure*
717 g_signal_type_cclosure_new (GType    itype,
718                             guint    struct_offset)
719 {
720   GClosure *closure;
721   
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);
724   
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);
728   else
729     g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
730   
731   return closure;
732 }
733
734 #define __G_CLOSURE_C__
735 #include "gobjectaliasdef.c"