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