libuv源码剖析

libuv-v1.11.0 - 源码剖析 - 01 - uv_loop_t

> uv_loop_t

struct {
    void *data;
    unsigned int active_handles;    /*
                                    活跃的handle计数。
                                    uv__handle_start()时若handle有UV__HANDLE_REF标志,\
                                    此处++。
                                    uv__handle_stop()时若handle有UV__HANDLE_REF标志,\
                                    此处--。 
                                    */
    
    void* handle_queue[2];          /*
                                    存放全部handle的队列。
                                    uv__handle_init()向其尾追加handle。
                                    uv_loop内部执行uv__finish_close(handle)时,handle出队。
                                    */
    
    void* active_reqs[2];           /* 
                                    存放全部req的队列。
                                    uv__req_register()向其尾部追加req。
                                    uv__req_unregister()将req从本队列移除。
                                    */
    
    unsigned int stop_flag;     /* 退出uv_run的标志,初始0,uv_stop()设其为1 */
    
    // UV_LOOP_PRIVATE_FIELDS (uv-unix.h)
    unsigned long flags;
    int backend_fd;             /* uv底层io时使用的io模型。unix上为kqueue,linux为epoll,... */
    void *pending_queue[2];     /* 队列中存放等待执行回调的uv__io_t */
    void *watcher_queue[2];     /* 队列中存放被监听的uv__io_t */
    uv__io_t ** watchers;       /* 存放被监听的uv__io_t指针的数组,以对应的fd作为数组索引 */
    unsigned int nwatchers;     /* nwatchers+2 是上面watchers数组的长度 */
    unsigned int nfds;          /* number of fds */
    
    void* wq[2];                /* 
                                uv_work在threadpool中执行完uv__work的wrok()函数后,\
                                将uv__work转移到此队列中,\
                                并用loop->wq_async通知uv_loop执行其done()函数。 
                                */
    uv_mutex_t wq_mutex;
    uv_async_t wq_async;        /*
                                uv_work在threadpool中执行完uv__work的work()函数后,
                                将uv__work转移到loop->wq队列中,并用wq_async通知uv_loop。\
                                wq_async的回调函数是uv__work_done(),\
                                uv__work_done()遍历loop->wq队列并执行各元素的done()函数。
                                */
    uv_rwlock_t cloexec_lock;
    uv_handle_t* closing_handles;   /* 
                                    等待执行close的handle。\
                                    uv_close()时将handle添加到队首。\
                                    uv_loop的loop iteration的最后会\
                                    执行队列中handle的close操作,并清空队列。
                                    */
    void* process_handles[2];
    void* prepare_handles[2];   /* 队列中存放活跃的uv_prepare_t */
    void* check_handles[2];     /* 队列中存放活跃的uv_check_t */
    void* idle_handles[2];      /*
                                队列中存放活跃的uv_idle_t
                                uv_idle_start()时入队首。
                                uv_idle_stop()时出队。
                                uv_loop每次loop iteration会遍历idle_handles中\
                                的idle并执行其idle_cb。 
                                */
    void* async_handles[2];     /*
                                uv_async_t的队列。
                                uv_async_init()时追加uv_async_t到尾部。
                                uv_close()时从队列移除uv_async_t。
                                uv_loop的循环中,通过io管道来监听是否有异步事件,\
                                如果有异步事件的话,uv_loop会遍历本队列中的async,\
                                执行需要回调的async。
                                */
    struct uv__async async_watcher; /*
                                    在第一次调用uv_async_init()时初始化。
                                    uv_loop从一个io管道监听是否有异步事件,\
                                    当有异步事件时,会调用async_watcher.cb,\
                                    async_wacther.cb在初始时被置为uv__async_event()方法,\
                                    该方法内会遍历上面的async_handles,从而执行异步回调。
                                    */
    
    struct {
        void* min;
        unsigned int nelts;
    } timer_heap;           /* 
                            定时器时间堆。
                            uv_timer_start()向时间堆插入节点。
                            uv_timer_stop()从时间堆移除节点。
                            uv_loop内部执行uv__run_timers()时从时间堆中\
                            取出已超时的uv_timer_t,执行其回调。
                            */
    
    uint64_t timer_counter; /*
                            定时器start_id计数器。
                            每次调用uv_timer_start()时,timer_counter++作为timer的start_id。
                            */
    
    uint64_t time;          /* 存储当前时间,用此时间判断定时器是否超时。 */
    int signal_pipefd[2];
    uv__io_t signal_io_watcher;
    uv_signal_t child_watcher;
    int emfile_fd;
    
    // UV_PLATFORM_LOOP_FIELDS (uv-linux.h)
    uv__io_t inotify_read_watcher;
    void* inotify_watchers;
    int inotify_fd;
};


> uv_run()

int uv_run(uv_loop_t* loop, uv_run_mode mode) {
  int timeout;
  int r;
  int ran_pending;

  r = uv__loop_alive(loop);
  if (!r)
    uv__update_time(loop);

  while (r != 0 && loop->stop_flag == 0) {
    uv__update_time(loop);
    uv__run_timers(loop);
    ran_pending = uv__run_pending(loop);
    uv__run_idle(loop);
    uv__run_prepare(loop);

    timeout = 0;
    if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
      timeout = uv_backend_timeout(loop);

    uv__io_poll(loop, timeout);
    uv__run_check(loop);
    uv__run_closing_handles(loop);

    if (mode == UV_RUN_ONCE) {
      /* UV_RUN_ONCE implies forward progress: at least one callback must have
       * been invoked when it returns. uv__io_poll() can return without doing
       * I/O (meaning: no callbacks) when its timeout expires - which means we
       * have pending timers that satisfy the forward progress constraint.
       *
       * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
       * the check.
       */
      uv__update_time(loop);
      uv__run_timers(loop);
    }

    r = uv__loop_alive(loop);
    if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
      break;
  }

  /* The if statement lets gcc compile it to a conditional store. Avoids
   * dirtying a cache line.
   */
  if (loop->stop_flag != 0)
    loop->stop_flag = 0;

  return r;
}


> uv__loop_alive()

static int uv__loop_alive(const uv_loop_t* loop) {
  return uv__has_active_handles(loop) ||   // loop->active_handles > 0
         uv__has_active_reqs(loop) ||       // QUEUE_EMPTY(&(loop)->active_reqs) == 0
         loop->closing_handles != NULL;
}


> uv_is_active()

int uv_is_active(const uv_handle_t* handle) {
  return uv__is_active(handle);     // (((h)->flags & UV__HANDLE_ACTIVE) != 0)
}


> uv_is_closing

int uv_is_closing(const uv_handle_t* handle) {
  return uv__is_closing(handle);    // (((h)->flags & (UV_CLOSING |  UV_CLOSED)) != 0)
}


libuv-v1.11.0 - 源码剖析 - 02 - uv_timer_t

> uv_timer_t

struct {
    // UV_HANDLE_FIELDS (uv.h)
    void *data;
    uv_loop_t *loop;        /* 所属的uv_loop */
    uv_handle_type type;    /* handle的类型,对于uv_timer_t初始化为UV_TIMER */
    uv_close_cb close_cb;   /* 
                            uv_close()时设置的回调。
                            uv_loop内部执行uv__finish_close(handle)时执行回调。
                            */
    
    void* handle_queue[2];  /*
                            用于插入loop->handle_queue的队列节点。
                            uv_timer_init()时被追加到loop->handle_queue尾部。
                            uv_loop内部执行uv__finish_close(handle)时,\
                            handle从loop->handle_queue出队。
                            */
    union {
        int fd;
        void *reserved[4];
    } u;
    
    // UV_HANDLE_PRIVATE_FIELDS (uv-unix.h)
    uv_handle_t* next_closing;  /* 
                                下一个待close的handle。
                                uv_handle_init()后为NULL。
                                uv_close()后:
                                指向loop->closing_handles, loop->closing_handles指向此。
                                */
    
    unsigned int flags;     /*
                            可取值:
                                UV__HANDLE_CLOSING (UV_CLOSING),
                                UV__HANDLE_REF,
                                UV__HANDLE_ACTIVE,
                                UV__HANDLE_INTERNAL,
                                UV_CLOSED。
                            uv_handle_init()后为UV__HANDLE_REF。
                            uv__handle_start()时 |=UV__HANDLE_ACTIVE。
                            uv__handle_stop()时 &=~UV__HANDLE_ACTIVE。
                            uv_close()时 |=UV_CLOSING。
                            uv_loop内部执行uv__finish_close(handle)时,\
                            |= UV_CLOSED, &=~UV__HANDLE_REF。
                            */
    
    // UV_TIMER_PRIVATE_FIELDS (uv-unix.h)
    uv_timer_cb timer_cb;   /*
                            定时器回调。
                            uv_timer_init()后为NULL。
                            uv_timer_start()时设置。
                            */
    
    void* heap_node[3];     /*
                            时间堆节点。
                            在uv_timer_start()时会将此节点插入loop->timer_heap。
                            在uv_timer_stop()时会将此节点从loop->timer_heap中移除。
                            uv_loop内部执行uv__run_timers()时从时间堆中\
                            取出已超时的uv_timer_t,执行其回调。
                            */
    
    uint64_t timeout;       /*
                            超时时间。
                            uv_timer_init()时不改变。
                            uv_timer_start()时设置值。
                            uv_loop内部执行uv__run_timers()时,\
                            通过比较timeout和loop->time来判断定时器超时。
                            */
    
    uint64_t repeat;        /*
                            定时器repeat时间间隔。0表示不repeat。
                            uv_timer_init()后为0。
                            uv_timre_start()时设置。
                            uv_loop内部的uv__run_timers()每当触发一次定时器回调后,\
                            通过判断repeat!=0来决定是否以repeat作为超时再次启动定时器。
                            */
    
    uint64_t start_id;      /*
                            start_id is the second index to be compared in \
                            uv__timer_cmp()
                            */
};


> uv_check_t、uv_prepare_t 的实现与uv_idle_t相同。


libuv-v1.11.0 - 源码剖析 - 03 - uv_idle_t

> uv_idle_t

struct {
    // UV_HANDLE_FIELDS (uv.h)
    void *data;
    uv_loop_t* loop;        
    uv_handle_type type;    /* handle的类型,对于uv_idle_t初始化为UV_IDLE */
    uv_close_cb close_cb;   /* 
                            uv_close()时设置的回调。
                            uv_loop内部执行uv__finish_close(handle)时执行回调。
                            */
    
    void *handle_queue[2];  /*
                            用于插入loop->handle_queue的队列节点。
                            uv_idle_init()时被追加到loop->handle_queue尾部。
                            uv_loop内部执行uv__finish_close(handle)时,\
                            handle从loop->handle_queue出队。
                            */
    
    union {
        int fd;
        void *reserved[4];
    } u;
    
    // UV_HANDLE_PRIVATE_FIELDS (uv-unix.h)
    uv_handle_t* next_closing;  /* 
                                下一个待close的handle。
                                uv_handle_init()后为NULL。
                                uv_close()后:
                                指向loop->closing_handles, loop->closing_handles指向此。
                                */
    
    unsigned int flags;     /*
                            可取值:
                                UV__HANDLE_CLOSING (UV_CLOSING),
                                UV__HANDLE_REF,
                                UV__HANDLE_ACTIVE,
                                UV__HANDLE_INTERNAL,
                                UV_CLOSED。
                            uv_idle_init()后为UV__HANDLE_REF。
                            uv__handle_start()时 |=UV__HANDLE_ACTIVE。
                            uv__handle_stop()时 &=~UV__HANDLE_ACTIVE。
                            uv_close()时 |=UV_CLOSING。
                            uv_loop内部执行uv__finish_close(handle)时,\
                            |= UV_CLOSED, &=~UV__HANDLE_REF。
                            */
    
    // UV_IDLE_PRIVATE_FIELDS (uv-unix.h)
    uv_idle_cb idle_cb;     /* 
                            idle的回调
                            uv_idle_init()时置空
                            uv_idle_start()时置值。 
                            */
    
    void *queue[2];         /* 
                            uv_idle_start()时将此queue挂接到loop->idle_handles队首
                            uv_idle_stop()时出队。 
                            uv_loop每次loop iteration会遍历idle_handles中\
                            的idle并执行其idle_cb。
                            */
};


libuv-v1.11.0 - 源码剖析 - 04 - uv_async_t

> uv__io_t

struct uv__io_s {
  uv__io_cb cb;     /* io事件回调, event类型:POLLIN | POLLOUT | UV__POLLRDHUP */
  void* pending_queue[2];
  void* watcher_queue[2];
  unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
  unsigned int events;  /* Current event mask. */
  int fd;           /* 监听的fd */
  UV_IO_PRIVATE_PLATFORM_FIELDS
};


> struct uv__async

struct uv__async {
  uv__async_cb cb;      /* 当从io_watcher.fd读取到数据后,调用该回调 */
  uv__io_t io_watcher;  /*
                        监听io_watcher.fd的读取事件,读取到数据后,触发上面的cb回调。
                        uv__async_init()设置io_watcher.fd = -1。
                        uv__async_start()设置io_watcher.fd = 管道读端fd。
                        */
    
  int wfd;              /*
                        管道写端fd。uv_async_send()会向其中写入一个字节。
                        uv__async_init()设置wfd = -1。
                        uv__async_start()设置wfd = 管道写端fd。
                        */
};


> uv_async_t

struct {
    // UV_HANDLE_FIELDS (uv.h)
    void *data;
    uv_loop_t *loop;
    uv_handle_type type;
    uv_close_cb close_cb;
    void* handle_queue[2];      /*
                                队列节点。该节点将在uv__handle_init()时挂接\
                                到loop->handle_queue尾
                                */
    union {
        int fd;
        void *reserved[4];
    } u;
    
    // UV_HANDLE_PRIVATE_FIELDS (uv-unix.h)
    uv_handle_t* next_closing;
    unsigned int flags;
    
    // UV_ASYNC_PRIVATE_FIELDS (uv-unix.h)
    uv_async_cb async_cb;   /*
                            异步事件回调。
                            uv_async_init()设置该回调。
                            */
    
    void* queue[2];         /*
                            队列节点。该节点将在uv_async_init()时挂接到\
                            loop->async_handles尾。
                            */
    
    int pending;            /*
                            等待回调异步事件的标志。
                            初始为0。
                            uv_async_send()设其为1。
                            事件回调后恢复为0。
                            */
};


libuv-v1.11.0 - 源码剖析 - 05 - uv_req_t

> uv_getaddrinfo_t

struct {
    // UV_REQ_FIELDS (uv.h)
    void *data;
    uv_req_type type;       /* 对于uv_getaddrinfo_t,此处初始化为UV_GETADDRINFO。 */
    void* active_queue[2];  /*
                            队列节点。用于挂接到loop->active_reqs队列。
                            uv__req_init()调用的uv__req_register()中将此节点添加到loop->active_reqs尾部。
                            uv__getaddrinfo_done()调用的uv__req_unregister()中将req从队列移除。
                            */
    
    void* reserved[4];
    //UV_REQ_PRIVATE_FIELDS
    
    // UV_GETADDRINFO_PRIVATE_FIELDS (uv-unix.h)
    struct uv__work work_req;   /*
                                work_req->wq字段可以挂接到全局work队列中,\
                                threadpool中的线程从该队列中互斥取work_req,\
                                并执行work_req->work()。\
                                执行完work()函数后,将uv__work转移到loop->wq队列中,\
                                并向loop->wq_async发送异步事件,\
                                loop->async的回调函数uv__work_done(),\
                                uv__work_done()遍历loop->wq队列并执行各元素的done()函数。\
                                done()函数中会执行uv_getaddrinfo_cb。
                                */
    uv_getaddrinfo_cb cb;
    struct addrinfo* hints;
    char* hostname;
    char* service;
    struct addrinfo* addrinfo;
    int retcode; 
};


> uv_write_t

struct {
    // UV_REQ_FIELDS (uv.h)
    void *data;
    uv_req_type type;
    void* active_queue[2];      /* 
                                uv_write()时挂接到loop->active_ques队列。
                                write完成之后,在uv__write_callbacks()中\
                                把req从loop->active_ques移除。
                                uv__stream_destroy()函数内部会把未完成的uv_write强制结束,\
                                并执行uv__write_callbacks()从loop->active_ques中移除。
                                */
    void* reserved[4];
    // UV_REQ_PRIVATE_FIELDS
    
    uv_write_cb cb;
    uv_stream_t* send_handle;
    uv_stream_t* handle;
    
    // UV_WRITE_PRIVATE_FIELDS (uv-unix.h)
    void* queue[2];         /* 
                            uv_write()时挂接到stream->write_queue队列。 \
                            当write完成后转移到stream->write_completed_queue队列,\
                            然后调用uv__write_callbacks(),uv__write_callbacks()取出\
                            stream->write_completed_queue队列中的req并执行回调。
                            */
    unsigned int write_index; 
    uv_buf_t* bufs;
    unsigned int nbufs;    
    int error;
    uv_buf_t bufsml[4];
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352