GObject 参考手册:概念:GObject 消息系统

Closures are central to the concept of asynchronous signal delivery which is widely used throughout GTK+ and GNOME applications. A closure is an abstraction, a generic representation of a callback. It is a small structure which contains three objects:

  • a function pointer (the callback itself) whose prototype looks like:
    return_type function_callback (... , gpointer user_data);
  • the user_data pointer which is passed to the callback upon invocation of the closure
  • a function pointer which represents the destructor of the closure: whenever the closure’s refcount reaches zero, this function will be called before the closure structure is freed.

The GClosure structure represents the common functionality of all closure implementations: there exists a different Closure implementation for each separate runtime which wants to use the GObject type system. [8] The GObject library provides a simple GCClosure type which is a specific implementation of closures to be used with C/C++ callbacks.

A GClosure provides simple services:

  • Invocation (g_closure_invoke): this is what closures were created for: they hide the details of callback invocation from the callback invoker.
  • Notification: the closure notifies listeners of certain events such as closure invocation, closure invalidation and closure finalization. Listeners can be registered with g_closure_add_finalize_notifier (finalization notification), g_closure_add_invalidate_notifier (invalidation notification) and g_closure_add_marshal_guards (invocation notification). There exist symmetric deregistration functions for finalization and invalidation events (g_closure_remove_finalize_notifier and g_closure_remove_invalidate_notifier) but not for the invocation process. [9]

C Closures

If you are using C or C++ to connect a callback to a given event, you will either use simple GCClosures which have a pretty minimal API or the even simpler g_signal_connect functions (which will be presented a bit later :).

GClosure* g_cclosure_new (GCallback        callback_func,
                          gpointer         user_data,
                          GClosureNotify   destroy_data);
GClosure* g_cclosure_new_swap (GCallback        callback_func,
                               gpointer         user_data,
                               GClosureNotify   destroy_data);
GClosure* g_signal_type_cclosure_new (GType  itype,
                                      guint  struct_offset);

g_cclosure_new will create a new closure which can invoke the user-provided callback_func with the user-provided user_data as last parameter. When the closure is finalized (second stage of the destruction process), it will invoke the destroy_data function if the user has supplied one.

g_cclosure_new_swap will create a new closure which can invoke the user-provided callback_func with the user-provided user_data as first parameter (instead of being the last parameter as with g_cclosure_new). When the closure is finalized (second stage of the destruction process), it will invoke the destroy_data function if the user has supplied one.

Non-C closures (for the fearless)

As was explained above, closures hide the details of callback invocation. In C, callback invocation is just like function invocation: it is a matter of creating the correct stack frame for the called function and executing a call assembly instruction.

C closure marshallers transform the array of GValues which represent the parameters to the target function into a C-style function parameter list, invoke the user-supplied C function with this new parameter list, get the return value of the function, transform it into a GValue and return this GValue to the marshaller caller.

The following code implements a simple marshaller in C for a C function which takes an integer as first parameter and returns void.

g_cclosure_marshal_VOID__INT (GClosure     *closure,
                              GValue       *return_value,
                              guint         n_param_values,
                              const GValue *param_values,
                              gpointer      invocation_hint,
                              gpointer      marshal_data)
{
  typedef void (*GMarshalFunc_VOID__INT) (gpointer     data1,
                                          gint         arg_1,
                                          gpointer     data2);
  register GMarshalFunc_VOID__INT callback;
  register GCClosure *cc = (GCClosure*) closure;
  register gpointer data1, data2;
 
  g_return_if_fail (n_param_values == 2);
 
  data1 = g_value_peek_pointer (param_values + 0);
  data2 = closure->data;
 
  callback = (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback);
 
  callback (data1,
            g_marshal_value_peek_int (param_values + 1),
            data2);
}

Of course, there exist other kinds of marshallers. For example, James Henstridge wrote a generic Python marshaller which is used by all Python closures (a Python closure is used to have Python-based callback be invoked by the closure invocation process). This Python marshaller transforms the input GValue list representing the function parameters into a Python tuple which is the equivalent structure in Python (you can look in pyg_closure_marshal in pygtype.c in the pygobject module in the GNOME Subversion server).

Leave a Reply

Your email address will not be published. Required fields are marked *