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