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