rx-lwp-fdsetsize-20040708
[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 #ifdef AFS_NT40_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             if (iomgr_timeout.tv_sec > (IOMGR_MAXWAITTIME - 1)) {
544               iomgr_timeout.tv_sec = IOMGR_MAXWAITTIME;
545               iomgr_timeout.tv_usec = 0;
546             }
547 #endif /* NT40 */
548
549 #ifdef AFS_DJGPP_ENV
550             /* We do this also for the DOS-box Win95 client, since
551                NCB calls don't interrupt a select, but we want to catch them
552                in a reasonable amount of time (say, half a second). */
553             iomgr_timeout.tv_sec = 0;
554             iomgr_timeout.tv_usec = IOMGR_WIN95WAITTIME;
555 #endif /* DJGPP */
556
557             /* Check one last time for a signal delivery.  If one comes after
558                this, the signal handler will set iomgr_timeout to zero, causing
559                the select to return immediately.  The timer package won't return
560                a zero timeval because all of those guys were handled above.
561
562                I'm assuming that the kernel masks signals while it's picking up
563                the parameters to select.  This may a bad assumption.  -DN */
564             if (anySigsDelivered)
565                 continue;       /* go to the top and handle them. */
566
567 #ifdef AFS_DJGPP_ENV
568             if (IOMGR_CheckNCB())    /* check for completed netbios requests */
569               LWP_DispatchProcess();
570 #endif /* AFS_DJGPP_ENV */
571
572 #ifdef AFS_NT40_ENV
573             if (IOMGR_readfds.fd_count == 0 && IOMGR_writefds.fd_count == 0
574                 && IOMGR_exceptfds.fd_count == 0) {
575                 DWORD stime;
576                 code = 0;
577                 if (iomgr_timeout.tv_sec || iomgr_timeout.tv_usec) {
578                     stime = iomgr_timeout.tv_sec * 1000
579                         + iomgr_timeout.tv_usec/1000;
580                     if (!stime)
581                         stime = 1;
582                     Sleep(stime);
583                 }
584             }
585             else
586 #endif
587                 {    /* select runs much faster if 0's are passed instead of &0s */
588                     code = select(IOMGR_nfds,
589                                   (FDSetEmpty(IOMGR_nfds, &IOMGR_readfds)) ?
590                                   (fd_set*)0 : &IOMGR_readfds,
591                                   (FDSetEmpty(IOMGR_nfds, &IOMGR_writefds)) ?
592                                   (fd_set*)0 : &IOMGR_writefds,
593                                   (FDSetEmpty(IOMGR_nfds, &IOMGR_exceptfds)) ?
594                                   (fd_set*)0 : &IOMGR_exceptfds,
595                                   &iomgr_timeout);
596                 }
597
598             if (code < 0) {
599                int e=1;
600
601 #if defined(AFS_SUN_ENV)
602                /* Tape drives on Sun boxes do not support select and return ENXIO */
603                if (errno == ENXIO) e=0, code=1;
604 #endif
605 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_AIX32_ENV)
606                /* For SGI and SVR4 - poll & select can return EAGAIN ... */
607                if (errno == EAGAIN) e=0;
608 #endif
609 #if defined(AFS_SUN5_ENV)
610                /* On sun4x_55, select doesn't block signal. It could be
611                   interupted by a signal that changes iomgr_timeout, and
612                   then select returns with EINVAL. In this case, we need
613                   to retry.
614                 */
615                if (errno==EINVAL && anySigsDelivered)
616                    e = 0;
617 #endif /* AFS_SUN5_ENV */
618
619                if ((errno != EINTR) && e) {
620 #ifndef AFS_NT40_ENV
621                   int i;
622                   for(i=0; i<FD_SETSIZE; i++) {
623                      if (fcntl(i, F_GETFD, 0) < 0 && errno == EBADF)
624                          FD_SET(i, &openMask);
625                   }
626 #endif
627                   iomgr_errno = errno;
628                   lwp_abort();
629                }
630             }
631
632             /* See what happened */
633             if (code > 0) {
634                 /* Action -- wake up everyone involved */
635                 SignalIO(IOMGR_nfds, &IOMGR_readfds, &IOMGR_writefds,
636                          &IOMGR_exceptfds, code);
637             }
638             else if (code == 0
639                 && (iomgr_timeout.tv_sec != 0 || iomgr_timeout.tv_usec != 0)) {
640                 /* Real timeout only if signal handler hasn't set
641                    iomgr_timeout to zero. */
642
643 #ifdef AFS_NT40_ENV
644                 /* On NT, real timeout only if above and if iomgr_timeout
645                  * interval is equal to timeout interval (i.e., not adjusted
646                  * to check for pseudo-signals).
647                  */
648                 if (iomgr_timeout.tv_sec  != timeout.tv_sec ||
649                     iomgr_timeout.tv_usec != timeout.tv_usec) {
650                     /* signal check interval timed out; not real timeout */
651                     continue;
652                 }
653 #endif /* AFS_NT40_ENV */
654 #ifndef AFS_DJGPP_ENV
655                 FT_GetTimeOfDay(&junk, 0);
656 #endif
657                 SignalTimeout(code, &timeout);
658             }
659 #ifdef AFS_DJGPP_ENV
660             IOMGR_CheckNCB();
661 #endif /* AFS_DJGPP_ENV */
662         }
663         LWP_DispatchProcess();
664     }
665     return -1; /* keeps compilers happy. */
666 }
667 \f
668 /************************\
669 *                        *
670 *  Signalling routines   *
671 *                        *
672 \************************/
673
674 static void SignalIO(int fds, fd_set *readfds, fd_set *writefds,
675                      fd_set *exceptfds, int code)
676 {
677     int nfds;
678     /* Look at everyone who's bit mask was affected */
679     FOR_ALL_ELTS(r, Requests, {
680         register struct IoRequest *req;
681         register PROCESS pid;
682         req = (struct IoRequest *) r -> BackPointer;
683         nfds = MIN(fds, req->nfds);
684         if (FDSetCmp(nfds, req->readfds, readfds) ||
685             FDSetCmp(nfds, req->writefds, writefds) ||
686             FDSetCmp(nfds, req->exceptfds, exceptfds)) {
687             /* put ready fd's into request. */
688             FDSetAnd(nfds, req->readfds, readfds);
689             FDSetAnd(nfds, req->writefds, writefds);
690             FDSetAnd(nfds, req->exceptfds, exceptfds);
691             req -> result = code;
692             TM_Remove(Requests, &req->timeout);
693             LWP_QSignal(pid=req->pid);
694             pid->iomgrRequest = 0;
695         }
696     })
697 }
698
699 static void SignalTimeout(int code, struct timeval *timeout)
700 {
701     /* Find everyone who has specified timeout */
702     FOR_ALL_ELTS(r, Requests, {
703         register struct IoRequest *req;
704         register PROCESS pid;
705         req = (struct IoRequest *) r -> BackPointer;
706         if (TM_eql(&r->TimeLeft, timeout)) {
707             req -> result = code;
708             TM_Remove(Requests, &req->timeout);
709             LWP_QSignal(pid=req->pid);
710             pid->iomgrRequest = 0;
711         } else
712             return;
713     })
714 }
715 \f
716 /*****************************************************\
717 *                                                     *
718 *  Signal handling routine (not to be confused with   *
719 *  signalling routines, above).                       *
720 *                                                     *
721 \*****************************************************/
722 static void SigHandler (signo)
723     int signo;
724 {
725     if (badsig(signo) || (sigsHandled & mysigmask(signo)) == 0)
726         return;         /* can't happen. */
727     sigDelivered[signo] = TRUE;
728     anySigsDelivered = TRUE;
729     /* Make sure that the IOMGR process doesn't pause on the select. */
730     iomgr_timeout.tv_sec = 0;
731     iomgr_timeout.tv_usec = 0;
732 }
733
734 /* Alright, this is the signal signalling routine.  It delivers LWP signals
735    to LWPs waiting on Unix signals. NOW ALSO CAN YIELD!! */
736 static int SignalSignals (void)
737 {
738     bool gotone = FALSE;
739     register int i;
740     register int (*p)();
741     afs_int32 stackSize;
742
743     anySigsDelivered = FALSE;
744
745     /* handle software signals */
746     stackSize = (AFS_LWP_MINSTACKSIZE < lwp_MaxStackSeen? lwp_MaxStackSeen : AFS_LWP_MINSTACKSIZE);
747     for (i=0; i < NSOFTSIG; i++) {
748         PROCESS pid;
749         if (p=sigProc[i]) /* This yields!!! */
750             LWP_CreateProcess2(p, stackSize, LWP_NORMAL_PRIORITY, 
751                                (void *) sigRock[i], "SignalHandler", &pid);
752         sigProc[i] = 0;
753     }
754
755     for (i = 1; i <= NSIG; ++i)  /* forall !badsig(i) */
756         if ((sigsHandled & mysigmask(i)) && sigDelivered[i] == TRUE) {
757             sigDelivered[i] = FALSE;
758             LWP_NoYieldSignal (sigEvents[i]);
759             gotone = TRUE;
760         }
761     return gotone;
762 }
763
764 \f
765 /***************************\
766 *                           *
767 *  User-callable routines   *
768 *                           *
769 \***************************/
770
771
772 /* Keep IOMGR process id */
773 static PROCESS IOMGR_Id = NULL;
774
775 int IOMGR_SoftSig(aproc, arock)
776 int (*aproc)();
777 char *arock; {
778     register int i;
779     for (i=0;i<NSOFTSIG;i++) {
780         if (sigProc[i] == 0) {
781             /* a free entry */
782             sigProc[i] = aproc;
783             sigRock[i] = arock;
784             anySigsDelivered = TRUE;
785             iomgr_timeout.tv_sec = 0;
786             iomgr_timeout.tv_usec = 0;
787             return 0;
788         }
789     }
790     return -1;
791 }
792
793
794 unsigned char allOnes[100];
795
796 int IOMGR_Initialize(void)
797 {
798     extern int TM_Init();
799     PROCESS pid;
800
801     /* If lready initialized, just return */
802     if (IOMGR_Id != NULL) return LWP_SUCCESS;
803
804     /* Init LWP if someone hasn't yet. */
805     if (LWP_InitializeProcessSupport (LWP_NORMAL_PRIORITY, &pid) != LWP_SUCCESS)
806         return -1;
807
808     /* Initialize request lists */
809     if (TM_Init(&Requests) < 0) return -1;
810
811     /* Initialize signal handling stuff. */
812     sigsHandled = 0;
813     anySigsDelivered = TRUE; /* A soft signal may have happened before
814         IOMGR_Initialize:  so force a check for signals regardless */
815     memset(allOnes, 0xff, sizeof(allOnes));
816
817 #ifdef AFS_DJGPP_ENV
818     install_ncb_handler();
819 #endif /* AFS_DJGPP_ENV */
820
821     return LWP_CreateProcess(IOMGR, AFS_LWP_MINSTACKSIZE, 0, (void *) 0, 
822                              "IO MANAGER", &IOMGR_Id);
823 }
824
825 int IOMGR_Finalize()
826 {
827     int status;
828
829     Purge(Requests)
830     TM_Final(&Requests);
831     status = LWP_DestroyProcess(IOMGR_Id);
832     IOMGR_Id = NULL;
833     return status;
834 }
835 \f
836 /* signal I/O for anyone who is waiting for a FD or a timeout; not too cheap,
837  * since forces select and timeofday check */
838 int IOMGR_Poll(void) {
839     fd_set *readfds, *writefds, *exceptfds;
840     afs_int32 code;
841     struct timeval tv;
842     int fds;
843
844     FT_GetTimeOfDay(&tv, 0);    /* force accurate time check */
845     TM_Rescan(Requests);
846     for (;;) {
847         register struct IoRequest *req;
848         struct TM_Elem *expired;
849         expired = TM_GetExpired(Requests);
850         if (expired == NULL) break;
851         req = (struct IoRequest *) expired -> BackPointer;
852 #ifdef DEBUG
853         if (lwp_debug != 0) puts("[Polling SELECT]");
854 #endif /* DEBUG */
855         /* no data ready */
856         if (req->readfds)   FD_N_ZERO(req->nfds, req->readfds);
857         if (req->writefds)  FD_N_ZERO(req->nfds, req->writefds);
858         if (req->exceptfds) FD_N_ZERO(req->nfds, req->exceptfds);
859         req->nfds = 0;
860         req->result = 0; /* no fds ready */
861         TM_Remove(Requests, &req->timeout);
862 #ifdef DEBUG
863         req -> timeout.Next = (struct TM_Elem *) 2;
864         req -> timeout.Prev = (struct TM_Elem *) 2;
865 #endif /* DEBUG */
866         LWP_QSignal(req->pid);
867         req->pid->iomgrRequest = 0;
868     }
869
870     /* Collect requests & update times */
871     readfds = IOMGR_AllocFDSet();
872     writefds = IOMGR_AllocFDSet();
873     exceptfds = IOMGR_AllocFDSet();
874     if (!(readfds && writefds && exceptfds)) {
875         fprintf(stderr, "IOMGR_Poll: Could not malloc space for fd_sets.\n");
876         fflush(stderr);
877     }
878
879     fds = 0;
880
881     FOR_ALL_ELTS(r, Requests, {
882         register struct IoRequest *req;
883         req = (struct IoRequest *) r -> BackPointer;
884         FDSetSet(req->nfds, readfds,   req->readfds);
885         FDSetSet(req->nfds, writefds,  req->writefds);
886         FDSetSet(req->nfds, exceptfds, req->exceptfds);
887         if (fds < req->nfds)
888             fds = req->nfds;
889     })
890         
891     tv.tv_sec = 0;
892     tv.tv_usec = 0;
893 #ifdef AFS_NT40_ENV
894     code = -1;
895     if (readfds->fd_count == 0 && writefds->fd_count == 0
896         && exceptfds->fd_count == 0)
897 #endif
898         code = select(fds, readfds, writefds, exceptfds, &tv);
899     if (code > 0) {
900         SignalIO(fds, readfds, writefds, exceptfds, code);
901     }
902
903     if (readfds) IOMGR_FreeFDSet(readfds);
904     if (writefds) IOMGR_FreeFDSet(writefds);
905     if (exceptfds) IOMGR_FreeFDSet(exceptfds);
906
907
908     LWP_DispatchProcess();  /* make sure others run */
909     LWP_DispatchProcess();
910     return 0;
911 }
912
913 int IOMGR_Select(fds, readfds, writefds, exceptfds, timeout)
914      int fds;
915      fd_set *readfds, *writefds, *exceptfds;
916      struct timeval *timeout;
917 {
918     register struct IoRequest *request;
919     int result;
920
921 #ifndef AFS_NT40_ENV
922     if(fds > FD_SETSIZE) {
923         fprintf(stderr, "IOMGR_Select: fds=%d, more than max %d\n",
924                 fds, FD_SETSIZE);
925         fflush(stderr);
926         lwp_abort();
927     }
928 #endif
929
930     /* See if polling request. If so, handle right here */
931     if (timeout != NULL) {
932         if (timeout->tv_sec == 0 && timeout->tv_usec == 0) {
933             int code;
934 #ifdef DEBUG
935             if (lwp_debug != 0) puts("[Polling SELECT]");
936 #endif /* DEBUG */
937 again:
938             code = select(fds, readfds, writefds, exceptfds, timeout);
939 #if     defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_AIX32_ENV)
940             /*
941              * For SGI and SVR4 - poll & select can return EAGAIN ...
942              */
943             /*
944              * this is basically for SGI, but I believe stock SVR4 (Solaris?)
945              * can also get this error return
946              */
947             if (code < 0 && errno == EAGAIN)
948                 goto again;     
949 #endif
950 #ifdef AFS_NT40_ENV
951             if (code == SOCKET_ERROR) {
952                 if (WSAGetLastError() == WSAEINPROGRESS)
953                     goto again;
954
955                 code = -1;
956             }
957 #endif
958             return (code > 1 ? 1 : code);
959         }
960     }
961
962     /* Construct request block & insert */
963     request = NewRequest(); /* zeroes fd_set's */
964     if (readfds && !FDSetEmpty(fds, readfds))
965         request->readfds = readfds;
966     if (writefds && !FDSetEmpty(fds, writefds))
967         request->writefds = writefds;
968     if (exceptfds && !FDSetEmpty(fds, exceptfds))
969         request->exceptfds = exceptfds;
970     request->nfds = fds;
971
972     if (timeout == NULL) {
973         request -> timeout.TotalTime.tv_sec = -1;
974         request -> timeout.TotalTime.tv_usec = -1;
975     } else {
976         request -> timeout.TotalTime = *timeout;
977         /* check for bad request */
978         if (timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec > 999999) {
979             /* invalid arg */
980             iomgr_badtv = *timeout;
981             iomgr_badpid = LWP_ActiveProcess;
982             /* now fixup request */
983             if(request->timeout.TotalTime.tv_sec < 0)
984                 request->timeout.TotalTime.tv_sec = 1;
985             request->timeout.TotalTime.tv_usec = 100000;
986         }
987     }
988
989     request -> timeout.BackPointer = (char *) request;
990
991     /* Insert my PID in case of IOMGR_Cancel */
992     request -> pid = LWP_ActiveProcess;
993     LWP_ActiveProcess -> iomgrRequest = request;
994
995 #ifdef DEBUG
996     request -> timeout.Next = (struct TM_Elem *) 1;
997     request -> timeout.Prev = (struct TM_Elem *) 1;
998 #endif /* DEBUG */
999     TM_Insert(Requests, &request->timeout);
1000
1001     /* Wait for action */
1002     LWP_QWait();
1003
1004     /* Update parameters & return */
1005     result = request -> result;
1006
1007     FreeRequest(request);
1008     return (result > 1 ? 1 : result);
1009 }
1010 \f
1011 int IOMGR_Cancel(PROCESS pid)
1012 {
1013     register struct IoRequest *request;
1014
1015     if ((request = pid->iomgrRequest) == 0) return -1;  /* Pid not found */
1016
1017     if (request->readfds)   FD_N_ZERO(request->nfds, request->readfds);
1018     if (request->writefds)  FD_N_ZERO(request->nfds, request->writefds);
1019     if (request->exceptfds) FD_N_ZERO(request->nfds, request->exceptfds);
1020     request->nfds = 0;
1021
1022     request -> result = -2;
1023     TM_Remove(Requests, &request->timeout);
1024 #ifdef DEBUG
1025     request -> timeout.Next = (struct TM_Elem *) 5;
1026     request -> timeout.Prev = (struct TM_Elem *) 5;
1027 #endif /* DEBUG */
1028     LWP_QSignal(request->pid);
1029     pid->iomgrRequest = 0;
1030
1031     return 0;
1032 }
1033 \f
1034 #ifndef AFS_NT40_ENV
1035 /* Cause delivery of signal signo to result in a LWP_SignalProcess of
1036    event. */
1037 int IOMGR_Signal (int signo, char *event)
1038 {
1039     struct sigaction sa;
1040
1041     if (badsig(signo))
1042         return LWP_EBADSIG;
1043     if (event == NULL)
1044         return LWP_EBADEVENT;
1045     sa.sa_handler = SigHandler;
1046     sa.sa_mask = *((sigset_t *) allOnes);       /* mask all signals */
1047     sa.sa_flags = 0;
1048     sigsHandled |= mysigmask(signo);
1049     sigEvents[signo] = event;
1050     sigDelivered[signo] = FALSE;
1051     if (sigaction (signo, &sa, &oldActions[signo]) == -1)
1052         return LWP_ESYSTEM;
1053     return LWP_SUCCESS;
1054 }
1055
1056 /* Stop handling occurrences of signo. */
1057 int IOMGR_CancelSignal (int signo)
1058 {
1059     if (badsig(signo) || (sigsHandled & mysigmask(signo)) == 0)
1060         return LWP_EBADSIG;
1061     sigaction (signo, &oldActions[signo], NULL);
1062     sigsHandled &= ~mysigmask(signo);
1063     return LWP_SUCCESS;
1064 }
1065 #endif /* AFS_NT40_ENV */
1066 /* This routine calls select is a fashion that simulates the standard sleep routine */
1067 void IOMGR_Sleep (int seconds)
1068 {
1069 #ifndef AFS_DJGPP_ENV
1070     struct timeval timeout;
1071
1072     timeout.tv_sec = seconds;
1073     timeout.tv_usec = 0;
1074     IOMGR_Select(0, 0, 0, 0, &timeout);
1075 #else
1076     struct timeval timeout;
1077     int s;
1078     fd_set set, empty;
1079     FD_ZERO(&empty);
1080     FD_ZERO(&set);
1081     s = socket(AF_INET,SOCK_STREAM,0);
1082     FD_SET(s,&set);
1083
1084     timeout.tv_sec = seconds;
1085     timeout.tv_usec = 0;
1086     IOMGR_Select(1,&set,&empty,&empty,&timeout);
1087     close(s);
1088 #endif            /* DJGPP  */
1089 }
1090 #endif  /* USE_PTHREADS */
1091
1092
1093 #ifdef AFS_DJGPP_ENV
1094
1095 /* Netbios code for djgpp port */
1096
1097 int IOMGR_NCBSelect(NCB *ncbp, dos_ptr dos_ncb, struct timeval *timeout)
1098 {
1099   struct IoRequest *request;
1100   int result;
1101   
1102   if (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1103   {
1104     /* Poll */
1105     if (ncbp->ncb_event != NULL)
1106     {
1107       /* error */
1108       return -1;
1109     }
1110     
1111     if (get_dos_member_b(NCB, dos_ncb, ncb_cmd_cplt) != 0xff)
1112     {
1113       return 1;
1114     }
1115     else {
1116       return 0;
1117     }
1118   }
1119
1120   /* Construct request block & insert */
1121   request = NewRequest();
1122   request->ncbp = ncbp;
1123   request->dos_ncb = dos_ncb;
1124   
1125   if (timeout == NULL)
1126   {
1127     request->timeout.TotalTime.tv_sec = -1;
1128     request->timeout.TotalTime.tv_usec = -1;
1129   }
1130   else
1131   {
1132     request -> timeout.TotalTime = *timeout;
1133     /* check for bad request */
1134     if (timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec > 999999)
1135     {
1136       /* invalid arg */
1137       iomgr_badtv = *timeout;
1138       iomgr_badpid = LWP_ActiveProcess;
1139       /* now fixup request */
1140       if(request->timeout.TotalTime.tv_sec < 0)
1141         request->timeout.TotalTime.tv_sec = 1;
1142       request->timeout.TotalTime.tv_usec = 100000;
1143     }
1144   }
1145
1146   request->timeout.BackPointer = (char *)request;
1147
1148   /* Insert my PID in case of IOMGR_Cancel */
1149   request -> pid = LWP_ActiveProcess;
1150   LWP_ActiveProcess -> iomgrRequest = request;
1151   
1152 #ifdef DEBUG
1153   request -> timeout.Next = (struct TM_Elem *) 1;
1154   request -> timeout.Prev = (struct TM_Elem *) 1;
1155 #endif /* DEBUG */
1156   TM_Insert(Requests, &request->timeout);
1157
1158   if (ncbp->ncb_event != NULL)
1159   {
1160     /* since we were given an event, we can return immediately and just
1161        signal the event once the request completes. */
1162     return 0;
1163   }
1164   else
1165   {
1166     /* Wait for action */
1167     
1168     LWP_QWait();
1169     
1170     /* Update parameters & return */
1171     result = request -> result;
1172
1173     FreeRequest(request);
1174     return (result > 1 ? 1 : result);
1175   }
1176 }
1177       
1178 int IOMGR_CheckNCB(void)
1179 {
1180   int woke_someone = FALSE;
1181   EVENT_HANDLE ev;
1182   PROCESS pid;
1183   
1184   anyNCBComplete = FALSE;
1185   FOR_ALL_ELTS(r, Requests, {
1186     register struct IoRequest *req;
1187     req = (struct IoRequest *) r -> BackPointer;
1188
1189     if (req->dos_ncb && get_dos_member_b(NCB, req->dos_ncb, ncb_cmd_cplt) != 0xff)
1190     {
1191       /* this NCB has completed */
1192       TM_Remove(Requests, &req->timeout);
1193
1194       /* copy out NCB from DOS to virtual space */
1195       dosmemget(req->dos_ncb, sizeof(NCB), (char *) req->ncbp);
1196
1197       if (ev = req->ncbp->ncb_event)
1198       {
1199         thrd_SetEvent(ev);
1200       }
1201       else
1202       {
1203         woke_someone = TRUE;
1204         LWP_QSignal(pid=req->pid);
1205         pid->iomgrRequest = 0;
1206       }
1207     }
1208   })
1209   return woke_someone;
1210 }
1211
1212 int ncb_handler(__dpmi_regs *r)
1213 {
1214   anyNCBComplete = TRUE;  /* NCB completed */
1215   /* Make sure that the IOMGR process doesn't pause on the select. */
1216   iomgr_timeout.tv_sec = 0;
1217   iomgr_timeout.tv_usec = 0;
1218   return;
1219 }
1220
1221 int install_ncb_handler(void)
1222 {
1223   callback_info.pm_offset = (long) ncb_handler;
1224   if (_go32_dpmi_allocate_real_mode_callback_retf(&callback_info,
1225                                                   &callback_regs))
1226  {
1227       fprintf(stderr, "error, allocate_real_mode_callback_retf failed\n");
1228       return -1;
1229  }
1230
1231  handler_seg = callback_info.rm_segment;
1232  handler_off = callback_info.rm_offset;
1233  
1234  /*printf("NCB handler_seg=0x%x, off=0x%x\n", handler_seg, handler_off);*/
1235 }
1236 #endif /* AFS_DJGPP_ENV */