LCOV - code coverage report
Current view: top level - gobject - gclosure.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 79.7 % 636 507
Test Date: 2026-02-10 05:15:13 Functions: 91.7 % 36 33
Branches: - 0 0

             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                 :             : }
        

Generated by: LCOV version 2.0-1