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