Annotation of libwww/Library/src/HTEvtLst.c, revision 1.1.2.4
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.4 ! eric 6: ** @(#) $Id: HTEvtLst.c,v 1.1.2.3 1996/11/04 16:31:56 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"
34: #include "HTEvtLst.h" /* Implemented here */
35:
36: /* Type definitions and global variables etc. local to this module */
37: PRIVATE fd_set FdArray[3];
38: PRIVATE fd_set all_fds ; /* any descriptor at all */
39:
40: PRIVATE int HTEndLoop = 0; /* If !0 then exit event loop */
41:
42: PRIVATE const int SecondsToWait = 5 ;
43:
44: PRIVATE void __DumpFDSet( fd_set *, const char *);
45:
46: /*
47: ** our internal structure to hold a socket, it's request
48: ** and our action. For version 1, we allow one action per socket
49: */
50:
51: /*
52: ** an action consists of a request, a set of requested operations
53: ** a HTEventCallback function
54: */
55:
56: typedef struct rq_t RQ;
57:
58: struct rq_t {
59: RQ * next ;
60: SOCKET s ; /* our socket */
61: BOOL unregister; /* notify app when completely unregistered */
1.1.2.4 ! eric 62: HTEvent * events[3]; /* event parameters for read, write, oob */
! 63: int bypassed[3]; /* how many times this event has been skipped */
1.1.2.1 eric 64: };
65:
66: #define PRIME_TABLE_SIZE 67
67:
68: #define HASH(s) ((s) % PRIME_TABLE_SIZE)
69:
70: /*
71: ** our internal table of requests,
72: ** indexed by socket
73: */
74: PRIVATE RQ * table[PRIME_TABLE_SIZE];
75: PRIVATE SOCKET max_sock = 0 ; /* max socket value in use */
76:
77: /* Select Timeout handling */
78: typedef struct _HTTimeout {
79: HTEventTimeout * tcbf;
80: HTRequest * request;
81: struct timeval tv;
82: BOOL always;
83: } HTTimeout;
84:
85: PRIVATE HTTimeout seltime;
86: PRIVATE struct timeval *tvptr = NULL;
87:
88: /*
89: ** Local functions
90: */
91: typedef enum {RQ_mayCreate, RQ_find} RQ_action;
92: PRIVATE RQ * RQ_get(SOCKET s, RQ_action action)
93: {
94: RQ * rqp;
95: RQ * last = NULL;
96: long v = HASH(s);
97: for (rqp = table[v]; rqp; rqp = rqp->next) {
98: if (rqp->s == s) {
99: return rqp;
100: }
101: last = rqp; /* to set next pointer when creating new */
102: }
103: if (action == RQ_mayCreate) {
104: if ((rqp = (RQ *) HT_CALLOC(1, sizeof(RQ))) == NULL)
105: HT_OUTOFMEM("HTEventList_register");
106: if (last) last->next = rqp;
107: else table[v] = rqp;
108: rqp->s = s;
109: return rqp;
110: }
111: return NULL;
112: }
113:
114: /* ------------------------------------------------------------------------- */
115:
116: /* HTEventList_registerTimeout
117: ** -----------------------
118: ** Set the timeout for sockets. This does only works on NON windows
119: ** platforms as we need to poll for the console on windows
120: ** The default is no timeout. If the tp points to a zero'ed structure
121: ** then the select is basically polling. If always is YES then
122: ** the callback is called at all times, if NO then only when Library
123: ** sockets are active.
124: ** Returns YES if OK else NO
125: */
126: PUBLIC BOOL HTEventList_registerTimeout (struct timeval *tp, HTRequest * request,
127: HTEventTimeout *tcbf, BOOL always)
128: {
129: if (tp) {
130: #ifdef WWW_WIN_ASYNC
131: /* same window process WWW_WIN_ASYNC stuff and TIMEOUT */
132: SetTimer(HTSocketWin, TIMEOUT, tp->tv_usec/1000 + tp->tv_sec*1000, 0);
133: #else
134: tvptr = &seltime.tv;
135: tvptr->tv_sec = tp->tv_sec;
136: tvptr->tv_usec = tp->tv_usec;
137: #endif
138: seltime.tcbf = tcbf;
139: seltime.request = request;
140: seltime.always = always;
141: if (THD_TRACE)
142: HTTrace("Timeout cbf. %p %s (req=%p, sec=%d, usec=%d)\n",
143: tcbf, always ? "always" : "active",
144: request, (int) tp->tv_sec, (int) tp->tv_usec);
145: }
146: return YES;
147: }
148:
149: /* HTEventList_unregisterTimeout
150: ** -------------------------
151: ** Disables the callback function.
152: ** Returns YES if OK else NO
153: */
154: PUBLIC BOOL HTEventList_unregisterTimeout(void)
155: {
156: #ifdef WWW_WIN_ASYNC
157: /* Same window process WWW_WIN_ASYNC stuff and TIMEOUT */
158: KillTimer(HTSocketWin, TIMEOUT);
159: #else
160: tvptr = NULL;
161: #endif
162: return YES;
163: }
164:
165: /*
166: ** HTEventList_register
167: ** for a given socket, reqister a request structure, a set of operations,
168: ** a HTEventCallback function, and a priority. For this implementation,
169: ** we allow only a single HTEventCallback function for all operations.
170: ** and the priority field is ignored.
171: */
1.1.2.2 eric 172: PUBLIC int HTEventList_register (SOCKET s, HTEventType type, HTEvent * event)
1.1.2.1 eric 173: {
174: RQ * rqp;
175: if (THD_TRACE)
176: HTTrace("Register.... socket %d, request %p HTEventCallback %p type %x at priority %d\n",
177: s, (void *)event->request, (void *)event->cbf, (unsigned) type, (unsigned) event->priority) ;
178:
179: if (s==INVSOC) return 0;
180: rqp = RQ_get(s, RQ_mayCreate);
181: rqp->s = s;
182: rqp->events[HTEvent_INDEX(type)] = event;
183:
184: /* insert socket into appropriate file descriptor set */
185:
186: if (THD_TRACE)
187: HTTrace("Register.... Registering socket for %d\n", type);
188: FD_SET(s, FdArray+HTEvent_INDEX(type));
189: if (!FD_ISSET(s, &all_fds))
190: FD_SET(s, &all_fds);
191:
192: if (s > max_sock)
193: max_sock = s ;
194:
195: return HT_OK;
196: }
197:
198: /*
199: ** HTEventList_unregister
200: ** remove the registered information for the specified socket for the actions
201: ** specified in ops. if no actions remain after the unregister, the registered
202: ** info is deleted, and, if the socket has been registered for notification,
203: ** the HTEventCallback will be invoked.
204: */
1.1.2.2 eric 205: PUBLIC int HTEventList_unregister(SOCKET s, HTEventType type)
1.1.2.1 eric 206: {
207: RQ * rqp;
208: RQ * last = NULL;
209: long v = HASH(s);
210: for (rqp = table[v]; rqp; rqp = rqp->next) {
211: if (rqp->s == s) {
212: rqp->events[HTEvent_INDEX(type)] = 0;
213: FD_CLR(s, FdArray+HTEvent_INDEX(type));
214: if (rqp->events[HTEvent_INDEX(HTEvent_READ)] == NULL &&
215: rqp->events[HTEvent_INDEX(HTEvent_WRITE)] == NULL &&
216: rqp->events[HTEvent_INDEX(HTEvent_OOB)] == NULL) {
217: HTTrace("UnRegister.. no more events registered for socket %d\n", s);
218: if (last) last->next = rqp->next;
219: else table[v] = rqp->next;
220: HT_FREE(rqp);
221: FD_CLR(s, &all_fds);
222: }
223: if (THD_TRACE)
224: HTTrace("UnRegister.. socket %d unregisterd for %x\n", s, type);
225: return HT_OK;
226: }
227: last = rqp; /* to set next pointer when creating new */
228: }
229: HTTrace("Unregister.. couldn't find socket %d.\n", s);
230: return HT_ERROR;
231: }
232:
233: /*
234: ** HTEventList_unregisterAll
235: ** unregister all sockets
236: ** N.B. we just remove them for our internal data structures: it is up to the
237: ** application to actually close the socket.
238: */
239: PUBLIC int HTEventList_unregisterAll( void )
240: {
241: int i;
242: register RQ * rqp, * next ;
243:
244: /* begin */
245: if (THD_TRACE)
246: HTTrace("Unregister.. all sockets\n");
247:
248: for (i = 0 ; i < PRIME_TABLE_SIZE; i++) {
249: for (rqp = table[i]; rqp != 0; rqp = next) {
250: next = rqp->next;
251: HT_FREE(rqp);
252: }
253: table[i] = NULL;
254: }
255:
256: max_sock = 0 ;
257: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_READ));
258: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_WRITE));
259: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_OOB));
260: FD_ZERO(&all_fds);
261:
262: return 0;
263: }
264:
265:
266: /* HTEventList_stopLoop
267: ** ----------------
268: ** Stops the (select based) event loop. The function does not guarantee
269: ** that all requests have terminated. This is for the app to do
270: */
271: PUBLIC void HTEventList_stopLoop (void)
272: {
273: HTEndLoop = 1;
274: }
275:
276: /* HTEventList_loop
277: ** ------------
278: ** event loop: that is, we wait for activity from one of our registered
279: ** channels, and dispatch on that.
280: **
281: ** There are now two versions of the event loop. The first is if you want
282: ** to use async I/O on windows, and the other is if you want to use normal
283: ** Unix setup with sockets
284: */
285: PUBLIC int HTEventList_loop( HTRequest * theRequest )
286: {
287: fd_set treadset, twriteset, texceptset;
288: int active_sockets;
289: int maxfds;
290: SOCKET s;
291: int status = 0;
292: struct timeval tvsave;
293:
294:
295: HTEndLoop = 0;
296: /* Don't leave this loop until we the application */
297: do {
298: treadset = FdArray[HTEvent_INDEX(HTEvent_READ)];
299: twriteset = FdArray[HTEvent_INDEX(HTEvent_WRITE)];
300: texceptset = FdArray[HTEvent_INDEX(HTEvent_OOB)];
301: maxfds = max_sock;
302:
303: if (THD_TRACE)
304: HTTrace("Event Loop.. calling select: maxfds is %d\n", maxfds);
305: /*
306: * timeval struct copy needed for linux, as it set the value to the remaining
307: * timeout while exiting the select. (and perhaps for other OS).
308: */
309: tvsave.tv_sec = tvptr->tv_sec;
310: tvsave.tv_usec = tvptr->tv_usec;
311:
312: #ifdef __hpux
313: active_sockets = select(maxfds+1, (int *)&treadset, (int *)&twriteset,
314: (int *)&texceptset, (struct timeval *) &tvsave);
315: #else
316: active_sockets = select(maxfds+1, &treadset, &twriteset, &texceptset,
317: (struct timeval *) &tvsave);
318: #endif
319: if (THD_TRACE)
320: HTTrace("Event Loop.. select returns %d\n",active_sockets);
321:
322: if (active_sockets == -1) {
323: HTRequest_addSystemError( theRequest, ERR_FATAL, socerrno, NO, "select");
324: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_READ), "Read");
325: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_WRITE), "Write") ;
326: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_OOB), "Exceptions");
327: return HT_ERROR;
328: }
329:
330: /* If timeout then see if we should call callback function */
331: if (active_sockets == 0) {
332: if (seltime.tcbf && (seltime.always || HTNet_isIdle())) {
333: #if 0
334: /* This drives you crazy! */
335: if (THD_TRACE) HTTrace("Event Loop.. select timeout\n");
336: #endif
337: if ((status = (*(seltime.tcbf))(seltime.request)) != HT_OK)
338: return status;
339: } else
340: continue;
341: }
342:
343: /*
344: * there were active sockets. Determine which fd sets they were in
345: */
346:
347: for (s = 0 ; s <= maxfds ; s++) {
348: {
349: if (FD_ISSET(s, &texceptset))
350: if ((status = HTEventList_dispatch(s, HTEvent_OOB)) != HT_OK)
351: return status;
352: if (FD_ISSET(s, &twriteset))
353: if ((status = HTEventList_dispatch(s, HTEvent_WRITE)) != HT_OK)
354: return status;
355: if (FD_ISSET(s, &treadset))
356: if ((status = HTEventList_dispatch(s, HTEvent_READ)) != HT_OK)
357: return status;
358: }
359: }
360:
361: } while (!HTEndLoop);
362: return HT_OK;
363: }
364:
365: /*
366: ** HTEventList_dispatch( SOCKET, SockOps )
367: **
368: ** a little function that just invokes the HTEventCallback routine associated
369: ** with the given socket.
370: **
371: */
1.1.2.2 eric 372: PUBLIC int HTEventList_dispatch (SOCKET s, HTEventType type)
1.1.2.1 eric 373: {
374: RQ * rqp = NULL;
375: if ((rqp = RQ_get(s, RQ_find)) == NULL ||
376: rqp->events[HTEvent_INDEX(type)]->priority == HT_PRIORITY_OFF) {
377: if (THD_TRACE) HTTrace("Callback.... No callback found\n");
378: return (0);
379: }
380: return (*rqp->events[HTEvent_INDEX(type)]->cbf)(s, rqp->events[HTEvent_INDEX(type)]->param, type);
1.1.2.3 eric 381: }
382:
383: PUBLIC HTEvent * HTEventList_lookup (SOCKET s, HTEventType type)
384: {
385: RQ * rqp = NULL;
386: if ((rqp = RQ_get(s, RQ_find)) == NULL)
387: return NULL;
388: return rqp->events[HTEvent_INDEX(type)];
1.1.2.1 eric 389: }
390:
391: PRIVATE void __DumpFDSet( fd_set * fdp, const char * str)
392: {
393: SOCKET s ;
394: #ifdef _WINSOCKAPI_
395: unsigned ui ;
396: #endif
397: if (THD_TRACE) {
398: HTTrace("Dumping..... %s file descriptor set\n", str );
399: #ifdef _WINSOCKAPI_
400: for (ui = 0 ; ui < fdp->fd_count; ui++) {
401: s = all_fds.fd_array[ui] ;
402: #else
403: for (s = 0 ; s <= max_sock; s++) {
404: if (FD_ISSET(s, fdp))
405: #endif
406: {
407: HTTrace("%4d\n", s);
408: }
409: } /* for */
410: } /* if */
411: return ;
412: }
413:
414: /* REGISTER DEFULT EVENT MANAGER
415: ** -----------------------------
416: ** Not done automaticly - may be done by application!
417: */
418: PUBLIC BOOL HTEventInit (void)
419: {
420: HTEvent_setRegisterCallback(HTEventList_register);
421: HTEvent_setUnregisterCallback(HTEventList_unregister);
422: return YES;
423: }
424:
425: PUBLIC BOOL HTEventTerminate (void)
426: {
427: return YES;
428: }
429:
Webmaster