简介
GLib提供了一组函数和数据的对应关系的功能,即hook函数。所有hook函数以链表形式组织在一起,该链表上每个节点都由数据和其处理函数组成,hook链表特有的遍历函数invoke及marshal可以在遍历时使用默认数据处理函数或指定新的处理函数处理数据。hook函数链表还提供了hook节点插入、节点查找、节点删除等功能。举例说明如下。
有一组数据 11 22 33 44,其默认处理函数分别为乘1,乘2,乘3,乘4,invoke遍历完,变成11,44,99,176,使用marshal函数,marshal回调为乘10,marshal遍历完,变成110,220,330,440,也可以只处理部分数据,只需调用g_hook_list_invoke_check或g_hook_list_marshal_check函数,在不需要处理的数据返回FALSE即可。
数据结构
hook函数有两个重要数据结构,GHookList和GHook,前者是hook函数链表,后者是其中的一个节点。
struct GHookList {
gulong seq_id;
guint hook_size : 16;
guint is_setup : 1;
GHook *hooks;
gpointer dummy3;
GHookFinalizeFunc finalize_hook;
gpointer dummy[2];
};
struct GHook {
gpointer data;
GHook *next;
GHook *prev;
guint ref_count;
gulong hook_id;
guint flags;
gpointer func;
GDestroyNotify destroy;
};
函数列表
g_hook_list_init ()
g_hook_list_invoke ()
g_hook_list_invoke_check ()
g_hook_list_marshal ()
g_hook_list_marshal_check ()
g_hook_list_clear ()
g_hook_alloc ()
g_hook_append()
g_hook_prepend ()
g_hook_insert_before ()
g_hook_insert_sorted ()
g_hook_compare_ids ()
g_hook_get ()
g_hook_find ()
g_hook_find_data ()
g_hook_find_func ()
g_hook_find_func_data ()
g_hook_first_valid ()
g_hook_next_valid ()
G_HOOK_FLAGS()
G_HOOK()
G_HOOK_IS_VALID()
G_HOOK_ACTIVE()
G_HOOK_IN_CALL()
G_HOOK_IS_UNLINKED()
g_hook_ref ()
g_hook_unref ()
g_hook_free ()
g_hook_destroy ()
g_hook_destroy_link ()
函数功能分类
// hook链表初始化
g_hook_list_init ()
// hook节点申请
g_hook_alloc ()
// 节点插入
g_hook_append()
g_hook_prepend ()
g_hook_insert_before ()
g_hook_insert_sorted ()
// 节点查找
// 通过hook_id查找一个hook节点
g_hook_get ()
// 查找hook节点,查找函数用户自己提供
g_hook_find ()
// 查找给定的data是否在hook列表中,如果有则返回该hook节点。
// 由于本函数内部比较是直接指针比较,所以要求传入的data只能是hook节点中的对象,值相等的变量不一定是同一个变量,会导致查找失败。
g_hook_find_data ()
// 给定func查找hook列表中是否有hook节点与此func相同(地址和值完全相等)
g_hook_find_func ()
// 给定func和data,查找hook列表中是否有hook节点与此func和data都相同(地址和值都相等)
g_hook_find_func_data ()
// 返回第一个活动状态的hook节点。hook节点有活动及正在执行两种状态。
g_hook_first_valid ()
// 返回下一个活动状态的hook节点。
g_hook_next_valid ()
// 遍历
// invoke函数对每个hook节点的data数据执行一遍func函数
// invoke_check函数和invoke相似,但hook回调函数返回失败则将该hook节点移出hook链表
// marshal函数对每个hook节点的data数据执行用户指定的marshal函数,而hook节点自身的函数不会被执行到。
// marshal_check函数和marshal函数相似,但hook回调函数返回失败则将该hook节点移出hook链表
g_hook_list_invoke ()
g_hook_list_invoke_check ()
g_hook_list_marshal ()
g_hook_list_marshal_check ()
// hook节点销毁
// 给定hook_id销毁一个hook节点,并调用该节点的释放函数。如果用户自定义的节点有内存,应在节点初始化时提供释放函数以释放内存。
g_hook_destroy ()
// 给定一个hook节点将其移出hook链表,并调用该节点释放函数。
g_hook_destroy_link ()
// 清空
// 将hook链表中所有节点全部移出hook链表,每个节点的释放函数均被调用。
g_hook_list_clear ()
// 释放
// 释放一个hook链表
g_hook_free ()
// 引用
// 计数加减一,如果引用计数为0,则该节点被释放,且节点的destroy释放函数会被调用。
g_hook_ref ()
g_hook_unref ()
// 标识
// 获取一个hook节点的标识(VALID、ACTIVE、IN_CALL、UNLINKED)
G_HOOK_FLAGS()
// hook节点是否有效(活动状态切未被销毁)
G_HOOK_IS_VALID()
// hook节点释放为活动状态
G_HOOK_ACTIVE()
// hook节点是否正在被执行
G_HOOK_IN_CALL()
// hook节点是否已经被销毁
G_HOOK_IS_UNLINKED()
函数功能说明及综合演示
hook节点插入-头插及尾插
这里演示将一个hook节点插入到hook链表中。
演示程序:
源码见glib_examples\glib_hook\glib_hook_insert
#include <glib.h>
typedef struct my_data_tag {
int id;
char *name;
}my_data_t;
static void hook_func (gpointer data)
{
my_data_t *d = (my_data_t *)data;
g_print("(hook_func)data->id:%d, data->name:%s \n", d->id, d->name);
}
static void hook_destroy (gpointer data)
{
my_data_t *d = (my_data_t *)data;
if(NULL != d) {
if(NULL != d->name) {
g_print("(hook_destroy) %s \n", d->name);
g_free(d->name);
}
g_free(d);
}
}
static void test_glib_ghook (void)
{
GHookList *hl;
GHook *hook1, *hook2;
my_data_t *d1, *d2;
d1 = g_new(my_data_t, 1);
d1->id = 100;
d1->name = g_strdup_printf("name-%d", d1->id);
d2 = g_new(my_data_t, 1);
d2->id = 200;
d2->name = g_strdup_printf("name-%d", d2->id);
hl = g_new (GHookList, 1);
g_hook_list_init (hl, sizeof (GHook));
hook1 = g_hook_alloc (hl);
hook1->data = d1;
hook1->func = hook_func;
hook1->flags = G_HOOK_FLAG_ACTIVE;
hook1->destroy = hook_destroy;
g_hook_append (hl, hook1);
hook2 = g_hook_alloc (hl);
hook2->data = d2;
hook2->func = hook_func;
hook2->flags = G_HOOK_FLAG_ACTIVE;
hook2->destroy = hook_destroy;
g_hook_prepend (hl, hook2);
g_hook_list_clear (hl);
g_free (hl);
}
int main(int argc, char **argv)
{
test_glib_ghook();
return 0;
}
运行结果:
[root@centos7_6 build]# ./glib_hook_insert
(hook_destroy) name-200
(hook_destroy) name-100
数据处理函数的执行
hook函数的重要功能就是使用对应的数据处理函数处理数据,g_hook_list_invoke
和g_hook_list_marshal
都可以对数据进行处理,链表内的所有节点都会被执行到。invoke函数和marshal函数的区别是,invoke在处理数据时使用的是hook节点添加时指定的处理函数,marshal在处理数据时,使用的是新的数据处理函数,此时将忽略默认数据处理函数。invoke的数据处理函数可以不同,但marshal的数据处理函数只有一个,即调用marshal函数时指定的数据处理函数,对每个hook节点的数据处理,都使用此函数。
演示程序:
源码见glib_examples\glib_hook\glib_hook_invoke_marshal
#include <glib.h>
typedef struct my_data_tag {
int id;
char *name;
}my_data_t;
static void hook_marshaller_func(GHook *hook, gpointer marshal_data)
{
my_data_t *d = (my_data_t *)hook->data;
d->id = d->id * GPOINTER_TO_INT(marshal_data);
}
static void hook1_func (gpointer data)
{
my_data_t *d = (my_data_t *)data;
g_print("(hook1)data->id:%d, data->name:%s \n", d->id, d->name);
d->id = d->id*10;
g_free(d->name);
d->name = g_strdup_printf("new-name-%d", d->id);
}
static void hook1_destroy (gpointer data)
{
my_data_t *d = (my_data_t *)data;
if(NULL != d) {
if(NULL != d->name) {
g_free(d->name);
}
g_free(d);
}
}
static void hook2_func (gpointer data)
{
my_data_t *d = (my_data_t *)data;
g_print("(hook2)data->id:%d, data->name:%s \n", d->id, d->name);
}
static void hook2_destroy (gpointer data)
{
my_data_t *d = (my_data_t *)data;
if(NULL != d) {
if(NULL != d->name) {
g_free(d->name);
}
g_free(d);
}
}
static void test_glib_ghook (void)
{
GHookList *hl;
GHook *hook1, *hook2;
my_data_t *d1, *d2;
d1 = g_new(my_data_t, 1);
d1->id = 100;
d1->name = g_strdup_printf("name-%d", d1->id);
d2 = g_new(my_data_t, 1);
d2->id = 200;
d2->name = g_strdup_printf("name-%d", d2->id);
hl = g_new (GHookList, 1);
g_hook_list_init (hl, sizeof (GHook));
hook1 = g_hook_alloc (hl);
hook1->data = d1;
hook1->func = hook1_func;
hook1->flags = G_HOOK_FLAG_ACTIVE;
hook1->destroy = hook1_destroy;
g_hook_append (hl, hook1);
hook2 = g_hook_alloc (hl);
hook2->data = d2;
hook2->func = hook2_func;
hook2->flags = G_HOOK_FLAG_ACTIVE;
hook2->destroy = hook2_destroy;
g_hook_prepend (hl, hook2);
g_hook_list_invoke (hl, TRUE);
g_print("after invoke: data1->id:%d, data1->name:%s \n", \
((my_data_t *)(hook1->data))->id, ((my_data_t *)(hook1->data))->name);
g_print("after invoke: data2->id:%d, data2->name:%s \n", \
((my_data_t *)(hook2->data))->id, ((my_data_t *)(hook2->data))->name);
g_hook_list_marshal(hl, TRUE, hook_marshaller_func, GINT_TO_POINTER(3));
g_print("after marshal: data1->id:%d, data1->name:%s \n", \
((my_data_t *)(hook1->data))->id, ((my_data_t *)(hook1->data))->name);
g_print("after marshal: data2->id:%d, data2->name:%s \n", \
((my_data_t *)(hook2->data))->id, ((my_data_t *)(hook2->data))->name);
g_hook_list_clear (hl);
g_free (hl);
}
int main(int argc, char **argv)
{
test_glib_ghook();
return 0;
}
运行结果:
[root@centos7_6 build]# ./glib_hook_invoke_marshal
(hook2)data->id:200, data->name:name-200
(hook1)data->id:100, data->name:name-100
after invoke: data1->id:1000, data1->name:new-name-1000
after invoke: data2->id:200, data2->name:name-200
after marshal: data1->id:3000, data1->name:new-name-1000
after marshal: data2->id:600, data2->name:name-200
只处理部分数据
g_hook_list_invoke_check
和g_hook_list_marshal_check
可实现对指定特征的数据进行处理,其实现方式为,当数据处理函数返回FALSE时,该数据不被处理,当数据处理函数返回TRUE时,才处理该数据。本程序演示g_hook_list_marshal_check
处理部分数据的效果,当数据为偶数时,跳过不处理,当数据为奇数时,才进行乘10的处理,程序见下。
演示程序:
源码见glib_examples\glib_hook\glib_hook_marshal_check
#include <glib.h>
typedef struct my_data_tag {
int id;
char *name;
}my_data_t;
gboolean hook_marshal_func(GHook *hook, gpointer marshal_data)
{
my_data_t *d = (my_data_t *)hook->data;
if((d->id/10)%2) {
return FALSE;
}
return TRUE;
}
static void hook_func (gpointer data)
{
my_data_t *d = (my_data_t *)data;
g_print("(hook_func)data->id:%d, data->name:%s \n", d->id, d->name);
d->id = d->id*10;
}
static void hook_destroy (gpointer data)
{
my_data_t *d = (my_data_t *)data;
if(NULL != d) {
if(NULL != d->name) {
g_print("(hook_destroy) id:%d, name:%s \n", d->id, d->name);
g_free(d->name);
}
g_free(d);
}
}
static void test_glib_ghook (void)
{
GHookList *hl;
GHook *hook1, *hook2, *hook3, *hook4;
my_data_t *d1, *d2, *d3, *d4;
d1 = g_new(my_data_t, 1);
d1->id = 1;
d1->name = g_strdup_printf("name-%d", d1->id);
d2 = g_new(my_data_t, 1);
d2->id = 2;
d2->name = g_strdup_printf("name-%d", d2->id);
d3 = g_new(my_data_t, 1);
d3->id = 3;
d3->name = g_strdup_printf("name-%d", d3->id);
d4 = g_new(my_data_t, 1);
d4->id = 4;
d4->name = g_strdup_printf("name-%d", d4->id);
hl = g_new (GHookList, 1);
g_hook_list_init (hl, sizeof (GHook));
hook1 = g_hook_alloc (hl);
hook1->data = d1;
hook1->func = hook_func;
hook1->flags = G_HOOK_FLAG_ACTIVE;
hook1->destroy = hook_destroy;
g_hook_append (hl, hook1);
hook2 = g_hook_alloc (hl);
hook2->data = d2;
hook2->func = hook_func;
hook2->flags = G_HOOK_FLAG_ACTIVE;
hook2->destroy = hook_destroy;
g_hook_append (hl, hook2);
hook3 = g_hook_alloc (hl);
hook3->data = d3;
hook3->func = hook_func;
hook3->flags = G_HOOK_FLAG_ACTIVE;
hook3->destroy = hook_destroy;
g_hook_append (hl, hook3);
hook4 = g_hook_alloc (hl);
hook4->data = d4;
hook4->func = hook_func;
hook4->flags = G_HOOK_FLAG_ACTIVE;
hook4->destroy = hook_destroy;
g_hook_append (hl, hook4);
g_print("invoke 1st \n");
g_hook_list_invoke(hl, TRUE);
g_print("marshal_check \n");
g_hook_list_marshal_check(hl, TRUE, hook_marshal_func, NULL);
g_print("invoke 2nd \n");
g_hook_list_invoke(hl, TRUE);
g_hook_list_clear (hl);
g_free (hl);
}
int main(int argc, char **argv)
{
test_glib_ghook();
return 0;
}
运行结果:
[root@centos7_6 build]# ./glib_hook_marshal_check
invoke 1st
(hook_func)data->id:1, data->name:name-1
(hook_func)data->id:2, data->name:name-2
(hook_func)data->id:3, data->name:name-3
(hook_func)data->id:4, data->name:name-4
marshal_check
(hook_destroy) id:10, name:name-1
(hook_destroy) id:30, name:name-3
invoke 2nd
(hook_func)data->id:20, data->name:name-2
(hook_func)data->id:40, data->name:name-4
(hook_destroy) id:200, name:name-2
(hook_destroy) id:400, name:name-4
hook节点销毁及hook链表清空
这里演示将一个hook节点销毁及将整个hook链表清空的效果。
演示程序:
源码见glib_examples\glib_hook\glib_hook_destroy
#include <glib.h>
typedef struct my_data_tag {
int id;
char *name;
}my_data_t;
static void hook_func (gpointer data)
{
my_data_t *d = (my_data_t *)data;
g_print("(hook_func)data->id:%d, data->name:%s \n", d->id, d->name);
}
static void hook_destroy (gpointer data)
{
my_data_t *d = (my_data_t *)data;
if(NULL != d) {
if(NULL != d->name) {
g_print("(hook_destroy) %s \n", d->name);
g_free(d->name);
}
g_free(d);
}
}
static void test_glib_ghook (void)
{
GHookList *hl;
GHook *hook1, *hook2, *hook3;
my_data_t *d1, *d2, *d3;
d1 = g_new(my_data_t, 1);
d1->id = 100;
d1->name = g_strdup_printf("name-%d", d1->id);
d2 = g_new(my_data_t, 1);
d2->id = 200;
d2->name = g_strdup_printf("name-%d", d2->id);
d3 = g_new(my_data_t, 1);
d3->id = 300;
d3->name = g_strdup_printf("name-%d", d3->id);
hl = g_new (GHookList, 1);
g_hook_list_init (hl, sizeof (GHook));
hook1 = g_hook_alloc (hl);
hook1->data = d1;
hook1->func = hook_func;
hook1->flags = G_HOOK_FLAG_ACTIVE;
hook1->destroy = hook_destroy;
g_hook_append (hl, hook1);
hook2 = g_hook_alloc (hl);
hook2->data = d2;
hook2->func = hook_func;
hook2->flags = G_HOOK_FLAG_ACTIVE;
hook2->destroy = hook_destroy;
g_hook_append (hl, hook2);
hook3 = g_hook_alloc (hl);
hook3->data = d3;
hook3->func = hook_func;
hook3->flags = G_HOOK_FLAG_ACTIVE;
hook3->destroy = hook_destroy;
g_hook_append (hl, hook3);
g_hook_list_invoke (hl, TRUE);
g_print("after invoke: data1->id:%d, data1->name:%s \n", \
((my_data_t *)(hook1->data))->id, ((my_data_t *)(hook1->data))->name);
g_print("after invoke: data2->id:%d, data2->name:%s \n", \
((my_data_t *)(hook2->data))->id, ((my_data_t *)(hook2->data))->name);
g_print("after invoke: data3->id:%d, data3->name:%s \n", \
((my_data_t *)(hook3->data))->id, ((my_data_t *)(hook3->data))->name);
g_print("destroy hook: %d \n", hook2->hook_id);
g_hook_destroy(hl, hook2->hook_id);
g_print("destroy_link hook: %d \n", hook1->hook_id);
g_hook_destroy_link(hl, hook1);
g_print("clear list! \n");
g_hook_list_clear (hl);
g_free (hl);
}
int main(int argc, char **argv)
{
test_glib_ghook();
return 0;
}
运行结果:
[root@centos7_6 build]# ./glib_hook_destroy
(hook_func)data->id:100, data->name:name-100
(hook_func)data->id:200, data->name:name-200
(hook_func)data->id:300, data->name:name-300
after invoke: data1->id:100, data1->name:name-100
after invoke: data2->id:200, data2->name:name-200
after invoke: data3->id:300, data3->name:name-300
destroy hook: 2
(hook_destroy) name-200
destroy_link hook: 1
(hook_destroy) name-100
clear list!
(hook_destroy) name-300