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