Standardize License information
[openafs.git] / src / lwp / iomgr.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #ifndef lint
11 #endif
12 /*******************************************************************\
13 *                                                                   *
14 *       Information Technology Center                               *
15 *       Carnegie-Mellon University                                  *
16 *                                                                   *
17 *                                                                   *
18 *                                                                   *
19 \*******************************************************************/
20
21
22 /*
23         IO Manager routines & server process for VICE server.
24 */
25
26 #include <afs/param.h>
27 #include <stdio.h>
28 #ifdef AFS_NT40_ENV
29 #include <winsock2.h>
30 #include <malloc.h>
31 extern void lwp_abort(void);
32 #else
33 #include <unistd.h>             /* select() prototype */
34 #include <sys/types.h>          /* fd_set on older platforms */
35 #include <sys/time.h>           /* struct timeval, select() prototype */
36 #ifndef FD_SET
37 # include <sys/select.h>        /* fd_set on newer platforms */
38 #endif
39 #include <sys/file.h>
40 #endif /* AFS_NT40_ENV */
41 #include "lwp.h"
42 #include "timer.h"
43 #include <signal.h>
44 #include <errno.h>
45 #ifdef AFS_SUN5_ENV
46 #include <fcntl.h>
47 #endif
48 #if     defined(USE_PTHREADS) || defined(USE_SOLARIS_THREADS)
49
50 void IOMGR_Initialize() /* noop */
51 { }
52
53 void IOMGR_Sleep (seconds)
54   unsigned seconds;
55 {
56     struct timespec itv;
57
58     itv.tv_sec = seconds;
59     itv.tv_nsec = 0;
60     assert(pthread_mutex_unlock(&lwp_mutex) == 0);
61     assert(pthread_delay_np(&itv) == 0);
62     assert(pthread_mutex_lock(&lwp_mutex) == 0);
63 }
64
65 #else
66
67 #ifdef  AFS_DECOSF_ENV
68 extern void *malloc();
69 #endif  /* AFS_DECOSF_ENV */
70
71 typedef unsigned char bool;
72 #define FALSE   0
73 #define TRUE    1
74
75 #ifndef MIN
76 #define MIN(a,b) ((a)>(b)) ? b : a
77 #endif
78
79 static int SignalSignals();
80 \f
81 /********************************\
82 *                                *
83 *  Stuff for managing IoRequests *
84 *                                *
85 \********************************/
86
87 struct IoRequest {
88
89     /* Pid of process making request (for use in IOMGR_Cancel */
90     PROCESS             pid;
91
92     /* Descriptor masks for requests */
93     int                 nfds;
94     fd_set              *readfds;
95     fd_set              *writefds;
96     fd_set              *exceptfds;
97
98     struct TM_Elem      timeout;
99
100     /* Result of select call */
101     long                        result;
102
103 };
104 \f
105 /********************************\
106 *                                *
107 *  Stuff for managing signals    *
108 *                                *
109 \********************************/
110
111 #define badsig(signo)           (((signo) <= 0) || ((signo) >= NSIG))
112 #define mysigmask(signo)                (1 << ((signo)-1))
113
114
115 fd_set openMask;                /* mask of open files on an IOMGR abort */
116 static afs_int32 sigsHandled;   /* sigmask(signo) is on if we handle signo */
117 static int anySigsDelivered;            /* true if any have been delivered. */
118 #ifndef AFS_NT40_ENV
119 static struct sigaction oldActions[NSIG];       /* the old signal vectors */
120 #endif
121 static char *sigEvents[NSIG];           /* the event to do an LWP signal on */
122 static int sigDelivered[NSIG];          /* True for signals delivered so far.
123                                            This is an int array to make sure
124                                            there are no conflicts when trying
125                                            to write it */
126 /* software 'signals' */
127 #define NSOFTSIG                4
128 static int (*sigProc[NSOFTSIG])();
129 static char *sigRock[NSOFTSIG];
130
131 \f
132 static struct IoRequest *iorFreeList = 0;
133
134 static struct TM_Elem *Requests;        /* List of requests */
135 static struct timeval iomgr_timeout;    /* global so signal handler can zap it */
136
137 /* stuff for debugging */
138 static int iomgr_errno;
139 static struct timeval iomgr_badtv;
140 static PROCESS iomgr_badpid;
141 static void SignalIO(int fds, fd_set *rfds, fd_set *wfds, fd_set *efs,
142                     int code);
143
144 /* fd_set pool managment. 
145  * Use the pool instead of creating fd_set's on the stack. fd_set's can be
146  * 2K in size, so making three could put 6K in the limited space of an LWP
147  * stack.
148  */
149 struct IOMGR_fd_set {
150     struct IOMGR_fd_set *next;
151 } *iomgrFreeFDSets = (struct IOMGR_fd_set*)0;
152
153 /* IOMGR_FreeFDSet
154  * Return fd_set to the free list.
155  */
156 void IOMGR_FreeFDSet(fd_set *s)
157 {
158     struct IOMGR_fd_set *t = (struct IOMGR_fd_set *)s;
159
160     t->next = iomgrFreeFDSets;
161     iomgrFreeFDSets = t;
162 }
163
164 /* IOMGR_AllocFDSet
165  * returns a zeroed fd_set or null if could not malloc one.
166  */
167 fd_set *IOMGR_AllocFDSet(void)
168 {
169     struct IOMGR_fd_set *t;
170     if (iomgrFreeFDSets) {
171         t =  iomgrFreeFDSets;
172         iomgrFreeFDSets = iomgrFreeFDSets->next;
173     }
174     else {
175         t = (struct IOMGR_fd_set *)malloc(sizeof(fd_set));
176     }
177     if (!t)
178         return (fd_set*)0;
179     else {
180         FD_ZERO((fd_set*)t);
181         return (fd_set*)t;
182     }
183 }
184
185 #define FreeRequest(x) ((x)->result = (long) iorFreeList, iorFreeList = (x))
186
187 static struct IoRequest *NewRequest()
188 {
189     struct IoRequest *request;
190
191     if (request=iorFreeList)
192         iorFreeList = (struct IoRequest *) (request->result);
193     else request = (struct IoRequest *) malloc(sizeof(struct IoRequest));
194
195     memset((char*)request, 0, sizeof(struct IoRequest));
196     return request;
197 }
198
199 #define Purge(list) FOR_ALL_ELTS(req, list, { free(req->BackPointer); })
200
201 \f
202 /* FD_SET support routines. All assume the fd_set size is a multiple of an int
203  * so we can at least do logical operations on ints instead of chars.
204  *
205  * For each routine, nfds is the highest bit set in either fd_set, starting
206  * with no bits == 0.
207  */
208 #ifdef AFS_NT40_ENV
209 #define FD_N_ZERO(A, x) FD_ZERO(x)
210 #else
211 #define FDS_P_POS (sizeof(int)*8)
212 #define INTS_PER_FDS(x) (((x)+(FDS_P_POS-1)) / FDS_P_POS)
213 #define FD_N_ZERO(nfds, x) bzero((char*)(x), (INTS_PER_FDS(nfds))*sizeof(int))
214 #endif
215
216 #if defined(AFS_LINUX22_ENV) && (__GLIBC_MINOR__ > 0)
217 /* Build for both glibc 2.0.x and 2.1.x */
218 #define FDS_BITS __fds_bits
219 #else
220 #define FDS_BITS fds_bits
221 #endif
222
223 /* FDSetCmp - returns 1 if any bits in fd_set1 are also set in fd_set2.
224  * If nfds is 0, or one of the fd_sets is null return 0 (since there is no bit
225  * set in both fd_sets).
226  */
227 static int FDSetCmp(int nfds, fd_set *fd_set1, fd_set *fd_set2)
228 {
229     unsigned int i, j;
230
231     if (fd_set1 == (fd_set*)0 || fd_set2 == (fd_set*)0)
232         return 0;
233
234 #ifdef AFS_NT40_ENV
235     if (fd_set1->fd_count == 0 || fd_set2->fd_count == 0)
236         return 0;
237
238     for (i=0; i<fd_set1->fd_count; i++) {
239         for (j=0; j<fd_set2->fd_count; j++) {
240         if (fd_set1->fd_array[i] == fd_set2->fd_array[j])
241             return 1;
242         }
243     }
244 #else
245     if (nfds == 0)
246         return 0;
247
248     j = INTS_PER_FDS(nfds);
249     for (i=0; i<j; i++) {
250         if (fd_set1->FDS_BITS[i] & fd_set2->FDS_BITS[i])
251             return 1;
252     }
253 #endif
254     return 0;
255 }
256
257 /* FDSetSet - set bits from fd_set2 into fd_set1
258  */
259 static void FDSetSet(int nfds, fd_set *fd_set1, fd_set *fd_set2)
260 {
261     unsigned int i, n;
262
263     if (fd_set1 == (fd_set*)0 || fd_set2 == (fd_set*)0)
264         return;
265
266 #ifdef AFS_NT40_ENV
267     if (fd_set2->fd_count==0)
268         return;
269
270     for (i=0; i<fd_set2->fd_count; i++)
271         FD_SET(fd_set2->fd_array[i], fd_set1);
272 #else
273     if (nfds == 0)
274         return;
275
276     n = INTS_PER_FDS(nfds);
277     for (i=0; i<n; i++) {
278         fd_set1->FDS_BITS[i] |= fd_set2->FDS_BITS[i];
279     }
280 #endif
281 }
282
283 /* FDSetAnd - fd_set1  <- fd_set1 & fd_set2. 
284  */
285 #ifdef AFS_NT40_ENV
286 static void FDSetAnd(int nfds, fd_set *fd_set1, fd_set *fd_set2)
287 {
288     unsigned int i;
289     fd_set tmpset;
290
291     if (fd_set1 == NULL || fd_set1->fd_count == 0)
292         return;
293     
294     if (fd_set2 == NULL || fd_set2->fd_count == 0) {
295         FD_ZERO(fd_set1);
296     }
297     else {
298         FD_ZERO(&tmpset);
299         for (i=0; i<fd_set2->fd_count; i++) {
300             if (FD_ISSET(fd_set2->fd_array[i], fd_set1))
301                 FD_SET(fd_set2->fd_array[i], &tmpset);
302         }
303         *fd_set1 = tmpset;
304     }
305 }
306 #else
307 static void FDSetAnd(int nfds, fd_set *fd_set1, fd_set *fd_set2)
308 {
309     int i, n;
310
311     if (nfds == 0 || fd_set1 == (fd_set*)0 || fd_set2 == (fd_set*)0)
312         return;
313
314     n = INTS_PER_FDS(nfds);
315     for (i=0; i<n; i++) {
316         fd_set1->FDS_BITS[i] &= fd_set2->FDS_BITS[i];
317     }
318 }
319 #endif
320             
321 /* FDSetEmpty - return true if fd_set is empty 
322  */
323 static int FDSetEmpty(int nfds, fd_set *fds)
324 {
325 #ifndef AFS_NT40_ENV
326     int i, n;
327
328     if (nfds == 0)
329         return 1;
330 #endif
331     if (fds == (fd_set*)0)
332         return 1;
333
334 #ifdef AFS_NT40_ENV
335     if (fds->fd_count == 0)
336         return 1;
337     else
338         return 0;
339 #else
340     n = INTS_PER_FDS(nfds);
341
342     for (i=n-1; i>=0; i--) {
343         if (fds->FDS_BITS[i])
344             break;
345     }
346
347     if (i>=0)
348         return 0;
349     else
350         return 1;
351 #endif
352 }
353
354 /* The IOMGR process */
355
356 /*
357  * Important invariant: process->iomgrRequest is null iff request not in timer
358  * queue.
359  * also, request->pid is valid while request is in queue,
360  * also, don't signal selector while request in queue, since selector frees
361  *  request.
362  */
363
364 /* These are not declared in IOMGR so that they don't use up 6K of stack. */
365 static fd_set IOMGR_readfds, IOMGR_writefds, IOMGR_exceptfds;
366 static int IOMGR_nfds = 0;
367
368 static int IOMGR(void *dummy)
369 {
370     for (;;) {
371         int code;
372         struct TM_Elem *earliest;
373         struct timeval timeout, junk;
374         bool woke_someone;
375 #ifndef AFS_NT40_ENV
376         int fds;
377 #endif
378
379         FD_ZERO(&IOMGR_readfds);
380         FD_ZERO(&IOMGR_writefds);
381         FD_ZERO(&IOMGR_exceptfds);
382         IOMGR_nfds = 0;
383
384         /* Wake up anyone who has expired or who has received a
385            Unix signal between executions.  Keep going until we
386            run out. */
387         do {
388             woke_someone = FALSE;
389             /* Wake up anyone waiting on signals. */
390             /* Note: SignalSignals() may yield! */
391             if (anySigsDelivered && SignalSignals ())
392                 woke_someone = TRUE;
393             FT_GetTimeOfDay(&junk, 0);    /* force accurate time check */
394             TM_Rescan(Requests);
395             for (;;) {
396                 register struct IoRequest *req;
397                 struct TM_Elem *expired;
398                 expired = TM_GetExpired(Requests);
399                 if (expired == NULL) break;
400                 woke_someone = TRUE;
401                 req = (struct IoRequest *) expired -> BackPointer;
402 #ifdef DEBUG
403                 if (lwp_debug != 0) puts("[Polling SELECT]");
404 #endif /* DEBUG */
405                 /* no data ready */
406                 if (req->readfds)   FD_N_ZERO(req->nfds, req->readfds);
407                 if (req->writefds)  FD_N_ZERO(req->nfds, req->writefds);
408                 if (req->exceptfds) FD_N_ZERO(req->nfds, req->exceptfds);
409                 req->nfds = 0;
410                 req->result = 0; /* no fds ready */
411                 TM_Remove(Requests, &req->timeout);
412 #ifdef DEBUG
413                 req -> timeout.Next = (struct TM_Elem *) 2;
414                 req -> timeout.Prev = (struct TM_Elem *) 2;
415 #endif /* DEBUG */
416                 LWP_QSignal(req->pid);
417                 req->pid->iomgrRequest = 0;
418             }
419             if (woke_someone) LWP_DispatchProcess();
420         } while (woke_someone);
421
422         /* Collect requests & update times */
423         FD_ZERO(&IOMGR_readfds);
424         FD_ZERO(&IOMGR_writefds);
425         FD_ZERO(&IOMGR_exceptfds);
426         IOMGR_nfds = 0;
427
428         FOR_ALL_ELTS(r, Requests, {
429             register struct IoRequest *req;
430             req = (struct IoRequest *) r -> BackPointer;
431             FDSetSet(req->nfds, &IOMGR_readfds,   req->readfds);
432             FDSetSet(req->nfds, &IOMGR_writefds,  req->writefds);
433             FDSetSet(req->nfds, &IOMGR_exceptfds, req->exceptfds);
434             if (req->nfds > IOMGR_nfds)
435                 IOMGR_nfds = req->nfds;
436         })
437         earliest = TM_GetEarliest(Requests);
438         if (earliest != NULL) {
439             timeout = earliest -> TimeLeft;
440
441
442             /* Do select */
443 #ifdef DEBUG
444             if (lwp_debug != 0) {
445 #ifdef AFS_NT40_ENV
446                 int idbg;
447                 printf("[Read Select:");
448                 if (IOMGR_readfds.fd_count == 0)
449                     printf(" none]\n");
450                 else {
451                     for (idbg=0; idbg<IOMGR_readfds.fd_count; idbg++)
452                         printf(" %d", IOMGR_readfds.fd_array[idbg]);
453                     printf("]\n");
454                 }
455                 printf("[Write Select:");
456                 if (IOMGR_writefds.fd_count == 0)
457                     printf(" none]\n");
458                 else {
459                     for (idbg=0; idbg<IOMGR_writefds.fd_count; idbg++)
460                         printf(" %d", IOMGR_writefds.fd_array[idbg]);
461                     printf("]\n");
462                 }
463                 printf("[Except Select:");
464                 if (IOMGR_exceptfds.fd_count == 0)
465                     printf(" none]\n");
466                 else {
467                     for (idbg=0; idbg<IOMGR_exceptfds.fd_count; idbg++)
468                         printf(" %d", IOMGR_exceptfds.fd_array[idbg]);
469                     printf("]\n");
470                 }
471 #else
472                 /* Only prints first 32. */
473                 printf("[select(%d, 0x%x, 0x%x, 0x%x, ", IOMGR_nfds,
474                        *(int*)&IOMGR_readfds, *(int*)&IOMGR_writefds,
475                        *(int*)&IOMGR_exceptfds);
476 #endif /* AFS_NT40_ENV */
477                 if (timeout.tv_sec == -1 && timeout.tv_usec == -1)
478                     puts("INFINITE)]");
479                 else
480                     printf("<%d, %d>)]\n", timeout.tv_sec, timeout.tv_usec);
481             }
482 #endif /* DEBUG */
483             iomgr_timeout = timeout;
484             if (timeout.tv_sec == -1 && timeout.tv_usec == -1) {
485                 /* infinite, sort of */
486                 iomgr_timeout.tv_sec = 100000000;
487                 iomgr_timeout.tv_usec = 0;
488             }
489 #ifdef AFS_NT40_ENV
490             /* On NT, signals don't interrupt a select call. So this can potentially
491              * lead to long wait times before a signal is honored. To avoid this we
492              * dont do select() for longer than IOMGR_MAXWAITTIME (5 secs) */
493             if (iomgr_timeout.tv_sec > (IOMGR_MAXWAITTIME - 1)) {
494               iomgr_timeout.tv_sec = IOMGR_MAXWAITTIME;
495               iomgr_timeout.tv_usec = 0;
496             }
497 #endif /* NT40 */
498
499             /* Check one last time for a signal delivery.  If one comes after
500                this, the signal handler will set iomgr_timeout to zero, causing
501                the select to return immediately.  The timer package won't return
502                a zero timeval because all of those guys were handled above.
503
504                I'm assuming that the kernel masks signals while it's picking up
505                the parameters to select.  This may a bad assumption.  -DN */
506             if (anySigsDelivered)
507                 continue;       /* go to the top and handle them. */
508
509 #ifdef AFS_NT40_ENV
510             if (IOMGR_readfds.fd_count == 0 && IOMGR_writefds.fd_count == 0
511                 && IOMGR_exceptfds.fd_count == 0) {
512                 DWORD stime;
513                 code = 0;
514                 if (iomgr_timeout.tv_sec || iomgr_timeout.tv_usec) {
515                     stime = iomgr_timeout.tv_sec * 1000
516                         + iomgr_timeout.tv_usec/1000;
517                     if (!stime)
518                         stime = 1;
519                     Sleep(stime);
520                 }
521             }
522             else
523 #endif
524                 {    /* select runs much faster if 0's are passed instead of &0s */
525                     code = select(IOMGR_nfds,
526                                   (FDSetEmpty(IOMGR_nfds, &IOMGR_readfds)) ?
527                                   (fd_set*)0 : &IOMGR_readfds,
528                                   (FDSetEmpty(IOMGR_nfds, &IOMGR_writefds)) ?
529                                   (fd_set*)0 : &IOMGR_writefds,
530                                   (FDSetEmpty(IOMGR_nfds, &IOMGR_exceptfds)) ?
531                                   (fd_set*)0 : &IOMGR_exceptfds,
532                                   &iomgr_timeout);
533                 }
534
535             if (code < 0) {
536                int e=1;
537
538 #if defined(AFS_SUN_ENV)
539                /* Tape drives on Sun boxes do not support select and return ENXIO */
540                if (errno == ENXIO) e=0, code=1;
541 #endif
542 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_AIX32_ENV)
543                /* For SGI and SVR4 - poll & select can return EAGAIN ... */
544                if (errno == EAGAIN) e=0;
545 #endif
546 #if defined(AFS_SUN5_ENV)
547                /* On sun4x_55, select doesn't block signal. It could be
548                   interupted by a signal that changes iomgr_timeout, and
549                   then select returns with EINVAL. In this case, we need
550                   to retry.
551                 */
552                if (errno==EINVAL && anySigsDelivered)
553                    e = 0;
554 #endif /* AFS_SUN5_ENV */
555
556                if ((errno != EINTR) && e) {
557 #ifndef AFS_NT40_ENV
558                   int i;
559                   for(i=0; i<FD_SETSIZE; i++) {
560                      if (fcntl(i, F_GETFD, 0) < 0 && errno == EBADF)
561                          FD_SET(i, &openMask);
562                   }
563 #endif
564                   iomgr_errno = errno;
565                   lwp_abort();
566                }
567             }
568
569             /* See what happened */
570             if (code > 0) {
571                 /* Action -- wake up everyone involved */
572                 SignalIO(IOMGR_nfds, &IOMGR_readfds, &IOMGR_writefds,
573                          &IOMGR_exceptfds, code);
574             }
575             else if (code == 0
576                 && (iomgr_timeout.tv_sec != 0 || iomgr_timeout.tv_usec != 0)) {
577                 /* Real timeout only if signal handler hasn't set
578                    iomgr_timeout to zero. */
579
580 #ifdef AFS_NT40_ENV
581                 /* On NT, real timeout only if above and if iomgr_timeout
582                  * interval is equal to timeout interval (i.e., not adjusted
583                  * to check for pseudo-signals).
584                  */
585                 if (iomgr_timeout.tv_sec  != timeout.tv_sec ||
586                     iomgr_timeout.tv_usec != timeout.tv_usec) {
587                     /* signal check interval timed out; not real timeout */
588                     continue;
589                 }
590 #endif /* AFS_NT40_ENV */
591
592                 FT_GetTimeOfDay(&junk, 0);
593                 SignalTimeout(code, &timeout);
594             }
595         }
596         LWP_DispatchProcess();
597     }
598     return -1; /* keeps compilers happy. */
599 }
600 \f
601 /************************\
602 *                        *
603 *  Signalling routines   *
604 *                        *
605 \************************/
606
607 static void SignalIO(int fds, fd_set *readfds, fd_set *writefds,
608                      fd_set *exceptfds, int code)
609 {
610     int nfds;
611     /* Look at everyone who's bit mask was affected */
612     FOR_ALL_ELTS(r, Requests, {
613         register struct IoRequest *req;
614         register PROCESS pid;
615         req = (struct IoRequest *) r -> BackPointer;
616         nfds = MIN(fds, req->nfds);
617         if (FDSetCmp(nfds, req->readfds, readfds) ||
618             FDSetCmp(nfds, req->writefds, writefds) ||
619             FDSetCmp(nfds, req->exceptfds, exceptfds)) {
620             /* put ready fd's into request. */
621             FDSetAnd(nfds, req->readfds, readfds);
622             FDSetAnd(nfds, req->writefds, writefds);
623             FDSetAnd(nfds, req->exceptfds, exceptfds);
624             req -> result = code;
625             TM_Remove(Requests, &req->timeout);
626             LWP_QSignal(pid=req->pid);
627             pid->iomgrRequest = 0;
628         }
629     })
630 }
631
632 static void SignalTimeout(int code, struct timeval *timeout)
633 {
634     /* Find everyone who has specified timeout */
635     FOR_ALL_ELTS(r, Requests, {
636         register struct IoRequest *req;
637         register PROCESS pid;
638         req = (struct IoRequest *) r -> BackPointer;
639         if (TM_eql(&r->TimeLeft, timeout)) {
640             req -> result = code;
641             TM_Remove(Requests, &req->timeout);
642             LWP_QSignal(pid=req->pid);
643             pid->iomgrRequest = 0;
644         } else
645             return;
646     })
647 }
648 \f
649 /*****************************************************\
650 *                                                     *
651 *  Signal handling routine (not to be confused with   *
652 *  signalling routines, above).                       *
653 *                                                     *
654 \*****************************************************/
655 static void SigHandler (signo)
656     int signo;
657 {
658     if (badsig(signo) || (sigsHandled & mysigmask(signo)) == 0)
659         return;         /* can't happen. */
660     sigDelivered[signo] = TRUE;
661     anySigsDelivered = TRUE;
662     /* Make sure that the IOMGR process doesn't pause on the select. */
663     iomgr_timeout.tv_sec = 0;
664     iomgr_timeout.tv_usec = 0;
665 }
666
667 /* Alright, this is the signal signalling routine.  It delivers LWP signals
668    to LWPs waiting on Unix signals. NOW ALSO CAN YIELD!! */
669 static int SignalSignals ()
670 {
671     bool gotone = FALSE;
672     register int i;
673     register int (*p)();
674     afs_int32 stackSize;
675
676     anySigsDelivered = FALSE;
677
678     /* handle software signals */
679     stackSize = (AFS_LWP_MINSTACKSIZE < lwp_MaxStackSeen? lwp_MaxStackSeen : AFS_LWP_MINSTACKSIZE);
680     for (i=0; i < NSOFTSIG; i++) {
681         PROCESS pid;
682         if (p=sigProc[i]) /* This yields!!! */
683             LWP_CreateProcess2(p, stackSize, LWP_NORMAL_PRIORITY, sigRock[i],
684                 "SignalHandler", &pid);
685         sigProc[i] = 0;
686     }
687
688     for (i = 1; i <= NSIG; ++i)  /* forall !badsig(i) */
689         if ((sigsHandled & mysigmask(i)) && sigDelivered[i] == TRUE) {
690             sigDelivered[i] = FALSE;
691             LWP_NoYieldSignal (sigEvents[i]);
692             gotone = TRUE;
693         }
694     return gotone;
695 }
696
697 \f
698 /***************************\
699 *                           *
700 *  User-callable routines   *
701 *                           *
702 \***************************/
703
704
705 /* Keep IOMGR process id */
706 static PROCESS IOMGR_Id = NULL;
707
708 int IOMGR_SoftSig(aproc, arock)
709 int (*aproc)();
710 char *arock; {
711     register int i;
712     for (i=0;i<NSOFTSIG;i++) {
713         if (sigProc[i] == 0) {
714             /* a free entry */
715             sigProc[i] = aproc;
716             sigRock[i] = arock;
717             anySigsDelivered = TRUE;
718             iomgr_timeout.tv_sec = 0;
719             iomgr_timeout.tv_usec = 0;
720             return 0;
721         }
722     }
723     return -1;
724 }
725
726
727 unsigned char allOnes[100];
728
729 int IOMGR_Initialize(void)
730 {
731     extern int TM_Init();
732     PROCESS pid;
733
734     /* If lready initialized, just return */
735     if (IOMGR_Id != NULL) return LWP_SUCCESS;
736
737     /* Init LWP if someone hasn't yet. */
738     if (LWP_InitializeProcessSupport (LWP_NORMAL_PRIORITY, &pid) != LWP_SUCCESS)
739         return -1;
740
741     /* Initialize request lists */
742     if (TM_Init(&Requests) < 0) return -1;
743
744     /* Initialize signal handling stuff. */
745     sigsHandled = 0;
746     anySigsDelivered = TRUE; /* A soft signal may have happened before
747         IOMGR_Initialize:  so force a check for signals regardless */
748     memset(allOnes, 0xff, sizeof(allOnes));
749
750     return LWP_CreateProcess(IOMGR, AFS_LWP_MINSTACKSIZE, 0, 0, "IO MANAGER",
751                              &IOMGR_Id);
752 }
753
754 int IOMGR_Finalize()
755 {
756     int status;
757
758     Purge(Requests)
759     TM_Final(&Requests);
760     status = LWP_DestroyProcess(IOMGR_Id);
761     IOMGR_Id = NULL;
762     return status;
763 }
764 \f
765 /* signal I/O for anyone who is waiting for a FD or a timeout; not too cheap,
766  * since forces select and timeofday check */
767 int IOMGR_Poll(void) {
768     fd_set *readfds, *writefds, *exceptfds;
769     afs_int32 code;
770     struct timeval tv;
771     int fds;
772
773     FT_GetTimeOfDay(&tv, 0);    /* force accurate time check */
774     TM_Rescan(Requests);
775     for (;;) {
776         register struct IoRequest *req;
777         struct TM_Elem *expired;
778         expired = TM_GetExpired(Requests);
779         if (expired == NULL) break;
780         req = (struct IoRequest *) expired -> BackPointer;
781 #ifdef DEBUG
782         if (lwp_debug != 0) puts("[Polling SELECT]");
783 #endif /* DEBUG */
784         /* no data ready */
785         if (req->readfds)   FD_N_ZERO(req->nfds, req->readfds);
786         if (req->writefds)  FD_N_ZERO(req->nfds, req->writefds);
787         if (req->exceptfds) FD_N_ZERO(req->nfds, req->exceptfds);
788         req->nfds = 0;
789         req->result = 0; /* no fds ready */
790         TM_Remove(Requests, &req->timeout);
791 #ifdef DEBUG
792         req -> timeout.Next = (struct TM_Elem *) 2;
793         req -> timeout.Prev = (struct TM_Elem *) 2;
794 #endif /* DEBUG */
795         LWP_QSignal(req->pid);
796         req->pid->iomgrRequest = 0;
797     }
798
799     /* Collect requests & update times */
800     readfds = IOMGR_AllocFDSet();
801     writefds = IOMGR_AllocFDSet();
802     exceptfds = IOMGR_AllocFDSet();
803     if (!(readfds && writefds && exceptfds)) {
804         fprintf(stderr, "IOMGR_Poll: Could not malloc space for fd_sets.\n");
805         fflush(stderr);
806     }
807
808     fds = 0;
809
810     FOR_ALL_ELTS(r, Requests, {
811         register struct IoRequest *req;
812         req = (struct IoRequest *) r -> BackPointer;
813         FDSetSet(req->nfds, readfds,   req->readfds);
814         FDSetSet(req->nfds, writefds,  req->writefds);
815         FDSetSet(req->nfds, exceptfds, req->exceptfds);
816         if (fds < req->nfds)
817             fds = req->nfds;
818     })
819         
820     tv.tv_sec = 0;
821     tv.tv_usec = 0;
822 #ifdef AFS_NT40_ENV
823     code = -1;
824     if (readfds->fd_count == 0 && writefds->fd_count == 0
825         && exceptfds->fd_count == 0)
826 #endif
827         code = select(fds, readfds, writefds, exceptfds, &tv);
828     if (code > 0) {
829         SignalIO(fds, readfds, writefds, exceptfds, code);
830     }
831
832     if (readfds) IOMGR_FreeFDSet(readfds);
833     if (writefds) IOMGR_FreeFDSet(writefds);
834     if (exceptfds) IOMGR_FreeFDSet(exceptfds);
835
836
837     LWP_DispatchProcess();  /* make sure others run */
838     LWP_DispatchProcess();
839     return 0;
840 }
841
842 int IOMGR_Select(fds, readfds, writefds, exceptfds, timeout)
843      int fds;
844      fd_set *readfds, *writefds, *exceptfds;
845      struct timeval *timeout;
846 {
847     register struct IoRequest *request;
848     int result;
849
850 #ifndef AFS_NT40_ENV
851     if(fds > FD_SETSIZE) {
852         fprintf(stderr, "IOMGR_Select: fds=%d, more than max %d\n",
853                 fds, FD_SETSIZE);
854         fflush(stderr);
855         lwp_abort();
856     }
857 #endif
858
859     /* See if polling request. If so, handle right here */
860     if (timeout != NULL) {
861         if (timeout->tv_sec == 0 && timeout->tv_usec == 0) {
862             int code;
863 #ifdef DEBUG
864             if (lwp_debug != 0) puts("[Polling SELECT]");
865 #endif /* DEBUG */
866 again:
867             code = select(fds, readfds, writefds, exceptfds, timeout);
868 #if     defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_AIX32_ENV)
869             /*
870              * For SGI and SVR4 - poll & select can return EAGAIN ...
871              */
872             /*
873              * this is basically for SGI, but I believe stock SVR4 (Solaris?)
874              * can also get this error return
875              */
876             if (code < 0 && errno == EAGAIN)
877                 goto again;     
878 #endif
879 #ifdef AFS_NT40_ENV
880             if (code == SOCKET_ERROR) {
881                 if (WSAGetLastError() == WSAEINPROGRESS)
882                     goto again;
883
884                 code = -1;
885             }
886 #endif
887             return (code > 1 ? 1 : code);
888         }
889     }
890
891     /* Construct request block & insert */
892     request = NewRequest(); /* zeroes fd_set's */
893     if (readfds && !FDSetEmpty(fds, readfds))
894         request->readfds = readfds;
895     if (writefds && !FDSetEmpty(fds, writefds))
896         request->writefds = writefds;
897     if (exceptfds && !FDSetEmpty(fds, exceptfds))
898         request->exceptfds = exceptfds;
899     request->nfds = fds;
900
901     if (timeout == NULL) {
902         request -> timeout.TotalTime.tv_sec = -1;
903         request -> timeout.TotalTime.tv_usec = -1;
904     } else {
905         request -> timeout.TotalTime = *timeout;
906         /* check for bad request */
907         if (timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec > 999999) {
908             /* invalid arg */
909             iomgr_badtv = *timeout;
910             iomgr_badpid = LWP_ActiveProcess;
911             /* now fixup request */
912             if(request->timeout.TotalTime.tv_sec < 0)
913                 request->timeout.TotalTime.tv_sec = 1;
914             request->timeout.TotalTime.tv_usec = 100000;
915         }
916     }
917
918     request -> timeout.BackPointer = (char *) request;
919
920     /* Insert my PID in case of IOMGR_Cancel */
921     request -> pid = LWP_ActiveProcess;
922     LWP_ActiveProcess -> iomgrRequest = request;
923
924 #ifdef DEBUG
925     request -> timeout.Next = (struct TM_Elem *) 1;
926     request -> timeout.Prev = (struct TM_Elem *) 1;
927 #endif /* DEBUG */
928     TM_Insert(Requests, &request->timeout);
929
930     /* Wait for action */
931     LWP_QWait();
932
933     /* Update parameters & return */
934     result = request -> result;
935
936     FreeRequest(request);
937     return (result > 1 ? 1 : result);
938 }
939 \f
940 int IOMGR_Cancel(PROCESS pid)
941 {
942     register struct IoRequest *request;
943
944     if ((request = pid->iomgrRequest) == 0) return -1;  /* Pid not found */
945
946     if (request->readfds)   FD_N_ZERO(request->nfds, request->readfds);
947     if (request->writefds)  FD_N_ZERO(request->nfds, request->writefds);
948     if (request->exceptfds) FD_N_ZERO(request->nfds, request->exceptfds);
949     request->nfds = 0;
950
951     request -> result = -2;
952     TM_Remove(Requests, &request->timeout);
953 #ifdef DEBUG
954     request -> timeout.Next = (struct TM_Elem *) 5;
955     request -> timeout.Prev = (struct TM_Elem *) 5;
956 #endif /* DEBUG */
957     LWP_QSignal(request->pid);
958     pid->iomgrRequest = 0;
959
960     return 0;
961 }
962 \f
963 #ifndef AFS_NT40_ENV
964 /* Cause delivery of signal signo to result in a LWP_SignalProcess of
965    event. */
966 IOMGR_Signal (signo, event)
967     int signo;
968     char *event;
969 {
970     struct sigaction sa;
971
972     if (badsig(signo))
973         return LWP_EBADSIG;
974     if (event == NULL)
975         return LWP_EBADEVENT;
976     sa.sa_handler = SigHandler;
977     sa.sa_mask = *((sigset_t *) allOnes);       /* mask all signals */
978     sa.sa_flags = 0;
979     sigsHandled |= mysigmask(signo);
980     sigEvents[signo] = event;
981     sigDelivered[signo] = FALSE;
982     if (sigaction (signo, &sa, &oldActions[signo]) == -1)
983         return LWP_ESYSTEM;
984     return LWP_SUCCESS;
985 }
986
987 /* Stop handling occurrences of signo. */
988 IOMGR_CancelSignal (signo)
989     int signo;
990 {
991     if (badsig(signo) || (sigsHandled & mysigmask(signo)) == 0)
992         return LWP_EBADSIG;
993     sigaction (signo, &oldActions[signo], (struct sigaction *)0);
994     sigsHandled &= ~mysigmask(signo);
995     return LWP_SUCCESS;
996 }
997 #endif /* AFS_NT40_ENV */
998 /* This routine calls select is a fashion that simulates the standard sleep routine */
999 void IOMGR_Sleep (int seconds)
1000 {
1001     struct timeval timeout;
1002
1003     timeout.tv_sec = seconds;
1004     timeout.tv_usec = 0;
1005     IOMGR_Select(0, 0, 0, 0, &timeout);
1006 }
1007 #endif  /* USE_PTHREADS */
1008