Annotation of libwww/Library/src/HTNet.c, revision 2.12
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:
11: ** 12 June 94 Written by Henrik Frystyk, frystyk@dxcern.cern.ch
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: {
! 290: if (HTThreads) {
! 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: } else {
! 313: if (THD_TRACE)
! 314: fprintf(TDEST, "Kill Thread. Thread is not registered\n");
! 315: return NO;
! 316: }
! 317: }
! 318: return NO;
! 319: }
! 320:
! 321:
2.1 frystyk 322: /* HTThread_getCallBack
323: **
324: ** Finds a socket and makes it the active thread. READ has a higher
325: ** priority than WRITE as it might influence (stop) the WRITE process.
326: ** Returns the request structure of the active thread, NULL on error.
327: ** A interrupted socket has the highest priority
328: */
329: PUBLIC HTRequest *HTThread_getRequest ARGS2(CONST fd_set *, fd_read,
330: CONST fd_set *, fd_write)
331: {
2.7 frystyk 332: SOCKFD cnt;
2.8 frystyk 333: SocAction found = SOC_INVALID;
2.9 frystyk 334:
335: #ifdef _WINSOCKAPI_
336: int ic = 0;
337: #endif
338:
2.12 ! frystyk 339: #if 0
! 340:
! 341: /* Should not be necessary after we have HTThread_kill() */
2.9 frystyk 342: #ifdef _WINSOCKAPI_
2.12 ! frystyk 343: for (ic = 0; ic < HTfd_set.fd_count; ic++) {
! 344: cnt = HTfd_set.fd_array[ic];
2.9 frystyk 345: #else
2.1 frystyk 346: for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) { /* INTERRUPT */
2.9 frystyk 347: #endif
2.1 frystyk 348: if (FD_ISSET(cnt, &HTfd_intr)) {
349: if (THD_TRACE)
2.7 frystyk 350: fprintf(TDEST, "GetSocket... Socket %d INTERRUPTED\n", cnt);
2.8 frystyk 351: found = SOC_INTERRUPT;
2.1 frystyk 352: break;
353: }
354: }
2.9 frystyk 355:
2.12 ! frystyk 356: #endif
! 357:
2.8 frystyk 358: if (found == SOC_INVALID) {
2.9 frystyk 359: #ifdef _WINSOCKAPI_
360: for (ic = 0; ic < HTfd_set.fd_count; ic++) {
361: cnt = HTfd_set.fd_array[ic];
362: #else
2.1 frystyk 363: for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) { /* READ */
2.9 frystyk 364: #endif
2.1 frystyk 365: if (FD_ISSET(cnt, fd_read)) {
366: if (THD_TRACE)
2.7 frystyk 367: fprintf(TDEST, "GetSocket... Socket %d for READ\n", cnt);
2.8 frystyk 368: found = SOC_READ;
2.1 frystyk 369: break;
370: }
371: }
372: }
2.9 frystyk 373:
2.8 frystyk 374: if (found == SOC_INVALID) {
2.9 frystyk 375: #ifdef _WINSOCKAPI_
376: for (ic = 0; ic < HTfd_set.fd_count; ic++) {
377: cnt = HTfd_set.fd_array[ic];
378: #else
379: for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) { /* WRITE */
380: #endif
2.1 frystyk 381: if (FD_ISSET(cnt, fd_write)) {
382: if (THD_TRACE)
2.7 frystyk 383: fprintf(TDEST, "GetSocket... Socket %d for WRITE\n", cnt);
2.8 frystyk 384: found = SOC_WRITE;
2.1 frystyk 385: break;
386: }
387: }
388: }
2.9 frystyk 389:
2.12 ! frystyk 390: if (found == SOC_INVALID)
2.1 frystyk 391: return NULL;
392:
2.8 frystyk 393: /* Find the corresponding HTNetInfo and HTRequest structure */
2.12 ! frystyk 394: {
! 395: HTList *cur = HTThreads;
! 396: HTNetInfo *pres;
! 397: if (cur) {
! 398: while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
! 399: if (pres->sockfd == cnt) {
! 400: pres->action = found;
! 401: return pres->request;
! 402: }
! 403: }
2.1 frystyk 404: }
405: }
406: return NULL;
407: }
2.9 frystyk 408:
Webmaster