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