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