gobjec相关学习文章的list.
上层: Caller (Signal connect + user callback )
下层: Callee (Signal New + Emission机制)
New signal:
gsttypefindelement.c:
/**
* GstTypeFindElement::have-type:
* @typefind: the typefind instance
* @probability: the probability of the type found
* @caps: the caps of the type found
*
* This signal gets emitted when the type and its probability has
* been found.
*/
gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have-type",
G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
typefind_class->have_type =
GST_DEBUG_FUNCPTR (gst_type_find_element_have_type);
这里2个比较重要:
1. 指定类的成员函数:G_STRUCT_OFFSET (GstTypeFindElementClass, have_type),
是通过偏移地址进行的,在后面的函数g_type_class_meta_marshal里面,会根据这个函数偏移地址offset, 提取出这个函数的指针
2. 指定c_marshal: gst_marshal_VOID__UINT_BOXED
跟着代码进去:
guint
g_signal_new (const gchar *signal_name,
GType itype,
GSignalFlags signal_flags,
guint class_offset,
GSignalAccumulator accumulator,
gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
...)
{
va_list args;
guint signal_id;
g_return_val_if_fail (signal_name != NULL, 0);
va_start (args, n_params);
signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
class_offset ? g_signal_type_cclosure_new (itype, class_offset) : NULL,
accumulator, accu_data, c_marshaller,
return_type, n_params, args);
因为class_offset !=0, 所以会首先调用g_signal_type_cclosure_new (itype, class_offset),
GClosure*
g_signal_type_cclosure_new (GType itype,
guint struct_offset)
{
GClosure *closure;
g_return_val_if_fail (G_TYPE_IS_CLASSED (itype) || G_TYPE_IS_INTERFACE (itype), NULL);
g_return_val_if_fail (struct_offset >= sizeof (GTypeClass), NULL);
closure = g_closure_new_simple (sizeof (GClosure), (gpointer) itype);
if (G_TYPE_IS_INTERFACE (itype))
g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal);
else
g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
return closure;
}
g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
void
g_closure_set_meta_marshal (GClosure *closure,
gpointer marshal_data,
GClosureMarshal meta_marshal)
{
GClosureNotifyData *notifiers;
g_return_if_fail (closure != NULL);
g_return_if_fail (meta_marshal != NULL);
g_return_if_fail (closure->is_invalid == FALSE);
g_return_if_fail (closure->in_marshal == FALSE);
g_return_if_fail (closure->meta_marshal == 0);
notifiers = closure->notifiers;
closure->notifiers = g_renew (GClosureNotifyData, NULL, CLOSURE_N_NOTIFIERS (closure) + 1);
if (notifiers)
{
/* usually the meta marshal will be setup right after creation, so the
* g_memmove() should be rare-case scenario
*/
g_memmove (closure->notifiers + 1, notifiers, CLOSURE_N_NOTIFIERS (closure) * sizeof (notifiers[0]));
g_free (notifiers);
}
//marshal_data -> gst_type_find_element_have_type()
closure->notifiers[0].data = marshal_data;
//mata_marshal --> g_type_class_meta_marshal
closure->notifiers[0].notify = (GClosureNotify) meta_marshal;
SET (closure, meta_marshal, 1);
}
注意,这个meta_marshal 函数暂时还不会被调用。
假设被调用,其实就是emit后,发生的动作:
先根据offset, 提取函数的指针:
static void
g_type_class_meta_marshal (GClosure *closure,
GValue /*out*/ *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
GTypeClass *class;
gpointer callback;
/* GType itype = (GType) closure->data; */
guint offset = GPOINTER_TO_UINT (marshal_data);
class = G_TYPE_INSTANCE_GET_CLASS (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
callback = G_STRUCT_MEMBER (gpointer, class, offset);
if (callback)
closure->marshal (closure,
return_value,
n_param_values, param_values,
invocation_hint,
callback);
}
callback = G_STRUCT_MEMBER (gpointer, class, offset);
到这里,
callback = gst_type_find_element_have_type()= marshal_data ,这个函数指针会作为marshal_data,传入meta_marshal,
meta_marshal = g_type_class_meta_marshal()
static void
g_type_class_meta_marshal (GClosure *closure,
GValue /*out*/ *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
GTypeClass *class;
gpointer callback;
/* GType itype = (GType) closure->data; */
guint offset = GPOINTER_TO_UINT (marshal_data);
class = G_TYPE_INSTANCE_GET_CLASS (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
callback = G_STRUCT_MEMBER (gpointer, class, offset);
if (callback)
closure->marshal (closure,
return_value,
n_param_values, param_values,
invocation_hint,
callback);
}
同时后面会继续进行初始化:
signal_id = g_signal_newv (signal_name, itype, signal_flags,
class_closure, accumulator, accu_data, c_marshaller,
return_type, n_params, param_types);
/* setup permanent portion of signal node */
if (!node)
{
SignalKey key;
signal_id = g_n_signal_nodes++;
node = g_new (SignalNode, 1);
node->signal_id = signal_id;
g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
g_signal_nodes[signal_id] = node;
node->itype = itype;
node->name = name;
key.itype = itype;
key.quark = g_quark_from_string (node->name);
key.signal_id = signal_id;
g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);
g_strdelimit (name, "_", '-');
node->name = g_intern_string (name);
key.quark = g_quark_from_string (name);
g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);
TRACE(GOBJECT_SIGNAL_NEW(signal_id, name, itype));
}
node->destroyed = FALSE;
node->test_class_offset = 0;
/* setup reinitializable portion */
node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
node->n_params = n_params;
node->param_types = g_memdup (param_types, sizeof (GType) * n_params);
node->return_type = return_type;
node->class_closure_bsa = NULL;
if (accumulator)
{
node->accumulator = g_new (SignalAccumulator, 1);
node->accumulator->func = accumulator;
node->accumulator->data = accu_data;
}
else
node->accumulator = NULL;
node->c_marshaller = c_marshaller;
node->emission_hooks = NULL;
if (class_closure)
signal_add_class_closure (node, 0, class_closure);
先把C_marshaller保存下来:node->c_marshaller = c_marshaller;
这里node->c_marshaller: gst_marshal_VOID__UINT_BOXED
前面g_signal_type_cclosure_new (itype, class_offset)创建了class的closure, 并且指定了:
1. ) 指向class成员的gst_type_find_element_have_type(),这个估计是default handler.
2. )指定 class closure的meta marshal: g_type_class_meta_marshal()
下面这个函数,又给这个class closure指定了一个C Marshaller:
static void
signal_add_class_closure (SignalNode *node,
GType itype,
GClosure *closure)
{
ClassClosure key;
/* can't optimize NOP emissions with overridden class closures */
node->test_class_offset = 0;
if (!node->class_closure_bsa)
node->class_closure_bsa = g_bsearch_array_create (&g_class_closure_bconfig);
key.instance_type = itype;
key.closure = g_closure_ref (closure);
node->class_closure_bsa = g_bsearch_array_insert (node->class_closure_bsa,
&g_class_closure_bconfig,
&key);
g_closure_sink (closure);
if (node->c_marshaller && closure && G_CLOSURE_NEEDS_MARSHAL (closure))
g_closure_set_marshal (closure, node->c_marshaller);
}
在后面调用时:
meta_marshal -->调用 C Marshaller --> 调用 callback类的成员函数(default handler)
此时:这个signal node节点手里握有3个API:
1. class的meta marshal: g_type_class_meta_marshal()
2. C marshaller: gst_marshal_VOID__UINT_BOXED
3. class的成员函数:gst_type_find_element_have_type()【default handler】
connect signal注册的user级别的callback, 会存放到handler list中;
Connect Signal:
很多地方可以connect那个signal:
比如:gst-typefind.c
g_signal_connect (G_OBJECT (typefind), "have-type",
G_CALLBACK (have_type_handler), &caps);
#define g_signal_connect(instance, detailed_signal, c_handler, data) \
g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0)
这里注册C_handler, 可以说是上层用户自己的callback.
gulong
g_signal_connect_data (gpointer instance,
const gchar *detailed_signal,
GCallback c_handler,
gpointer data,
GClosureNotify destroy_data,
GConnectFlags connect_flags)
{
guint signal_id;
gulong handler_seq_no = 0;
GQuark detail = 0;
GType itype;
gboolean swapped, after;
swapped = (connect_flags & G_CONNECT_SWAPPED) != FALSE;
after = (connect_flags & G_CONNECT_AFTER) != FALSE;
SIGNAL_LOCK ();
itype = G_TYPE_FROM_INSTANCE (instance);
signal_id = signal_parse_name (detailed_signal, itype, &detail, TRUE);
if (signal_id)
{
SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
{
Handler *handler = handler_new (after);
handler_seq_no = handler->sequential_number;
handler->detail = detail;
handler->closure = g_closure_ref ((swapped ? g_cclosure_new_swap : g_cclosure_new) (c_handler, data, destroy_data));
g_closure_sink (handler->closure);
handler_insert (signal_id, instance, handler);
if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (handler->closure))
g_closure_set_marshal (handler->closure, node->c_marshaller);
}
}
else
g_warning ("%s: signal `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance);
SIGNAL_UNLOCK ();
return handler_seq_no;
}
1. 分配一个hanlder内存
2. 创建一个C closure, 并且绑定user 自己的callback
3. handler只有这个closure, 也就是拿住了用户的callback
4. 把hanlder, 插入到全局的handler list中去
5. 也把signal node的C marshal: gst_marshal_VOID__UINT_BOXED, 和handler的closure绑定。
此时:这个handler的closure掌握了:
1. User defined callback: have_type_handler() 【user defined handler】
2. C Marshal: gst_marshal_VOID__UINT_BOXED
从上面的2个步骤可以看出:
Signal的Class Closure 和Signal Handler的Closure的 C Marshaller
指向同一个:C Marshal: gst_marshal_VOID__UINT_BOXED
Signal Emit:
在某种条件下,会调用
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
probability, caps);
激发条件,暂时先不看。
看发射的过程,这里干了什么?如何和new/connect呼应起来?
void
g_signal_emit (gpointer instance,
guint signal_id,
GQuark detail,
...)
{
va_list var_args;
va_start (var_args, detail);
g_signal_emit_valist (instance, signal_id, detail, var_args);
va_end (var_args);
}
void
g_signal_emit_valist (gpointer instance,
guint signal_id,
GQuark detail,
va_list var_args)
{
GValue *instance_and_params;
GType signal_return_type;
GValue *param_values;
SignalNode *node;
guint i, n_params;
g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
g_return_if_fail (signal_id > 0);
SIGNAL_LOCK ();
node = LOOKUP_SIGNAL_NODE (signal_id);
if (!node || !g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype))
{
g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
SIGNAL_UNLOCK ();
return;
}
#ifndef G_DISABLE_CHECKS
if (detail && !(node->flags & G_SIGNAL_DETAILED))
{
g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
SIGNAL_UNLOCK ();
return;
}
#endif /* !G_DISABLE_CHECKS */
/* optimize NOP emissions */
if (signal_check_skip_emission (node, instance, detail))
{
/* nothing to do to emit this signal */
SIGNAL_UNLOCK ();
/* g_printerr ("omitting emission of \"%s\"\n", node->name); */
return;
}
n_params = node->n_params;
signal_return_type = node->return_type;
instance_and_params = g_slice_alloc0 (sizeof (GValue) * (n_params + 1));
param_values = instance_and_params + 1;
for (i = 0; i < node->n_params; i++)
{
gchar *error;
GType ptype = node->param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
gboolean static_scope = node->param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE;
SIGNAL_UNLOCK ();
G_VALUE_COLLECT_INIT (param_values + i, ptype,
var_args,
static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
&error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
/* we purposely leak the value here, it might not be
* in a sane state if an error condition occoured
*/
while (i--)
g_value_unset (param_values + i);
g_slice_free1 (sizeof (GValue) * (n_params + 1), instance_and_params);
return;
}
SIGNAL_LOCK ();
}
SIGNAL_UNLOCK ();
instance_and_params->g_type = 0;
g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (instance));
g_value_set_instance (instance_and_params, instance);
if (signal_return_type == G_TYPE_NONE)
signal_emit_unlocked_R (node, detail, instance, NULL, instance_and_params);
else
{
GValue return_value = { 0, };
gchar *error = NULL;
GType rtype = signal_return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE;
gboolean static_scope = signal_return_type & G_SIGNAL_TYPE_STATIC_SCOPE;
g_value_init (&return_value, rtype);
signal_emit_unlocked_R (node, detail, instance, &return_value, instance_and_params);
G_VALUE_LCOPY (&return_value,
var_args,
static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
&error);
if (!error)
g_value_unset (&return_value);
else
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
/* we purposely leak the value here, it might not be
* in a sane state if an error condition occured
*/
}
}
for (i = 0; i < n_params; i++)
g_value_unset (param_values + i);
g_value_unset (instance_and_params);
g_slice_free1 (sizeof (GValue) * (n_params + 1), instance_and_params);
}
1. 把输入的C参数list放到一个GValue, Collect 中
2. 调用signal_emit_unblocked_R(), 并且GValue参数作为最后一个参数
3. 把返回的值再弄回C语言的形式。
下面重点看看:signal_emit_unblocked_R(),
在这个函数里面,会做如下的动作:
1. 找到class closure ( callback [default handler] + c_marshaller)
2. 找到别人注册到该信号的handlers (User callback + c_marshaller)
之后就是根据条件进行回调的处理:
有3个重要的条件:
1. if ((node->flags & G_SIGNAL_RUN_FIRST) && class_closure) //这个处理class自己注册的handler, 一般是指定好的成员函数
if ((node->flags & G_SIGNAL_RUN_LAST) && class_closure)
2. if (node->emission_hooks)
3. if (handler_list) //这个处理用g_signal_connect_xxx()注册的用户自己的callback (user defined handlers)
先看第一个:
if ((node->flags & G_SIGNAL_RUN_FIRST) && class_closure)
{
emission.state = EMISSION_RUN;
emission.chain_type = G_TYPE_FROM_INSTANCE (instance);
SIGNAL_UNLOCK ();
g_closure_invoke (class_closure,
return_accu,
node->n_params + 1,
instance_and_params,
&emission.ihint);
if (!accumulate (&emission.ihint, emission_return, &accu, accumulator) &&
emission.state == EMISSION_RUN)
emission.state = EMISSION_STOP;
SIGNAL_LOCK ();
emission.chain_type = G_TYPE_NONE;
return_value_altered = TRUE;
if (emission.state == EMISSION_STOP)
goto EMIT_CLEANUP;
else if (emission.state == EMISSION_RESTART)
goto EMIT_RESTART;
}
void
g_closure_invoke (GClosure *closure,
GValue /*out*/ *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint)
{
g_return_if_fail (closure != NULL);
g_closure_ref (closure); /* preserve floating flag */
if (!closure->is_invalid)
{
GClosureMarshal marshal;
gpointer marshal_data;
gboolean in_marshal = closure->in_marshal;
g_return_if_fail (closure->marshal || closure->meta_marshal);
SET (closure, in_marshal, TRUE);
if (closure->meta_marshal)
{
marshal_data = closure->notifiers[0].data;
marshal = (GClosureMarshal) closure->notifiers[0].notify;
}
else
{
marshal_data = NULL;
marshal = closure->marshal;
}
if (!in_marshal)
closure_invoke_notifiers (closure, PRE_NOTIFY);
marshal (closure,
return_value,
n_param_values, param_values,
invocation_hint,
marshal_data);
if (!in_marshal)
closure_invoke_notifiers (closure, POST_NOTIFY);
SET (closure, in_marshal, in_marshal);
}
g_closure_unref (closure);
}
前面在New Signal的时候,就已经创建了class closure, 并且注册了:
marshal_data = gst_type_find_element_have_type()
mashal = g_type_class_meta_marshal()//这个mashal是我们指定的meta mashaller
所以会执行下面的:
marshal (closure,
return_value,
n_param_values, param_values,
invocation_hint,
marshal_data);
即:
static void
g_type_class_meta_marshal (GClosure *closure,
GValue /*out*/ *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
GTypeClass *class;
gpointer callback;
/* GType itype = (GType) closure->data; */
guint offset = GPOINTER_TO_UINT (marshal_data);
class = G_TYPE_INSTANCE_GET_CLASS (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
callback = G_STRUCT_MEMBER (gpointer, class, offset);
if (callback)
closure->marshal (closure,
return_value,
n_param_values, param_values,
invocation_hint,
callback);
}
这个函数非常有意思:
1. 根据传入的marshal_data ( gst_type_find_element_have_typed的地址),取出其offset
2. 根据offset, 取出对应class中的成员函数:callback = G_STRUCT_MEMBER (gpointer, class, offset);
提取的结果:callback = gst_type_find_element_have_typed()
3. 在把这个callback作为最后一个参数传入到closure的C marshal: gst_marshal_VOID__UINT_BOXED
真正执行的是下面的函数:
gst_marshal_VOID_UINT_BOXED(closure,
return_value,
n_param_values, param_values,
invocation_hint,
gst_type_find_element_have_typed);
在gstmarshal.c中:
/* VOID:UINT,BOXED (./gstmarshal.list:19) */
void
gst_marshal_VOID__UINT_BOXED (GClosure *closure,
GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef void (*GMarshalFunc_VOID__UINT_BOXED) (gpointer data1,
guint arg_1,
gpointer arg_2,
gpointer data2);
register GMarshalFunc_VOID__UINT_BOXED callback;
register GCClosure *cc = (GCClosure*) closure;
register gpointer data1, data2;
g_return_if_fail (n_param_values == 3);
if (G_CCLOSURE_SWAP_DATA (closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer (param_values + 0);
}
else
{
data1 = g_value_peek_pointer (param_values + 0);
data2 = closure->data;
}
callback = (GMarshalFunc_VOID__UINT_BOXED) (marshal_data ? marshal_data : cc->callback);
callback (data1,
g_marshal_value_peek_uint (param_values + 1),
g_marshal_value_peek_boxed (param_values + 2),
data2);
}
{
data1 = g_value_peek_pointer (param_values + 0); //拿到输入参数list
data2 = closure->data; // = (gpointer) itype, 在GClosure*g_closure_new_simple (guint sizeof_closure, gpointer data)指定的
}
callback = (GMarshalFunc_VOID__UINT_BOXED) (marshal_data ? marshal_data : cc->callback);
marshal_data != NULL, 所以这里的callback使用的是marshal_data: gst_type_find_element_have_typed
gst_type_find_element_have_typed (参数GValue,
g_marshal_value_peek_uint (param_values + 1),
g_marshal_value_peek_boxed (param_values + 2),
itype);
在gsttypefindelement.c
static void
gst_type_find_element_have_type (GstTypeFindElement * typefind,
guint probability, const GstCaps * caps)
{
GstCaps *copy;
g_assert (caps != NULL);
GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u",
caps, probability);
GST_OBJECT_LOCK (typefind);
if (typefind->caps)
gst_caps_unref (typefind->caps);
typefind->caps = gst_caps_copy (caps);
copy = gst_caps_ref (typefind->caps);
GST_OBJECT_UNLOCK (typefind);
gst_pad_set_caps (typefind->src, copy);
gst_caps_unref (copy);
}
G_VALUE_LCOPY (&return_value, var_args, static_scope ? G_VALUE_NOCOPY_CONTENTS : 0, &error);
这个是把GValue的值再转回C语言的形式。
gobjec相关学习文章的list.