Libev源码分析01:Libev中的监视器结构(C结构体实现继承)
在Libev的源码中,用到了一种用C实现类似C++中继承的技巧,主要是用宏和结构体实现。
在Libev中,最关键的数据结构就是各种监视器,比如IO监视器,信号监视器等等。这些监视器的多数成员都是一样的,只有少部分成员为各自独有。这就非常类似于C++中继承的使用场景了。废话少说,代码如下(略有改动,某些宏做了展开):
# define EV_CB_DECLARE(type) void (*cb)(struct ev_loop *loop, struct type *w, int revents); #define EV_WATCHER(type) \ int active; /* private */ \ int pending; /* private */ \ int priority; /* private */ \ void *data; /* rw */ \ EV_CB_DECLARE (type) /* private */ #define EV_WATCHER_LIST(type) \ EV_WATCHER (type) \ struct ev_watcher_list *next; /* private */ typedef struct ev_watcher { EV_WATCHER (ev_watcher) } ev_watcher; typedef struct ev_watcher_list { EV_WATCHER_LIST (ev_watcher_list) } ev_watcher_list; typedef struct ev_io { EV_WATCHER_LIST (ev_io) int fd; /* ro */ int events; /* ro */ } ev_io; typedef struct ev_signal { EV_WATCHER_LIST (ev_signal) int signum; /* ro */ } ev_signal;
ev_watcher是所有结构的“基类”,宏EV_WATCHER定义了它的所有成员。像IO监视器、信号监视器等是以链表的形式进行组织的,所以,在ev_watcher基类的基础上,定义了ev_watcher的子类ev_watcher_list,宏EV_WATCHER_LIST就定义了该基类的所有成员。
ev_io和ev_signal相当于ev_watcher_list的子类,它们的前5个成员于ev_watcher相同,前6个成员与ev_watcher_list相同。
上面的代码可能还不是太清楚,下面将上面代码中的所有宏都展开,代码如下:
# define EV_CB_DECLARE(type) void (*cb)(struct ev_loop *loop, struct type *w, int revents); #define EV_WATCHER(type) \ int active; /* private */ \ int pending; /* private */ \ int priority; /* private */ \ void *data; /* rw */ \ EV_CB_DECLARE (type) /* private */ #define EV_WATCHER_LIST(type) \ int active; /* private */ \ int pending; /* private */ \ int priority; /* private */ \ void *data; /* rw */ \ EV_CB_DECLARE (type) /* private */ \ struct ev_watcher_list *next; /* private */ typedef struct ev_watcher { int active; int pending; int priority; void *data; EV_CB_DECLARE (ev_watcher) } ev_watcher; typedef struct ev_watcher_list { int active; int pending; int priority; void *data; EV_CB_DECLARE (ev_watcher_list) struct ev_watcher_list *next; } ev_watcher_list; typedef struct ev_io { int active; int pending; int priority; void *data; EV_CB_DECLARE (ev_io) struct ev_watcher_list *next; int fd; /* ro */ int events; /* ro */ } ev_io; typedef struct ev_signal { int active; int pending; int priority; void *data; EV_CB_DECLARE (ev_signal) struct ev_watcher_list *next; int signum; } ev_signal;
下面是Libev中如何使用这些结构体的代码:
void ev_start (struct ev_loop *loop, ev_watcher* w, int active) { ... w->active = active; ... } void wlist_add (ev_watcher_list **head, ev_watcher_list *elem) { elem->next = *head; *head = elem; } void ev_io_start (struct ev_loop *loop, ev_io *w) { ... ev_start (loop, (ev_watcher*)w, 1); ... wlist_add (&anfds[fd].head, (ev_watcher_list *)w); }
在ev_io_start函数中,w是指向ev_io结构的指针,使用ev_start函数设置其成员active时,将其强制转换成基类ev_watcher,在将其添加进链表时,又将其强制转化为ev_watcher_list类型。
下面的代码是模拟上面的方法,写出的例子代码:
typedef struct { char *color; int weight; }fruit; typedef struct fruitlist { char *color; int weight; struct fruitlist *next; }fruitlist; typedef struct { char *color; int weight; struct fruitlist *next; char *taste; }apple; void setcolorweight(fruit *f, char *color, int weight) { f->color = color; f->weight = weight; } void putinlist(fruitlist **head, fruitlist *ele) { ele->next = *head; *head = ele; } void testinherit() { fruitlist *head = NULL; apple ap1; setcolorweight((fruit *)&ap1, "red", 2); ap1.taste = "sweet"; putinlist(&head, (fruitlist *)&ap1); apple ap2; setcolorweight((fruit *)&ap2, "yellow", 1); ap2.taste = "sour"; putinlist(&head, (fruitlist *)&ap2); fruitlist *p = head; while(p != NULL) { printf("color is %s, weight is %d\n", p->color, p->weight); p = (fruitlist *)(p->next); } }
结果如下:
color is yellow, weight is 1
color is red, weight is 2
呵呵