上层: Caller (Signal connect + user callback )
下层: Callee (Signal New + Emission机制)
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:
比如: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
在某种条件下,会调用
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语言的形式。
2024年2月21日 22:31
I came to your website for the first time I like your website very much such nice information providing much such