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

posted @ 2015-09-13 17:11  gqtc  阅读(369)  评论(0编辑  收藏  举报