GLib
概述
-
实现跨平台
-
避免重复造轮子
GLib的上下层结构:

GLib的组成部分:

GLib代码组成:

GModule代码组成:

GObject代码组成:

GIO代码组成:530个文件,太多不列了!
如何使用glib
安装glib(ubuntu系统)
直接通过命令安装:
sudo apt install -y libglib2.0-dev
下载源码包自己编译安装:
git clone https://gitlab.gnome.org/GNOME/glib.git
cd glib
mkdir out
meson out
cd out
ninja
sudo ninja install
使用glib
包含相关的头文件,即可开展编程
#include <glib.h> //GLib#include <gmodule.h> //GModlule#include <glib-object.h> //GObject#include <gio/gdesktopappinfo.h> //GIO
#include <gio/gfiledescriptorbased.h>
#include <gio/gio.h>
#include <gio/gunixfdlist.h>
#include <gio/gunixfdmessage.h>
#include <gio/gunixinputstream.h>
#include <gio/gunixmounts.h>
#include <gio/gunixoutputstream.h>
编译
--------------------------------------简易版--------------------------------------------------
gcc glib_test.c -o glib_test `pkg-config --libs --cflags glib-2.0`
fuqiang@fuqiang-virtual:~/workspace$ pkg-config --libs --cflags glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -lglib-2.0--------------------------------------完整版--------------------------------------------------
gcc glib_test.c -o glib_test `pkg-config --libs --cflags glib-2.0 gmodule-2.0 gobject-2.0 gio-2.0`
fuqiang@fuqiang-virtual:~/workspace/test_gstreamer$ pkg-config --libs --cflags glib-2.0 gmodule-2.0 gobject-2.0 gio-2.0
-pthread -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -Wl,--export-dynamic -lgmodule-2.0 -pthread -lgio-2.0 -lgobject-2.0 -lglib-2.0
优势
-
跨平台的动态库加载函数(GModule)
-
事件循环分发处理机制GMainLoop (GLib)
-
跨平台的线程(线程池)函数,信号量函数,互斥锁函数(GLib)
-
提供了异步队列、线性表、动态数组、单/双向链表、哈希表、多叉树、平衡二叉树、字符串等常用容器(GLib)
-
词法分析,xml语言解析、ini文件读写等功能(GLib)
-
命令行参数解析(GLib)
-
一套完整的log机制(GLib)
-
slice内存分配结构(GLib)
-
简单的正则表达式功能(GLib)
-
GObject面向对象封装设计(GObject)
-
IO函数(GIO)
特性说明(docs.gtk.org/glib/index.html)
GModule(Dynamically loaded modules)
Gstreamer中的动态加载插件就是通过这个实现

#if (G_MODULE_IMPL == G_MODULE_IMPL_DL)
#include "gmodule-dl.c"
#elif (G_MODULE_IMPL == G_MODULE_IMPL_WIN32)
#include "gmodule-win32.c"
#elif (G_MODULE_IMPL == G_MODULE_IMPL_AR)
#include "gmodule-ar.c"
GModule结构体定义:
struct _GModule
{
gchar *file_name;
gpointer handle;
guint ref_count : 31; //引用计数,多次open
guint is_resident : 1; //需要常驻,不能unload
GModuleUnload unload; //回调函数
GModule *next; //加载的modules链表
};
一些代码:
GModule*
g_module_open_full (const gchar *file_name,
GModuleFlags flags,
GError **error)
{
...
module = g_module_find_by_name (file_name);
if (module)
{
module->ref_count++;
}
...
/* we don't call unload() if the initialization check failed. */
if (!check_failed)
g_module_symbol (module, "g_module_unload", (gpointer) &module->unload);
...
}
gboolean
g_module_close (GModule *module)
{
...
module->ref_count--;
if (!module->ref_count && !module->is_resident && module->unload)
{
GModuleUnload unload;
unload = module->unload;
module->unload = NULL;
unload (module);
}
...
}
官方示例:
// the function signature for 'say_hello'
typedef void (* SayHelloFunc) (const char *message);
gboolean
just_say_hello (const char *filename, GError **error)
{
SayHelloFunc say_hello;
GModule *module;
module = g_module_open (filename, G_MODULE_BIND_LAZY);//dlopen
if (module == NULL)
{
g_set_error (error, FOO_ERROR, FOO_ERROR_BLAH,
"%s", g_module_error ());
return FALSE;
}
if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello)) //dlsym {
g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
"%s: %s", filename, g_module_error ());
if (!g_module_close (module))
g_warning ("%s: %s", filename, g_module_error ());
return FALSE;
}
if (say_hello == NULL)
{
g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
"symbol say_hello is NULL");
if (!g_module_close (module))
g_warning ("%s: %s", filename, g_module_error ());
return FALSE;
}
// call our function in the module
say_hello ("Hello world!");
if (!g_module_close (module)) //dlclose
g_warning ("%s: %s", filename, g_module_error ());
return TRUE;
}
GMainLoop(gmain.h/gmain.c)

-
基于IO多路复用(select/poll/epoll)
-
事件动态添加
-
优先级管理
#define G_PRIORITY_HIGH -100
#define G_PRIORITY_DEFAULT 0
#define G_PRIORITY_HIGH_IDLE 100
#define G_PRIORITY_DEFAULT_IDLE 200
#define G_PRIORITY_LOW 300 //background
结构体:
struct _GMainLoop
{
GMainContext *context;
gboolean is_running; /* (atomic) */
gint ref_count; /* (atomic) */
};
...
struct _GSource
{
/*< private >*/
gpointer callback_data;
GSourceCallbackFuncs *callback_funcs;
const GSourceFuncs *source_funcs;
guint ref_count;
GMainContext *context;gint priority;//优先级管理
guint flags;
guint source_id;
GSList *poll_fds;
GSource *prev; //检索,添加,删除
GSource *next;
char *name;
GSourcePrivate *priv;
};
常规事件处理
#include<glib.h>
GMainLoop* loop;
gint counter = 10;
gboolean callback(gpointer arg)
{
if(--counter == 0){
g_main_loop_quit(loop);
return FALSE;
}
return TRUE;
}
int main(int argc, char* argv[])
{
if(g_thread_supported() == 0)
g_thread_init(NULL);
loop = g_main_loop_new(NULL, FALSE);
g_timeout_add(100, callback, NULL); //增加一个定时器,100毫秒运行一次callback
g_main_loop_run(loop);
g_main_loop_unref(loop);
return 0;
}
unref:
g_main_loop_unref (GMainLoop *loop)
{
g_return_if_fail (loop != NULL);
g_return_if_fail (g_atomic_int_get (&loop->ref_count) > 0);
if (!g_atomic_int_dec_and_test (&loop->ref_count))
return;
g_main_context_unref (loop->context);
g_free (loop);
}
自定义事件处理
#include <glib.h>
#include <stdio.h>
#include <strings.h>
GMainLoop* loop;
//当stdin有数据可读时被GSource调用的回调函数
gboolean callback(GIOChannel *channel)
{
gchar* str;
gsize len;
//从stdin读取一行字符串
g_io_channel_read_line(channel, &str, &len, NULL, NULL);
//去掉回车键()
while(len > 0 && (str[len-1] == '/r' || str[len-1] == '/n'))
str[--len]='/0';
//反转字符串
for(;len;len--)
g_print("%c",str[len-1]);
g_print("/n");
//判断结束符
if(strcasecmp(str, "q") == 0){
g_main_loop_quit(loop);
}
g_free(str);
}
void add_source(GMainContext *context)
{
GIOChannel* channel;
GSource* source;
//这里我们监视stdin是否可读, stdin的fd默认等于1
channel = g_io_channel_unix_new(1);
//g_io_create_watch创建一个默认的io监视作用的GSource,参数G_IO_IN表示监视stdin的读取状态
source = g_io_create_watch(channel, G_IO_IN);
g_io_channel_unref(channel);
//设置stdin可读的时候调用的回调函数
g_source_set_callback(source, (GSourceFunc)callback, channel, NULL);
//把GSource附加到GMainContext
g_source_attach(source, context);
g_source_unref(source);
}
int main(int argc, char* argv[])
{
GMainContext *context;
if(g_thread_supported() == 0)
g_thread_init(NULL);
context = g_main_context_new();
add_source(context);
//把Context赋给GMainLoop
loop = g_main_loop_new(context, FALSE);
g_print("input string('q' to quit)/n");
g_main_loop_run(loop);
g_main_loop_unref(loop);
g_main_context_unref(context);
return 0;
}
Thread(gthread.h/gthread.c)

typedef struct _GThread GThread;
typedef struct _GMutex GMutex;
typedef struct _GRecMutex GRecMutex;
typedef struct _GRWLock GRWLock;
typedef struct _GCond GCond;
官方示例:
#include <glib.h>
void thread_call(gpointer data)
{
gint i = GPOINTER_TO_INT(data);
g_print("%d\n", i);
g_print("Thread %d was created\n", i);
}
int main()
{
gint i;
GThread* thread = NULL;
GError* error = NULL;
if (!g_thread_supported())
{
g_thread_init(NULL);
}
for (i = 1; i < 10; i++)
{
thread = g_thread_create((GThreadFunc)thread_call,(gpointer)i, FALSE, &error);
g_usleep(500);
if (thread == NULL)
{
g_critical("Create thread error: %s\n",error->message);
g_error_free(error);
}
}
return 0;
}
ThreadPool(gthreadpool.h/gthreadpool.c)
频繁创建和销毁执行过程相似而数据不同的线程,系统的效率和资源的利用率将会受到很大的影响--->threadpool

#include <glib.h>
#include <glib/gprintf.h>
#include <unistd.h>
#include <sys/syscall.h>
//线程执行函数,进入后打印数据,并睡眠5秒
void thread_execute (gpointer data, gpointer user_data)
{
g_printf("thread_execute %ld in\n", syscall(__NR_gettid));
g_printf("thread_execute %ld data is : %d\n", syscall(__NR_gettid), *((gint *)data));
g_usleep (5000000);
g_printf("thread_execute %ld out\n", syscall(__NR_gettid));
}
gint data[10];
int main(int argc, char **argv)
{
g_printf ("main in\n");
gint count;
GError *gerr = NULL;
GThreadPool *gpool = NULL;
//最大同时执行2个线程,由于exclusive设置为FALSE,所以不会有错误发生,error被设置为NULL
gpool = g_thread_pool_new (thread_execute, NULL, 2, FALSE, NULL);
//线程池中最大允许线程数3个
if(!g_thread_pool_set_max_threads (gpool, 3, &gerr))
g_printf("g_thread_pool_set_max_threads is error: %s\n", gerr->message);
/**
* 实际线程池中最多有3个线程同时运行
*/
for (count = 0; count < (sizeof(data)/sizeof(gint)); count++)
{
data[count] = count;
g_thread_pool_push(gpool, (gpointer)(&(data[count])), &gerr);
if(gerr != NULL)
{
g_printf("g_thread_pool_push is error: %s\n", gerr->message);
}
}
g_usleep (100000);
//插入优先级高的新任务
if(g_thread_pool_move_to_front (gpool, (gpointer)(&(data[9]))))
g_printf("g_thread_pool_move_to_front is 9\n");
//立即释放,不继续执行任务队列
//g_thread_pool_free (gpool, TRUE, TRUE);
//等待任务队列中的任务全部执行完成
g_thread_pool_free (gpool, FALSE, TRUE);
g_printf ("main out\n");
return 0;
}
AsyncQueue(gasyncqueue.h/gasyncqueue.c)

#include <glib.h>
static gpointer test_aqueue_push_func(gpointer data)
{
GAsyncQueue *aqueue = NULL;
g_print("%s \n", __FUNCTION__);
g_print("delay 2 seconds to push data \n");
g_usleep(2*1000*1000);
aqueue = (GAsyncQueue *)data;
g_async_queue_push(aqueue, GINT_TO_POINTER(99));
return NULL;
}
static gpointer test_aqueue_pop_func(gpointer data)
{
gpointer val = NULL;
GAsyncQueue *aqueue = NULL;
g_print("%s \n", __FUNCTION__);
aqueue = (GAsyncQueue *)data;
val = g_async_queue_pop(aqueue);
g_print("val: %d \n", GPOINTER_TO_INT(val));
return NULL;
}
gint main(gint argc, gchar **argv)
{
GThread *thd_push, *thd_pop;
GAsyncQueue *aqueue = NULL;
aqueue = g_async_queue_new();
thd_push = g_thread_new("thd_push", test_aqueue_push_func, aqueue);
thd_pop = g_thread_new("thd_pop", test_aqueue_pop_func, aqueue);
g_thread_join(thd_push);
g_thread_join(thd_pop);
g_async_queue_unref(aqueue);
return 0;
}
线性表
-
顺序表GArray(garray.h/garray.c)
-
单链表GSList(gslist.h/gslist.c)
-
双链表GList(glist.h/glist.c)

词法分析
-
XML语言解析GMarkupParser(gmarkup.h/gmarkup.c)
-
ini文件解析GKeyFile(gkeyfile.h/gkeyfile.c)
命令行参数解析GOption(goption.h/goption.c)
#include <glib.h>
#include <locale.h>
static gint repeats = 2;
static gint max_size = 8;
static gboolean verbose = FALSE;
static gboolean beep = FALSE;
static GOptionEntry entries[] =
{
// longname shortname flag arg arg_data description arg_description
{"repeats" , 'r' , 0, G_OPTION_ARG_INT, &repeats, "Average over N repetitions" , "N" },
{"max-size" , 'm' , 0, G_OPTION_ARG_INT, &max_size, "Test up to 2^M items" , "M" },
{"verbose" , 'v' , 0, G_OPTION_ARG_NONE, &verbose, "Be verbose" , NULL},
{"beep" , 'b' , 0, G_OPTION_ARG_NONE, &beep, "Beep when done" , NULL},
{NULL}
};
int main (int argc, char *argv[])
{
GError *error = NULL;
GOptionContext *context = NULL;
GOptionGroup *group = NULL;
// 创建一个新的选项上下文
context = g_option_context_new("- test tree model performance" );
g_option_context_add_main_entries(context, entries, NULL);
//添加要在选项列表之前的--help输出中显示的字符串。 这通常是程序功能的摘要
g_option_context_set_summary(context, "This is a glib demo" );
// 解析命令行参数,识别已添加到上下文的选项
if (!g_option_context_parse(context, &argc, &argv, &error))
{
exit (1);
}
// 释放被解析的参数
g_option_context_free(context);
g_print("Now value is: repeats=%d, max_size=%d, verbose=%d, beep=%d\n",
repeats, max_size, verbose, beep);
return 0;
}
执行情况:
fuqiang@fuqiang-virtual:~/workspace/test_gstreamer$ ./glib_test_option -h
Usage:
glib_test_option [OPTION?] - test tree model performance
This is a glib demo
Help Options:
-h, --help Show help options
Application Options:
-r, --repeats=N Average over N repetitions
-m, --max-size=M Test up to 2^M items
-v, --verbose Be verbose
-b, --beep Beep when done
fuqiang@fuqiang-virtual:~/workspace/test_gstreamer$ ./glib_test_option
Now value is: repeats=2, max_size=8, verbose=0, beep=0
fuqiang@fuqiang-virtual:~/workspace/test_gstreamer$ ./glib_test_option -r 1000
Now value is: repeats=1000, max_size=8, verbose=0, beep=0
Log机制(gmessages.h/gmessages.c)
跨平台,统一linux和win32:
#ifdef G_OS_UNIX
#include <unistd.h>
#endif
#ifdef G_OS_WIN32
#include <process.h> /* For getpid() */
#include <io.h>
#include <windows.h>
#endif
log等级划分:
#define g_error(...) G_STMT_START { \
g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
__FILE__, G_STRINGIFY (__LINE__), \
G_STRFUNC, __VA_ARGS__); \
for (;;) ; \
} G_STMT_END
#define g_message(...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, \
__FILE__, G_STRINGIFY (__LINE__), \
G_STRFUNC, __VA_ARGS__)
#define g_critical(...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
__FILE__, G_STRINGIFY (__LINE__), \
G_STRFUNC, __VA_ARGS__)
#define g_warning(...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, \
__FILE__, G_STRINGIFY (__LINE__), \
G_STRFUNC, __VA_ARGS__)
#define g_info(...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, \
__FILE__, G_STRINGIFY (__LINE__), \
G_STRFUNC, __VA_ARGS__)
#define g_debug(...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
__FILE__, G_STRINGIFY (__LINE__), \
G_STRFUNC, __VA_ARGS__)
使用:
g_error ("%s: failed to allocate memory", G_STRLOC);
内存分配
-
gmem.h/gmem.c
-
gslice.h/gslice.c
-
推荐使用gslice

gslice:
-
分层设计
-
用于优化许多大小相等的块的分配,线程内存空闲列表,快速满足已知结构的内存分配
-
对齐约束而未使用的内存用于缓存着色(块地址的随机分布),以提高CPU缓存利用率
gchar *mem[10000];
gint i;
// Allocate 10000 blocks.
for (i = 0; i < 10000; i++)
{
mem[i] = g_slice_alloc (50);
// Fill in the memory with some junk.
for (j = 0; j < 50; j++)
mem[i][j] = i * j;
}
// Now free all of the blocks.
for (i = 0; i < 10000; i++)
g_slice_free1 (50, mem[i]);
正则表达式GRegex(gregex.h/gregex.c)
#include <glib.h>
int main (int argc, char** argv)
{
GRegex* regex;
GMatchInfo *match_info;
GError *error = NULL;
const gchar *str = "11aa222bb33333cccc44444dddddddd";
const gchar *pat = "[0-9]+"; regex = g_regex_new(pat, 0, 0, &error);
g_regex_match(regex, str, 0, &match_info);
while (g_match_info_matches(match_info)) {
gchar* word = g_match_info_fetch(match_info, 0);
g_print("%s \n",word);
g_free(word);
g_match_info_next(match_info, NULL);
}
g_match_info_free(match_info);
g_regex_unref(regex);
return 0;
}
GObject(面向对象实现)
封装&继承:

G_DEFINE_TYPE:
G_DEFINE_TYPE
G_DEFINE_TYPE_EXTENDED
_G_DEFINE_TYPE_EXTENDED_BEGIN
_G_DEFINE_TYPE_EXTENDED_BEGIN_PRE
_G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER
_G_DEFINE_TYPE_EXTENDED_END
// G_DEFINE_TYPE
#define G_DEFINE_TYPE(TN, t_n, T_P) G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, 0, {})
#define G_DEFINE_TYPE_EXTENDED(TN, t_n, T_P, _f_, _C_) _G_DEFINE_TYPE_EXTENDED_BEGIN (TN, t_n, T_P, _f_) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()
//_G_DEFINE_TYPE_EXTENDED_BEGIN
#define _G_DEFINE_TYPE_EXTENDED_BEGIN(TypeName, type_name, TYPE_PARENT, flags) \
_G_DEFINE_TYPE_EXTENDED_BEGIN_PRE(TypeName, type_name, TYPE_PARENT) \
_G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER(TypeName, type_name, TYPE_PARENT, flags) \
//_G_DEFINE_TYPE_EXTENDED_END
#define _G_DEFINE_TYPE_EXTENDED_END() \
/* following custom code */ \
} \
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \
} \
return g_define_type_id__volatile; \
} /* closes type_name##_get_type() */
// _G_DEFINE_TYPE_EXTENDED_BEGIN_PRE
#define _G_DEFINE_TYPE_EXTENDED_BEGIN_PRE(TypeName, type_name, TYPE_PARENT) \
\
static void type_name##_init (TypeName *self); \
static void type_name##_class_init (TypeName##Class *klass); \
static gpointer type_name##_parent_class = NULL; \
static gint TypeName##_private_offset; \
\
_G_DEFINE_TYPE_EXTENDED_CLASS_INIT(TypeName, type_name) \
\
G_GNUC_UNUSED \
static inline gpointer \
type_name##_get_instance_private (TypeName *self) \
{ \
return (G_STRUCT_MEMBER_P (self, TypeName##_private_offset)); \
} \
\
GType \
type_name##_get_type (void) \
{ \
static volatile gsize g_define_type_id__volatile = 0;
/* Prelude goes here */
// _G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER
#define _G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER(TypeName, type_name, TYPE_PARENT, flags) \
if (g_once_init_enter (&g_define_type_id__volatile)) \
{ \
GType g_define_type_id = \
g_type_register_static_simple (TYPE_PARENT, \
g_intern_static_string (#TypeName), \
sizeof (TypeName##Class), \
(GClassInitFunc)(void (*)(void)) type_name##_class_intern_init, \
sizeof (TypeName), \
(GInstanceInitFunc)(void (*)(void)) type_name##_init, \
(GTypeFlags) flags); \
{ /* custom code follows */
将下面代入:
-
TypeName:MyObject
-
type_name:my_object
-
TYPE_PARENT:G_TYPE_OBJECT
static void my_object_init (MyObject *self);
static void my_object_class_init (MyObjectClass *klass);
static gpointer my_object_parent_class = NULL;
static gint MyObject_private_offset;
static void my_object_class_intern_init (gpointer klass)
{
my_object_parent_class = g_type_class_peek_parent (klass);//获取父类
if (MyObject_private_offset != 0)
g_type_class_adjust_private_offset (klass, &MyObject_private_offset);
my_object_class_init ((MyObjectClass*) klass);//子类初始化
}
G_GNUC_UNUSED
static inline gpointer
my_object_get_instance_private (TypeName *self)
{
return (G_STRUCT_MEMBER_P (self, MyObject_private_offset));
}
GType
my_object_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
GType g_define_type_id = g_type_register_static_simple (G_TYPE_OBJECT,
g_intern_static_string ("MyObject"),
sizeof (MyObjectClass),
(GClassInitFunc)(void (*)(void)) my_object_class_intern_init,
sizeof (TypeName),
(GInstanceInitFunc)(void (*)(void)) my_object_init,
(GTypeFlags) flags);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
TypeNode:
/* --- structures --- */
struct _TypeNode
{
guint ref_count; /* (atomic) */
GTypePlugin *plugin;
guint n_children; /* writable with lock */
guint n_supers : 8;
guint n_prerequisites : 9;
guint is_classed : 1;
guint is_instantiatable : 1;
guint mutatable_check_cache : 1; /* combines some common path checks */
GType *children; /* writable with lock */
TypeData *data;
GQuark qname;
GData *global_gdata;
union {
GAtomicArray iface_entries; /* for !iface types */
GAtomicArray offsets;
} _prot;
GType *prerequisites;
GType supers[1]; /* flexible array */
};
gpointer
g_type_class_peek_parent (gpointer g_class)
{
TypeNode *node;
gpointer class = NULL;
g_return_val_if_fail (g_class != NULL, NULL);
node = lookup_type_node_I (G_TYPE_FROM_CLASS (g_class));
g_return_val_if_fail (node != NULL, NULL);
/* We used to acquire a read lock here. That is not necessary, since
* parent->data->class.class is constant as long as the derived class
* exists.
*/
if (node->is_classed && node->data && NODE_PARENT_TYPE (node))
{
node = lookup_type_node_I (NODE_PARENT_TYPE (node)); //#define NODE_PARENT_TYPE(node) (node->supers[1])
class = node->data->class.class;
}
else if (NODE_PARENT_TYPE (node))
g_warning (G_STRLOC ": invalid class pointer '%p'", g_class);
return class;
}
register:
GType
g_type_register_static (GType parent_type,
const gchar *type_name,
const GTypeInfo *info,
GTypeFlags flags)
{
TypeNode *pnode, *node;
GType type = 0;
g_assert_type_system_initialized ();
g_return_val_if_fail (parent_type > 0, 0);
g_return_val_if_fail (type_name != NULL, 0);
g_return_val_if_fail (info != NULL, 0);
if (!check_type_name_I (type_name) ||
!check_derivation_I (parent_type, type_name))
return 0;
if (info->class_finalize)
{
g_warning ("class finalizer specified for static type '%s'",
type_name);
return 0;
}
pnode = lookup_type_node_I (parent_type);
G_WRITE_LOCK (&type_rw_lock);
type_data_ref_Wm (pnode);
if (check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (pnode), type_name, info))
{
node = type_node_new_W (pnode, type_name, NULL);
type_add_flags_W (node, flags);
type = NODE_TYPE (node);
type_data_make_W (node, info,
check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
}
G_WRITE_UNLOCK (&type_rw_lock);
return type;
}
static TypeNode*
type_node_any_new_W (TypeNode *pnode,//父节点
GType ftype,
const gchar *name,//要创建的子节点名称
GTypePlugin *plugin,
GTypeFundamentalFlags type_flags)
{
guint n_supers;
GType type;
TypeNode *node;
guint i, node_size = 0;
n_supers = pnode ? pnode->n_supers + 1 : 0;//父节点树
if (!pnode)
node_size += SIZEOF_FUNDAMENTAL_INFO; /* fundamental type info */
node_size += SIZEOF_BASE_TYPE_NODE (); /* TypeNode structure */
node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + (0) for ->supers[] */
node = g_malloc0 (node_size);
if (!pnode) /* offset fundamental types */
{
node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO);
static_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node;
type = ftype;
}
else
type = (GType) node;
g_assert ((type & TYPE_ID_MASK) == 0);
node->n_supers = n_supers;
if (!pnode)
{
node->supers[0] = type;
node->supers[1] = 0;
node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0;
node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0;
if (NODE_IS_IFACE (node))
{
IFACE_NODE_N_PREREQUISITES (node) = 0;
IFACE_NODE_PREREQUISITES (node) = NULL;
}
else
_g_atomic_array_init (CLASSED_NODE_IFACES_ENTRIES (node));
}
else
{
node->supers[0] = type;memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1));
node->is_classed = pnode->is_classed;
node->is_instantiatable = pnode->is_instantiatable;
if (NODE_IS_IFACE (node))
{
IFACE_NODE_N_PREREQUISITES (node) = 0;
IFACE_NODE_PREREQUISITES (node) = NULL;
}
else
{
guint j;
IFaceEntries *entries;
entries = _g_atomic_array_copy (CLASSED_NODE_IFACES_ENTRIES (pnode),
IFACE_ENTRIES_HEADER_SIZE,
0);
if (entries)
{
for (j = 0; j < IFACE_ENTRIES_N_ENTRIES (entries); j++)
{
entries->entry[j].vtable = NULL;
entries->entry[j].init_state = UNINITIALIZED;
}
_g_atomic_array_update (CLASSED_NODE_IFACES_ENTRIES (node),
entries);
}
}
i = pnode->n_children++;
pnode->children = g_renew (GType, pnode->children, pnode->n_children);
pnode->children[i] = type;
}
TRACE(GOBJECT_TYPE_NEW(name, node->supers[1], type));
node->plugin = plugin;
node->n_children = 0;
node->children = NULL;
node->data = NULL;
node->qname = g_quark_from_string (name);
node->global_gdata = NULL;g_hash_table_insert (static_type_nodes_ht,
(gpointer) g_quark_to_string (node->qname),
(gpointer) type);
g_atomic_int_inc ((gint *)&type_registration_serial);
return node;
}
目前为止,MyObject作为GObject的子类,已经完成了注册。
下面,看看当new一个instance的时候,进行那些操作
gpointer
g_object_new (GType object_type,
const gchar *first_property_name,
...)
{
GObject *object;
va_list var_args;
/* short circuit for calls supplying no properties */
if (!first_property_name)
return g_object_new_with_properties (object_type, 0, NULL, NULL);
va_start (var_args, first_property_name);
object = g_object_new_valist (object_type, first_property_name, var_args);
va_end (var_args);
return object;
}
GObject *
g_object_new_with_properties (GType object_type,
guint n_properties,
const char *names[],
const GValue values[])
{
GObjectClass *class, *unref_class = NULL;
GObject *object;
g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL);
/* Try to avoid thrashing the ref_count if we don't need to (since
* it's a locked operation).
*/
class = g_type_class_peek_static (object_type);
if (class == NULL)
class = unref_class = g_type_class_ref (object_type);
if (n_properties > 0)