3_17_GLib库入门与实践_hook函数

简介

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_invokeg_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
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值