Annotation of libwww/Library/src/HTNet.c, revision 2.18
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.17 frystyk 12: ** 31 May 95 Charlie Brooks cbrooks@osf.org
13: **
2.1 frystyk 14: */
15:
2.9 frystyk 16: /* Implemention dependent include files */
17: #include "tcp.h"
18:
2.1 frystyk 19: /* Library include files */
20: #include "HTUtils.h"
21: #include "HTAccess.h"
2.16 frystyk 22: #include "HTProt.h"
2.1 frystyk 23: #include "HTError.h"
24: #include "HTThread.h" /* Implemented here */
2.17 frystyk 25: #include "HTEvntrg.h"
2.1 frystyk 26:
2.9 frystyk 27: #ifdef WIN32
28: #include <io.h>
29: #endif
30:
2.1 frystyk 31:
2.17 frystyk 32: PRIVATE HTList *HTThreads = NULL; /* List of the HTNetInfo structures */
33: PRIVATE fd_set nullSet ;
34: PRIVATE fd_set HTfd_intr;
35: PRIVATE fd_set HTfd_libs ;
36: PRIVATE SOCKET libMaxSock = 0 ;
2.1 frystyk 37:
2.9 frystyk 38:
2.17 frystyk 39: int LibraryCallback( SOCKET, HTRequest *, SockOps) ;
2.1 frystyk 40:
41: /* ------------------------------------------------------------------------- */
42:
43: /* HTThreadInit
44: **
45: ** Initiates the thread socket registers. It is very important that
46: ** this function is called. It is currently done inside HTAccess in the
47: ** HTAccessInit function.
48: */
49: PUBLIC BOOL HTThreadInit NOARGS
50: {
51: static BOOL done=NO;
52:
53: if (done) {
54: if (THD_TRACE)
2.7 frystyk 55: fprintf(TDEST, "ThreadInit.. Already done\n");
2.1 frystyk 56: return NO;
57: }
58: done = YES;
2.17 frystyk 59: FD_ZERO( &HTfd_intr) ;
2.1 frystyk 60: return YES;
61: }
62:
63:
64: /* HTThreadGetFDInfo
65: **
66: ** Returns the maximum bit width and the read and write bit array.
2.17 frystyk 67: ** N.B. Only used by old HTEvent.c module
2.1 frystyk 68: */
2.17 frystyk 69:
2.1 frystyk 70: PUBLIC int HTThreadGetFDInfo ARGS2(fd_set *, read, fd_set *, write)
71: {
2.17 frystyk 72: *read = nullSet;
73: *write = nullSet;
74: return libMaxSock;
2.1 frystyk 75: }
76:
2.15 frystyk 77: /* HTThreadStateByRequest
78: **
79: ** This function registers a socket as waiting for the action given
80: ** (read or write etc.). It uses the request structure to find the socket
81: */
82: PUBLIC void HTThreadStateByRequest ARGS2(HTRequest *, request,
83: HTThreadAction, action)
84: {
85: if (request && request->net_info && request->net_info->sockfd != INVSOC)
86: HTThreadState(request->net_info->sockfd, action);
87: }
88:
2.17 frystyk 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.).
2.17 frystyk 95: **
96: ** Charlie Brooks - we handle the interrupt thread state internally to this module
97: ** setting the interrupt on a socket disables it from read/write.
2.1 frystyk 98: */
2.7 frystyk 99: PUBLIC void HTThreadState ARGS2(SOCKFD, sockfd, HTThreadAction, action)
2.1 frystyk 100: {
2.17 frystyk 101: register HTNetInfo * pres ;
102: HTList * cur = HTThreads ;
103: int found = 0 ;
104: HTRequest * reqst ;
105:
2.9 frystyk 106: #ifdef _WIN32
2.17 frystyk 107: if (sockfd <= 2)
108: sockfd = _get_osfhandle(sockfd) ;
2.9 frystyk 109: #endif
110:
2.1 frystyk 111: if (THD_TRACE) {
112: static char *actionmsg[] = {
113: "SET WRITE",
114: "CLEAR WRITE",
115: "SET READ",
116: "CLEAR READ",
2.4 frystyk 117: "SET INTERRUPT",
118: "CLEAR INTERRUPT",
2.17 frystyk 119: "CLOSE",
120: "SET CONNECT",
121: "CLEAR CONNECT"
2.1 frystyk 122: };
2.7 frystyk 123: fprintf(TDEST,
2.17 frystyk 124: "Thread...... Registering socket number %d for action %s\n",
2.1 frystyk 125: sockfd, *(actionmsg+action));
2.17 frystyk 126: } /* if */
127:
128: FD_SET( sockfd, &HTfd_libs) ;
129: if (libMaxSock < sockfd)
130: libMaxSock = sockfd ;
131:
132:
133: while ((pres = (HTNetInfo *)HTList_nextObject(cur) ) != 0) {
134: if (pres->sockfd == sockfd) {
135: found = 1 ;
136: break ;
137: } /* if */
138: } /* while */
139:
140: if (! found) /* how'd you get here? */
141: return ;
142:
143: reqst = pres->request ;
2.1 frystyk 144: switch (action) {
145: case THD_SET_WRITE:
2.17 frystyk 146: case THD_SET_CONNECT:
147: HTEvent_Register( sockfd, reqst, action == THD_SET_WRITE ? (SockOps)FD_WRITE : (SockOps)FD_CONNECT ,
148: LibraryCallback, 0);
2.1 frystyk 149: break;
150:
151: case THD_CLR_WRITE:
2.17 frystyk 152: case THD_CLR_CONNECT:
153: HTEvent_UnRegister( sockfd, action == THD_CLR_WRITE ? (SockOps)FD_WRITE : (SockOps)FD_CONNECT) ;
2.1 frystyk 154: break;
155:
156: case THD_SET_READ:
2.17 frystyk 157: HTEvent_Register( sockfd, reqst, (SockOps)FD_READ, LibraryCallback, 0);
2.1 frystyk 158: break;
159:
160: case THD_CLR_READ:
2.17 frystyk 161: HTEvent_UnRegister( sockfd, FD_WRITE) ;
2.1 frystyk 162: break;
163:
164: case THD_CLOSE:
2.17 frystyk 165: HTEvent_UnRegister( sockfd, FD_ALL) ;
166: FD_CLR( sockfd, &HTfd_libs);
167: FD_CLR( sockfd, &HTfd_intr);
168: libMaxSock = 0 ;
169: while ((pres = (HTNetInfo *)HTList_nextObject(cur) ) != 0) {
170: if (pres->sockfd > libMaxSock) {
171: libMaxSock = sockfd ;
172: } /* if */
173: } /* while */
174:
2.1 frystyk 175: break;
176:
2.17 frystyk 177: /*
178: * we handle interrupts locally ... only library sockets can
179: * be interrupted?
180: */
181:
2.2 frystyk 182: case THD_SET_INTR:
2.17 frystyk 183: HTEvent_UnRegister( sockfd, (SockOps)(FD_READ | FD_WRITE) );
184: FD_SET( sockfd, &HTfd_intr) ;
2.1 frystyk 185: break;
186:
2.2 frystyk 187: case THD_CLR_INTR:
2.17 frystyk 188: FD_CLR( sockfd, &HTfd_intr) ;
189: HTEvent_UnRegister(sockfd, FD_ALL) ; /* no sin to unregister and unregistered socket */
2.2 frystyk 190: break;
191:
2.1 frystyk 192: default:
193: if (THD_TRACE)
2.17 frystyk 194: fprintf(TDEST, "Thread...... Illegal socket action (%d)\n", (int)action);
2.1 frystyk 195: }
2.17 frystyk 196: return ;
2.1 frystyk 197: }
198:
199:
200: /* HTThreadIntr
201: **
202: ** This function returns YES or NO to the question
203: */
2.7 frystyk 204: PUBLIC BOOL HTThreadIntr ARGS1(SOCKFD, sockfd)
2.1 frystyk 205: {
206: return FD_ISSET(sockfd, &HTfd_intr) ? YES : NO;
207: }
208:
209:
210: /* HTThreadMarkIntrAll
211: **
2.2 frystyk 212: ** Marks all Library sockets as interrupted. User sockets can not be
2.17 frystyk 213: ** interrupted
2.1 frystyk 214: */
2.17 frystyk 215: PUBLIC BOOL HTThreadMarkIntrAll( CONST fd_set * fd_user )
2.1 frystyk 216: {
2.12 frystyk 217: HTNetInfo *pres;
218: if (HTThreads) {
219: while ((pres = (HTNetInfo *) HTList_lastObject(HTThreads)) != NULL)
220: HTThread_kill(pres);
221: return YES;
222: }
223: return NO;
224:
2.1 frystyk 225: }
226:
227:
228: /* HTThreadActive
229: **
230: ** Returns yes as long as a socket other than stdin is registered in
231: ** the total set of sockets.
232: */
233: PUBLIC BOOL HTThreadActive NOARGS
234: {
2.17 frystyk 235: if (libMaxSock > 0)
236: return YES;
237: else
238: return NO;
2.1 frystyk 239: }
240:
241:
242: /* HTThread_new
243: **
244: ** Register the HTNetInfo structure in a list so that we can find the
2.17 frystyk 245: ** request which corresponds to a socket descriptor
2.1 frystyk 246: */
2.12 frystyk 247: PUBLIC BOOL HTThread_new ARGS1(HTNetInfo *, new_net)
2.1 frystyk 248: {
249: if (!HTThreads)
2.17 frystyk 250: HTThreads = HTList_new();
2.12 frystyk 251: return HTList_addObject(HTThreads, (void *) new_net);
2.1 frystyk 252: }
253:
254:
255: /* HTThread_clear
256: **
2.17 frystyk 257: ** Remove the HTNetInfo from the list of acrive threads.
2.1 frystyk 258: */
2.12 frystyk 259: PUBLIC BOOL HTThread_clear ARGS1(HTNetInfo *, old_net)
2.1 frystyk 260: {
261: if (HTThreads)
262: return HTList_removeObject(HTThreads, (void *) old_net);
263: return NO;
264: }
265:
2.17 frystyk 266: /* HTThread_isAlive
267: **
268: ** Checks whether a thread is still registered and if so returns the
269: ** corresponding HTRequest structure, else return NULL.
270: */
271: PUBLIC HTRequest *HTThread_isAlive ARGS1(HTNetInfo *, net)
272: {
273: HTList *cur = HTThreads;
274: HTNetInfo *pres;
275: if (cur && net) {
276: while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
277: if (pres == net) return pres->request;
278: }
279: }
280: if (THD_TRACE)
281: fprintf(TDEST, "Thread...... Thread is not alive\n");
282: return NULL;
283: }
284:
285:
286: /*
287: * LibraryCallback - "glue" between 3.0 thread code and new callback functions
288: * map return codes into a simple yes/no model.
289: */
290:
291: int LibraryCallback( SOCKET s, HTRequest * rq, SockOps f)
292: {
293: int status = 0 ;
294: HTEventState state ;
295: HTProtocol * proto = (HTProtocol *)
296: HTAnchor_protocol( rq -> anchor) ;
297:
298: /* begin */
299:
300: if (proto == 0) /* Whoa! No protocol! */
301: return -1;
302: status = proto->load( rq ) ;
303: if (status != HT_WOULD_BLOCK) { /* completed - good or bad... */
304: if (THD_TRACE)
305: fprintf(TDEST, "LibCallBack. Calling Terminate...\n");
306:
307: HTLoadTerminate( rq, status ) ;
2.18 ! frystyk 308: if (status != HT_OK) {
! 309: state = HTEventRequestTerminate( rq, status) ;
! 310: /* if the state isn't EVENT_QUIT */
! 311: if (! HTEventCheckState( rq, state ))
2.17 frystyk 312: return HT_OK; /* treat as failure */
2.18 ! frystyk 313: }
2.17 frystyk 314: } /* if status */
315: return HT_WOULD_BLOCK;
316: }
2.1 frystyk 317:
2.12 frystyk 318: /* HTThread_kill
319: **
320: ** Kill the thread and remove the HTNetInfo from the list of active
321: ** threads.
322: ** Returns YES on success, NO on error
323: **
324: ** BUG: We do not take ANSI C file descriptors into account
325: */
2.17 frystyk 326:
2.12 frystyk 327: PUBLIC BOOL HTThread_kill ARGS1(HTNetInfo *, kill_net)
328: {
2.17 frystyk 329: if (HTThreads) {
2.12 frystyk 330: HTList *cur = HTThreads;
331: HTNetInfo *pres;
332:
333: /* Find the corresponding HTRequest structure */
334: while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
335: if (pres == kill_net) break;
336: }
337:
338: /*
339: ** Now see if a socket is active (or an ANSI C file descriptor).
340: ** If so then mark the thread as interrupted and call the load
341: ** function.
342: */
343: if (pres) {
344: if (kill_net->sockfd != INVSOC) { /* @@@ ANSI C FIlE DES @@@ */
345: HTProtocol *prot = (HTProtocol *)
346: HTAnchor_protocol(kill_net->request->anchor);
347: HTThreadState(kill_net->sockfd, THD_SET_INTR);
348: (*(prot->load))(kill_net->request);
349: }
350: return HTThread_clear(kill_net);
2.17 frystyk 351: } else {
352: if (THD_TRACE)
353: fprintf(TDEST, "Kill Thread. Thread is not registered\n");
354: return NO;
2.12 frystyk 355: }
356: }
357: return NO;
2.13 frystyk 358: }
Webmaster