linux系統(tǒng)編程-第14天廣播組播本地套接字libevent源碼深度剖析_第1頁(yè)
linux系統(tǒng)編程-第14天廣播組播本地套接字libevent源碼深度剖析_第2頁(yè)
linux系統(tǒng)編程-第14天廣播組播本地套接字libevent源碼深度剖析_第3頁(yè)
linux系統(tǒng)編程-第14天廣播組播本地套接字libevent源碼深度剖析_第4頁(yè)
linux系統(tǒng)編程-第14天廣播組播本地套接字libevent源碼深度剖析_第5頁(yè)
已閱讀5頁(yè),還剩38頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

的。希望能給學(xué)習(xí)和使用libevent的朋友們有所幫助。 序 前 小 三基本使用場(chǎng)景和流 前 實(shí)例代 4處理流 5小 四libevent源代碼文件組 前 小 五libevent的: 3設(shè)置的接口函 4小 六初見(jiàn)處理框 1處理框架- 接口函 小 七主循 2處理主循 I/O和Timer的統(tǒng) I/O和Signal的統(tǒng) 小 八集成信號(hào)處 集成策略——使用socket 5、注銷(xiāo)signal................................................................................................小 九集成定時(shí)器....................................................................................................................... 小 十支持I/O多路復(fù)用技 小 十一時(shí)間管 時(shí)間緩 時(shí)間校 小 十二讓libevent支持多線 例子—— 小 前Libevent是一個(gè)輕量級(jí)的開(kāi)源高性能網(wǎng)絡(luò)庫(kù),使用者眾多,研究者更甚,相關(guān)文章也不不函數(shù)指針,學(xué)習(xí)其源代碼也需要相當(dāng)?shù)腸語(yǔ)言基礎(chǔ)。上來(lái)當(dāng)然要先夸獎(jiǎng)啦,Libevent有幾個(gè)顯著的亮點(diǎn):drivenI/Oepoll、poll、dev/poll、selectkqueue等;支持I/O,定時(shí)器和信號(hào)等;libevent有助于提升程序設(shè)計(jì)功力,除了網(wǎng)絡(luò)程序設(shè)計(jì)方面外,Libevent的代碼里libevent本身的框架大概了解,那或許僅僅是一知半解,不深入代碼分析,就難以了解其設(shè)LibeventReactorReactorLibevent:前面講到,整libevent本身就是一Reactor,因此本節(jié)將專(zhuān)Reactor模式進(jìn)行必要libevnetReactor的對(duì)應(yīng)關(guān)系,在后面的章節(jié)中可能還 的處理機(jī)序不是主動(dòng)的調(diào)用某個(gè)API完成處理,而是恰恰相反,Reactor逆置了處理流程,應(yīng)用用程序的接口,這些接口又稱(chēng)為“回調(diào)函數(shù)”。使用Libevent也是想Libevent框架相應(yīng)的和回調(diào)函數(shù);當(dāng)這些時(shí)間時(shí),Libevent會(huì)調(diào)用這些回調(diào)函數(shù)處理相應(yīng)的(I/O讀寫(xiě)、定時(shí)和信號(hào)程序,先來(lái)看看Reactor模型的整體框架,接下來(lái)再對(duì)每個(gè)組件做逐一說(shuō)明。源Linux上是文件描述符,WindowsSocketHandle了,這里統(tǒng)一稱(chēng)為“句柄當(dāng)有到達(dá)時(shí),eventdemultiplexer會(huì)發(fā)出通知“在已經(jīng)的句柄集中,一個(gè)或多Reactor,是管理的接口,eventdemultiplexer、注銷(xiāo);并運(yùn)行事class{ intregister_handler(Event_Handler*pHandler,int intremove_handler(Event_Handler*pHandler,int voidhandle_events(timeval //classclass{ virtualvoidhandle_read()= virtualvoidhandle_write()= virtualvoidhandle_timeout()=virtualvirtualvoidhandle_close()=0;virtualHANDLEget_handle()= //class{ //eventsmayberead/write/timeout/close virtualvoidhandle_events(intevents)= virtualHANDLEget_handle()= //前面Reactor將流“逆置”了,那么使用Reactor模式后,控制流是什么小Pattern-OrientedSoftwareArchitecture,PatternsforConcurrentandNetworkedObjects,Volume三基本使用場(chǎng)景和流前是個(gè)不錯(cuò)的方法,至少?gòu)膫€(gè)人的經(jīng)驗(yàn)上講,用此方法分析libevent是比較有效的?;緫?yīng)用場(chǎng)景基本應(yīng)用場(chǎng)景也是使用 structevent_base*base=evtimer_set(&ev,timer_cb,NULL);voidevent_set(structeventvoidevent_set(structevent*ev,intfd,shortevent,voidshort,void*),voidfd:該event綁定的“句柄”,對(duì)于信號(hào),它就是關(guān)注的信號(hào)event:在該fd上關(guān)注的類(lèi)型,它可以是EV_READ,EV_WRITE,EV_SIGNAL;調(diào)用時(shí)由event_base負(fù)責(zé)傳入,按順序,實(shí)際上就是event_set時(shí)的fd,eventarg;arg:傳遞給cb函數(shù)指針的參數(shù);由于定件不需要fd,并且定件是根據(jù)添加時(shí)(event_add)的超時(shí)值設(shè)定的,因此這里event也不需要設(shè)置。注意:libevent并不會(huì)管理event集合,這需要應(yīng)用程序自行管理;event_base_set(base,&ev);event_add(&ev,voidtime_cb(voidtime_cb(intfd,shortevent,void{printf("timerstructeventstructeventev;structtimevaltv;event_add(&ev,&tv);event_add(&ev,&tv);//reschedule}int{ structevent_base*base= tv.tv_sec=10;//10s tv.tv_usec= evtimer_set(&ev,time_cb, event_add(&ev, }4處理流當(dāng)應(yīng)用程序向libevent一個(gè)后,libevent內(nèi)部是怎么樣進(jìn)行處理的呢?下面的2向libevent添加該event。對(duì)于定件,libevent使用一個(gè)小根堆管理,key為超時(shí)時(shí)間;對(duì)于Signal和I/O,libevent將其放入到等待鏈表(waitlist)中,這是一每次循環(huán)前l(fā)ibevent會(huì)檢查定件的最小超時(shí)時(shí)間tv,根據(jù)tv設(shè)置select()的最大等5本節(jié)介紹了libevent的簡(jiǎn)單實(shí)用場(chǎng)景,并旋風(fēng)般的介紹了libevent的處理流程,讀式中的Reactor框架)做詳細(xì)的介紹,在此之前會(huì)對(duì)源代碼文件做簡(jiǎn)單的分類(lèi)。libevent源代碼文件前源代碼組織結(jié)構(gòu)頭文件、的頭文件、輔助功能函數(shù)、日志、libevent框架、對(duì)系統(tǒng)I/O多路復(fù)用機(jī)3)libevent框架event.c:event整體框架的代碼實(shí)現(xiàn);4)對(duì)系統(tǒng)I/O多路復(fù)用機(jī)制的封裝epoll.c:對(duì)epoll的封裝;select.c:對(duì)select的封裝;devpoll.c:對(duì)dev/poll的封裝;kqueue.c:對(duì)kqueue的封裝;evutil.hevutil.csocketpair和一些時(shí)間操作函數(shù):加、減小五libevent的:libevent對(duì)event的管理。event就是Reactor框架中的處理程序組件;它提供了函數(shù)接口,供Reactor在發(fā)生structevent TAILQ_ENTRY(event)TAILQ_ENTRYTAILQ_ENTRY(event)ev_active_next;TAILQ_ENTRY(event) unsignedintmin_heap_idx;/*formanagingtimeouts structevent_base intshortshortev_events;short short /*Allowsdeletesincallbackvoid(*ev_callback)(intvoid(*ev_callback)(int,short,voidint /*smallernumbersarehigherpriority void int /*resultpassedtoeventcallback intevent關(guān)注的類(lèi)型,它可以是以下3種類(lèi)型:I/O: 輔助選項(xiàng):EV_PERSIST,表明是一個(gè)永久#defineEV_WRITE#defineEV_WRITE0x04#defineEV_SIGNAL#defineEV_TIMEOUT #define #define /*Persistantevent可以看出類(lèi)型可以使用“|”運(yùn)算符進(jìn)行組合,需要說(shuō)明的是,信號(hào)和I/O不能同還可以看出libevent使用event結(jié)構(gòu)體將這3種的處理統(tǒng)一起來(lái);2)ev_next,ev_active_next和ev_signal_next都是雙向鏈表節(jié)點(diǎn)指針;它們是libevent對(duì)不同類(lèi)型和libevent使向鏈表保存所有的I/O和Signal,ev_next就是該I/O在鏈表中ev_active_next:libevent將所有的激活放入到鏈表activelist中,然后遍歷activelist執(zhí)行調(diào)度,ev_active_next就指明了eventactivelist中的位置;2)min_heap_idx和ev_timeout,如果是timeout,它們是event在小根堆中的索引和超時(shí)值,libevent使用小根堆來(lái)管理定件,這將在后面定件處理時(shí)專(zhuān)門(mén)講解3)ev_base該所屬的反應(yīng)堆實(shí)例,這是一個(gè)event_base結(jié)構(gòu)體,下一節(jié)將會(huì)詳細(xì)講解;4)ev_fd,對(duì)于I/O,是綁定的文件描述符;對(duì)于signal,是綁定的信號(hào);5)ev_callback,event的回調(diào)函數(shù),被ev_base調(diào)用,執(zhí)行處理程序,這是一個(gè)函數(shù)指void(*ev_callback)(intfd,shortevents,void其中參數(shù)fd對(duì)應(yīng)于ev_fd;events對(duì)應(yīng)于ev_events;arg對(duì)應(yīng)于ev_arg;6)ev_arg:void*,表明可以是任意類(lèi)型的數(shù)據(jù),在設(shè)置event時(shí)指定;7)eb_flags:libevent用于標(biāo)記event信息的字段,表明其當(dāng)前的狀態(tài),可能的值有:#define 0x01//event在time堆中#defineEVLIST_INSERTED0x02//event在 鏈表#define 0x04#defineEVLIST_ACTIVE 0x08//event在激活鏈表中#defineEVLIST_INTERNAL0x10// #defineEVLIST_INIT 0x80//event已被初始化9)ev_pncalls:指針,通常指向ev_ncalls或者為NULL;10)libeventevent處理;并根據(jù)就緒的句柄和類(lèi)型填充cb_callback函數(shù)的參數(shù)。3設(shè)置的接口函voidevent_set(structevent*ev,intfd,shortevents,void(*callback)(int,short,void*),voidevent_set(structevent*ev,intfd,shortevents,void(*callback)(int,short,void*),void intevent_base_set(structevent_base*base,structevent設(shè)置eventev將要到的libevent有一個(gè)全局event_base指針current_base,默認(rèn)情況下置不同的event_base;intevent_priority_set(structevent*ev,int小六初見(jiàn)處理框刪除的具體流程,可結(jié)合前一節(jié)libevent對(duì)event的管理。1處理框架-structevent_basestructevent_base conststructeventop void int /*countsnumberoftotalevents intevent_count_active;/*countsnumberofactiveevents int /*Settoterminateloop/*Settoterminateloopinty/*Settoterminateloopint /*activeeventmanagement structevent_list int /*signalhandlinginfo structevsignal_info structevent_list structtimeval structmin_heap structtimevalevsel和evbase這兩個(gè)字段的設(shè)置可能會(huì)讓人有些迷惑,這里你可以把evsel和evbase看作是類(lèi)和靜態(tài)函數(shù)的關(guān)系,比如添加時(shí)的調(diào)用行為:evsel->add(evbase,ev),evbase;這相當(dāng)class::add(instance,ev),instanceclass的一個(gè)對(duì)象實(shí)例。evsel指向了全局變量staticconststructeventop*eventops[]中的一個(gè);evbase實(shí)際上是一個(gè)eventop實(shí)例對(duì)象,structeventopconstcharvoid*(*init)(structevent_base*); int int(*add)(void*,structevent*);int(*del)(void*,structevent*);int(*dispatch)(structevent_base*,void*,structtimeval*); void(*dealloc)(structevent_base*,void*); /*setifweneedtoreinitializetheeventbase intepoll,libevent5eventop55epollI/Odemultiplex機(jī)制了,這個(gè)看作是數(shù)組,其中的元素activequeues[priority]是一個(gè)鏈表,鏈表的每個(gè)節(jié)點(diǎn)指向一個(gè)優(yōu)先級(jí)為priority的就緒event。timeheap是管理定件的小根堆,將在后面定件處理時(shí)專(zhuān)門(mén)講解;6)event_tv和tv_cache是libevent用于時(shí)間管理的變量,將在后面講到;創(chuàng)建和初始化創(chuàng)建一個(gè)event_base對(duì)象也既是創(chuàng)建了一個(gè)新的libevent實(shí)例,程序需要通過(guò)調(diào)用event_init()(event_base_new函數(shù)執(zhí)行具體操作)函數(shù)來(lái)創(chuàng)建,該函數(shù)同時(shí)還對(duì)新生成的libevent實(shí)例進(jìn)行了初始化。該函數(shù)event_base實(shí)例申請(qǐng)空間,然后初timermini-heap,選擇并初始化合適的系統(tǒng)I/O的demultiplexer機(jī)制,初始化各鏈表;。intevent_add(structevent*ev,conststructtimeval*timeout);intevent_del(structevent*ev);intevent_base_loop(structevent_base*base,intloops);voidevent_active(structevent*event,intres,shortevents);voidevent_process_active(structevent_base*base);本節(jié)將按介紹和刪除的代碼流程,libevent的循環(huán)框架將在下一節(jié)再具體1)intevent_add(structevent*ev,conststructtimeval函數(shù)將ev到ev->ev_base上,類(lèi)型由ev->ev_events指明,如果成功,ev將入到已鏈表中;如果tv不是NULL,則會(huì)同時(shí)定件,將ev添加到timerintevent_add(structevent*ev,conststructtimeval{structevent_base*base=ev->ev_base;// 到的conststructeventop*evsel=base-void*evbasebase->evbase;base使用的系統(tǒng)I/O//新的 ,調(diào)用timerheap接口在堆上預(yù)留一個(gè)位//向系統(tǒng)I/O機(jī) // if(tv!=NULL&&!(ev->ev_flags&EVLIST_TIMEOUT)) if(min_heap_reserve(&base- 1+min_heap_size(&base->timeheap))==- return(-1);/*ENOMEM==errno//如 ev不在 或者激活鏈表中,則調(diào)用if((ev->ev_events&(EV_READ|EV_WRITE|EV_SIGNAL)) !(ev->ev_flags&(EVLIST_INSERTED|EVLIST_ACTIVE))) res=evsel->add(evbase, if(res!=-1)// event_queue_insert(base,ev,//準(zhǔn)備添加 if(res!=-1&&tv!=NULL){structtimevalnow; EVLIST_TIMEOUT表明event if(ev->ev_flags& event_queue_remove(base,ev,evutil_timeraddevutil_timeradd(&now,tv,&ev-event_queue_insert(base,ev,if((ev->ev_flags&EVLIST_ACTIVE)&&(ev->ev_res&EV_TIMEOUT)){//將ev_callback調(diào)用次數(shù)設(shè)置為if(ev->ev_ncalls&&ev->ev_pncalls)*ev->ev_pncalls=}event_queue_remove(base,ev,}gettime(base, return} voidevent_queue_insert(structevent_base*base,structevent*ev,intqueue){evif(ev->ev_flags&queue) if(queue& //ev->ev_flags|=queue;queueswitch(queue)caseEVLIST_INSERTED://I/O或 ,加入 鏈 TAILQ_INSERT_TAIL(&base->eventqueue,ev, caseEVLIST_ACTIVE://就 base- TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],ev, caseEVLIST_TIMEOUT:// 件,加入 min_heap_push(&base->timeheap, }2)刪除函數(shù)原型為:intevent_del(structeventintevent_del(structevent{structevent_baseconststructeventopvoid//ev_base為NULL,表明ev沒(méi)有 if(ev->ev_base== return(-//取得 base=ev-evsel=base-evbase=base-ev_callbackif(ev->ev_ncalls&&ev->ev_pncalls) *ev->ev_pncalls=if(ev->ev_flags& event_queue_remove(base,ev,if(ev->ev_flags& event_queue_remove(base,ev,if(ev->ev_flags&EVLIST_INSERTED) event_queue_remove(base,ev, //EVLIST_INSERTED表明是I/O或者 I/Odemultiplexer return(evsel->del(evbase,return}小裝event_op結(jié)構(gòu),并結(jié)合源代碼分析了的和刪除處理,下面將會(huì)接著分析管理框架中的主循環(huán)部分。七主循階段性的勝利Libevent將I/O、定時(shí)器和信號(hào)處理很好的結(jié)合到了一起,本節(jié)也會(huì)介在看完本節(jié)的內(nèi)容后,讀者應(yīng)該會(huì)對(duì)Libevent的基本框架:管理和主循環(huán)有比較2處理主循圖所示,event_base_loop所作的就是持續(xù)執(zhí)行下面的循環(huán)。intevent_base_loop(structevent_baseintevent_base_loop(structevent_base*base,int{conststructeventop*evsel=base-structstructtimevalstructtimevalvoid*evbase=base-intres, base->tv_cache.tv_sec= evsignal_base是全局變量,在處理signal時(shí),用于指名signal所屬的 if(base-done=done=while(!done) event_base_loopbreak()設(shè)置event_break if(base->event_gotterm) base->event_gotterm= if(base->event_break) base->event_break= MONOTONIC時(shí)間,用戶可能會(huì)向 timeout_correct函數(shù)里,比較lastwaittime和當(dāng)前時(shí)間,如果當(dāng)前時(shí)間<lastwaittime //表明時(shí)間有問(wèn)題,這是需要更新timer_heap中所有定 timeout_correct(base, //根據(jù)timer //根據(jù)timerheap tv_p= if(!base->event_count_active&&!(flags&EVLOOP_NONBLOCK)) timeout_next(base, }else I/Odemultiplexer //下面會(huì)提到,在libevent中,低優(yōu)先級(jí)的就緒 if(!event_haveevents(base)) event_debug(("%s:noeventsregistered.",func return lastwaittime,并清空timecachegettime(base,&base->event_tv); base->tv_cache.tv_sec= I/Odemultiplexer等待就緒I/Oevents, res=evsel->dispatch(base,evbase, if(res==- return(- timecache gettime(base,&base- heap中的timerevents,將就緒的timerevent從heap上刪除, //該函數(shù)會(huì)尋找最高優(yōu)先級(jí)(priority值越小優(yōu)先級(jí)越高)的激活 //然后處理鏈表中的所有就 //因此低優(yōu)先級(jí)的就 if(base->event_count_active) if(!base->event_count_active&&(flags& done= }elseif(flags& done=base->tv_cache.tv_sec=I/O和Timer的統(tǒng)Libevent將Timer和Signal都統(tǒng)一到了系統(tǒng)的I/O的demultiplex機(jī)制中了,相信首先將Timer融合到系統(tǒng)I/O多路復(fù)用機(jī)制中,還是相當(dāng)清晰的,因?yàn)橄到y(tǒng)的I/O機(jī)制像select()和epoll_wait()都允許程序制定一個(gè)最大等待時(shí)間(也稱(chēng)為最大超時(shí)時(shí)間)timeout,即使沒(méi)有I/O發(fā)生,它們也保證能在timeout時(shí)間內(nèi)返回。那么根據(jù)所有Timer的最小超時(shí)時(shí)間來(lái)設(shè)置系統(tǒng)I/O的timeout時(shí)間;當(dāng)系統(tǒng)I/O返回時(shí),再激活所有就緒的Timer就可以了,這樣就能將Timer完美的融合到系統(tǒng)的I/O機(jī)制中了。這是ReactorProactor模式(主動(dòng)器模式WindowsIOCP)中Timer的經(jīng)典方法了,ACE采用的也是這種方法,大家可以參考POSAvol2ReactorO(lgN),N為堆中元素的個(gè)數(shù),而獲取最小key值(小根堆)的復(fù)雜度為O(1);因此變成了管理Timer的絕佳人選(當(dāng)然是非唯一的,libevent就是采用的堆結(jié)構(gòu)。I/O和Signal的統(tǒng)Signal是異步的經(jīng)典事例,將Signal統(tǒng)一到系統(tǒng)的I/O多路復(fù)用中就不像Timer那么自然了,Signal的出現(xiàn)對(duì)于進(jìn)程來(lái)講是完全隨機(jī)的,進(jìn)程不能只是測(cè)試一個(gè)變Signalevent的callback函數(shù)處理信號(hào),而是設(shè)法通知系統(tǒng)的I/O機(jī)制,讓其返回,然后再統(tǒng)一和I/O以及Timer一起處理,不就可以了嘛。是的,這也是libevent中使用的方法。問(wèn)題的在于,當(dāng)Signal發(fā)生時(shí),如何通知系統(tǒng)的I/O多路復(fù)用機(jī)制,這里先買(mǎi)個(gè)小小介紹了libevent的主循環(huán),描述了libevent是如何處理就緒的I/O、定時(shí)器和信號(hào),以及如何將它們無(wú)縫的融合到一起。成信號(hào)處現(xiàn)在我們已經(jīng)了解了libevent的基本框架:管理框架和主循環(huán)。上節(jié)提到了libevent中I/O和Signal以及Timer的集成,這一節(jié)將分析如何將Signal集成到事集成策略——使用socket通過(guò)socketpair完成的,下面就來(lái)詳細(xì)分析一下。Socketpairsocketsocketsocketsocket。工作集成到主循環(huán)——通知Socketpair創(chuàng)建好了,可是libevent的主循環(huán)還是不知道Signal是否發(fā)生了啊,看來(lái)我們還差了最后一步,那就是:為socketpair的讀socketlibeventevent_base實(shí)例上一個(gè)persist的讀。前面提到過(guò),Libevent會(huì)在主循環(huán)中檢查標(biāo)記,來(lái)確定是否有觸發(fā)的signal,如果標(biāo)記被設(shè)置就處理這些signal,這段代碼在各個(gè)具體的I/O機(jī)制中,以Epoll為例,在 if(res==-1) if(errno!=EINTR) evsignal_process(base); evsignal_process(base); return }elseif(base->sig.evsignal_caught){evsignal_process(base); 注1:libevent中,初始化階段并不讀socket的讀,而是在信號(hào)階段才會(huì)測(cè)試并注2:libevent中,檢查I/O是在各系統(tǒng)I/O機(jī)制的dispatch()函數(shù)中完成的,該dispatch()函數(shù)在volatilesig_atomic_tvolatilesig_atomic_tintintstructeventstructevsignal_info structevent_list #ifdefHAVE_SIGACTION structsigaction**sh_old; ev_sighandler_t intev_signal_added,記錄ev_signal是否已經(jīng)了evsignal_caughtvolatile類(lèi)型,因?yàn)樗鼤?huì)在另外的線程中被evsigvents[NSIG],數(shù)組,evsigevents[signo]表示到信號(hào)signo的鏈表;6)sh_old記錄了原來(lái)的signal處理函數(shù)指針,當(dāng)信號(hào)signo的event被清空時(shí),需要重是等到有信號(hào)時(shí)才檢查并,并將所有標(biāo)記置零,初始化信號(hào)的鏈表指針5、注銷(xiāo)signalsignal是通過(guò)evsignal_add(structevent*ev)函數(shù)完成的,libevent對(duì)所有的信號(hào)同一個(gè)處理函數(shù)evsignal_handler(),該函數(shù)將在下一段介紹,過(guò)程如下:取得ev要到的信號(hào)如果ev_signal還沒(méi)喲,就ev_signal將ev添加到signo的event鏈表中staticvoidstaticvoidevsignal_handler(int{intsave_errnoerrno;func,event_warn("%s:receivedsignal%d,buthavenobaseif(evsignal_base==NULL) sig的觸發(fā)次數(shù),并設(shè)置eventevsignal_base-evsignal_base->sig.evsignal_caught=1;#ifndefHAVE_SIGACTIONsignal(sig,evsignal_handler);//重 send(evsignal_base->sig.ev_signal_pair[0],"a",1,errnosave_errno;}小成定時(shí)現(xiàn)在再來(lái)詳細(xì)分析libevent中I/O和Timer的集成,與Signal相比,Timer事集成到主循為最大超時(shí)時(shí)間)timeout,即使沒(méi)有I/O發(fā)生,它們也保證能在timeout時(shí)間內(nèi)返回。那么根據(jù)所有Timer的最小超時(shí)時(shí)間來(lái)設(shè)置系統(tǒng)I/O的timeout時(shí)間;當(dāng)系統(tǒng)I/O的I/O機(jī)制中了。if(!base->event_count_active&&!(flags&EVLOOP_NONBLOCK))//根據(jù)//根據(jù) timeout_next(base, }else // ////調(diào)用select()orepoll_wait()等待就緒 res=evsel->dispatch(base,evbase, // {structtimevalstructeventstructtimeval*tv= if((ev=min_heap_top(&base->timeheap))==NULL) *tv_p=returnreturnif(evutil_timercmp(&ev->ev_timeout,&now,<=))gettime(base,}return return evutil_timersub(&ev->ev_timeout,&now,Libevent使用堆來(lái)管理Timer,其key值就是的超時(shí)時(shí)間,源代碼位于文O(lgN),N為堆中元素的個(gè)數(shù),而獲取最小key值(小根堆)的復(fù)雜度為O(1)。堆是一個(gè)完全Libevent實(shí)現(xiàn)的堆還是比較輕巧的,雖然我不喜歡這種編碼方式(搞一些復(fù)雜的表達(dá)Heap[size++]Heap[size++]new;//先放到數(shù)組末尾,元素個(gè)數(shù)//_child=size;while(_child>0循環(huán){_parent(_child-1)/2;//計(jì)算parentif(Heap[_parent].keyHeap[_child].key)break;//調(diào)整結(jié)束,跳出循環(huán)swap(_parent,_child//parent}libeventheap代碼對(duì)這一過(guò)程做了優(yōu)化,在插入新元素時(shí),只是為新元素預(yù)留了一個(gè)位置hole(初始時(shí)hole位于數(shù)組尾部),但并不立刻將新元素插入到hole上,而是不斷向holehole就是新元素的所在位置時(shí),才會(huì)真正hole上,因此在調(diào)整過(guò)程中就比上面的代碼少了一次賦值的操作,代碼while(_hole>0//{_parent_hole-1)/2;parentif(Heap[_parent].key<new.key)break;_hole_parent;//將_hole調(diào)整到}//size++;//元素個(gè)數(shù)數(shù)是min_heap_shift_down_()。3,5,8,7,122,使用第一中典型的代碼邏輯,小十支持I/O多路復(fù)用提到過(guò),它的成員是一系列的函數(shù)指針,定義在event-internal.h文件中:intint(*add)(void*,structevent*);int(*del)(void*,structevent*);void*(*init)(structevent_base*);constcharstructeventopint(*dispatch)(structevent_base*,void*,structint(*dispatch)(structevent_base*,void*,structtimeval*); /*setifweneedtoreinitializetheeventbase int/*Inorderofpreferencestaticconststructeventop*eventops[]{#ifdef&evportops,#ifdef&kqops,#ifdef#ifdef#ifdef#ifdef#ifdef #ifdefWIN32 在函數(shù)event_base_new()中: base->evbase= for(i=0;eventops[i]&&!base->evbase;i++) base->evsel= base->evbase=base->evsel- 可以看出,libeventI/Odemultiplex機(jī)制,而不支持在運(yùn)行階段conststructeventopepollops=1/*needreinitstaticvoid*epoll_init(structevent_basestaticstaticintepoll_add(void*,structevent*);staticintepoll_del(void*,structeventstaticintepoll_dispatch(structevent_base*,void*,structtimevalstaticvoid (structevent_base*,void那么如果選擇的是epoll,那么調(diào)用結(jié)構(gòu)體eventop的init和dispatch函數(shù)指針時(shí),實(shí)際調(diào)用的函數(shù)就是epoll的初始化函數(shù)epoll_init()和分發(fā)函數(shù)epoll_dispatch()了;.aspx.aspx同樣的epollopsepoll的各種函數(shù)都直接定義在epoll.c源文件中,對(duì)外都是libeventepoll的使用也是通過(guò)eventop來(lái)完成的,達(dá)到了信息隱藏的目的。小間管staticvoid{staticvoid{#ifdefined(HAVE_CLOCK_GETTIME)&&struct if(clock_gettime(CLOCK_MONOTONIC,&ts)== use_monotonic1;monotonic時(shí)間}Monotonic時(shí)間指示的是系boot后到現(xiàn)在所經(jīng)過(guò)的時(shí)間,如果Monotonic時(shí)間就將全局變量use_monotonic設(shè)置為1,設(shè)置use_monotonic到底有什么用,這個(gè)在后面說(shuō)結(jié)構(gòu)event_basetv_cache,用來(lái)記錄時(shí)間緩存。這個(gè)還要從函gettime()說(shuō)起,先

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論