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