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