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