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