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