国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 操作系統(tǒng) > 正文

Event Poll epoll 詳解

2024-06-28 13:23:31
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
Event Poll epoll 詳解

由于poll()和select()的局限,2.6內(nèi)核引入了event poll(epoll)機(jī)制。雖然稍微復(fù)雜,但是epoll解決了它們共有的基本性能問題,并增加了一些新的特性。

poll()和select()每次調(diào)用都需要所有被監(jiān)聽的文件描述符。內(nèi)核必須遍歷所有被監(jiān)視的文件描述符。當(dāng)這個(gè)表變得很大時(shí),成千上百的文件描述符,每次調(diào)用時(shí)的遍歷就成為了明顯的瓶頸。

1、創(chuàng)建一個(gè)新的epoll實(shí)例

使用epoll_create()或者epoll_cerate1()創(chuàng)建一個(gè)epoll上下文。這里epoll_cerate1()是epoll_cerate()的擴(kuò)展版本。

#include <sys/epoll.h>int epoll_create (int size)

調(diào)用成功后,epoll_create()創(chuàng)建一個(gè)epoll實(shí)例,返回與該實(shí)例關(guān)聯(lián)的文件描述符。這個(gè)文件描述符和真正的文件沒有關(guān)系,僅僅是為了后續(xù)調(diào)用使用epoll而創(chuàng)建的。size參數(shù)告訴內(nèi)核需要監(jiān)聽的文件描述符數(shù)目,但不是最大值。傳遞一個(gè)適當(dāng)?shù)慕浦禃?huì)帶來(lái)性能的提升,但不需要給出確切的數(shù)字。出錯(cuò)時(shí),返回-1,設(shè)置errno為下列值之一:

EINVAL   size不是正數(shù)

ENFILE    系統(tǒng)達(dá)到打開文件數(shù)的上限

ENOMEN    沒有足夠內(nèi)存完成該次操作。

標(biāo)準(zhǔn)調(diào)用如下:

int epfd;epfd = epoll_create (100); if (epfd <0 )perror("epoll_create");

epoll_create返回的文件描述符需要用close()關(guān)閉。

2、控制 epoll

epoll_ctl 可以向指定的epoll上下文加入或刪除文件描述符:

#include <sys/epoll.h>int epoll_ctl (int epfd, int op, int fd, struct epoll_event *event);
頭文件<sys/epoll.h>中定義了epoll event結(jié)構(gòu)體
struct epoll_event {_u32 events;union {void * ptr;int fd;_u32 u32;_u64 u64;}data;};
epoll_ctl()成功調(diào)用將關(guān)聯(lián)epoll實(shí)例和epfd。參數(shù)op指定對(duì)fd要進(jìn)行的操作。event參數(shù)描述epoll更具體的行為
以下是參數(shù)op的有效值:
EPOLL_CTL_ADD 把fd指定的文件添加到epfd指定的epoll實(shí)例監(jiān)聽集中,監(jiān)聽event中定義的事件。
EPOLL_CTL_DEL 把fd指定的文件從epfd指定的epoll監(jiān)聽集中刪除。
EPOLL_CTL_MOD 使用event改變?cè)谝延衒d上的監(jiān)聽行為。
epoll_event結(jié)構(gòu)體中的event參數(shù)列出了在給定文件描述符上監(jiān)聽的事件。多個(gè)事件可以使用位或運(yùn)算同時(shí)指定。以下是有效值:
EPOLLERR 文件出錯(cuò)。即使不設(shè)置這個(gè)標(biāo)志,這個(gè)事件也是被監(jiān)聽的。
EPOLLET 使用邊沿觸發(fā)。默認(rèn)是水平觸發(fā)。
EPOLLHUP 文件被掛起。即使不設(shè)置這個(gè)標(biāo)志,這個(gè)事件也是被監(jiān)聽的。
EPOLLIN 文件未阻塞,可讀。
EPOLLONESHOT 在一次事件產(chǎn)生被處理之后,文件不在被監(jiān)聽。必須不再被監(jiān)聽。必須使用EPOLL_CTL_MOD指定新的事件,以便重新監(jiān)聽文件。
EPOLLOUT 文件未阻塞,可寫。
EPOLLPRI 高優(yōu)先級(jí)的帶外數(shù)據(jù)可讀。
event_poll中的data字段由用戶使用。確認(rèn)監(jiān)聽事件后,data會(huì)被返回給用戶。通常將event.data.fd設(shè)定為fd,這樣就可以知道那個(gè)文件描述符觸發(fā)事件。
成功后,epoll_ctl()返回0.失敗返回-1,并設(shè)置errno為下列值:
EBADF epfd不是一個(gè)有效的epoll實(shí)例,或者fd不是有效文件描述符。
EEXIST op為EPOLL_CTL_ADD,但是fd已經(jīng)與epfd關(guān)聯(lián)。
EINVAL epfd不是一個(gè)epoll實(shí)例,epfd和fd相同,或者op無(wú)效。
ENOENT op是EPOLL_CTL_MOD或者是EPOLL_CTL_DEL,但是fd沒有與epfd關(guān)聯(lián)。
ENOMEN 沒有足夠內(nèi)存完成進(jìn)程的請(qǐng)求。
EPERM fd不支持epoll。
在epfd實(shí)例中加入一個(gè)fd指定的監(jiān)聽文件,使用如下代碼:
struct epoll_event event;int ret;event.data.fd = fd;/*return the fd to us later*/event.events = EPOLLIN|EPOLLOUT  ;ret = epoll_ctl (epfd,EPOLL_CTL_MOD,fd,&event);if (ret)perror ("epoll_ctl");
修改epfd實(shí)例中的fd上的一個(gè)監(jiān)聽事件,可以使用如下代碼:
struct epoll_event event;int ret;event.data.fd = fd;/*return the fd to us later*/event.events = EPOLLIN ;ret = epoll_ctl (epfd,EPOLL_CTL_MOD,fd,&event);if (ret)perror ("epoll_ctl");
刪除一個(gè)fd監(jiān)聽事件,可以使用如下代碼:
struct epoll_event event;int ret;event.data.fd = fd;/*return the fd to us later*/event.events = EPOLLIN ;ret = epoll_ctl (epfd,EPOLL_CTL_DEL,fd,&event);if (ret)perror ("epoll_ctl");
3、等待Epoll事件
epoll_wait()等待給定epoll實(shí)例關(guān)聯(lián)的文件描述符上的事件:
#include <sys/epoll.h>int epoll_wait (int epfd, struct epoll_event * * events, int maxevents, int timeout);
對(duì)epoll_wait()的調(diào)用等待epoll實(shí)例epfd中的文件fd上的事件,時(shí)限為timeout毫秒。成功返回,struct epoll_event *events指向包含epoll_event結(jié)構(gòu)體(該結(jié)構(gòu)體描述了每個(gè)事件)的內(nèi)存,且最多可以有maxevents
個(gè)事件。這樣可以根據(jù)events結(jié)構(gòu)體來(lái)確定哪些fd觸發(fā)了事件,從而做出相應(yīng)的處理。返回值是事件數(shù),出錯(cuò)返回-1,并將errno設(shè)置為以下值
EBADF epfd是無(wú)效文件描述符
EFAULT 進(jìn)程對(duì)events指向的內(nèi)存無(wú)寫權(quán)限
EINTR 系統(tǒng)調(diào)用在完成前被信號(hào)中斷
EINVAL epfd不是有效的epoll實(shí)例,或者maxevents小于等于0
如果timeout 為0.即使沒有事件發(fā)生,調(diào)用也立即發(fā)生,此時(shí)調(diào)用返回0.如果timeout為-1,調(diào)用將一直等待到有事件發(fā)生。
當(dāng)調(diào)用epoll_wait()返回,epoll_event結(jié)構(gòu)體中的events數(shù)組描述了一次等待發(fā)生的事件,最多返回maxevents個(gè)事件。data字段包含了用戶在調(diào)用epoll_ctl前的設(shè)置,
如文件的句柄,用來(lái)區(qū)分那個(gè)文件所發(fā)生的事件。
一個(gè)完整的epoll_wait()例子如下:
#define MAX_EVENTS   64struct epoll_event * events = NULL;int nr_events, i, epfd;events = malloc (sizeof(struct epoll_event) * MAX_EVENTS);if (! events ){perror("malloc");exit(-1);}nr_events = epoll_wait (epfd,events,MAX_EVENTS,-1);if (nr_events < 0){perror("epoll_wait");free(events);exit (-1);}for (int i=0; i<nr_eventsl i++)printf("event = %d on fd = %d /n",events[i].events,events[i].data.fd); 
4、邊沿觸發(fā)時(shí)間和水平觸發(fā)事件

EPOLL事件有兩種模型 Level Triggered (LT)Edge Triggered (ET):

LT(level triggered,水平觸發(fā)模式)是缺省的工作方式,并且同時(shí)支持 block 和 non-block socket。在這種做法中,內(nèi)核告訴你一個(gè)文件描述符是否就緒了,然后你可以對(duì)這個(gè)就緒的fd進(jìn)行IO操作。如果你不作任何操作,內(nèi)核還是會(huì)繼續(xù)通知你的,所以,這種模式編程出錯(cuò)誤可能性要小一點(diǎn)。

ET(edge-triggered,邊緣觸發(fā)模式)是高速工作方式,只支持no-block socket。在這種模式下,當(dāng)描述符從未就緒變?yōu)榫途w時(shí),內(nèi)核通過epoll告訴你。然后它會(huì)假設(shè)你知道文件描述符已經(jīng)就緒,并且不會(huì)再為那個(gè)文件描述符發(fā)送更多的就緒通知,等到下次有新的數(shù)據(jù)進(jìn)來(lái)的時(shí)候才會(huì)再次出發(fā)就緒事件。

5、man epoll 中的實(shí)例

setnonblocking()函數(shù)將socket文件設(shè)置為非阻塞,因?yàn)槭褂玫氖荅T模式。do_use_fd()是對(duì)此文件做出一定的處理,如讀寫等。

#define MAX_EVENTS 10struct epoll_event ev, events[MAX_EVENTS];int listen_sock, conn_sock, nfds, epollfd;/* Set up listening socket, 'listen_sock' (socket(),    bind(), listen()) */epollfd = epoll_create(10);if (epollfd == -1) {    perror("epoll_create");    exit(EXIT_FAILURE);}ev.events = EPOLLIN;ev.data.fd = listen_sock;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {    perror("epoll_ctl: listen_sock");    exit(EXIT_FAILURE);}for (;;) {    nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);    if (nfds == -1) {        perror("epoll_pwait");        exit(EXIT_FAILURE);    }    for (n = 0; n < nfds; ++n) {        if (events[n].data.fd == listen_sock) {            conn_sock = accept(listen_sock,                            (struct sockaddr *) &local, &addrlen);            if (conn_sock == -1) {                perror("accept");                exit(EXIT_FAILURE);            }            setnonblocking(conn_sock);            ev.events = EPOLLIN | EPOLLET;            ev.data.fd = conn_sock;            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,                        &ev) == -1) {                perror("epoll_ctl: conn_sock");                exit(EXIT_FAILURE);            }        } else {            do_use_fd(events[n].data.fd);        }    }}

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 祁连县| 甘南县| 嘉荫县| 海原县| 阳城县| 六盘水市| 浑源县| 遂昌县| 永仁县| 浙江省| 顺昌县| 尚志市| 建始县| 长垣县| 永仁县| 通山县| 安塞县| 诏安县| 湟中县| 璧山县| 木兰县| 新民市| 南乐县| 永平县| 获嘉县| 婺源县| 中西区| 姚安县| 阳山县| 阿拉善右旗| 科尔| 将乐县| 汕尾市| 甘肃省| 方山县| 哈尔滨市| 呼玛县| 台山市| 富蕴县| 沈丘县| 衡东县|