Branch data Line data Source code
1 : : /* GObject - GLib Type, Object, Parameter and Signal Library
2 : : * Copyright (C) 2000-2001 Red Hat, Inc.
3 : : * Copyright (C) 2005 Imendio AB
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : */
20 : :
21 : : /*
22 : : * MT safe with regards to reference counting.
23 : : */
24 : :
25 : : #include "config.h"
26 : :
27 : : #include "../glib/gvalgrind.h"
28 : : #include <string.h>
29 : :
30 : : #include <ffi.h>
31 : :
32 : : #include "gclosure.h"
33 : : #include "gboxed.h"
34 : : #include "gobject.h"
35 : : #include "genums.h"
36 : : #include "gvalue.h"
37 : : #include "gvaluetypes.h"
38 : : #include "gtype-private.h"
39 : :
40 : :
41 : : /**
42 : : * GClosure:
43 : : * @in_marshal: Indicates whether the closure is currently being invoked with
44 : : * g_closure_invoke()
45 : : * @is_invalid: Indicates whether the closure has been invalidated by
46 : : * g_closure_invalidate()
47 : : *
48 : : * A `GClosure` represents a callback supplied by the programmer.
49 : : *
50 : : * It will generally comprise a function of some kind and a marshaller
51 : : * used to call it. It is the responsibility of the marshaller to
52 : : * convert the arguments for the invocation from #GValues into
53 : : * a suitable form, perform the callback on the converted arguments,
54 : : * and transform the return value back into a #GValue.
55 : : *
56 : : * In the case of C programs, a closure usually just holds a pointer
57 : : * to a function and maybe a data argument, and the marshaller
58 : : * converts between #GValue and native C types. The GObject
59 : : * library provides the #GCClosure type for this purpose. Bindings for
60 : : * other languages need marshallers which convert between #GValues
61 : : * and suitable representations in the runtime of the language in
62 : : * order to use functions written in that language as callbacks. Use
63 : : * g_closure_set_marshal() to set the marshaller on such a custom
64 : : * closure implementation.
65 : : *
66 : : * Within GObject, closures play an important role in the
67 : : * implementation of signals. When a signal is registered, the
68 : : * @c_marshaller argument to g_signal_new() specifies the default C
69 : : * marshaller for any closure which is connected to this
70 : : * signal. GObject provides a number of C marshallers for this
71 : : * purpose, see the g_cclosure_marshal_*() functions. Additional C
72 : : * marshallers can be generated with the [glib-genmarshal][glib-genmarshal]
73 : : * utility. Closures can be explicitly connected to signals with
74 : : * g_signal_connect_closure(), but it usually more convenient to let
75 : : * GObject create a closure automatically by using one of the
76 : : * g_signal_connect_*() functions which take a callback function/user
77 : : * data pair.
78 : : *
79 : : * Using closures has a number of important advantages over a simple
80 : : * callback function/data pointer combination:
81 : : *
82 : : * - Closures allow the callee to get the types of the callback parameters,
83 : : * which means that language bindings don't have to write individual glue
84 : : * for each callback type.
85 : : *
86 : : * - The reference counting of #GClosure makes it easy to handle reentrancy
87 : : * right; if a callback is removed while it is being invoked, the closure
88 : : * and its parameters won't be freed until the invocation finishes.
89 : : *
90 : : * - g_closure_invalidate() and invalidation notifiers allow callbacks to be
91 : : * automatically removed when the objects they point to go away.
92 : : */
93 : :
94 : : #define CLOSURE_MAX_REF_COUNT ((1 << 15) - 1)
95 : : #define CLOSURE_MAX_N_GUARDS ((1 << 1) - 1)
96 : : #define CLOSURE_MAX_N_FNOTIFIERS ((1 << 2) - 1)
97 : : #define CLOSURE_MAX_N_INOTIFIERS ((1 << 8) - 1)
98 : : #define CLOSURE_N_MFUNCS(cl) ((size_t) ((cl)->n_guards << 1L))
99 : : /* same as G_CLOSURE_N_NOTIFIERS() (keep in sync) */
100 : : #define CLOSURE_N_NOTIFIERS(cl) ((size_t) (CLOSURE_N_MFUNCS (cl) + \
101 : : (cl)->n_fnotifiers + \
102 : : (cl)->n_inotifiers))
103 : :
104 : : /* A copy of the flags bitfield from the beginning of `struct _GClosure`, which
105 : : * is in union with an int for atomic access to all fields at the same time.
106 : : *
107 : : * This must be kept in sync with `struct _GClosure`, but that’s easy because
108 : : * it’s (unfortunately) a public struct, so can never change for ABI
109 : : * compatibility reasons. */
110 : : typedef union {
111 : : struct {
112 : : guint ref_count : 15; /* (atomic) */
113 : : /* meta_marshal is not used anymore but must be zero for historical reasons
114 : : as it was exposed in the G_CLOSURE_N_NOTIFIERS macro */
115 : : guint meta_marshal_nouse : 1; /* (atomic) */
116 : : guint n_guards : 1; /* (atomic) */
117 : : guint n_fnotifiers : 2; /* finalization notifiers (atomic) */
118 : : guint n_inotifiers : 8; /* invalidation notifiers (atomic) */
119 : : guint in_inotify : 1; /* (atomic) */
120 : : guint floating : 1; /* (atomic) */
121 : : guint derivative_flag : 1; /* (atomic) */
122 : : guint in_marshal : 1; /* (atomic) */
123 : : guint is_invalid : 1; /* (atomic) */
124 : : } flags;
125 : : GClosure closure;
126 : : int atomic_int;
127 : : } GClosureFlags;
128 : :
129 : : G_STATIC_ASSERT (sizeof (GClosureFlags) == sizeof (GClosure));
130 : : G_STATIC_ASSERT (G_ALIGNOF (GClosureFlags) == G_ALIGNOF (GClosure));
131 : :
132 : : #define ATOMIC_CHANGE_FIELD(_closure, _field, _OP, _value, _SET_OLD, _SET_NEW) \
133 : : G_STMT_START { \
134 : : GClosureFlags *cunion = (GClosureFlags *) _closure; \
135 : : gint new_int, old_int, success; \
136 : : old_int = g_atomic_int_get (&cunion->atomic_int); \
137 : : do \
138 : : { \
139 : : GClosureFlags tmp; \
140 : : tmp.atomic_int = old_int; \
141 : : _SET_OLD tmp.flags._field; \
142 : : tmp.flags._field _OP _value; \
143 : : _SET_NEW tmp.flags._field; \
144 : : new_int = tmp.atomic_int; \
145 : : success = g_atomic_int_compare_and_exchange_full (&cunion->atomic_int, old_int, new_int, \
146 : : &old_int); \
147 : : } \
148 : : while (!success); \
149 : : } G_STMT_END
150 : :
151 : : #define ATOMIC_SWAP(_closure, _field, _value, _oldv) ATOMIC_CHANGE_FIELD (_closure, _field, =, _value, *(_oldv) =, (void) )
152 : : #define ATOMIC_SET(_closure, _field, _value) ATOMIC_CHANGE_FIELD (_closure, _field, =, _value, (void), (void) )
153 : : #define ATOMIC_INC(_closure, _field) ATOMIC_CHANGE_FIELD (_closure, _field, +=, 1, (void), (void) )
154 : : #define ATOMIC_INC_ASSIGN(_closure, _field, _newv) ATOMIC_CHANGE_FIELD (_closure, _field, +=, 1, (void), *(_newv) = )
155 : : #define ATOMIC_DEC(_closure, _field) ATOMIC_CHANGE_FIELD (_closure, _field, -=, 1, (void), (void) )
156 : : #define ATOMIC_DEC_ASSIGN(_closure, _field, _newv) ATOMIC_CHANGE_FIELD (_closure, _field, -=, 1, (void), *(_newv) = )
157 : :
158 : : static inline GClosureFlags
159 : 87758067 : closure_atomic_get_flags (GClosure *closure)
160 : : {
161 : : GClosureFlags tmp;
162 : 87758067 : tmp.atomic_int = g_atomic_int_get (&((GClosureFlags *) closure)->atomic_int);
163 : 87758067 : return tmp;
164 : : }
165 : :
166 : : enum {
167 : : FNOTIFY,
168 : : INOTIFY,
169 : : PRE_NOTIFY,
170 : : POST_NOTIFY
171 : : };
172 : :
173 : :
174 : : /* --- functions --- */
175 : : /**
176 : : * g_closure_new_simple:
177 : : * @sizeof_closure: the size of the structure to allocate, must be at least
178 : : * `sizeof (GClosure)`
179 : : * @data: data to store in the @data field of the newly allocated #GClosure
180 : : *
181 : : * Allocates a struct of the given size and initializes the initial
182 : : * part as a #GClosure.
183 : : *
184 : : * This function is mainly useful when implementing new types of closures:
185 : : *
186 : : * |[<!-- language="C" -->
187 : : * typedef struct _MyClosure MyClosure;
188 : : * struct _MyClosure
189 : : * {
190 : : * GClosure closure;
191 : : * // extra data goes here
192 : : * };
193 : : *
194 : : * static void
195 : : * my_closure_finalize (gpointer notify_data,
196 : : * GClosure *closure)
197 : : * {
198 : : * MyClosure *my_closure = (MyClosure *)closure;
199 : : *
200 : : * // free extra data here
201 : : * }
202 : : *
203 : : * MyClosure *my_closure_new (gpointer data)
204 : : * {
205 : : * GClosure *closure;
206 : : * MyClosure *my_closure;
207 : : *
208 : : * closure = g_closure_new_simple (sizeof (MyClosure), data);
209 : : * my_closure = (MyClosure *) closure;
210 : : *
211 : : * // initialize extra data here
212 : : *
213 : : * g_closure_add_finalize_notifier (closure, notify_data,
214 : : * my_closure_finalize);
215 : : * return my_closure;
216 : : * }
217 : : * ]|
218 : : *
219 : : * Returns: (transfer floating): a floating reference to a new #GClosure
220 : : */
221 : : GClosure*
222 : 545398 : g_closure_new_simple (guint sizeof_closure,
223 : : gpointer data)
224 : : {
225 : : GClosure *closure;
226 : : size_t private_size;
227 : : gchar *allocated;
228 : :
229 : 545398 : g_return_val_if_fail (sizeof_closure >= sizeof (GClosure), NULL);
230 : :
231 : 545398 : private_size = sizeof (GRealClosure) - sizeof (GClosure);
232 : :
233 : : #ifdef ENABLE_VALGRIND
234 : : /* See comments in gtype.c about what's going on here... */
235 : 545398 : if (RUNNING_ON_VALGRIND)
236 : : {
237 : 0 : private_size += sizeof (gpointer);
238 : :
239 : 0 : allocated = g_malloc0 (private_size + sizeof_closure + sizeof (gpointer));
240 : :
241 : 0 : *(gpointer *) (allocated + private_size + sizeof_closure) = allocated + sizeof (gpointer);
242 : :
243 : 0 : VALGRIND_MALLOCLIKE_BLOCK (allocated + private_size, sizeof_closure + sizeof (gpointer), 0, TRUE);
244 : 0 : VALGRIND_MALLOCLIKE_BLOCK (allocated + sizeof (gpointer), private_size - sizeof (gpointer), 0, TRUE);
245 : : }
246 : : else
247 : : #endif
248 : 545398 : allocated = g_malloc0 (private_size + sizeof_closure);
249 : :
250 : 545398 : closure = (GClosure *) (allocated + private_size);
251 : :
252 : 545398 : ATOMIC_SET (closure, ref_count, 1);
253 : 545398 : ATOMIC_SET (closure, floating, TRUE);
254 : 545398 : closure->data = data;
255 : :
256 : 545398 : return closure;
257 : : }
258 : :
259 : : static inline void
260 : 28594410 : closure_invoke_notifiers (GClosure *closure,
261 : : guint notify_type)
262 : : {
263 : : /* notifier layout:
264 : : * n_guards n_guards n_fnotif. n_inotifiers
265 : : * ->[[pre_guards][post_guards][fnotifiers][inotifiers]]
266 : : *
267 : : * CLOSURE_N_MFUNCS(cl) = n_guards + n_guards;
268 : : * CLOSURE_N_NOTIFIERS(cl) = CLOSURE_N_MFUNCS(cl) + n_fnotifiers + n_inotifiers
269 : : *
270 : : * constrains/catches:
271 : : * - closure->notifiers may be reloacted during callback
272 : : * - closure->n_fnotifiers and closure->n_inotifiers may change during callback
273 : : * - i.e. callbacks can be removed/added during invocation
274 : : * - must prepare for callback removal during FNOTIFY and INOTIFY (done via ->marshal= & ->data=)
275 : : * - must distinguish (->marshal= & ->data=) for INOTIFY vs. FNOTIFY (via ->in_inotify)
276 : : * + closure->n_guards is const during PRE_NOTIFY & POST_NOTIFY
277 : : * + none of the callbacks can cause recursion
278 : : * + closure->n_inotifiers is const 0 during FNOTIFY
279 : : */
280 : 28594410 : switch (notify_type)
281 : : {
282 : : GClosureNotifyData *ndata;
283 : : guint i, offs;
284 : 542966 : case FNOTIFY:
285 : 656742 : while (closure->n_fnotifiers)
286 : : {
287 : : guint n;
288 : 113776 : ATOMIC_DEC_ASSIGN (closure, n_fnotifiers, &n);
289 : :
290 : 113776 : ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + n;
291 : 113776 : closure->marshal = (GClosureMarshal) ndata->notify;
292 : 113776 : closure->data = ndata->data;
293 : 113776 : ndata->notify (ndata->data, closure);
294 : : }
295 : 542966 : closure->marshal = NULL;
296 : 542966 : closure->data = NULL;
297 : 542966 : break;
298 : 542966 : case INOTIFY:
299 : 542966 : ATOMIC_SET (closure, in_inotify, TRUE);
300 : 557277 : while (closure->n_inotifiers)
301 : : {
302 : : guint n;
303 : 14311 : ATOMIC_DEC_ASSIGN (closure, n_inotifiers, &n);
304 : :
305 : 14311 : ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + n;
306 : 14311 : closure->marshal = (GClosureMarshal) ndata->notify;
307 : 14311 : closure->data = ndata->data;
308 : 14311 : ndata->notify (ndata->data, closure);
309 : : }
310 : 542966 : closure->marshal = NULL;
311 : 542966 : closure->data = NULL;
312 : 542966 : ATOMIC_SET (closure, in_inotify, FALSE);
313 : 542966 : break;
314 : 13754243 : case PRE_NOTIFY:
315 : 13754243 : i = closure->n_guards;
316 : 13754243 : offs = 0;
317 : 13754303 : while (i--)
318 : : {
319 : 60 : ndata = closure->notifiers + offs + i;
320 : 60 : ndata->notify (ndata->data, closure);
321 : : }
322 : 13754243 : break;
323 : 13754235 : case POST_NOTIFY:
324 : 13754235 : i = closure->n_guards;
325 : 13754235 : offs = i;
326 : 13754295 : while (i--)
327 : : {
328 : 60 : ndata = closure->notifiers + offs + i;
329 : 60 : ndata->notify (ndata->data, closure);
330 : : }
331 : 13754235 : break;
332 : : }
333 : 28594410 : }
334 : :
335 : : static void
336 : 1944 : g_closure_set_meta_va_marshal (GClosure *closure,
337 : : GVaClosureMarshal va_meta_marshal)
338 : : {
339 : : GClosureFlags old_flags;
340 : : GRealClosure *real_closure;
341 : :
342 : 1944 : g_return_if_fail (closure != NULL);
343 : 1944 : g_return_if_fail (va_meta_marshal != NULL);
344 : :
345 : 1944 : old_flags = closure_atomic_get_flags (closure);
346 : 1944 : g_return_if_fail (!old_flags.flags.is_invalid);
347 : 1944 : g_return_if_fail (!old_flags.flags.in_marshal);
348 : :
349 : 1944 : real_closure = G_REAL_CLOSURE (closure);
350 : :
351 : 1944 : g_return_if_fail (real_closure->meta_marshal != NULL);
352 : :
353 : 1944 : real_closure->va_meta_marshal = va_meta_marshal;
354 : : }
355 : :
356 : : /**
357 : : * g_closure_set_meta_marshal: (skip)
358 : : * @closure: a #GClosure
359 : : * @marshal_data: (closure meta_marshal): context-dependent data to pass
360 : : * to @meta_marshal
361 : : * @meta_marshal: a #GClosureMarshal function
362 : : *
363 : : * Sets the meta marshaller of @closure.
364 : : *
365 : : * A meta marshaller wraps the @closure's marshal and modifies the way
366 : : * it is called in some fashion. The most common use of this facility
367 : : * is for C callbacks.
368 : : *
369 : : * The same marshallers (generated by [glib-genmarshal][glib-genmarshal]),
370 : : * are used everywhere, but the way that we get the callback function
371 : : * differs. In most cases we want to use the @closure's callback, but in
372 : : * other cases we want to use some different technique to retrieve the
373 : : * callback function.
374 : : *
375 : : * For example, class closures for signals (see
376 : : * g_signal_type_cclosure_new()) retrieve the callback function from a
377 : : * fixed offset in the class structure. The meta marshaller retrieves
378 : : * the right callback and passes it to the marshaller as the
379 : : * @marshal_data argument.
380 : : */
381 : : void
382 : 16243 : g_closure_set_meta_marshal (GClosure *closure,
383 : : gpointer marshal_data,
384 : : GClosureMarshal meta_marshal)
385 : : {
386 : : GClosureFlags old_flags;
387 : : GRealClosure *real_closure;
388 : :
389 : 16243 : g_return_if_fail (closure != NULL);
390 : 16243 : g_return_if_fail (meta_marshal != NULL);
391 : :
392 : 16243 : old_flags = closure_atomic_get_flags (closure);
393 : 16243 : g_return_if_fail (!old_flags.flags.is_invalid);
394 : 16243 : g_return_if_fail (!old_flags.flags.in_marshal);
395 : :
396 : 16243 : real_closure = G_REAL_CLOSURE (closure);
397 : :
398 : 16243 : g_return_if_fail (real_closure->meta_marshal == NULL);
399 : :
400 : 16243 : real_closure->meta_marshal = meta_marshal;
401 : 16243 : real_closure->meta_marshal_data = marshal_data;
402 : : }
403 : :
404 : : /**
405 : : * g_closure_add_marshal_guards: (skip)
406 : : * @closure: a #GClosure
407 : : * @pre_marshal_data: (closure pre_marshal_notify): data to pass
408 : : * to @pre_marshal_notify
409 : : * @pre_marshal_notify: a function to call before the closure callback
410 : : * @post_marshal_data: (closure post_marshal_notify): data to pass
411 : : * to @post_marshal_notify
412 : : * @post_marshal_notify: a function to call after the closure callback
413 : : *
414 : : * Adds a pair of notifiers which get invoked before and after the
415 : : * closure callback, respectively.
416 : : *
417 : : * This is typically used to protect the extra arguments for the
418 : : * duration of the callback. See g_object_watch_closure() for an
419 : : * example of marshal guards.
420 : : */
421 : : void
422 : 85 : g_closure_add_marshal_guards (GClosure *closure,
423 : : gpointer pre_marshal_data,
424 : : GClosureNotify pre_marshal_notify,
425 : : gpointer post_marshal_data,
426 : : GClosureNotify post_marshal_notify)
427 : : {
428 : : GClosureFlags old_flags;
429 : : guint i;
430 : :
431 : 85 : g_return_if_fail (closure != NULL);
432 : 85 : g_return_if_fail (pre_marshal_notify != NULL);
433 : 85 : g_return_if_fail (post_marshal_notify != NULL);
434 : :
435 : 85 : old_flags = closure_atomic_get_flags (closure);
436 : 85 : g_return_if_fail (!old_flags.flags.is_invalid);
437 : 85 : g_return_if_fail (!old_flags.flags.in_marshal);
438 : 85 : g_return_if_fail (old_flags.flags.n_guards < CLOSURE_MAX_N_GUARDS);
439 : :
440 : 85 : closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 2);
441 : 85 : if (closure->n_inotifiers)
442 : 85 : closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
443 : 85 : closure->n_fnotifiers +
444 : 85 : closure->n_inotifiers + 1)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
445 : 85 : closure->n_fnotifiers + 0)];
446 : 85 : if (closure->n_inotifiers > 1)
447 : 0 : closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
448 : 0 : closure->n_fnotifiers +
449 : 0 : closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
450 : 0 : closure->n_fnotifiers + 1)];
451 : 85 : if (closure->n_fnotifiers)
452 : 0 : closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
453 : 0 : closure->n_fnotifiers + 1)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 0];
454 : 85 : if (closure->n_fnotifiers > 1)
455 : 0 : closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
456 : 0 : closure->n_fnotifiers)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 1];
457 : 85 : if (closure->n_guards)
458 : 0 : closure->notifiers[(closure->n_guards +
459 : 0 : closure->n_guards + 1)] = closure->notifiers[closure->n_guards];
460 : 85 : i = closure->n_guards;
461 : 85 : closure->notifiers[i].data = pre_marshal_data;
462 : 85 : closure->notifiers[i].notify = pre_marshal_notify;
463 : 85 : closure->notifiers[i + 1].data = post_marshal_data;
464 : 85 : closure->notifiers[i + 1].notify = post_marshal_notify;
465 : 85 : ATOMIC_INC (closure, n_guards);
466 : : }
467 : :
468 : : /**
469 : : * g_closure_add_finalize_notifier: (skip)
470 : : * @closure: a #GClosure
471 : : * @notify_data: (closure notify_func): data to pass to @notify_func
472 : : * @notify_func: the callback function to register
473 : : *
474 : : * Registers a finalization notifier which will be called when the
475 : : * reference count of @closure goes down to 0.
476 : : *
477 : : * Multiple finalization notifiers on a single closure are invoked in
478 : : * unspecified order. If a single call to g_closure_unref() results in
479 : : * the closure being both invalidated and finalized, then the invalidate
480 : : * notifiers will be run before the finalize notifiers.
481 : : */
482 : : void
483 : 114113 : g_closure_add_finalize_notifier (GClosure *closure,
484 : : gpointer notify_data,
485 : : GClosureNotify notify_func)
486 : : {
487 : : size_t i;
488 : :
489 : 114113 : g_return_if_fail (closure != NULL);
490 : 114113 : g_return_if_fail (notify_func != NULL);
491 : 114113 : g_return_if_fail (closure->n_fnotifiers < CLOSURE_MAX_N_FNOTIFIERS);
492 : :
493 : 114113 : closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1);
494 : 114113 : if (closure->n_inotifiers)
495 : 0 : closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
496 : 0 : closure->n_fnotifiers +
497 : 0 : closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
498 : 0 : closure->n_fnotifiers + 0)];
499 : 114113 : i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers;
500 : 114113 : closure->notifiers[i].data = notify_data;
501 : 114113 : closure->notifiers[i].notify = notify_func;
502 : 114113 : ATOMIC_INC (closure, n_fnotifiers);
503 : : }
504 : :
505 : : /**
506 : : * g_closure_add_invalidate_notifier: (skip)
507 : : * @closure: a #GClosure
508 : : * @notify_data: (closure notify_func): data to pass to @notify_func
509 : : * @notify_func: the callback function to register
510 : : *
511 : : * Registers an invalidation notifier which will be called when the
512 : : * @closure is invalidated with g_closure_invalidate().
513 : : *
514 : : * Invalidation notifiers are invoked before finalization notifiers,
515 : : * in an unspecified order.
516 : : */
517 : : void
518 : 24645 : g_closure_add_invalidate_notifier (GClosure *closure,
519 : : gpointer notify_data,
520 : : GClosureNotify notify_func)
521 : : {
522 : : GClosureFlags old_flags;
523 : : size_t i;
524 : :
525 : 24645 : g_return_if_fail (closure != NULL);
526 : 24645 : g_return_if_fail (notify_func != NULL);
527 : :
528 : 24645 : old_flags = closure_atomic_get_flags (closure);
529 : 24645 : g_return_if_fail (!old_flags.flags.is_invalid);
530 : 24645 : g_return_if_fail (old_flags.flags.n_inotifiers < CLOSURE_MAX_N_INOTIFIERS);
531 : :
532 : 24645 : closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1);
533 : 24645 : i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + closure->n_inotifiers;
534 : 24645 : closure->notifiers[i].data = notify_data;
535 : 24645 : closure->notifiers[i].notify = notify_func;
536 : 24645 : ATOMIC_INC (closure, n_inotifiers);
537 : : }
538 : :
539 : : static inline gboolean
540 : 10251 : closure_try_remove_inotify (GClosure *closure,
541 : : gpointer notify_data,
542 : : GClosureNotify notify_func)
543 : : {
544 : : GClosureNotifyData *ndata, *nlast;
545 : :
546 : 10251 : nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - 1;
547 : 10280 : for (ndata = nlast + 1 - closure->n_inotifiers; ndata <= nlast; ndata++)
548 : 10280 : if (ndata->notify == notify_func && ndata->data == notify_data)
549 : : {
550 : 10251 : ATOMIC_DEC (closure, n_inotifiers);
551 : 10251 : if (ndata < nlast)
552 : 58 : *ndata = *nlast;
553 : :
554 : 10251 : return TRUE;
555 : : }
556 : 0 : return FALSE;
557 : : }
558 : :
559 : : static inline gboolean
560 : 0 : closure_try_remove_fnotify (GClosure *closure,
561 : : gpointer notify_data,
562 : : GClosureNotify notify_func)
563 : : {
564 : : GClosureNotifyData *ndata, *nlast;
565 : :
566 : 0 : nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - closure->n_inotifiers - 1;
567 : 0 : for (ndata = nlast + 1 - closure->n_fnotifiers; ndata <= nlast; ndata++)
568 : 0 : if (ndata->notify == notify_func && ndata->data == notify_data)
569 : : {
570 : 0 : ATOMIC_DEC (closure, n_fnotifiers);
571 : 0 : if (ndata < nlast)
572 : 0 : *ndata = *nlast;
573 : 0 : if (closure->n_inotifiers)
574 : 0 : closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
575 : 0 : closure->n_fnotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
576 : 0 : closure->n_fnotifiers +
577 : 0 : closure->n_inotifiers)];
578 : 0 : return TRUE;
579 : : }
580 : 0 : return FALSE;
581 : : }
582 : :
583 : : static GClosureFlags
584 : 66501049 : closure_ref_internal (GClosure *closure)
585 : : {
586 : : guint new_ref_count;
587 : : int old_int, success;
588 : 66501049 : GClosureFlags tmp = { .atomic_int = 0, };
589 : :
590 : 66501049 : old_int = g_atomic_int_get (&((GClosureFlags *) closure)->atomic_int);
591 : : do
592 : : {
593 : 72122769 : tmp.atomic_int = old_int;
594 : 72122769 : tmp.flags.ref_count += 1;
595 : 72122769 : success = g_atomic_int_compare_and_exchange_full (&((GClosureFlags *) closure)->atomic_int, old_int, tmp.atomic_int, &old_int);
596 : : }
597 : 72122769 : while (!success);
598 : :
599 : 66501049 : new_ref_count = tmp.flags.ref_count;
600 : :
601 : 66501049 : g_return_val_if_fail (new_ref_count > 1, tmp);
602 : 66501049 : g_return_val_if_fail (new_ref_count < CLOSURE_MAX_REF_COUNT + 1, tmp);
603 : :
604 : 66501049 : return tmp;
605 : : }
606 : :
607 : : /**
608 : : * g_closure_ref:
609 : : * @closure: #GClosure to increment the reference count on
610 : : *
611 : : * Increments the reference count on a closure to force it staying
612 : : * alive while the caller holds a pointer to it.
613 : : *
614 : : * Returns: (transfer full): The @closure passed in, for convenience
615 : : */
616 : : GClosure*
617 : 49996761 : g_closure_ref (GClosure *closure)
618 : : {
619 : 49996761 : g_return_val_if_fail (closure != NULL, NULL);
620 : :
621 : 49996761 : closure_ref_internal (closure);
622 : 49996761 : return closure;
623 : : }
624 : :
625 : : static void
626 : 542966 : closure_invalidate_internal (GClosure *closure)
627 : : {
628 : : gboolean was_invalid;
629 : :
630 : 542966 : ATOMIC_SWAP (closure, is_invalid, TRUE, &was_invalid);
631 : : /* invalidate only once */
632 : 542966 : if (!was_invalid)
633 : 542966 : closure_invoke_notifiers (closure, INOTIFY);
634 : 542966 : }
635 : :
636 : : /**
637 : : * g_closure_invalidate:
638 : : * @closure: #GClosure to invalidate
639 : : *
640 : : * Sets a flag on the closure to indicate that its calling
641 : : * environment has become invalid, and thus causes any future
642 : : * invocations of g_closure_invoke() on this @closure to be
643 : : * ignored.
644 : : *
645 : : * Also, invalidation notifiers installed on the closure will
646 : : * be called at this point. Note that unless you are holding a
647 : : * reference to the closure yourself, the invalidation notifiers may
648 : : * unref the closure and cause it to be destroyed, so if you need to
649 : : * access the closure after calling g_closure_invalidate(), make sure
650 : : * that you've previously called g_closure_ref().
651 : : *
652 : : * Note that g_closure_invalidate() will also be called when the
653 : : * reference count of a closure drops to zero (unless it has already
654 : : * been invalidated before).
655 : : */
656 : : void
657 : 90 : g_closure_invalidate (GClosure *closure)
658 : : {
659 : : GClosureFlags old_flags;
660 : :
661 : 90 : g_return_if_fail (closure != NULL);
662 : :
663 : 90 : old_flags = closure_atomic_get_flags (closure);
664 : 90 : if (!old_flags.flags.is_invalid)
665 : : {
666 : 86 : g_closure_ref (closure); /* preserve floating flag */
667 : 86 : closure_invalidate_internal (closure);
668 : 86 : g_closure_unref (closure);
669 : : }
670 : : }
671 : :
672 : : /**
673 : : * g_closure_unref:
674 : : * @closure: (transfer full): #GClosure to decrement the reference count on
675 : : *
676 : : * Decrements the reference count of a closure after it was previously
677 : : * incremented by the same caller.
678 : : *
679 : : * If no other callers are using the closure, then the closure will be
680 : : * destroyed and freed.
681 : : */
682 : : void
683 : 67044007 : g_closure_unref (GClosure *closure)
684 : : {
685 : : guint new_ref_count;
686 : : GClosureFlags old_flags;
687 : :
688 : 67044007 : g_return_if_fail (closure != NULL);
689 : :
690 : 67044007 : old_flags = closure_atomic_get_flags (closure);
691 : 67044007 : g_return_if_fail (old_flags.flags.ref_count > 0);
692 : :
693 : : /* last unref, invalidate first */
694 : 67044007 : if (old_flags.flags.ref_count == 1 && !old_flags.flags.is_invalid)
695 : 542880 : closure_invalidate_internal (closure);
696 : :
697 : 86309939 : ATOMIC_DEC_ASSIGN (closure, ref_count, &new_ref_count);
698 : :
699 : 67044007 : if (new_ref_count == 0)
700 : : {
701 : 542966 : closure_invoke_notifiers (closure, FNOTIFY);
702 : 542966 : g_free (closure->notifiers);
703 : :
704 : : #ifdef ENABLE_VALGRIND
705 : : /* See comments in gtype.c about what's going on here... */
706 : 542966 : if (RUNNING_ON_VALGRIND)
707 : : {
708 : : gchar *allocated;
709 : :
710 : 0 : allocated = (gchar *) G_REAL_CLOSURE (closure);
711 : 0 : allocated -= sizeof (gpointer);
712 : :
713 : 0 : g_free (allocated);
714 : :
715 : 0 : VALGRIND_FREELIKE_BLOCK (allocated + sizeof (gpointer), 0);
716 : 0 : VALGRIND_FREELIKE_BLOCK (closure, 0);
717 : : }
718 : : else
719 : : #endif
720 : 542966 : g_free (G_REAL_CLOSURE (closure));
721 : : }
722 : : }
723 : :
724 : : /**
725 : : * g_closure_sink:
726 : : * @closure: #GClosure to decrement the initial reference count on, if it's
727 : : * still being held
728 : : *
729 : : * Takes over the initial ownership of a closure.
730 : : *
731 : : * Each closure is initially created in a "floating" state, which means
732 : : * that the initial reference count is not owned by any caller.
733 : : *
734 : : * This function checks to see if the object is still floating, and if so,
735 : : * unsets the floating state and decreases the reference count. If the
736 : : * closure is not floating, g_closure_sink() does nothing.
737 : : *
738 : : * The reason for the existence of the floating state is to prevent
739 : : * cumbersome code sequences like:
740 : : *
741 : : * |[<!-- language="C" -->
742 : : * closure = g_cclosure_new (cb_func, cb_data);
743 : : * g_source_set_closure (source, closure);
744 : : * g_closure_unref (closure); // GObject doesn't really need this
745 : : * ]|
746 : : *
747 : : * Because g_source_set_closure() (and similar functions) take ownership of the
748 : : * initial reference count, if it is unowned, we instead can write:
749 : : *
750 : : * |[<!-- language="C" -->
751 : : * g_source_set_closure (source, g_cclosure_new (cb_func, cb_data));
752 : : * ]|
753 : : *
754 : : * Generally, this function is used together with g_closure_ref(). An example
755 : : * of storing a closure for later notification looks like:
756 : : *
757 : : * |[<!-- language="C" -->
758 : : * static GClosure *notify_closure = NULL;
759 : : * void
760 : : * foo_notify_set_closure (GClosure *closure)
761 : : * {
762 : : * if (notify_closure)
763 : : * g_closure_unref (notify_closure);
764 : : * notify_closure = closure;
765 : : * if (notify_closure)
766 : : * {
767 : : * g_closure_ref (notify_closure);
768 : : * g_closure_sink (notify_closure);
769 : : * }
770 : : * }
771 : : * ]|
772 : : *
773 : : * Because g_closure_sink() may decrement the reference count of a closure
774 : : * (if it hasn't been called on @closure yet) just like g_closure_unref(),
775 : : * g_closure_ref() should be called prior to this function.
776 : : */
777 : : void
778 : 1045125 : g_closure_sink (GClosure *closure)
779 : : {
780 : : GClosureFlags old_flags;
781 : :
782 : 1045125 : g_return_if_fail (closure != NULL);
783 : :
784 : 1045125 : old_flags = closure_atomic_get_flags (closure);
785 : 1045125 : g_return_if_fail (old_flags.flags.ref_count > 0);
786 : :
787 : : /* floating is basically a kludge to avoid creating closures
788 : : * with a ref_count of 0. so the initial ref_count a closure has
789 : : * is unowned. with invoking g_closure_sink() code may
790 : : * indicate that it takes over that initial ref_count.
791 : : */
792 : 1045125 : if (old_flags.flags.floating)
793 : : {
794 : : gboolean was_floating;
795 : 545395 : ATOMIC_SWAP (closure, floating, FALSE, &was_floating);
796 : : /* unref floating flag only once */
797 : 545395 : if (was_floating)
798 : 545395 : g_closure_unref (closure);
799 : : }
800 : : }
801 : :
802 : : /**
803 : : * g_closure_remove_invalidate_notifier: (skip)
804 : : * @closure: a #GClosure
805 : : * @notify_data: data which was passed to g_closure_add_invalidate_notifier()
806 : : * when registering @notify_func
807 : : * @notify_func: the callback function to remove
808 : : *
809 : : * Removes an invalidation notifier.
810 : : *
811 : : * Notice that notifiers are automatically removed after they are run.
812 : : */
813 : : void
814 : 10251 : g_closure_remove_invalidate_notifier (GClosure *closure,
815 : : gpointer notify_data,
816 : : GClosureNotify notify_func)
817 : : {
818 : : GClosureFlags old_flags;
819 : :
820 : 10251 : g_return_if_fail (closure != NULL);
821 : 10251 : g_return_if_fail (notify_func != NULL);
822 : :
823 : 10251 : old_flags = closure_atomic_get_flags (closure);
824 : :
825 : 10251 : if (old_flags.flags.is_invalid && old_flags.flags.in_inotify && /* account removal of notify_func() while it's called */
826 : 0 : ((gpointer) closure->marshal) == ((gpointer) notify_func) &&
827 : 0 : closure->data == notify_data)
828 : 0 : closure->marshal = NULL;
829 : 10251 : else if (!closure_try_remove_inotify (closure, notify_data, notify_func))
830 : 0 : g_critical (G_STRLOC ": unable to remove uninstalled invalidation notifier: %p (%p)",
831 : : notify_func, notify_data);
832 : : }
833 : :
834 : : /**
835 : : * g_closure_remove_finalize_notifier: (skip)
836 : : * @closure: a #GClosure
837 : : * @notify_data: data which was passed to g_closure_add_finalize_notifier()
838 : : * when registering @notify_func
839 : : * @notify_func: the callback function to remove
840 : : *
841 : : * Removes a finalization notifier.
842 : : *
843 : : * Notice that notifiers are automatically removed after they are run.
844 : : */
845 : : void
846 : 0 : g_closure_remove_finalize_notifier (GClosure *closure,
847 : : gpointer notify_data,
848 : : GClosureNotify notify_func)
849 : : {
850 : : GClosureFlags old_flags;
851 : :
852 : 0 : g_return_if_fail (closure != NULL);
853 : 0 : g_return_if_fail (notify_func != NULL);
854 : :
855 : 0 : old_flags = closure_atomic_get_flags (closure);
856 : :
857 : 0 : if (old_flags.flags.is_invalid && !old_flags.flags.in_inotify && /* account removal of notify_func() while it's called */
858 : 0 : ((gpointer) closure->marshal) == ((gpointer) notify_func) &&
859 : 0 : closure->data == notify_data)
860 : 0 : closure->marshal = NULL;
861 : 0 : else if (!closure_try_remove_fnotify (closure, notify_data, notify_func))
862 : 0 : g_critical (G_STRLOC ": unable to remove uninstalled finalization notifier: %p (%p)",
863 : : notify_func, notify_data);
864 : : }
865 : :
866 : : /**
867 : : * g_closure_invoke:
868 : : * @closure: a #GClosure
869 : : * @return_value: (optional) (out): a #GValue to store the return
870 : : * value. May be %NULL if the callback of @closure
871 : : * doesn't return a value.
872 : : * @n_param_values: the length of the @param_values array
873 : : * @param_values: (array length=n_param_values): an array of
874 : : * #GValues holding the arguments on which to
875 : : * invoke the callback of @closure
876 : : * @invocation_hint: (nullable): a context-dependent invocation hint
877 : : *
878 : : * Invokes the closure, i.e. executes the callback represented by the @closure.
879 : : */
880 : : void
881 : 15537357 : g_closure_invoke (GClosure *closure,
882 : : GValue /*out*/ *return_value,
883 : : guint n_param_values,
884 : : const GValue *param_values,
885 : : gpointer invocation_hint)
886 : : {
887 : : GClosureFlags reffed_flags;
888 : : GRealClosure *real_closure;
889 : :
890 : 15537357 : g_return_if_fail (closure != NULL);
891 : :
892 : 15537357 : real_closure = G_REAL_CLOSURE (closure);
893 : :
894 : 15537357 : reffed_flags = closure_ref_internal (closure); /* preserve floating flag */
895 : 15537357 : if (!reffed_flags.flags.is_invalid)
896 : : {
897 : : GClosureMarshal marshal;
898 : : gpointer marshal_data;
899 : 15537357 : gboolean in_marshal = reffed_flags.flags.in_marshal;
900 : :
901 : 15537357 : g_return_if_fail (closure->marshal || real_closure->meta_marshal);
902 : :
903 : 17048502 : ATOMIC_SET (closure, in_marshal, TRUE);
904 : 15537357 : if (real_closure->meta_marshal)
905 : : {
906 : 8944597 : marshal_data = real_closure->meta_marshal_data;
907 : 8944597 : marshal = real_closure->meta_marshal;
908 : : }
909 : : else
910 : : {
911 : 6592760 : marshal_data = NULL;
912 : 6592760 : marshal = closure->marshal;
913 : : }
914 : 15537357 : if (!in_marshal)
915 : 12787312 : closure_invoke_notifiers (closure, PRE_NOTIFY);
916 : 15537357 : marshal (closure,
917 : : return_value,
918 : : n_param_values, param_values,
919 : : invocation_hint,
920 : : marshal_data);
921 : 15537351 : if (!in_marshal)
922 : 12787306 : closure_invoke_notifiers (closure, POST_NOTIFY);
923 : 16676611 : ATOMIC_SET (closure, in_marshal, (guint) in_marshal);
924 : : }
925 : 15537351 : g_closure_unref (closure);
926 : : }
927 : :
928 : : gboolean
929 : 9870346 : _g_closure_supports_invoke_va (GClosure *closure)
930 : : {
931 : : GRealClosure *real_closure;
932 : :
933 : 9870346 : g_return_val_if_fail (closure != NULL, FALSE);
934 : :
935 : 9870346 : real_closure = G_REAL_CLOSURE (closure);
936 : :
937 : : return
938 : 13722202 : real_closure->va_marshal != NULL &&
939 : 3851856 : (real_closure->meta_marshal == NULL ||
940 : 678053 : real_closure->va_meta_marshal != NULL);
941 : : }
942 : :
943 : : void
944 : 966931 : _g_closure_invoke_va (GClosure *closure,
945 : : GValue /*out*/ *return_value,
946 : : gpointer instance,
947 : : va_list args,
948 : : int n_params,
949 : : GType *param_types)
950 : : {
951 : : GClosureFlags reffed_flags;
952 : : GRealClosure *real_closure;
953 : :
954 : 966931 : g_return_if_fail (closure != NULL);
955 : :
956 : 966931 : real_closure = G_REAL_CLOSURE (closure);
957 : :
958 : 966931 : reffed_flags = closure_ref_internal (closure); /* preserve floating flag */
959 : 966931 : if (!reffed_flags.flags.is_invalid)
960 : : {
961 : : GVaClosureMarshal marshal;
962 : : gpointer marshal_data;
963 : 966931 : gboolean in_marshal = reffed_flags.flags.in_marshal;
964 : :
965 : 966931 : g_return_if_fail (closure->marshal || real_closure->meta_marshal);
966 : :
967 : 966931 : ATOMIC_SET (closure, in_marshal, TRUE);
968 : 966931 : if (real_closure->va_meta_marshal)
969 : : {
970 : 436801 : marshal_data = real_closure->meta_marshal_data;
971 : 436801 : marshal = real_closure->va_meta_marshal;
972 : : }
973 : : else
974 : : {
975 : 530130 : marshal_data = NULL;
976 : 530130 : marshal = real_closure->va_marshal;
977 : : }
978 : 966931 : if (!in_marshal)
979 : 966931 : closure_invoke_notifiers (closure, PRE_NOTIFY);
980 : 966931 : marshal (closure,
981 : : return_value,
982 : : instance, args,
983 : : marshal_data,
984 : : n_params, param_types);
985 : 966929 : if (!in_marshal)
986 : 966929 : closure_invoke_notifiers (closure, POST_NOTIFY);
987 : 966929 : ATOMIC_SET (closure, in_marshal, (guint) in_marshal);
988 : : }
989 : 966929 : g_closure_unref (closure);
990 : : }
991 : :
992 : :
993 : : /**
994 : : * g_closure_set_marshal: (skip)
995 : : * @closure: a #GClosure
996 : : * @marshal: a #GClosureMarshal function
997 : : *
998 : : * Sets the marshaller of @closure.
999 : : *
1000 : : * The `marshal_data` of @marshal provides a way for a meta marshaller to
1001 : : * provide additional information to the marshaller.
1002 : : *
1003 : : * For GObject's C predefined marshallers (the `g_cclosure_marshal_*()`
1004 : : * functions), what it provides is a callback function to use instead of
1005 : : * @closure->callback.
1006 : : *
1007 : : * See also: g_closure_set_meta_marshal()
1008 : : */
1009 : : void
1010 : 545390 : g_closure_set_marshal (GClosure *closure,
1011 : : GClosureMarshal marshal)
1012 : : {
1013 : 545390 : g_return_if_fail (closure != NULL);
1014 : 545390 : g_return_if_fail (marshal != NULL);
1015 : :
1016 : 545390 : if (closure->marshal && closure->marshal != marshal)
1017 : 0 : g_critical ("attempt to override closure->marshal (%p) with new marshal (%p)",
1018 : : closure->marshal, marshal);
1019 : : else
1020 : 545390 : closure->marshal = marshal;
1021 : : }
1022 : :
1023 : : void
1024 : 530737 : _g_closure_set_va_marshal (GClosure *closure,
1025 : : GVaClosureMarshal marshal)
1026 : : {
1027 : : GRealClosure *real_closure;
1028 : :
1029 : 530737 : g_return_if_fail (closure != NULL);
1030 : 530737 : g_return_if_fail (marshal != NULL);
1031 : :
1032 : 530737 : real_closure = G_REAL_CLOSURE (closure);
1033 : :
1034 : 530737 : if (real_closure->va_marshal && real_closure->va_marshal != marshal)
1035 : 0 : g_critical ("attempt to override closure->va_marshal (%p) with new marshal (%p)",
1036 : : real_closure->va_marshal, marshal);
1037 : : else
1038 : 530737 : real_closure->va_marshal = marshal;
1039 : : }
1040 : :
1041 : : /**
1042 : : * g_cclosure_new: (skip)
1043 : : * @callback_func: the function to invoke
1044 : : * @user_data: (closure callback_func): user data to pass to @callback_func
1045 : : * @destroy_data: destroy notify to be called when @user_data is no longer used
1046 : : *
1047 : : * Creates a new closure which invokes @callback_func with @user_data as
1048 : : * the last parameter.
1049 : : *
1050 : : * @destroy_data will be called as a finalize notifier on the #GClosure.
1051 : : *
1052 : : * Returns: (transfer floating): a floating reference to a new #GCClosure
1053 : : */
1054 : : GClosure*
1055 : 528893 : g_cclosure_new (GCallback callback_func,
1056 : : gpointer user_data,
1057 : : GClosureNotify destroy_data)
1058 : : {
1059 : : GClosure *closure;
1060 : :
1061 : 528893 : g_return_val_if_fail (callback_func != NULL, NULL);
1062 : :
1063 : 528893 : closure = g_closure_new_simple (sizeof (GCClosure), user_data);
1064 : 528893 : if (destroy_data)
1065 : 114113 : g_closure_add_finalize_notifier (closure, user_data, destroy_data);
1066 : 528893 : ((GCClosure*) closure)->callback = (gpointer) callback_func;
1067 : :
1068 : 528893 : return closure;
1069 : : }
1070 : :
1071 : : /**
1072 : : * g_cclosure_new_swap: (skip)
1073 : : * @callback_func: the function to invoke
1074 : : * @user_data: (closure callback_func): user data to pass to @callback_func
1075 : : * @destroy_data: destroy notify to be called when @user_data is no longer used
1076 : : *
1077 : : * Creates a new closure which invokes @callback_func with @user_data as
1078 : : * the first parameter.
1079 : : *
1080 : : * @destroy_data will be called as a finalize notifier on the #GClosure.
1081 : : *
1082 : : * Returns: (transfer floating): a floating reference to a new #GCClosure
1083 : : */
1084 : : GClosure*
1085 : 262 : g_cclosure_new_swap (GCallback callback_func,
1086 : : gpointer user_data,
1087 : : GClosureNotify destroy_data)
1088 : : {
1089 : : GClosure *closure;
1090 : :
1091 : 262 : g_return_val_if_fail (callback_func != NULL, NULL);
1092 : :
1093 : 262 : closure = g_closure_new_simple (sizeof (GCClosure), user_data);
1094 : 262 : if (destroy_data)
1095 : 0 : g_closure_add_finalize_notifier (closure, user_data, destroy_data);
1096 : 262 : ((GCClosure*) closure)->callback = (gpointer) callback_func;
1097 : 262 : ATOMIC_SET (closure, derivative_flag, TRUE);
1098 : :
1099 : 262 : return closure;
1100 : : }
1101 : :
1102 : : static void
1103 : 8840142 : g_type_class_meta_marshal (GClosure *closure,
1104 : : GValue /*out*/ *return_value,
1105 : : guint n_param_values,
1106 : : const GValue *param_values,
1107 : : gpointer invocation_hint,
1108 : : gpointer marshal_data)
1109 : : {
1110 : : GTypeClass *class;
1111 : : gpointer callback;
1112 : : /* GType itype = (GType) closure->data; */
1113 : 8840142 : guint offset = GPOINTER_TO_UINT (marshal_data);
1114 : :
1115 : 8840142 : class = G_TYPE_INSTANCE_GET_CLASS (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
1116 : 8840142 : callback = G_STRUCT_MEMBER (gpointer, class, offset);
1117 : 8840142 : if (callback)
1118 : 4628358 : closure->marshal (closure,
1119 : : return_value,
1120 : : n_param_values, param_values,
1121 : : invocation_hint,
1122 : : callback);
1123 : 8840142 : }
1124 : :
1125 : : static void
1126 : 436801 : g_type_class_meta_marshalv (GClosure *closure,
1127 : : GValue *return_value,
1128 : : gpointer instance,
1129 : : va_list args,
1130 : : gpointer marshal_data,
1131 : : int n_params,
1132 : : GType *param_types)
1133 : : {
1134 : : GRealClosure *real_closure;
1135 : : GTypeClass *class;
1136 : : gpointer callback;
1137 : : /* GType itype = (GType) closure->data; */
1138 : 436801 : guint offset = GPOINTER_TO_UINT (marshal_data);
1139 : :
1140 : 436801 : real_closure = G_REAL_CLOSURE (closure);
1141 : :
1142 : 436801 : class = G_TYPE_INSTANCE_GET_CLASS (instance, itype, GTypeClass);
1143 : 436801 : callback = G_STRUCT_MEMBER (gpointer, class, offset);
1144 : 436801 : if (callback)
1145 : 436801 : real_closure->va_marshal (closure,
1146 : : return_value,
1147 : : instance, args,
1148 : : callback,
1149 : : n_params,
1150 : : param_types);
1151 : 436801 : }
1152 : :
1153 : : static void
1154 : 100379 : g_type_iface_meta_marshal (GClosure *closure,
1155 : : GValue /*out*/ *return_value,
1156 : : guint n_param_values,
1157 : : const GValue *param_values,
1158 : : gpointer invocation_hint,
1159 : : gpointer marshal_data)
1160 : : {
1161 : : GTypeClass *class;
1162 : : gpointer callback;
1163 : 100379 : GType itype = (GType) closure->data;
1164 : 100379 : guint offset = GPOINTER_TO_UINT (marshal_data);
1165 : :
1166 : 100379 : class = G_TYPE_INSTANCE_GET_INTERFACE (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
1167 : 100379 : callback = G_STRUCT_MEMBER (gpointer, class, offset);
1168 : 100379 : if (callback)
1169 : 78 : closure->marshal (closure,
1170 : : return_value,
1171 : : n_param_values, param_values,
1172 : : invocation_hint,
1173 : : callback);
1174 : 100379 : }
1175 : :
1176 : : gboolean
1177 : 19615677 : _g_closure_is_void (GClosure *closure,
1178 : : gpointer instance)
1179 : : {
1180 : : GClosureFlags old_flags;
1181 : : GRealClosure *real_closure;
1182 : : GTypeClass *class;
1183 : : gpointer callback;
1184 : : GType itype;
1185 : : guint offset;
1186 : :
1187 : 19615677 : old_flags = closure_atomic_get_flags (closure);
1188 : :
1189 : 19615677 : if (old_flags.flags.is_invalid)
1190 : 0 : return TRUE;
1191 : :
1192 : 19615677 : real_closure = G_REAL_CLOSURE (closure);
1193 : :
1194 : 19615677 : if (real_closure->meta_marshal == g_type_iface_meta_marshal)
1195 : : {
1196 : 0 : itype = (GType) closure->data;
1197 : 0 : offset = GPOINTER_TO_UINT (real_closure->meta_marshal_data);
1198 : :
1199 : 0 : class = G_TYPE_INSTANCE_GET_INTERFACE (instance, itype, GTypeClass);
1200 : 0 : callback = G_STRUCT_MEMBER (gpointer, class, offset);
1201 : 0 : return callback == NULL;
1202 : : }
1203 : 19615677 : else if (real_closure->meta_marshal == g_type_class_meta_marshal)
1204 : : {
1205 : 19615676 : offset = GPOINTER_TO_UINT (real_closure->meta_marshal_data);
1206 : :
1207 : 19615676 : class = G_TYPE_INSTANCE_GET_CLASS (instance, itype, GTypeClass);
1208 : 19615676 : callback = G_STRUCT_MEMBER (gpointer, class, offset);
1209 : 19615676 : return callback == NULL;
1210 : : }
1211 : :
1212 : 1 : return FALSE;
1213 : : }
1214 : :
1215 : : static void
1216 : 0 : g_type_iface_meta_marshalv (GClosure *closure,
1217 : : GValue *return_value,
1218 : : gpointer instance,
1219 : : va_list args,
1220 : : gpointer marshal_data,
1221 : : int n_params,
1222 : : GType *param_types)
1223 : : {
1224 : : GRealClosure *real_closure;
1225 : : GTypeClass *class;
1226 : : gpointer callback;
1227 : 0 : GType itype = (GType) closure->data;
1228 : 0 : guint offset = GPOINTER_TO_UINT (marshal_data);
1229 : :
1230 : 0 : real_closure = G_REAL_CLOSURE (closure);
1231 : :
1232 : 0 : class = G_TYPE_INSTANCE_GET_INTERFACE (instance, itype, GTypeClass);
1233 : 0 : callback = G_STRUCT_MEMBER (gpointer, class, offset);
1234 : 0 : if (callback)
1235 : 0 : real_closure->va_marshal (closure,
1236 : : return_value,
1237 : : instance, args,
1238 : : callback,
1239 : : n_params,
1240 : : param_types);
1241 : 0 : }
1242 : :
1243 : : /**
1244 : : * g_signal_type_cclosure_new:
1245 : : * @itype: the #GType identifier of an interface or classed type
1246 : : * @struct_offset: the offset of the member function of @itype's class
1247 : : * structure which is to be invoked by the new closure
1248 : : *
1249 : : * Creates a new closure which invokes the function found at the offset
1250 : : * @struct_offset in the class structure of the interface or classed type
1251 : : * identified by @itype.
1252 : : *
1253 : : * Returns: (transfer floating): a floating reference to a new #GCClosure
1254 : : */
1255 : : GClosure*
1256 : 1944 : g_signal_type_cclosure_new (GType itype,
1257 : : guint struct_offset)
1258 : : {
1259 : : GClosure *closure;
1260 : :
1261 : 1944 : g_return_val_if_fail (G_TYPE_IS_CLASSED (itype) || G_TYPE_IS_INTERFACE (itype), NULL);
1262 : 1944 : g_return_val_if_fail (struct_offset >= sizeof (GTypeClass), NULL);
1263 : :
1264 : 1944 : closure = g_closure_new_simple (sizeof (GClosure), GTYPE_TO_POINTER (itype));
1265 : 1944 : if (G_TYPE_IS_INTERFACE (itype))
1266 : : {
1267 : 272 : g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal);
1268 : 272 : g_closure_set_meta_va_marshal (closure, g_type_iface_meta_marshalv);
1269 : : }
1270 : : else
1271 : : {
1272 : 1672 : g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
1273 : 1672 : g_closure_set_meta_va_marshal (closure, g_type_class_meta_marshalv);
1274 : : }
1275 : 1944 : return closure;
1276 : : }
1277 : :
1278 : : #include <ffi.h>
1279 : : static ffi_type *
1280 : 3381392 : value_to_ffi_type (const GValue *gvalue,
1281 : : gpointer *value,
1282 : : gint *enum_tmpval,
1283 : : gboolean *tmpval_used)
1284 : : {
1285 : 3381392 : ffi_type *rettype = NULL;
1286 : 3381392 : GType type = g_type_fundamental (G_VALUE_TYPE (gvalue));
1287 : 3381392 : g_assert (type != G_TYPE_INVALID);
1288 : :
1289 : 3381392 : if (enum_tmpval)
1290 : : {
1291 : 3381392 : g_assert (tmpval_used != NULL);
1292 : 3381392 : *tmpval_used = FALSE;
1293 : : }
1294 : :
1295 : 3381392 : switch (type)
1296 : : {
1297 : 1127049 : case G_TYPE_BOOLEAN:
1298 : : case G_TYPE_CHAR:
1299 : : case G_TYPE_INT:
1300 : 1127049 : rettype = &ffi_type_sint;
1301 : 1127049 : *value = (gpointer)&(gvalue->data[0].v_int);
1302 : 1127049 : break;
1303 : 9 : case G_TYPE_ENUM:
1304 : : /* enums are stored in v_long even though they are integers, which makes
1305 : : * marshalling through libffi somewhat complicated. They need to be
1306 : : * marshalled as signed ints, but we need to use a temporary int sized
1307 : : * value to pass to libffi otherwise it'll pull the wrong value on
1308 : : * BE machines with 32-bit integers when treating v_long as 32-bit int.
1309 : : */
1310 : 9 : g_assert (enum_tmpval != NULL);
1311 : 9 : rettype = &ffi_type_sint;
1312 : 9 : *enum_tmpval = g_value_get_enum (gvalue);
1313 : 9 : *value = enum_tmpval;
1314 : 9 : *tmpval_used = TRUE;
1315 : 9 : break;
1316 : 7 : case G_TYPE_FLAGS:
1317 : 7 : g_assert (enum_tmpval != NULL);
1318 : 7 : rettype = &ffi_type_uint;
1319 : 7 : *enum_tmpval = (int) g_value_get_flags (gvalue);
1320 : 7 : *value = enum_tmpval;
1321 : 7 : *tmpval_used = TRUE;
1322 : 7 : break;
1323 : 12 : case G_TYPE_UCHAR:
1324 : : case G_TYPE_UINT:
1325 : 12 : rettype = &ffi_type_uint;
1326 : 12 : *value = (gpointer)&(gvalue->data[0].v_uint);
1327 : 12 : break;
1328 : 2254280 : case G_TYPE_STRING:
1329 : : case G_TYPE_OBJECT:
1330 : : case G_TYPE_BOXED:
1331 : : case G_TYPE_PARAM:
1332 : : case G_TYPE_POINTER:
1333 : : case G_TYPE_INTERFACE:
1334 : : case G_TYPE_VARIANT:
1335 : 2254280 : rettype = &ffi_type_pointer;
1336 : 2254280 : *value = (gpointer)&(gvalue->data[0].v_pointer);
1337 : 2254280 : break;
1338 : 5 : case G_TYPE_FLOAT:
1339 : 5 : rettype = &ffi_type_float;
1340 : 5 : *value = (gpointer)&(gvalue->data[0].v_float);
1341 : 5 : break;
1342 : 5 : case G_TYPE_DOUBLE:
1343 : 5 : rettype = &ffi_type_double;
1344 : 5 : *value = (gpointer)&(gvalue->data[0].v_double);
1345 : 5 : break;
1346 : 5 : case G_TYPE_LONG:
1347 : 5 : rettype = &ffi_type_slong;
1348 : 5 : *value = (gpointer)&(gvalue->data[0].v_long);
1349 : 5 : break;
1350 : 6 : case G_TYPE_ULONG:
1351 : 6 : rettype = &ffi_type_ulong;
1352 : 6 : *value = (gpointer)&(gvalue->data[0].v_ulong);
1353 : 6 : break;
1354 : 9 : case G_TYPE_INT64:
1355 : 9 : rettype = &ffi_type_sint64;
1356 : 9 : *value = (gpointer)&(gvalue->data[0].v_int64);
1357 : 9 : break;
1358 : 5 : case G_TYPE_UINT64:
1359 : 5 : rettype = &ffi_type_uint64;
1360 : 5 : *value = (gpointer)&(gvalue->data[0].v_uint64);
1361 : 5 : break;
1362 : 0 : default:
1363 : 0 : rettype = &ffi_type_pointer;
1364 : 0 : *value = NULL;
1365 : 0 : g_critical ("value_to_ffi_type: Unsupported fundamental type: %s", g_type_name (type));
1366 : 0 : break;
1367 : : }
1368 : 3381392 : return rettype;
1369 : : }
1370 : :
1371 : : static void
1372 : 1127071 : value_from_ffi_type (GValue *gvalue, gpointer *value)
1373 : : {
1374 : 1127071 : ffi_arg *int_val = (ffi_arg*) value;
1375 : : GType type;
1376 : :
1377 : 1127071 : type = G_VALUE_TYPE (gvalue);
1378 : :
1379 : 1127072 : restart:
1380 : 1127072 : switch (g_type_fundamental (type))
1381 : : {
1382 : 7 : case G_TYPE_INT:
1383 : 7 : g_value_set_int (gvalue, (gint) *int_val);
1384 : 7 : break;
1385 : 0 : case G_TYPE_FLOAT:
1386 : 0 : g_value_set_float (gvalue, *(gfloat*)value);
1387 : 0 : break;
1388 : 0 : case G_TYPE_DOUBLE:
1389 : 0 : g_value_set_double (gvalue, *(gdouble*)value);
1390 : 0 : break;
1391 : 26 : case G_TYPE_BOOLEAN:
1392 : 26 : g_value_set_boolean (gvalue, (gboolean) *int_val);
1393 : 26 : break;
1394 : 1127021 : case G_TYPE_STRING:
1395 : 1127021 : g_value_take_string (gvalue, *(gchar**)value);
1396 : 1127021 : break;
1397 : 0 : case G_TYPE_CHAR:
1398 : 0 : g_value_set_schar (gvalue, (gint8) *int_val);
1399 : 0 : break;
1400 : 0 : case G_TYPE_UCHAR:
1401 : 0 : g_value_set_uchar (gvalue, (guchar) *int_val);
1402 : 0 : break;
1403 : 2 : case G_TYPE_UINT:
1404 : 2 : g_value_set_uint (gvalue, (guint) *int_val);
1405 : 2 : break;
1406 : 0 : case G_TYPE_POINTER:
1407 : 0 : g_value_set_pointer (gvalue, *(gpointer*)value);
1408 : 0 : break;
1409 : 0 : case G_TYPE_LONG:
1410 : 0 : g_value_set_long (gvalue, (glong) *int_val);
1411 : 0 : break;
1412 : 0 : case G_TYPE_ULONG:
1413 : 0 : g_value_set_ulong (gvalue, (gulong) *int_val);
1414 : 0 : break;
1415 : 0 : case G_TYPE_INT64:
1416 : 0 : g_value_set_int64 (gvalue, (gint64) *int_val);
1417 : 0 : break;
1418 : 0 : case G_TYPE_UINT64:
1419 : 0 : g_value_set_uint64 (gvalue, (guint64) *int_val);
1420 : 0 : break;
1421 : 0 : case G_TYPE_BOXED:
1422 : 0 : g_value_take_boxed (gvalue, *(gpointer*)value);
1423 : 0 : break;
1424 : 4 : case G_TYPE_ENUM:
1425 : 4 : g_value_set_enum (gvalue, (gint) *int_val);
1426 : 4 : break;
1427 : 0 : case G_TYPE_FLAGS:
1428 : 0 : g_value_set_flags (gvalue, (guint) *int_val);
1429 : 0 : break;
1430 : 0 : case G_TYPE_PARAM:
1431 : 0 : g_value_take_param (gvalue, *(gpointer*)value);
1432 : 0 : break;
1433 : 1 : case G_TYPE_OBJECT:
1434 : 1 : g_value_take_object (gvalue, *(gpointer*)value);
1435 : 1 : break;
1436 : 10 : case G_TYPE_VARIANT:
1437 : 10 : g_value_take_variant (gvalue, *(gpointer*)value);
1438 : 10 : break;
1439 : 1 : case G_TYPE_INTERFACE:
1440 : 1 : type = g_type_interface_instantiatable_prerequisite (type);
1441 : 1 : if (type)
1442 : 1 : goto restart;
1443 : : G_GNUC_FALLTHROUGH;
1444 : : default:
1445 : 0 : g_critical ("value_from_ffi_type: Unsupported fundamental type %s for type %s",
1446 : : g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue))),
1447 : : g_type_name (G_VALUE_TYPE (gvalue)));
1448 : : }
1449 : 1127071 : }
1450 : :
1451 : : typedef union {
1452 : : gpointer _gpointer;
1453 : : float _float;
1454 : : double _double;
1455 : : gint _gint;
1456 : : guint _guint;
1457 : : glong _glong;
1458 : : gulong _gulong;
1459 : : gint64 _gint64;
1460 : : guint64 _guint64;
1461 : : } va_arg_storage;
1462 : :
1463 : : static ffi_type *
1464 : 31 : va_to_ffi_type (GType gtype,
1465 : : va_list *va,
1466 : : va_arg_storage *storage)
1467 : : {
1468 : 31 : ffi_type *rettype = NULL;
1469 : 31 : GType type = g_type_fundamental (gtype);
1470 : 31 : g_assert (type != G_TYPE_INVALID);
1471 : :
1472 : 31 : switch (type)
1473 : : {
1474 : 11 : case G_TYPE_BOOLEAN:
1475 : : case G_TYPE_CHAR:
1476 : : case G_TYPE_INT:
1477 : : case G_TYPE_ENUM:
1478 : 11 : rettype = &ffi_type_sint;
1479 : 11 : storage->_gint = va_arg (*va, gint);
1480 : 11 : break;
1481 : 4 : case G_TYPE_UCHAR:
1482 : : case G_TYPE_UINT:
1483 : : case G_TYPE_FLAGS:
1484 : 4 : rettype = &ffi_type_uint;
1485 : 4 : storage->_guint = va_arg (*va, guint);
1486 : 4 : break;
1487 : 7 : case G_TYPE_STRING:
1488 : : case G_TYPE_OBJECT:
1489 : : case G_TYPE_BOXED:
1490 : : case G_TYPE_PARAM:
1491 : : case G_TYPE_POINTER:
1492 : : case G_TYPE_INTERFACE:
1493 : : case G_TYPE_VARIANT:
1494 : 7 : rettype = &ffi_type_pointer;
1495 : 7 : storage->_gpointer = va_arg (*va, gpointer);
1496 : 7 : break;
1497 : 2 : case G_TYPE_FLOAT:
1498 : : /* Float args are passed as doubles in varargs */
1499 : 2 : rettype = &ffi_type_float;
1500 : 2 : storage->_float = (float)va_arg (*va, double);
1501 : 2 : break;
1502 : 2 : case G_TYPE_DOUBLE:
1503 : 2 : rettype = &ffi_type_double;
1504 : 2 : storage->_double = va_arg (*va, double);
1505 : 2 : break;
1506 : 2 : case G_TYPE_LONG:
1507 : 2 : rettype = &ffi_type_slong;
1508 : 2 : storage->_glong = va_arg (*va, glong);
1509 : 2 : break;
1510 : 1 : case G_TYPE_ULONG:
1511 : 1 : rettype = &ffi_type_ulong;
1512 : 1 : storage->_gulong = va_arg (*va, gulong);
1513 : 1 : break;
1514 : 1 : case G_TYPE_INT64:
1515 : 1 : rettype = &ffi_type_sint64;
1516 : 1 : storage->_gint64 = va_arg (*va, gint64);
1517 : 1 : break;
1518 : 1 : case G_TYPE_UINT64:
1519 : 1 : rettype = &ffi_type_uint64;
1520 : 1 : storage->_guint64 = va_arg (*va, guint64);
1521 : 1 : break;
1522 : 0 : default:
1523 : 0 : rettype = &ffi_type_pointer;
1524 : 0 : storage->_guint64 = 0;
1525 : 0 : g_critical ("va_to_ffi_type: Unsupported fundamental type: %s", g_type_name (type));
1526 : 0 : break;
1527 : : }
1528 : 31 : return rettype;
1529 : : }
1530 : :
1531 : : /**
1532 : : * g_cclosure_marshal_generic:
1533 : : * @closure: A #GClosure.
1534 : : * @return_gvalue: A #GValue to store the return value. May be %NULL
1535 : : * if the callback of closure doesn't return a value.
1536 : : * @n_param_values: The length of the @param_values array.
1537 : : * @param_values: An array of #GValues holding the arguments
1538 : : * on which to invoke the callback of closure.
1539 : : * @invocation_hint: The invocation hint given as the last argument to
1540 : : * g_closure_invoke().
1541 : : * @marshal_data: Additional data specified when registering the
1542 : : * marshaller, see g_closure_set_marshal() and
1543 : : * g_closure_set_meta_marshal()
1544 : : *
1545 : : * A generic marshaller function implemented via
1546 : : * [libffi](http://sourceware.org/libffi/).
1547 : : *
1548 : : * Normally this function is not passed explicitly to g_signal_new(),
1549 : : * but used automatically by GLib when specifying a %NULL marshaller.
1550 : : *
1551 : : * Since: 2.30
1552 : : */
1553 : : void
1554 : 1127090 : g_cclosure_marshal_generic (GClosure *closure,
1555 : : GValue *return_gvalue,
1556 : : guint n_param_values,
1557 : : const GValue *param_values,
1558 : : gpointer invocation_hint,
1559 : : gpointer marshal_data)
1560 : : {
1561 : : ffi_type *rtype;
1562 : : void *rvalue;
1563 : : size_t n_args;
1564 : : ffi_type **atypes;
1565 : : void **args;
1566 : : size_t i;
1567 : : ffi_cif cif;
1568 : 1127090 : GCClosure *cc = (GCClosure*) closure;
1569 : : gint *enum_tmpval;
1570 : 1127090 : gboolean tmpval_used = FALSE;
1571 : :
1572 : 1127090 : enum_tmpval = g_alloca (sizeof (gint));
1573 : 1127090 : if (return_gvalue && G_VALUE_TYPE (return_gvalue))
1574 : : {
1575 : 1127061 : rtype = value_to_ffi_type (return_gvalue, &rvalue, enum_tmpval, &tmpval_used);
1576 : : }
1577 : : else
1578 : : {
1579 : 29 : rtype = &ffi_type_void;
1580 : : }
1581 : :
1582 : 1127090 : rvalue = g_alloca (MAX (rtype->size, sizeof (ffi_arg)));
1583 : :
1584 : 1127090 : n_args = n_param_values + 1;
1585 : 1127090 : atypes = g_alloca (sizeof (ffi_type *) * n_args);
1586 : 1127090 : args = g_alloca (sizeof (gpointer) * n_args);
1587 : :
1588 : 1127090 : if (tmpval_used)
1589 : 0 : enum_tmpval = g_alloca (sizeof (gint));
1590 : :
1591 : 1127090 : if (G_CCLOSURE_SWAP_DATA (closure))
1592 : : {
1593 : 0 : atypes[n_args-1] = value_to_ffi_type (param_values + 0,
1594 : 0 : &args[n_args-1],
1595 : : enum_tmpval,
1596 : : &tmpval_used);
1597 : 0 : atypes[0] = &ffi_type_pointer;
1598 : 0 : args[0] = &closure->data;
1599 : : }
1600 : : else
1601 : : {
1602 : 1127090 : atypes[0] = value_to_ffi_type (param_values + 0,
1603 : : &args[0],
1604 : : enum_tmpval,
1605 : : &tmpval_used);
1606 : 1127090 : atypes[n_args-1] = &ffi_type_pointer;
1607 : 1127090 : args[n_args-1] = &closure->data;
1608 : : }
1609 : :
1610 : 2254321 : for (i = 1; i < n_args - 1; i++)
1611 : : {
1612 : 1127231 : if (tmpval_used)
1613 : 10 : enum_tmpval = g_alloca (sizeof (gint));
1614 : :
1615 : 1127231 : atypes[i] = value_to_ffi_type (param_values + i,
1616 : 1127231 : &args[i],
1617 : : enum_tmpval,
1618 : : &tmpval_used);
1619 : : }
1620 : :
1621 : 1127090 : g_assert (n_args <= UINT_MAX);
1622 : :
1623 : 1127090 : if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, (unsigned int) n_args, rtype, atypes) != FFI_OK)
1624 : 0 : return;
1625 : :
1626 : 1127090 : ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args);
1627 : :
1628 : 1127090 : if (return_gvalue && G_VALUE_TYPE (return_gvalue))
1629 : 1127061 : value_from_ffi_type (return_gvalue, rvalue);
1630 : : }
1631 : :
1632 : : /**
1633 : : * g_cclosure_marshal_generic_va:
1634 : : * @closure: the #GClosure to which the marshaller belongs
1635 : : * @return_value: (nullable): a #GValue to store the return
1636 : : * value. May be %NULL if the callback of @closure doesn't return a
1637 : : * value.
1638 : : * @instance: (type GObject.TypeInstance): the instance on which the closure is
1639 : : * invoked.
1640 : : * @args_list: va_list of arguments to be passed to the closure.
1641 : : * @marshal_data: (nullable): additional data specified when
1642 : : * registering the marshaller, see g_closure_set_marshal() and
1643 : : * g_closure_set_meta_marshal()
1644 : : * @n_params: the length of the @param_types array
1645 : : * @param_types: (array length=n_params): the #GType of each argument from
1646 : : * @args_list.
1647 : : *
1648 : : * A generic #GVaClosureMarshal function implemented via
1649 : : * [libffi](http://sourceware.org/libffi/).
1650 : : *
1651 : : * Since: 2.30
1652 : : */
1653 : : void
1654 : 13 : g_cclosure_marshal_generic_va (GClosure *closure,
1655 : : GValue *return_value,
1656 : : gpointer instance,
1657 : : va_list args_list,
1658 : : gpointer marshal_data,
1659 : : int n_params,
1660 : : GType *param_types)
1661 : : {
1662 : : ffi_type *rtype;
1663 : : void *rvalue;
1664 : : size_t n_args;
1665 : : size_t unsigned_n_params;
1666 : : ffi_type **atypes;
1667 : : void **args;
1668 : : va_arg_storage *storage;
1669 : : size_t i;
1670 : : ffi_cif cif;
1671 : 13 : GCClosure *cc = (GCClosure*) closure;
1672 : : gint *enum_tmpval;
1673 : 13 : gboolean tmpval_used = FALSE;
1674 : : va_list args_copy;
1675 : :
1676 : 13 : g_return_if_fail (n_params >= 0);
1677 : :
1678 : 13 : unsigned_n_params = (size_t) n_params;
1679 : :
1680 : 13 : enum_tmpval = g_alloca (sizeof (gint));
1681 : 13 : if (return_value && G_VALUE_TYPE (return_value))
1682 : : {
1683 : 10 : rtype = value_to_ffi_type (return_value, &rvalue, enum_tmpval, &tmpval_used);
1684 : : }
1685 : : else
1686 : : {
1687 : 3 : rtype = &ffi_type_void;
1688 : : }
1689 : :
1690 : 13 : rvalue = g_alloca (MAX (rtype->size, sizeof (ffi_arg)));
1691 : :
1692 : 13 : n_args = unsigned_n_params + 2;
1693 : 13 : atypes = g_alloca (sizeof (ffi_type *) * n_args);
1694 : 13 : args = g_alloca (sizeof (gpointer) * n_args);
1695 : 13 : storage = g_alloca (sizeof (va_arg_storage) * unsigned_n_params);
1696 : :
1697 : 13 : if (G_CCLOSURE_SWAP_DATA (closure))
1698 : : {
1699 : 0 : atypes[n_args-1] = &ffi_type_pointer;
1700 : 0 : args[n_args-1] = &instance;
1701 : 0 : atypes[0] = &ffi_type_pointer;
1702 : 0 : args[0] = &closure->data;
1703 : : }
1704 : : else
1705 : : {
1706 : 13 : atypes[0] = &ffi_type_pointer;
1707 : 13 : args[0] = &instance;
1708 : 13 : atypes[n_args-1] = &ffi_type_pointer;
1709 : 13 : args[n_args-1] = &closure->data;
1710 : : }
1711 : :
1712 : 13 : va_copy (args_copy, args_list);
1713 : :
1714 : : /* Box non-primitive arguments */
1715 : 44 : for (i = 0; i < unsigned_n_params; i++)
1716 : : {
1717 : 31 : GType type = param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
1718 : 31 : GType fundamental = G_TYPE_FUNDAMENTAL (type);
1719 : :
1720 : 62 : atypes[i+1] = va_to_ffi_type (type,
1721 : : &args_copy,
1722 : 31 : &storage[i]);
1723 : 31 : args[i+1] = &storage[i];
1724 : :
1725 : 31 : if ((param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0)
1726 : : {
1727 : 31 : if (fundamental == G_TYPE_STRING && storage[i]._gpointer != NULL)
1728 : 2 : storage[i]._gpointer = g_strdup (storage[i]._gpointer);
1729 : 30 : else if (fundamental == G_TYPE_PARAM && storage[i]._gpointer != NULL)
1730 : 1 : storage[i]._gpointer = g_param_spec_ref (storage[i]._gpointer);
1731 : 29 : else if (fundamental == G_TYPE_BOXED && storage[i]._gpointer != NULL)
1732 : 1 : storage[i]._gpointer = g_boxed_copy (type, storage[i]._gpointer);
1733 : 28 : else if (fundamental == G_TYPE_VARIANT && storage[i]._gpointer != NULL)
1734 : 1 : storage[i]._gpointer = g_variant_ref_sink (storage[i]._gpointer);
1735 : : }
1736 : 31 : if (fundamental == G_TYPE_OBJECT && storage[i]._gpointer != NULL)
1737 : 1 : storage[i]._gpointer = g_object_ref (storage[i]._gpointer);
1738 : : }
1739 : :
1740 : 13 : va_end (args_copy);
1741 : :
1742 : 13 : g_assert (n_args <= UINT_MAX);
1743 : :
1744 : 13 : if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, (unsigned int) n_args, rtype, atypes) != FFI_OK)
1745 : 0 : return;
1746 : :
1747 : 13 : ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args);
1748 : :
1749 : : /* Unbox non-primitive arguments */
1750 : 44 : for (i = 0; i < unsigned_n_params; i++)
1751 : : {
1752 : 31 : GType type = param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
1753 : 31 : GType fundamental = G_TYPE_FUNDAMENTAL (type);
1754 : :
1755 : 31 : if ((param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0)
1756 : : {
1757 : 31 : if (fundamental == G_TYPE_STRING && storage[i]._gpointer != NULL)
1758 : 1 : g_free (storage[i]._gpointer);
1759 : 30 : else if (fundamental == G_TYPE_PARAM && storage[i]._gpointer != NULL)
1760 : 1 : g_param_spec_unref (storage[i]._gpointer);
1761 : 29 : else if (fundamental == G_TYPE_BOXED && storage[i]._gpointer != NULL)
1762 : 1 : g_boxed_free (type, storage[i]._gpointer);
1763 : 28 : else if (fundamental == G_TYPE_VARIANT && storage[i]._gpointer != NULL)
1764 : 1 : g_variant_unref (storage[i]._gpointer);
1765 : : }
1766 : 31 : if (fundamental == G_TYPE_OBJECT && storage[i]._gpointer != NULL)
1767 : 1 : g_object_unref (storage[i]._gpointer);
1768 : : }
1769 : :
1770 : 13 : if (return_value && G_VALUE_TYPE (return_value))
1771 : 10 : value_from_ffi_type (return_value, rvalue);
1772 : : }
|