📄 htevtlst.c
字号:
/* HTEvtLst.c** EVENT MANAGER**** (c) COPYRIGHT MIT 1995.** Please first read the full copyright statement in the file COPYRIGH.** @(#) $Id: HTEvtLst.c,v 2.45 2000/08/02 10:38:07 kahan Exp $**** Updated HTEvent module ** This new module combines the functions of the old HTEvent module and ** the HTThread module. We retain the old HTThread module, but it** consists of calls to the HTEvent interfaces**** Authors:** HFN Henrik Frystyk <frystyk@w3.org>** CLB Charlie Brooks <cbrooks@osf.org>** Bugs***//* WSAAsyncSelect and windows app stuff need the following definitions: * WWW_WIN_ASYNC - enable WSAAsyncSelect instead of select * _WIN23 - win32 libararies - may be window or console app * _WINSOCKAPI_ - using WINSOCK.DLL - not necessarily the async routines. * _CONSOLE - the console app for NT * * first pass: EGP - 10/26/95 *//* Implementation dependent include files */#include "wwwsys.h"#include "WWWUtil.h"#include "WWWCore.h"#include "HTReqMan.h"#include "HTTimer.h"#include "HTEvent.h"#include "HTEvtLst.h" /* Implemented here *//* Type definitions and global variables etc. local to this module */#define MILLI_PER_SECOND 1000#define HASH(s) ((s) % HT_M_HASH_SIZE) #define EVENTS_TO_EXECUTE 10 /* how many to execute in one select loop */#define HT_FS_BYTES(a) ((((a)/16)+1) * 4)typedef struct { SOCKET s ; /* our socket */ HTEvent * events[HTEvent_TYPES]; /* event parameters for read, write, oob */ HTTimer * timeouts[HTEvent_TYPES];} SockEvents;typedef struct { HTEvent * event; SOCKET s; HTEventType type; HTPriority skipped;} EventOrder;typedef enum { SockEvents_mayCreate, SockEvents_find} SockEvents_action;PRIVATE HTList * HashTable [HT_M_HASH_SIZE]; PRIVATE HTList * EventOrderList = NULL;PRIVATE int HTEndLoop = 0; /* If !0 then exit event loop */PRIVATE BOOL HTInLoop = NO;#ifdef WWW_WIN_ASYNC#define TIMEOUT 1 /* WM_TIMER id */PRIVATE HWND HTSocketWin;PRIVATE ATOM HTclass;PRIVATE HINSTANCE HTinstance;PRIVATE unsigned long HTwinMsg;#else /* WWW_WIN_ASYNC */PRIVATE fd_set FdArray[HTEvent_TYPES];PRIVATE SOCKET MaxSock = 0; /* max socket value in use */#endif /* !WWW_WIN_ASYNC *//* ------------------------------------------------------------------------- *//* DEBUG FUNCTIONS *//* ------------------------------------------------------------------------- */#ifdef HTDEBUGPRIVATE void Event_trace (HTEvent * event){ if (event) { HTTRACE(ALL_TRACE, "%8p: %3d %6d %8p %8p %8p" _ event _ event->priority _ event->millis _ event->cbf _ event->param _ event->request); }}PRIVATE void Event_traceHead (void){ HTTRACE(ALL_TRACE, " event: pri millis callback param request ");}PRIVATE void Timer_trace (HTTimer * timer){ if (timer) { HTTRACE(ALL_TRACE, "%8p: %6d %ld %c %8p" _ timer _ HTTimer_expiresAbsolute(timer) _ HTTimer_expiresRelative(timer) _ HTTimer_isRelative(timer) ? 'R' : 'A' _ HTTimer_callback(timer)); }}PRIVATE void Timer_traceHead (void){ HTTRACE(ALL_TRACE, " timer: millis expires ? param callback ");}/*** A simple debug function that dumps all the socket arrays** as trace messages*/PRIVATE void EventList_dump (void){ int v = 0; HTList* cur; SockEvents * pres; HTTRACE(ALL_TRACE, "Event....... Dumping socket events\n"); HTTRACE(ALL_TRACE, "soc "); Event_traceHead(); HTTRACE(ALL_TRACE, " "); Timer_traceHead(); HTTRACE(ALL_TRACE, "\n"); for (v = 0; v < HT_M_HASH_SIZE; v++) { cur = HashTable[v]; while ((pres = (SockEvents *) HTList_nextObject(cur))) { int i; HTTRACE(ALL_TRACE, "%3d \n" _ pres->s); for (i = 0; i < HTEvent_TYPES; i++) if (pres->events[i]) { static char * names[HTEvent_TYPES] = {"read", "writ", "xcpt"}; HTTRACE(ALL_TRACE, "%s " _ names[i]); Event_trace(pres->events[i]); HTTRACE(ALL_TRACE, " "); Timer_trace(pres->timeouts[i]); HTTRACE(ALL_TRACE, " "); } HTTRACE(ALL_TRACE, "\n"); } }}PRIVATE void fd_dump (SOCKET maxfs, fd_set * rset, fd_set * wset, fd_set * oset, struct timeval * wt){ SOCKET cnt; /* Check read set */ HTTRACE(THD_TRACE, "............ READ :"); for (cnt=0; cnt<=maxfs; cnt++) if (FD_ISSET(cnt, rset)) HTTRACE(THD_TRACE, " %d" _ cnt); HTTRACE(THD_TRACE, "\n"); /* Check write set */ HTTRACE(THD_TRACE, "............ WRITE:"); for (cnt=0; cnt<=maxfs; cnt++) if (FD_ISSET(cnt, wset)) HTTRACE(THD_TRACE, " %d" _ cnt); HTTRACE(THD_TRACE, "\n"); /* Check oob set */ HTTRACE(THD_TRACE, "............ OOB :"); for (cnt=0; cnt<=maxfs; cnt++) if (FD_ISSET(cnt, oset)) HTTRACE(THD_TRACE, " %d" _ cnt); HTTRACE(THD_TRACE, "\n"); if (wt) HTTRACE(THD_TRACE, "............ Timeout is %ld s, %ld microsecs\n" _ wt->tv_sec _ wt->tv_usec);}#endif /* HTDEBUG *//* ------------------------------------------------------------------------- *//* EVENT TIMING FUNCTIONS *//* ------------------------------------------------------------------------- */#ifdef WWW_WIN_ASYNCPRIVATE BOOL Timer_setWindowsTimer (HTTimer * timer){ UINT id; HWND hwnd = HTEventList_getWinHandle(&id); BOOL status = (SetTimer(hwnd, (UINT)timer, (UINT)HTTimer_getTime(timer), NULL) == 0) ? NO : YES; return status;}PRIVATE BOOL Timer_deleteWindowsTimer (HTTimer * timer){ UINT id; HWND hwnd = HTEventList_getWinHandle(&id); BOOL status = (KillTimer(hwnd, (UINT)timer) == 0) ? NO : YES; return status;}#endif /* WWW_WIN_ASYNC *//*** Event timeout handler** If an event didn't occur before the timeout then call it explicitly** indicating that it timed out.*/PRIVATE int EventListTimerHandler (HTTimer * timer, void * param, HTEventType type){ SockEvents * sockp = (SockEvents *) param; HTEvent * event = NULL; /* Check for read timeout */ if (sockp->timeouts[HTEvent_INDEX(HTEvent_READ)] == timer) { event = sockp->events[HTEvent_INDEX(HTEvent_READ)]; HTTRACE(THD_TRACE, "Event....... READ timed out on %d.\n" _ sockp->s); return (*event->cbf) (sockp->s, event->param, HTEvent_TIMEOUT); } /* Check for write timeout */ if (sockp->timeouts[HTEvent_INDEX(HTEvent_WRITE)] == timer) { event = sockp->events[HTEvent_INDEX(HTEvent_WRITE)]; HTTRACE(THD_TRACE, "Event....... WRITE timed out on %d.\n" _ sockp->s); return (*event->cbf) (sockp->s, event->param, HTEvent_TIMEOUT); } /* Check for out-of-band data timeout */ if (sockp->timeouts[HTEvent_INDEX(HTEvent_OOB)] == timer) { event = sockp->events[HTEvent_INDEX(HTEvent_OOB)]; HTTRACE(THD_TRACE, "Event....... OOB timed out on %d.\n" _ sockp->s); return (*event->cbf) (sockp->s, event->param, HTEvent_TIMEOUT); } HTTRACE(THD_TRACE, "Event....... No event for timer %p with context %p\n" _ timer _ param); return HT_ERROR;}PUBLIC void CheckSockEvent (HTTimer * timer, HTTimerCallback * cbf, void * param){ SockEvents * sockp = (SockEvents *)param; if (cbf == EventListTimerHandler && sockp->timeouts[0] != timer && sockp->timeouts[1] != timer && sockp->timeouts[2] != timer) { HTDEBUGBREAK("Bad timer %p\n" _ timer); }}/* ------------------------------------------------------------------------- *//* EVENT ORDERING STUFF *//* ------------------------------------------------------------------------- */PRIVATE SockEvents * SockEvents_get (SOCKET s, SockEvents_action action){ long v = HASH(s); HTList* cur; SockEvents * pres; /* if the socket doesn't exists, don't do anything */ if (s == INVSOC) return NULL; if (HashTable[v] == NULL) HashTable[v] = HTList_new(); cur = HashTable[v]; while ((pres = (SockEvents *) HTList_nextObject(cur))) if (pres->s == s) return pres; if (action == SockEvents_mayCreate) { if ((pres = (SockEvents *) HT_CALLOC(1, sizeof(SockEvents))) == NULL) HT_OUTOFMEM("HTEventList_register"); pres->s = s; HTList_addObject(HashTable[v], (void *)pres); return pres; } return NULL;}PRIVATE int EventOrder_add (SOCKET s, HTEventType type, ms_t now){ EventOrder * pres; HTList * cur = EventOrderList; HTList * insertAfter = cur; SockEvents * sockp = SockEvents_get(s, SockEvents_find); HTEvent * event; if (sockp == NULL || (event = sockp->events[HTEvent_INDEX(type)]) == NULL) { HTTRACE(THD_TRACE, "EventOrder.. no event found for socket %d, type %s.\n" _ s _ HTEvent_type2str(type)); return HT_ERROR; } /* Fixup the timeout */ if (sockp->timeouts[HTEvent_INDEX(type)]) HTTimer_refresh(sockp->timeouts[HTEvent_INDEX(type)], now); /* Look to see if it's already here from before */ while ((pres = (EventOrder *) HTList_nextObject(cur))) { if (pres->s == s && pres->event == event && pres->type == type) { pres->skipped++; return HT_OK; } if (pres->event->priority+pres->skipped > event->priority) insertAfter = cur; } /* Create a new element */ if ((pres = (EventOrder *) HT_CALLOC(1, sizeof(EventOrder))) == NULL) HT_OUTOFMEM("EventOrder_add"); pres->event = event; pres->s = s; pres->type = type; HTList_addObject(insertAfter, (void *)pres); return HT_OK;}PUBLIC int EventOrder_executeAndDelete (void) { HTList * cur = EventOrderList; EventOrder * pres; int i = 0; HTTRACE(THD_TRACE, "EventOrder.. execute ordered events\n"); if (cur == NULL) return NO; while ((pres=(EventOrder *) HTList_removeLastObject(cur)) && i<EVENTS_TO_EXECUTE) { HTEvent * event = pres->event; int ret; HTTRACE(THD_TRACE, "EventList... calling socket %d, request %p handler %p type %s\n" _ pres->s _ (void *) event->request _ (void *) event->cbf _ HTEvent_type2str(pres->type)); ret = (*pres->event->cbf)(pres->s, pres->event->param, pres->type); HT_FREE(pres); if (ret != HT_OK) return ret; i++; } return HT_OK;}PRIVATE BOOL EventOrder_clearAll (void){ HTList * cur = EventOrderList; EventOrder * pres; HTTRACE(THD_TRACE, "EventOrder.. Clearing all ordered events\n"); if (cur) { while ((pres = (EventOrder *) HTList_nextObject(cur))) HT_FREE(pres); return YES; } return NO;}PUBLIC BOOL EventOrder_deleteAll (void) { EventOrder_clearAll(); HTList_delete(EventOrderList); EventOrderList = NULL; return YES;}/* ------------------------------------------------------------------------- *//* EVENT REGISTRATION *//* ------------------------------------------------------------------------- *//*** ResetMaxSock - reset the value of the maximum socket in use */#ifndef WWW_WIN_ASYNCPRIVATE void __ResetMaxSock (void){ SOCKET cnt; SOCKET t_max = 0; SOCKET old_max = MaxSock; for (cnt = 0 ; cnt <= MaxSock; cnt++) { if (FD_ISSET(cnt, (FdArray + HTEvent_INDEX(HTEvent_READ))) || FD_ISSET(cnt, (FdArray + HTEvent_INDEX(HTEvent_WRITE))) || FD_ISSET(cnt, (FdArray + HTEvent_INDEX(HTEvent_OOB)))) if (cnt > t_max) t_max = cnt; } MaxSock = t_max+1; HTTRACE(THD_TRACE, "Event....... Reset MaxSock from %u to %u\n" _ old_max _ MaxSock); return;} #endif /* !WWW_WIN_ASYNC */PRIVATE int EventList_remaining (SockEvents * pres){ int ret = 0; int i; for (i = 0; i < HTEvent_TYPES; i++) if (pres->events[i] != NULL) ret |= 1<<i; return ret;}/*** For a given socket, reqister a request structure, a set of operations, ** a HTEventCallback function, and a priority. For this implementation, ** we allow only a single HTEventCallback function for all operations.** and the priority field is ignored.*/PUBLIC int HTEventList_register (SOCKET s, HTEventType type, HTEvent * event){ int newset = 0; SockEvents * sockp; HTTRACE(THD_TRACE, "Event....... Register socket %d, request %p handler %p type %s at priority %d\n" _ s _ (void *) event->request _ (void *) event->cbf _ HTEvent_type2str(type) _ (unsigned) event->priority); if (s==INVSOC || HTEvent_INDEX(type) >= HTEvent_TYPES) return 0; /* ** Insert socket into appropriate file descriptor set. We also make sure ** that it is registered in the global set. */ HTTRACE(THD_TRACE, "Event....... Registering socket for %s\n" _ HTEvent_type2str(type)); sockp = SockEvents_get(s, SockEvents_mayCreate); sockp->s = s; sockp->events[HTEvent_INDEX(type)] = event; newset = EventList_remaining(sockp);#ifdef WWW_WIN_ASYNC if (WSAAsyncSelect(s, HTSocketWin, HTwinMsg, HTEvent_BITS(newset)) < 0) { HTTRACE(THD_TRACE, "Event....... WSAAsyncSelect returned `%s'!" _ HTErrnoString(socerrno)); return HT_ERROR; }#else /* WWW_WIN_ASYNC */ FD_SET(s, FdArray+HTEvent_INDEX(type)); HTTRACEDATA((char *) FdArray+HTEvent_INDEX(type), 8, "HTEventList_register: (s:%d)" _ s); if (s > MaxSock) { MaxSock = s ; HTTRACE(THD_TRACE, "Event....... New value for MaxSock is %d\n" _ MaxSock); }#endif /* !WWW_WIN_ASYNC */ /* ** If the timeout has been set (relative in millis) then we register ** a new timeout for this event unless we already have a timer. */ if (event->millis >= 0) { sockp->timeouts[HTEvent_INDEX(type)] = HTTimer_new(sockp->timeouts[HTEvent_INDEX(type)], EventListTimerHandler, sockp, event->millis, YES, YES); } return HT_OK;}/*** Remove the registered information for the specified socket for the actions ** specified in ops. if no actions remain after the unregister, the registered** info is deleted, and, if the socket has been registered for notification, ** the HTEventCallback will be invoked.*/PUBLIC int HTEventList_unregister (SOCKET s, HTEventType type) { long v = HASH(s); HTList * cur = HashTable[v]; HTList * last = cur; SockEvents * pres; int ret = HT_ERROR; /* if the socket doesn't exists, don't do anything */ if (s == INVSOC) return HT_OK; while (cur && (pres = (SockEvents *) HTList_nextObject(cur))) { if (pres->s == s) { int remaining = 0; /* ** Unregister the event from this action */ pres->events[HTEvent_INDEX(type)] = NULL; remaining = EventList_remaining(pres); /* ** Check to see of there was a timeout connected with the event. ** If so then delete the timeout as well. */ { HTTimer * timer = pres->timeouts[HTEvent_INDEX(type)]; if (timer) HTTimer_delete(timer); pres->timeouts[HTEvent_INDEX(type)] = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -