Annotation of libwww/Library/src/HTEvtLst.c, revision 1.1.2.8
1.1.2.1 eric 1: /* HTEvntrg.c
2: ** EVENT MANAGER
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
1.1.2.8 ! frystyk 6: ** @(#) $Id: HTEvtLst.c,v 1.1.2.7 1996/11/22 22:42:26 eric Exp $
1.1.2.1 eric 7: **
8: ** Updated HTEvent module
9: ** This new module combines the functions of the old HTEvent module and
10: ** the HTThread module. We retain the old HTThread module, but it
11: ** consists of calls to the HTEvent interfaces
12: **
13: ** Authors:
14: ** HFN Henrik Frystyk <frystyk@w3.org>
15: ** CLB Charlie Brooks <cbrooks@osf.org>
16: ** Bugs
17: **
18: */
19:
20: /* WSAAsyncSelect and windows app stuff need the following definitions:
21: * WWW_WIN_ASYNC - enable WSAAsyncSelect instead of select
22: * _WIN23 - win32 libararies - may be window or console app
23: * _WINSOCKAPI_ - using WINSOCK.DLL - not necessarily the async routines.
24: * _CONSOLE - the console app for NT
25: *
26: * first pass: EGP - 10/26/95
27: */
28:
29: /* Implementation dependent include files */
30: #include "sysdep.h"
31: #include "WWWUtil.h"
32: #include "WWWCore.h"
33: #include "HTReqMan.h"
1.1.2.6 eric 34: #include "HTTimer.h"
1.1.2.1 eric 35: #include "HTEvtLst.h" /* Implemented here */
36:
37: /* Type definitions and global variables etc. local to this module */
1.1.2.5 frystyk 38: #define PRIME_TABLE_SIZE 67
39: #define MILLI_PER_SECOND 1000
40: #define HASH(s) ((s) % PRIME_TABLE_SIZE)
1.1.2.1 eric 41:
42: typedef struct rq_t RQ;
1.1.2.5 frystyk 43: struct rq_t {
44: RQ * next ;
45: SOCKET s ; /* our socket */
46: BOOL unregister; /* notify app when completely unregistered */
47: HTEvent * events[3]; /* event parameters for read, write, oob */
48: HTTimer * timeouts[3]; /* timeout for each of the events */
1.1.2.1 eric 49: };
50:
1.1.2.5 frystyk 51: typedef enum _RQ_action {
52: RQ_mayCreate,
53: RQ_find
54: } RQ_action;
1.1.2.1 eric 55:
56: PRIVATE RQ * table[PRIME_TABLE_SIZE];
1.1.2.5 frystyk 57: PRIVATE SOCKET max_sock = 0 ; /* max socket value in use */
1.1.2.1 eric 58:
1.1.2.5 frystyk 59: PRIVATE fd_set FdArray[HTEvent_TYPES];
60: PRIVATE fd_set all_fds ; /* any descriptor at all */
1.1.2.1 eric 61:
1.1.2.5 frystyk 62: PRIVATE int HTEndLoop = 0; /* If !0 then exit event loop */
63:
64: /* ------------------------------------------------------------------------- */
1.1.2.1 eric 65:
66: PRIVATE RQ * RQ_get(SOCKET s, RQ_action action)
67: {
68: RQ * rqp;
69: RQ * last = NULL;
70: long v = HASH(s);
71: for (rqp = table[v]; rqp; rqp = rqp->next) {
72: if (rqp->s == s) {
73: return rqp;
74: }
75: last = rqp; /* to set next pointer when creating new */
76: }
77: if (action == RQ_mayCreate) {
78: if ((rqp = (RQ *) HT_CALLOC(1, sizeof(RQ))) == NULL)
79: HT_OUTOFMEM("HTEventList_register");
80: if (last) last->next = rqp;
81: else table[v] = rqp;
82: rqp->s = s;
83: return rqp;
84: }
85: return NULL;
86: }
87:
1.1.2.5 frystyk 88: /*
89: ** A simple debug function that dumps all the socket arrays
90: ** as trace messages
1.1.2.1 eric 91: */
1.1.2.5 frystyk 92: PRIVATE void __DumpFDSet( fd_set * fdp, const char * str)
1.1.2.1 eric 93: {
1.1.2.5 frystyk 94: SOCKET s ;
95: #ifdef _WINSOCKAPI_
96: unsigned ui ;
1.1.2.1 eric 97: #endif
1.1.2.5 frystyk 98: if (THD_TRACE) {
99: HTTrace("Event....... Dumping %s file descriptor set\n", str);
100: #ifdef _WINSOCKAPI_
101: for (ui = 0 ; ui < fdp->fd_count; ui++) {
102: s = all_fds.fd_array[ui] ;
103: #else
104: for (s = 0 ; s <= max_sock; s++) {
105: if (FD_ISSET(s, fdp))
106: #endif
107: {
108: HTTrace("%4d\n", s);
109: }
110: } /* for */
111: } /* if */
112: return ;
113: }
114:
115: /* ------------------------------------------------------------------------- */
116:
1.1.2.6 eric 117: PRIVATE int EventListTimerHandler (HTTimer * timer, void * param)
1.1.2.5 frystyk 118: {
1.1.2.6 eric 119: RQ * rqp = (RQ *)param;
120: HTEvent * event;
121: if (rqp->timeouts[HTEvent_INDEX(HTEvent_READ)] == timer) {
122: event = rqp->events[HTEvent_INDEX(HTEvent_READ)];
123: if (THD_TRACE) HTTrace("Event....... READ timed out on %d.\n", rqp->s);
124: return (*event->cbf) (rqp->s, event->param, HTEvent_TIMEOUT);
1.1.2.1 eric 125: }
1.1.2.6 eric 126: if (rqp->timeouts[HTEvent_INDEX(HTEvent_WRITE)] == timer) {
127: event = rqp->events[HTEvent_INDEX(HTEvent_WRITE)];
128: if (THD_TRACE) HTTrace("Event....... WRITE timed out on %d.\n", rqp->s);
129: return (*event->cbf) (rqp->s, event->param, HTEvent_TIMEOUT);
1.1.2.5 frystyk 130: }
1.1.2.6 eric 131: if (rqp->timeouts[HTEvent_INDEX(HTEvent_OOB)] == timer) {
132: event = rqp->events[HTEvent_INDEX(HTEvent_OOB)];
133: if (THD_TRACE) HTTrace("Event....... OOB timed out on %d.\n", rqp->s);
134: return (*event->cbf) (rqp->s, event->param, HTEvent_TIMEOUT);
1.1.2.5 frystyk 135: }
1.1.2.6 eric 136: HTTrace("Event....... can't find event for timer %p.\n", timer);
137: return HT_ERROR;
1.1.2.1 eric 138: }
139:
1.1.2.5 frystyk 140: /* ------------------------------------------------------------------------- */
141:
1.1.2.1 eric 142: /*
1.1.2.5 frystyk 143: ** For a given socket, reqister a request structure, a set of operations,
1.1.2.1 eric 144: ** a HTEventCallback function, and a priority. For this implementation,
145: ** we allow only a single HTEventCallback function for all operations.
146: ** and the priority field is ignored.
147: */
1.1.2.2 eric 148: PUBLIC int HTEventList_register (SOCKET s, HTEventType type, HTEvent * event)
1.1.2.1 eric 149: {
150: RQ * rqp;
151: if (THD_TRACE)
1.1.2.5 frystyk 152: HTTrace("Event....... Register socket %d, request %p handler %p type %x at priority %d\n",
153: s, (void *) event->request,
154: (void *) event->cbf, (unsigned) type,
155: (unsigned) event->priority);
1.1.2.6 eric 156: if (s==INVSOC || HTEvent_INDEX(type) > 2)
157: return 0;
158: #if 0
159: /*
160: ** Don't write down TIMEOUT events in the RQ list or the fd sets.
161: ** They just manifest in the HTTimer
162: */
163: if (type == HTEvent_TIMEOUT)
164: return HT_OK;
165: #endif /* 0 */
166:
1.1.2.5 frystyk 167: /*
168: ** Insert socket into appropriate file descriptor set. We also make sure
169: ** that it is registered in the global set.
170: */
171: if (THD_TRACE) HTTrace("Event....... Registering socket for %d\n", type);
1.1.2.6 eric 172: rqp = RQ_get(s, RQ_mayCreate);
173: rqp->s = s;
174: rqp->events[HTEvent_INDEX(type)] = event;
1.1.2.1 eric 175: FD_SET(s, FdArray+HTEvent_INDEX(type));
1.1.2.6 eric 176: FD_SET(s, &all_fds);
1.1.2.1 eric 177:
1.1.2.5 frystyk 178: /*
179: ** If the timeout has been set (relative in millis) then we register
180: ** a new timeout for this event
181: */
182: if (event->millis >= 0) {
1.1.2.6 eric 183: rqp->timeouts[HTEvent_INDEX(type)] = HTTimer_new(NULL, EventListTimerHandler, rqp, event->millis, YES);
1.1.2.5 frystyk 184: }
185:
186: if (s > max_sock) max_sock = s ;
1.1.2.1 eric 187: return HT_OK;
188: }
189:
190: /*
1.1.2.5 frystyk 191: ** Remove the registered information for the specified socket for the actions
1.1.2.1 eric 192: ** specified in ops. if no actions remain after the unregister, the registered
193: ** info is deleted, and, if the socket has been registered for notification,
194: ** the HTEventCallback will be invoked.
195: */
1.1.2.2 eric 196: PUBLIC int HTEventList_unregister(SOCKET s, HTEventType type)
1.1.2.1 eric 197: {
198: RQ * rqp;
199: RQ * last = NULL;
200: long v = HASH(s);
201: for (rqp = table[v]; rqp; rqp = rqp->next) {
202: if (rqp->s == s) {
1.1.2.5 frystyk 203:
204: /*
205: ** Unregister the event from this action
206: */
207: rqp->events[HTEvent_INDEX(type)] = NULL;
1.1.2.1 eric 208: FD_CLR(s, FdArray+HTEvent_INDEX(type));
1.1.2.5 frystyk 209:
210: /*
211: ** Check to see of there was a timeout connected with the event.
212: ** If so then delete the timeout as well.
213: */
214: {
215: HTTimer * timer = rqp->timeouts[HTEvent_INDEX(type)];
216: if (timer) HTTimer_delete(timer);
217: }
218:
219: /*
220: ** Check to see if we can delete the action completely. We do this
221: ** if there are no more events registered.
222: */
1.1.2.1 eric 223: if (rqp->events[HTEvent_INDEX(HTEvent_READ)] == NULL &&
224: rqp->events[HTEvent_INDEX(HTEvent_WRITE)] == NULL &&
225: rqp->events[HTEvent_INDEX(HTEvent_OOB)] == NULL) {
1.1.2.5 frystyk 226: if (THD_TRACE)
227: HTTrace("Event....... No more events registered for socket %d\n", s);
1.1.2.1 eric 228: if (last) last->next = rqp->next;
229: else table[v] = rqp->next;
230: HT_FREE(rqp);
231: FD_CLR(s, &all_fds);
232: }
233: if (THD_TRACE)
1.1.2.5 frystyk 234: HTTrace("Event....... Socket %d unregisterd for %x\n", s, type);
1.1.2.1 eric 235: return HT_OK;
236: }
237: last = rqp; /* to set next pointer when creating new */
238: }
1.1.2.5 frystyk 239: if (THD_TRACE) HTTrace("Event....... Couldn't find socket %d.\n", s);
1.1.2.1 eric 240: return HT_ERROR;
241: }
242:
243: /*
1.1.2.5 frystyk 244: ** Unregister all sockets
1.1.2.1 eric 245: ** N.B. we just remove them for our internal data structures: it is up to the
246: ** application to actually close the socket.
247: */
248: PUBLIC int HTEventList_unregisterAll( void )
249: {
250: int i;
251: register RQ * rqp, * next ;
1.1.2.5 frystyk 252: if (THD_TRACE) HTTrace("Unregister.. all sockets\n");
1.1.2.1 eric 253: for (i = 0 ; i < PRIME_TABLE_SIZE; i++) {
254: for (rqp = table[i]; rqp != 0; rqp = next) {
255: next = rqp->next;
256: HT_FREE(rqp);
257: }
258: table[i] = NULL;
259: }
260: max_sock = 0 ;
261: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_READ));
262: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_WRITE));
263: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_OOB));
264: FD_ZERO(&all_fds);
265: return 0;
266: }
267:
1.1.2.5 frystyk 268: /*
1.1.2.6 eric 269: ** Dispatch the event to the appropriate event handler.
270: ** If no event handler is found then just return.
271: */
272: PUBLIC int HTEventList_dispatch (SOCKET s, HTEventType type)
273: {
274: RQ * rqp = RQ_get(s, RQ_find);
275: if (rqp) {
276: HTEvent * event = rqp->events[HTEvent_INDEX(type)];
277:
278: /*
279: ** If we have found an event object for this event then see
280: ** is we should call it.
281: */
282: if (event && event->priority!=HT_PRIORITY_OFF)
283: return (*event->cbf) (s, event->param, type);
284: if (THD_TRACE) HTTrace("Dispatch.... Handler %p NOT called\n", rqp);
285: return HT_OK;
286: }
287: if (THD_TRACE) HTTrace("Dispatch.... Bad socket %d\n", s);
288: return NO;
289: }
290:
291: /*
1.1.2.5 frystyk 292: ** Stops the (select based) event loop. The function does not guarantee
293: ** that all requests have terminated. This is for the app to do
1.1.2.1 eric 294: */
295: PUBLIC void HTEventList_stopLoop (void)
296: {
297: HTEndLoop = 1;
298: }
299:
1.1.2.5 frystyk 300: /*
301: ** We wait for activity from one of our registered
1.1.2.1 eric 302: ** channels, and dispatch on that.
303: **
304: ** There are now two versions of the event loop. The first is if you want
305: ** to use async I/O on windows, and the other is if you want to use normal
306: ** Unix setup with sockets
307: */
1.1.2.5 frystyk 308: PUBLIC int HTEventList_loop (HTRequest * theRequest)
1.1.2.1 eric 309: {
310: fd_set treadset, twriteset, texceptset;
1.1.2.5 frystyk 311: struct timeval waittime, * wt;
1.1.2.1 eric 312: int active_sockets;
313: int maxfds;
1.1.2.6 eric 314: int timeout;
1.1.2.1 eric 315: SOCKET s;
316: int status = 0;
317: HTEndLoop = 0;
1.1.2.5 frystyk 318:
319: /* Don't leave this loop until we leave the application */
320: do {
1.1.2.1 eric 321: treadset = FdArray[HTEvent_INDEX(HTEvent_READ)];
322: twriteset = FdArray[HTEvent_INDEX(HTEvent_WRITE)];
323: texceptset = FdArray[HTEvent_INDEX(HTEvent_OOB)];
324: maxfds = max_sock;
325:
1.1.2.5 frystyk 326: if (THD_TRACE) HTTrace("Event Loop.. calling select: maxfds is %d\n", maxfds);
327:
328: /*
329: ** Timeval struct copy needed for linux, as it set the value to the
330: ** remaining timeout while exiting the select. (and perhaps for
331: ** other OS). Code borrowed from X server.
332: */
333: wt = NULL;
1.1.2.6 eric 334: if ((timeout = HTTimer_soonest())) {
335: waittime.tv_sec = timeout / MILLI_PER_SECOND;
336: waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
337: (1000000 / MILLI_PER_SECOND);
338: wt = &waittime;
1.1.2.5 frystyk 339: }
1.1.2.1 eric 340:
341: #ifdef __hpux
342: active_sockets = select(maxfds+1, (int *)&treadset, (int *)&twriteset,
1.1.2.5 frystyk 343: (int *)&texceptset, wt);
1.1.2.1 eric 344: #else
1.1.2.5 frystyk 345: active_sockets = select(maxfds+1, &treadset, &twriteset, &texceptset, wt);
1.1.2.1 eric 346: #endif
1.1.2.5 frystyk 347:
1.1.2.8 ! frystyk 348: HTWatch_logData("", 0, "HTEventList_loop: select returned %d", active_sockets);
1.1.2.7 eric 349: HTWatch_logData(&treadset, (active_sockets+7)/8, " treadset");
350: HTWatch_logData(&twriteset, (active_sockets+7)/8, " twriteset");
351: HTWatch_logData(&texceptset, (active_sockets+7)/8, " texceptset");
1.1.2.5 frystyk 352: if (THD_TRACE) HTTrace("Event Loop.. select returns %d\n", active_sockets);
1.1.2.1 eric 353:
354: if (active_sockets == -1) {
355: HTRequest_addSystemError( theRequest, ERR_FATAL, socerrno, NO, "select");
356: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_READ), "Read");
357: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_WRITE), "Write") ;
358: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_OOB), "Exceptions");
359: return HT_ERROR;
360: }
361:
1.1.2.5 frystyk 362: /*
363: ** We had a timeout so now we check and see if we have a timeout
364: ** handler to call
365: */
1.1.2.1 eric 366: if (active_sockets == 0) {
1.1.2.6 eric 367: HTTimer_dispatchAll();
1.1.2.5 frystyk 368: continue;
1.1.2.1 eric 369: }
370:
371: /*
1.1.2.5 frystyk 372: ** There were active sockets. Determine which fd sets they were in
373: */
1.1.2.1 eric 374: for (s = 0 ; s <= maxfds ; s++) {
1.1.2.5 frystyk 375: if (FD_ISSET(s, &texceptset))
376: if ((status = HTEventList_dispatch(s, HTEvent_OOB)) != HT_OK)
377: return status;
378: if (FD_ISSET(s, &twriteset))
379: if ((status = HTEventList_dispatch(s, HTEvent_WRITE)) != HT_OK)
380: return status;
381: if (FD_ISSET(s, &treadset))
382: if ((status = HTEventList_dispatch(s, HTEvent_READ)) != HT_OK)
383: return status;
1.1.2.1 eric 384: }
385: } while (!HTEndLoop);
1.1.2.5 frystyk 386:
1.1.2.1 eric 387: return HT_OK;
1.1.2.3 eric 388: }
389:
390: PUBLIC HTEvent * HTEventList_lookup (SOCKET s, HTEventType type)
391: {
392: RQ * rqp = NULL;
393: if ((rqp = RQ_get(s, RQ_find)) == NULL)
394: return NULL;
395: return rqp->events[HTEvent_INDEX(type)];
1.1.2.1 eric 396: }
397:
398: /* REGISTER DEFULT EVENT MANAGER
399: ** -----------------------------
400: ** Not done automaticly - may be done by application!
401: */
402: PUBLIC BOOL HTEventInit (void)
403: {
404: HTEvent_setRegisterCallback(HTEventList_register);
405: HTEvent_setUnregisterCallback(HTEventList_unregister);
406: return YES;
407: }
408:
409: PUBLIC BOOL HTEventTerminate (void)
410: {
411: return YES;
412: }
Webmaster