libevent的Select事件

libevent的Select事件

收獲

  1. 特別大的收獲阵赠,好像也沒有数初。就只是看懂了它寫的代碼是什么意思拷况。
  2. 程序結(jié)果的設計會有點意思作煌。其他沒什么特別的印象。

結(jié)構(gòu)體

struct selectop {
    /* 最大的文件句柄赚瘦。*/
    int event_fds;      /* Highest fd in fd set */
    int event_fdsz;
    fd_set *event_readset;/* 讀信號事件集合*/
    fd_set *event_writeset;/* 寫信號事件集合*/
    sigset_t evsigmask;// linux 信號集粟誓。用于檢測是否有信號發(fā)送過來。
} sop;

結(jié)構(gòu)體說明

selectop含有成員變量

evsigmask是用于檢測select時起意,有信號發(fā)送的鹰服。

成員函數(shù)

select類的成員函數(shù)。

void *select_init   (void);
int select_add      (void *, struct event *);
int select_del      (void *, struct event *);
int select_recalc   (void *, int);
int select_dispatch (void *, struct timeval *);

select類揽咕,類似于c++的多態(tài)實現(xiàn)

struct eventop {
    char *name;
    void *(*init)(void);
    int (*add)(void *, struct event *);
    int (*del)(void *, struct event *);
    int (*recalc)(void *, int);
    int (*dispatch)(void *, struct timeval *);
};//基類
struct eventop selectops = {
    "select",
    select_init,
    select_add,
    select_del,
    select_recalc,
    select_dispatch
};
select_recalc
  1. 初始化結(jié)構(gòu)體和信號集
void *
select_init(void)
{
    memset(&sop, 0, sizeof(sop));

    sigemptyset(&sop.evsigmask);

    return (&sop);
}
select_recalc
  1. 重新申請悲酷,存儲監(jiān)聽信號集的變量的大小。(事件是安位監(jiān)聽的亲善。)
int
select_recalc(void *arg, int max)
{
    struct selectop *sop = arg;
    fd_set *readset, *writeset;
    struct event *ev;
    int fdsz;
    /*
    設置event_fds為最大值
    */
    if (sop->event_fds < max)
        sop->event_fds = max;
    /*
    如果event_fds不存在设易,則遍歷隊列,取最大值蛹头。
    */
    if (!sop->event_fds) {
        TAILQ_FOREACH(ev, &eventqueue, ev_next)
            if (ev->ev_fd > sop->event_fds)
                sop->event_fds = ev->ev_fd;
    }
    /*
    計算存儲event_fds所需要的位數(shù)顿肺。
    */
    fdsz = howmany(sop->event_fds + 1, NFDBITS) * sizeof(fd_mask);
    if (fdsz > sop->event_fdsz) {
        if ((readset = realloc(sop->event_readset, fdsz)) == NULL) {
            log_error("malloc");
            return (-1);
        }

        if ((writeset = realloc(sop->event_writeset, fdsz)) == NULL) {
            log_error("malloc");
            free(readset);
            return (-1);
        }

        memset((char *)readset + sop->event_fdsz, 0,
            fdsz - sop->event_fdsz);
        memset((char *)writeset + sop->event_fdsz, 0,
            fdsz - sop->event_fdsz);

        sop->event_readset = readset;
        sop->event_writeset = writeset;
        sop->event_fdsz = fdsz;
    }

    return (signal_recalc());
}
signal_recalc
/*
重新計算,并重新注冊信號事件渣蜗。只注冊signalqueue里的even
注冊到信號事件里的函數(shù)為signal_handler屠尊。
該事件,只是在數(shù)組里對應的字段加一耕拷。
因為信號事件知染,只有64個。所以這其實就是個信號數(shù)組斑胜。表示該信號發(fā)生了幾次控淡。
*/
static void
signal_handler(int sig)
{
    evsigcaught[sig]++;
}
int
signal_recalc(void)
{
    struct sigaction sa;
    struct event *ev;

    if (sigprocmask(SIG_BLOCK, &sop.evsigmask, NULL) == -1)
        return (-1);
    
    /* Reinstall our signal handler. */
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signal_handler;
    sa.sa_mask = sop.evsigmask;
    sa.sa_flags |= SA_RESTART;
    
    TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
        if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1)
            return (-1);
    }
    return (0);
}
select_dispatch

事件處理函數(shù)

/*
下發(fā)任務嫌吠,發(fā)起一次,select掺炭。等待信號發(fā)送辫诅。
*/
int
select_dispatch(void *arg, struct timeval *tv)
{
    int maxfd, res;
    struct event *ev, *next;
    struct selectop *sop = arg;

    memset(sop->event_readset, 0, sop->event_fdsz);
    memset(sop->event_writeset, 0, sop->event_fdsz);
    /*
    再初始化,信號集涧狮。
    */
    TAILQ_FOREACH(ev, &eventqueue, ev_next) {
        if (ev->ev_events & EV_WRITE)
            FD_SET(ev->ev_fd, sop->event_writeset);
        if (ev->ev_events & EV_READ)
            FD_SET(ev->ev_fd, sop->event_readset);
    }
    /*
    先注冊信號炕矮。
    */
    if (signal_deliver() == -1)
        return (-1);
    /*
    調(diào)用select函數(shù),等待事件發(fā)送者冤。
    tv如果有值肤视,則超時自動返回。
    */
    res = select(sop->event_fds + 1, sop->event_readset, 
        sop->event_writeset, NULL, tv);
    /*
    select函數(shù)完后涉枫。需再重新注冊信號事件邢滑。
    如果select中有事件發(fā)生,需要再重新注冊一遍事件愿汰±Ш螅或者select中,是事件觸發(fā)select結(jié)束
    會導致程序未處理接下來的信號事件
    */
    if (signal_recalc() == -1)
        return (-1);

    if (res == -1) {
        if (errno != EINTR) {
            log_error("select");
            return (-1);
        }
        /*
        處理信號衬廷。
        */
        signal_process();
        return (0);
    }

    LOG_DBG((LOG_MISC, 80, __FUNCTION__": select reports %d",
         res));
    /*
    監(jiān)聽讀事件摇予,或者寫事件,是否有事件發(fā)生吗跋。
    */
    maxfd = 0;
    for (ev = TAILQ_FIRST(&eventqueue); ev != NULL; ev = next) {
        next = TAILQ_NEXT(ev, ev_next);

        res = 0;
        if (FD_ISSET(ev->ev_fd, sop->event_readset))
            res |= EV_READ;
        if (FD_ISSET(ev->ev_fd, sop->event_writeset))
            res |= EV_WRITE;
        res &= ev->ev_events;

        if (res) {
            if (!(ev->ev_events & EV_PERSIST))
                event_del(ev);
            event_active(ev, res, 1);
        } else if (ev->ev_fd > maxfd)
            maxfd = ev->ev_fd;
    }

    sop->event_fds = maxfd;

    return (0);
}
select_add
/*
添加事件侧戴。
如果只是select的信號事件,就增加到信號事件集里跌宛。
如果不是select的信號事件救鲤。就增加最大的文件fd
這樣,自然就添加到了select的監(jiān)聽事件集里秩冈。
*/
int
select_add(void *arg, struct event *ev)
{
    struct selectop *sop = arg;

    if (ev->ev_events & EV_SIGNAL) {
        int signal;

        if (ev->ev_events & (EV_READ|EV_WRITE))
            errx(1, "%s: EV_SIGNAL incompatible use",
                __FUNCTION__);
        signal = EVENT_SIGNAL(ev);
        sigaddset(&sop->evsigmask, signal);

        return (0);
    }

    /* 
     * Keep track of the highest fd, so that we can calculate the size
     * of the fd_sets for select(2)
     */
    if (sop->event_fds < ev->ev_fd)
        sop->event_fds = ev->ev_fd;

    return (0);
}
select_del
/*
 * Nothing to be done here.
 文件句柄,擴大了就沒有再縮小了斥扛。
 刪除信號事件入问。
 */
int
select_del(void *arg, struct event *ev)
{
    struct selectop *sop = arg;

    int signal;

    if (!(ev->ev_events & EV_SIGNAL))
        return (0);

    signal = EVENT_SIGNAL(ev);
    sigdelset(&sop->evsigmask, signal);

    return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市稀颁,隨后出現(xiàn)的幾起案子芬失,更是在濱河造成了極大的恐慌,老刑警劉巖匾灶,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棱烂,死亡現(xiàn)場離奇詭異,居然都是意外死亡阶女,警方通過查閱死者的電腦和手機颊糜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門哩治,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人衬鱼,你說我怎么就攤上這事业筏。” “怎么了鸟赫?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵蒜胖,是天一觀的道長。 經(jīng)常有香客問我抛蚤,道長台谢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任岁经,我火速辦了婚禮朋沮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蒿偎。我一直安慰自己朽们,他們只是感情好,可當我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布诉位。 她就那樣靜靜地躺著骑脱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪苍糠。 梳的紋絲不亂的頭發(fā)上叁丧,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天,我揣著相機與錄音岳瞭,去河邊找鬼拥娄。 笑死,一個胖子當著我的面吹牛瞳筏,可吹牛的內(nèi)容都是我干的稚瘾。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼姚炕,長吁一口氣:“原來是場噩夢啊……” “哼摊欠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柱宦,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤些椒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后掸刊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體免糕,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了石窑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牌芋。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖尼斧,靈堂內(nèi)的尸體忽然破棺而出姜贡,到底是詐尸還是另有隱情,我是刑警寧澤棺棵,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布楼咳,位于F島的核電站,受9級特大地震影響烛恤,放射性物質(zhì)發(fā)生泄漏母怜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一缚柏、第九天 我趴在偏房一處隱蔽的房頂上張望苹熏。 院中可真熱鬧,春花似錦币喧、人聲如沸轨域。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽干发。三九已至,卻和暖如春史翘,著一層夾襖步出監(jiān)牢的瞬間枉长,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工琼讽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留必峰,地道東北人。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓钻蹬,卻偏偏與公主長得像吼蚁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子问欠,可洞房花燭夜當晚...
    茶點故事閱讀 45,876評論 2 361