Annotation of libwww/Library/src/HTNet.c, revision 2.16
2.4 frystyk 1: /* HTThread.c
2: ** MULTIPLE THREAD SOCKET MANAGEMENT
2.1 frystyk 3: **
2.10 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.4 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
6: **
7: ** This is the implementation of the internal library multithreading
2.1 frystyk 8: ** functions. This includes an interrupt handler and a event loop.
9: **
10: ** History:
2.14 frystyk 11: ** 12 June 94 Written by Henrik Frystyk, frystyk@w3.org
2.1 frystyk 12: */
13:
2.9 frystyk 14: /* Implemention dependent include files */
15: #include "tcp.h"
16:
2.1 frystyk 17: /* Library include files */
18: #include "HTUtils.h"
19: #include "HTAccess.h"
2.16 ! frystyk 20: #include "HTProt.h"
2.1 frystyk 21: #include "HTError.h"
22: #include "HTThread.h" /* Implemented here */
23:
2.9 frystyk 24: #ifdef WIN32
25: #include <io.h>
26: #endif
27:
2.1 frystyk 28: /* Type definitions and global variables etc. local to this module */
29: PRIVATE fd_set HTfd_read; /* Bit array of sockets ready for read */
30: PRIVATE fd_set HTfd_write; /* Bit array of sockets ready for write */
31: PRIVATE int HTMaxfdpl = 0; /* Max number of sockets + 1 */
32:
33: PRIVATE fd_set HTfd_intr; /* All sockets currently interrupted */
34: PRIVATE fd_set HTfd_set; /* All sockets currently registered */
35:
2.9 frystyk 36:
2.1 frystyk 37: PRIVATE HTList *HTThreads = NULL; /* List of the HTNetInfo structures */
38:
39: /* ------------------------------------------------------------------------- */
40:
41: /* HTThreadInit
42: **
43: ** Initiates the thread socket registers. It is very important that
44: ** this function is called. It is currently done inside HTAccess in the
45: ** HTAccessInit function.
46: */
47: PUBLIC BOOL HTThreadInit NOARGS
48: {
49: static BOOL done=NO;
50:
51: if (done) {
52: if (THD_TRACE)
2.7 frystyk 53: fprintf(TDEST, "ThreadInit.. Already done\n");
2.1 frystyk 54: return NO;
55: }
56: done = YES;
57:
58: /* Initialize the other internal bit arrays */
59: FD_ZERO(&HTfd_write);
60: FD_ZERO(&HTfd_set);
61: FD_ZERO(&HTfd_intr);
2.9 frystyk 62: FD_ZERO(&HTfd_read) ;
63:
2.1 frystyk 64: return YES;
65: }
66:
67:
68: /* HTThreadGetFDInfo
69: **
70: ** Returns the maximum bit width and the read and write bit array.
71: */
72: PUBLIC int HTThreadGetFDInfo ARGS2(fd_set *, read, fd_set *, write)
73: {
74: *read = HTfd_read;
75: *write = HTfd_write;
76: return HTMaxfdpl;
77: }
78:
79:
2.15 frystyk 80: /* HTThreadStateByRequest
81: **
82: ** This function registers a socket as waiting for the action given
83: ** (read or write etc.). It uses the request structure to find the socket
84: */
85: PUBLIC void HTThreadStateByRequest ARGS2(HTRequest *, request,
86: HTThreadAction, action)
87: {
88: if (request && request->net_info && request->net_info->sockfd != INVSOC)
89: HTThreadState(request->net_info->sockfd, action);
90: }
91:
2.1 frystyk 92: /* HTThreadState
93: **
94: ** This function registers a socket as waiting for the action given
95: ** (read or write etc.).
96: */
2.7 frystyk 97: PUBLIC void HTThreadState ARGS2(SOCKFD, sockfd, HTThreadAction, action)
2.1 frystyk 98: {
2.9 frystyk 99: #ifdef _WIN32
2.12 frystyk 100: if (sockfd <= 2)
101: sockfd = _get_osfhandle(sockfd);
2.9 frystyk 102: #endif
103:
2.1 frystyk 104: if (THD_TRACE) {
105: static char *actionmsg[] = {
106: "SET WRITE",
107: "CLEAR WRITE",
108: "SET READ",
109: "CLEAR READ",
2.4 frystyk 110: "SET INTERRUPT",
111: "CLEAR INTERRUPT",
2.1 frystyk 112: "CLOSE"
113: };
2.7 frystyk 114: fprintf(TDEST,
2.1 frystyk 115: "Thread...... Register socket number %d for action %s\n",
116: sockfd, *(actionmsg+action));
117: }
118: switch (action) {
119: case THD_SET_WRITE:
2.12 frystyk 120: if (!FD_ISSET(sockfd, &HTfd_write))
121: FD_SET(sockfd, &HTfd_write);
122: if (!FD_ISSET(sockfd, &HTfd_set))
123: FD_SET(sockfd, &HTfd_set);
2.1 frystyk 124: break;
125:
126: case THD_CLR_WRITE:
127: FD_CLR(sockfd, &HTfd_write);
2.15 frystyk 128: if (!FD_ISSET(sockfd, &HTfd_read))
129: FD_CLR(sockfd, &HTfd_set);
2.1 frystyk 130: break;
131:
132: case THD_SET_READ:
2.12 frystyk 133: if (!FD_ISSET(sockfd, &HTfd_read))
134: FD_SET(sockfd, &HTfd_read);
135: if (!FD_ISSET(sockfd, &HTfd_set))
136: FD_SET(sockfd, &HTfd_set);
2.1 frystyk 137: break;
138:
139: case THD_CLR_READ:
140: FD_CLR(sockfd, &HTfd_read);
2.15 frystyk 141: if (!FD_ISSET(sockfd, &HTfd_write))
142: FD_CLR(sockfd, &HTfd_set);
2.1 frystyk 143: break;
144:
145: case THD_CLOSE:
146: FD_CLR(sockfd, &HTfd_read);
147: FD_CLR(sockfd, &HTfd_write);
148: FD_CLR(sockfd, &HTfd_intr);
149: FD_CLR(sockfd, &HTfd_set);
150: break;
151:
2.2 frystyk 152: case THD_SET_INTR:
2.12 frystyk 153: if (!FD_ISSET(sockfd, &HTfd_intr))
154: FD_SET(sockfd, &HTfd_intr);
2.1 frystyk 155: break;
156:
2.2 frystyk 157: case THD_CLR_INTR:
158: FD_CLR(sockfd, &HTfd_intr);
159: break;
160:
2.1 frystyk 161: default:
162: if (THD_TRACE)
2.7 frystyk 163: fprintf(TDEST, "Thread...... Illigal socket action\n");
2.1 frystyk 164: }
165:
166: /* Update max bit width. The method used ignores any other default
2.2 frystyk 167: opened file descriptors between 0 and the actual set of file
168: descriptors used. However, they are not registered anyway */
2.9 frystyk 169:
2.1 frystyk 170: if (action == THD_CLOSE) {
2.9 frystyk 171: #ifdef _WINSOCKAPI_
172: HTMaxfdpl = HTfd_set.fd_count ;
173: #else
2.1 frystyk 174: if (sockfd+1 >= HTMaxfdpl) {
2.2 frystyk 175: while (HTMaxfdpl > 0 && !FD_ISSET(HTMaxfdpl-1, &HTfd_set))
2.1 frystyk 176: HTMaxfdpl--;
177: }
2.9 frystyk 178: #endif
2.1 frystyk 179: } else {
2.9 frystyk 180: #ifdef _WINSOCKAPI_
181: HTMaxfdpl = HTfd_set.fd_count;
182: #else
2.1 frystyk 183: if (sockfd+1 > HTMaxfdpl)
184: HTMaxfdpl = sockfd+1;
2.9 frystyk 185: #endif
2.1 frystyk 186: }
187: if (THD_TRACE)
2.7 frystyk 188: fprintf(TDEST, "Thread...... Max bitwidth is %d\n", HTMaxfdpl);
2.1 frystyk 189: }
190:
191:
192: /* HTThreadIntr
193: **
194: ** This function returns YES or NO to the question
195: */
2.7 frystyk 196: PUBLIC BOOL HTThreadIntr ARGS1(SOCKFD, sockfd)
2.1 frystyk 197: {
198: return FD_ISSET(sockfd, &HTfd_intr) ? YES : NO;
199: }
200:
201:
202: /* HTThreadMarkIntrAll
203: **
2.2 frystyk 204: ** Marks all Library sockets as interrupted. User sockets can not be
2.12 frystyk 205: ** interrupted.
2.1 frystyk 206: */
2.12 frystyk 207: PUBLIC BOOL HTThreadMarkIntrAll ARGS1(CONST fd_set *, fd_user)
2.1 frystyk 208: {
2.12 frystyk 209: HTNetInfo *pres;
210: if (HTThreads) {
211: while ((pres = (HTNetInfo *) HTList_lastObject(HTThreads)) != NULL)
212: HTThread_kill(pres);
213: return YES;
214: }
215: return NO;
216:
217: #if 0
218: /*
219: ** Use the HTThread list instead of the bit arrays. This makes it easier
220: ** to execute a kill thread right away
221: */
2.1 frystyk 222: int cnt;
2.9 frystyk 223: #ifdef _WINSOCKAPI_
224: int i;
225: #endif
2.1 frystyk 226: if (THD_TRACE)
2.7 frystyk 227: fprintf(TDEST, "Thread...... Mark ALL Library sockfd INTERRUPTED\n");
2.9 frystyk 228: #ifdef _WINSOCKAPI_
229: for (i = 0 ; i < HTfd_set.fd_count; i++) {
230: cnt = HTfd_set.fd_array[i];
231: if (!FD_ISSET(cnt, fd_user))
232: #else
2.2 frystyk 233: for (cnt=0; cnt<HTMaxfdpl; cnt++) {
2.4 frystyk 234: if (FD_ISSET(cnt, &HTfd_set) && !FD_ISSET(cnt, fd_user))
2.9 frystyk 235: #endif
2.4 frystyk 236: FD_SET(cnt, &HTfd_intr);
2.2 frystyk 237: }
2.12 frystyk 238: #endif
2.1 frystyk 239: }
240:
241:
242: /* HTThreadActive
243: **
244: ** Returns yes as long as a socket other than stdin is registered in
245: ** the total set of sockets.
246: */
247: PUBLIC BOOL HTThreadActive NOARGS
248: {
249: int cnt;
2.9 frystyk 250: #ifdef _WINSOCKAPI_
251: if (HTfd_set.fd_count > 0)
252: return YES;
253: #else
2.1 frystyk 254: for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++)
255: if (FD_ISSET(cnt, &HTfd_set))
256: return YES;
2.9 frystyk 257: #endif
2.1 frystyk 258: return NO;
259: }
260:
261:
262: /* HTThread_new
263: **
264: ** Register the HTNetInfo structure in a list so that we can find the
2.12 frystyk 265: ** request which corresponds to a socket descriptor.
266: ** Returns YES on success, NO on error
2.1 frystyk 267: */
2.12 frystyk 268: PUBLIC BOOL HTThread_new ARGS1(HTNetInfo *, new_net)
2.1 frystyk 269: {
270: if (!HTThreads)
271: HTThreads = HTList_new();
2.12 frystyk 272: return HTList_addObject(HTThreads, (void *) new_net);
2.1 frystyk 273: }
274:
275:
276: /* HTThread_clear
277: **
2.12 frystyk 278: ** Remove the HTNetInfo from the list of active threads.
279: ** Returns YES on success, NO on error
2.1 frystyk 280: */
2.12 frystyk 281: PUBLIC BOOL HTThread_clear ARGS1(HTNetInfo *, old_net)
2.1 frystyk 282: {
283: if (HTThreads)
284: return HTList_removeObject(HTThreads, (void *) old_net);
285: return NO;
286: }
287:
288:
2.12 frystyk 289: /* HTThread_kill
290: **
291: ** Kill the thread and remove the HTNetInfo from the list of active
292: ** threads.
293: ** Returns YES on success, NO on error
294: **
295: ** BUG: We do not take ANSI C file descriptors into account
296: */
297: PUBLIC BOOL HTThread_kill ARGS1(HTNetInfo *, kill_net)
298: {
2.13 frystyk 299: if (kill_net && HTThreads) {
2.12 frystyk 300: HTList *cur = HTThreads;
301: HTNetInfo *pres;
302:
303: /* Find the corresponding HTRequest structure */
304: while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
305: if (pres == kill_net) break;
306: }
307:
308: /*
309: ** Now see if a socket is active (or an ANSI C file descriptor).
310: ** If so then mark the thread as interrupted and call the load
311: ** function.
312: */
313: if (pres) {
314: if (kill_net->sockfd != INVSOC) { /* @@@ ANSI C FIlE DES @@@ */
315: HTProtocol *prot = (HTProtocol *)
316: HTAnchor_protocol(kill_net->request->anchor);
317: HTThreadState(kill_net->sockfd, THD_SET_INTR);
318: (*(prot->load))(kill_net->request);
319: }
320: return HTThread_clear(kill_net);
321: }
322: }
2.13 frystyk 323: if (THD_TRACE)
324: fprintf(TDEST, "Kill Thread. Thread is not registered\n");
2.12 frystyk 325: return NO;
2.13 frystyk 326: }
327:
328:
329: /* HTThread_isAlive
330: **
331: ** Checks whether a thread is still registered and if so returns the
332: ** corresponding HTRequest structure, else return NULL.
333: */
334: PUBLIC HTRequest *HTThread_isAlive ARGS1(HTNetInfo *, net)
335: {
336: HTList *cur = HTThreads;
337: HTNetInfo *pres;
338: if (cur && net) {
339: while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
340: if (pres == net) return pres->request;
341: }
342: }
343: if (THD_TRACE)
344: fprintf(TDEST, "Thread...... Thread is not alive\n");
345: return NULL;
2.12 frystyk 346: }
347:
348:
2.1 frystyk 349: /* HTThread_getCallBack
350: **
351: ** Finds a socket and makes it the active thread. READ has a higher
352: ** priority than WRITE as it might influence (stop) the WRITE process.
353: ** Returns the request structure of the active thread, NULL on error.
354: ** A interrupted socket has the highest priority
355: */
356: PUBLIC HTRequest *HTThread_getRequest ARGS2(CONST fd_set *, fd_read,
357: CONST fd_set *, fd_write)
358: {
2.7 frystyk 359: SOCKFD cnt;
2.8 frystyk 360: SocAction found = SOC_INVALID;
2.9 frystyk 361:
362: #ifdef _WINSOCKAPI_
363: int ic = 0;
364: #endif
365:
2.12 frystyk 366: #if 0
367:
368: /* Should not be necessary after we have HTThread_kill() */
2.9 frystyk 369: #ifdef _WINSOCKAPI_
2.12 frystyk 370: for (ic = 0; ic < HTfd_set.fd_count; ic++) {
371: cnt = HTfd_set.fd_array[ic];
2.9 frystyk 372: #else
2.1 frystyk 373: for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) { /* INTERRUPT */
2.9 frystyk 374: #endif
2.1 frystyk 375: if (FD_ISSET(cnt, &HTfd_intr)) {
376: if (THD_TRACE)
2.7 frystyk 377: fprintf(TDEST, "GetSocket... Socket %d INTERRUPTED\n", cnt);
2.8 frystyk 378: found = SOC_INTERRUPT;
2.1 frystyk 379: break;
380: }
381: }
2.9 frystyk 382:
2.12 frystyk 383: #endif
384:
2.8 frystyk 385: if (found == SOC_INVALID) {
2.9 frystyk 386: #ifdef _WINSOCKAPI_
387: for (ic = 0; ic < HTfd_set.fd_count; ic++) {
388: cnt = HTfd_set.fd_array[ic];
389: #else
2.1 frystyk 390: for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) { /* READ */
2.9 frystyk 391: #endif
2.1 frystyk 392: if (FD_ISSET(cnt, fd_read)) {
393: if (THD_TRACE)
2.7 frystyk 394: fprintf(TDEST, "GetSocket... Socket %d for READ\n", cnt);
2.8 frystyk 395: found = SOC_READ;
2.1 frystyk 396: break;
397: }
398: }
399: }
2.9 frystyk 400:
2.8 frystyk 401: if (found == SOC_INVALID) {
2.9 frystyk 402: #ifdef _WINSOCKAPI_
403: for (ic = 0; ic < HTfd_set.fd_count; ic++) {
404: cnt = HTfd_set.fd_array[ic];
405: #else
406: for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) { /* WRITE */
407: #endif
2.1 frystyk 408: if (FD_ISSET(cnt, fd_write)) {
409: if (THD_TRACE)
2.7 frystyk 410: fprintf(TDEST, "GetSocket... Socket %d for WRITE\n", cnt);
2.8 frystyk 411: found = SOC_WRITE;
2.1 frystyk 412: break;
413: }
414: }
415: }
2.9 frystyk 416:
2.12 frystyk 417: if (found == SOC_INVALID)
2.1 frystyk 418: return NULL;
419:
2.8 frystyk 420: /* Find the corresponding HTNetInfo and HTRequest structure */
2.12 frystyk 421: {
422: HTList *cur = HTThreads;
423: HTNetInfo *pres;
424: if (cur) {
425: while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
426: if (pres->sockfd == cnt) {
427: pres->action = found;
428: return pres->request;
429: }
430: }
2.1 frystyk 431: }
432: }
433: return NULL;
434: }
2.9 frystyk 435:
Webmaster