2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /*******************************************************************\
12 * Information Technology Center *
13 * Carnegie-Mellon University *
17 \*******************************************************************/
21 IO Manager routines & server process for VICE server.
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) */
33 #define FD_SETSIZE 65536
36 #include <afsconfig.h>
37 #include <afs/param.h>
47 extern void lwp_abort(void);
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 */
53 # include <sys/select.h> /* fd_set on newer platforms */
56 #endif /* AFS_NT40_ENV */
65 #include "dosdefs95.h"
66 #include "netbios95.h"
67 #include <sys/socket.h>
68 #include <sys/farptr.h>
72 int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY;
73 #endif /* AFS_DJGPP_ENV */
75 #if defined(USE_PTHREADS) || defined(USE_SOLARIS_THREADS)
77 void IOMGR_Initialize() /* noop */
80 void IOMGR_Sleep (seconds)
87 assert(pthread_mutex_unlock(&lwp_mutex) == 0);
88 assert(pthread_delay_np(&itv) == 0);
89 assert(pthread_mutex_lock(&lwp_mutex) == 0);
95 extern void *malloc();
96 #endif /* AFS_DECOSF_ENV */
98 typedef unsigned char bool;
103 #define MIN(a,b) (((a)>(b)) ? (b) : (a))
107 #define NSIG 8*sizeof(sigset_t)
110 static int SignalSignals();
112 /********************************\
114 * Stuff for managing IoRequests *
116 \********************************/
120 /* Pid of process making request (for use in IOMGR_Cancel */
123 /* Descriptor masks for requests */
129 struct TM_Elem timeout;
131 /* Result of select call */
137 #endif /* AFS_DJGPP_ENV */
141 /********************************\
143 * Stuff for managing signals *
145 \********************************/
147 #define badsig(signo) (((signo) <= 0) || ((signo) >= NSIG))
148 #define mysigmask(signo) (1 << ((signo)-1))
151 fd_set openMask; /* mask of open files on an IOMGR abort */
152 static afs_int32 sigsHandled; /* sigmask(signo) is on if we handle signo */
153 static int anySigsDelivered; /* true if any have been delivered. */
155 static struct sigaction oldActions[NSIG]; /* the old signal vectors */
157 static char *sigEvents[NSIG]; /* the event to do an LWP signal on */
158 static int sigDelivered[NSIG]; /* True for signals delivered so far.
159 This is an int array to make sure
160 there are no conflicts when trying
162 /* software 'signals' */
164 static int (*sigProc[NSOFTSIG])();
165 static char *sigRock[NSOFTSIG];
168 static struct IoRequest *iorFreeList = 0;
170 static struct TM_Elem *Requests; /* List of requests */
171 static struct timeval iomgr_timeout; /* global so signal handler can zap it */
173 /* stuff for debugging */
174 static int iomgr_errno;
175 static struct timeval iomgr_badtv;
176 static PROCESS iomgr_badpid;
177 static void SignalIO(int fds, fd_set *rfds, fd_set *wfds, fd_set *efs,
179 static void SignalTimeout(int code, struct timeval *timeout);
182 /* handle Netbios NCB completion */
184 int anyNCBComplete = FALSE;
185 int handler_seg, handler_off; /* seg:off of NCB completion handler */
186 static __dpmi_regs callback_regs;
187 static _go32_dpmi_seginfo callback_info;
188 #endif /* AFS_DJGPP_ENV */
190 /* fd_set pool managment.
191 * Use the pool instead of creating fd_set's on the stack. fd_set's can be
192 * 8K in size, so making three could put 24K in the limited space of an LWP
195 struct IOMGR_fd_set {
196 struct IOMGR_fd_set *next;
197 } *iomgrFreeFDSets = (struct IOMGR_fd_set*)0;
200 * Return fd_set to the free list.
202 void IOMGR_FreeFDSet(fd_set *s)
204 struct IOMGR_fd_set *t = (struct IOMGR_fd_set *)s;
206 t->next = iomgrFreeFDSets;
211 * returns a zeroed fd_set or null if could not malloc one.
213 fd_set *IOMGR_AllocFDSet(void)
215 struct IOMGR_fd_set *t;
216 if (iomgrFreeFDSets) {
218 iomgrFreeFDSets = iomgrFreeFDSets->next;
221 t = (struct IOMGR_fd_set *)malloc(sizeof(fd_set));
231 #define FreeRequest(x) ((x)->result = (long) iorFreeList, iorFreeList = (x))
233 static struct IoRequest *NewRequest()
235 struct IoRequest *request;
237 if ((request=iorFreeList))
238 iorFreeList = (struct IoRequest *) (request->result);
239 else request = (struct IoRequest *) malloc(sizeof(struct IoRequest));
241 memset((char*)request, 0, sizeof(struct IoRequest));
245 #define Purge(list) FOR_ALL_ELTS(req, list, { free(req->BackPointer); })
248 /* FD_SET support routines. All assume the fd_set size is a multiple of an int
249 * so we can at least do logical operations on ints instead of chars.
251 * For each routine, nfds is the highest bit set in either fd_set, starting
255 #define FD_N_ZERO(A, x) FD_ZERO(x)
257 #define FDS_P_POS (sizeof(int)*8)
258 #define INTS_PER_FDS(x) (((x)+(FDS_P_POS-1)) / FDS_P_POS)
259 #define FD_N_ZERO(nfds, x) memset((char*)(x), 0, (INTS_PER_FDS(nfds))*sizeof(int))
262 #if defined(AFS_LINUX22_ENV) && (__GLIBC_MINOR__ > 0)
263 /* Build for both glibc 2.0.x and 2.1.x */
264 #define FDS_BITS __fds_bits
266 #define FDS_BITS fds_bits
269 /* FDSetCmp - returns 1 if any bits in fd_set1 are also set in fd_set2.
270 * If nfds is 0, or one of the fd_sets is null return 0 (since there is no bit
271 * set in both fd_sets).
273 static int FDSetCmp(int nfds, fd_set *fd_set1, fd_set *fd_set2)
277 if (fd_set1 == (fd_set*)0 || fd_set2 == (fd_set*)0)
281 if (fd_set1->fd_count == 0 || fd_set2->fd_count == 0)
284 for (i=0; i<fd_set1->fd_count; i++) {
285 for (j=0; j<fd_set2->fd_count; j++) {
286 if (fd_set1->fd_array[i] == fd_set2->fd_array[j])
294 j = INTS_PER_FDS(nfds);
295 for (i=0; i<j; i++) {
296 if (fd_set1->FDS_BITS[i] & fd_set2->FDS_BITS[i])
303 /* FDSetSet - set bits from fd_set2 into fd_set1
305 static void FDSetSet(int nfds, fd_set *fd_set1, fd_set *fd_set2)
309 if (fd_set1 == (fd_set*)0 || fd_set2 == (fd_set*)0)
313 if (fd_set2->fd_count==0)
316 for (i=0; i<fd_set2->fd_count; i++)
317 FD_SET(fd_set2->fd_array[i], fd_set1);
322 for (i = 0, n = INTS_PER_FDS(nfds); i < n; i++) {
323 fd_set1->FDS_BITS[i] |= fd_set2->FDS_BITS[i];
328 /* FDSetAnd - fd_set1 <- fd_set1 & fd_set2.
331 static void FDSetAnd(int nfds, fd_set *fd_set1, fd_set *fd_set2)
336 if (fd_set1 == NULL || fd_set1->fd_count == 0)
339 if (fd_set2 == NULL || fd_set2->fd_count == 0) {
344 for (i=0; i<fd_set2->fd_count; i++) {
345 if (FD_ISSET(fd_set2->fd_array[i], fd_set1))
346 FD_SET(fd_set2->fd_array[i], &tmpset);
352 static void FDSetAnd(int nfds, fd_set *fd_set1, fd_set *fd_set2)
356 if (nfds == 0 || fd_set1 == (fd_set*)0 || fd_set2 == (fd_set*)0)
359 n = INTS_PER_FDS(nfds);
360 for (i=0; i<n; i++) {
361 fd_set1->FDS_BITS[i] &= fd_set2->FDS_BITS[i];
366 /* FDSetEmpty - return true if fd_set is empty
368 static int FDSetEmpty(int nfds, fd_set *fds)
376 if (fds == (fd_set*)0)
380 if (fds->fd_count == 0)
385 n = INTS_PER_FDS(nfds);
387 for (i=n-1; i>=0; i--) {
388 if (fds->FDS_BITS[i])
399 /* The IOMGR process */
402 * Important invariant: process->iomgrRequest is null iff request not in timer
404 * also, request->pid is valid while request is in queue,
405 * also, don't signal selector while request in queue, since selector frees
409 /* These are not declared in IOMGR so that they don't use up 6K of stack. */
410 static fd_set IOMGR_readfds, IOMGR_writefds, IOMGR_exceptfds;
411 static int IOMGR_nfds = 0;
413 static int IOMGR(void *dummy)
417 struct TM_Elem *earliest;
418 struct timeval timeout, junk;
421 FD_ZERO(&IOMGR_readfds);
422 FD_ZERO(&IOMGR_writefds);
423 FD_ZERO(&IOMGR_exceptfds);
426 /* Wake up anyone who has expired or who has received a
427 Unix signal between executions. Keep going until we
430 woke_someone = FALSE;
431 /* Wake up anyone waiting on signals. */
432 /* Note: SignalSignals() may yield! */
433 if (anySigsDelivered && SignalSignals ())
435 #ifndef AFS_DJGPP_ENV
436 FT_GetTimeOfDay(&junk, 0); /* force accurate time check */
440 register struct IoRequest *req;
441 struct TM_Elem *expired;
442 expired = TM_GetExpired(Requests);
443 if (expired == NULL) break;
445 req = (struct IoRequest *) expired -> BackPointer;
447 if (lwp_debug != 0) puts("[Polling SELECT]");
450 if (req->readfds) FD_N_ZERO(req->nfds, req->readfds);
451 if (req->writefds) FD_N_ZERO(req->nfds, req->writefds);
452 if (req->exceptfds) FD_N_ZERO(req->nfds, req->exceptfds);
454 req->result = 0; /* no fds ready */
455 TM_Remove(Requests, &req->timeout);
457 req -> timeout.Next = (struct TM_Elem *) 2;
458 req -> timeout.Prev = (struct TM_Elem *) 2;
460 LWP_QSignal(req->pid);
461 req->pid->iomgrRequest = 0;
465 if (IOMGR_CheckNCB()) /* check for completed netbios requests */
467 #endif /* AFS_DJGPP_ENV */
469 if (woke_someone) LWP_DispatchProcess();
470 } while (woke_someone);
472 /* Collect requests & update times */
473 FD_ZERO(&IOMGR_readfds);
474 FD_ZERO(&IOMGR_writefds);
475 FD_ZERO(&IOMGR_exceptfds);
478 FOR_ALL_ELTS(r, Requests, {
479 register struct IoRequest *req;
480 req = (struct IoRequest *) r -> BackPointer;
481 FDSetSet(req->nfds, &IOMGR_readfds, req->readfds);
482 FDSetSet(req->nfds, &IOMGR_writefds, req->writefds);
483 FDSetSet(req->nfds, &IOMGR_exceptfds, req->exceptfds);
484 if (req->nfds > IOMGR_nfds)
485 IOMGR_nfds = req->nfds;
487 earliest = TM_GetEarliest(Requests);
488 if (earliest != NULL) {
489 timeout = earliest -> TimeLeft;
494 if (lwp_debug != 0) {
497 printf("[Read Select:");
498 if (IOMGR_readfds.fd_count == 0)
501 for (idbg=0; idbg<IOMGR_readfds.fd_count; idbg++)
502 printf(" %d", IOMGR_readfds.fd_array[idbg]);
505 printf("[Write Select:");
506 if (IOMGR_writefds.fd_count == 0)
509 for (idbg=0; idbg<IOMGR_writefds.fd_count; idbg++)
510 printf(" %d", IOMGR_writefds.fd_array[idbg]);
513 printf("[Except Select:");
514 if (IOMGR_exceptfds.fd_count == 0)
517 for (idbg=0; idbg<IOMGR_exceptfds.fd_count; idbg++)
518 printf(" %d", IOMGR_exceptfds.fd_array[idbg]);
522 /* Only prints first 32. */
523 printf("[select(%d, 0x%x, 0x%x, 0x%x, ", IOMGR_nfds,
524 *(int*)&IOMGR_readfds, *(int*)&IOMGR_writefds,
525 *(int*)&IOMGR_exceptfds);
526 #endif /* AFS_NT40_ENV */
527 if (timeout.tv_sec == -1 && timeout.tv_usec == -1)
530 printf("<%d, %d>)]\n", timeout.tv_sec, timeout.tv_usec);
533 iomgr_timeout = timeout;
534 if (timeout.tv_sec == -1 && timeout.tv_usec == -1) {
535 /* infinite, sort of */
536 iomgr_timeout.tv_sec = 100000000;
537 iomgr_timeout.tv_usec = 0;
539 #if defined(AFS_NT40_ENV) || defined(AFS_LINUX24_ENV)
540 /* On NT, signals don't interrupt a select call. So this can potentially
541 * lead to long wait times before a signal is honored. To avoid this we
542 * dont do select() for longer than IOMGR_MAXWAITTIME (5 secs) */
543 /* Whereas Linux seems to sometimes "lose" signals */
544 if (iomgr_timeout.tv_sec > (IOMGR_MAXWAITTIME - 1)) {
545 iomgr_timeout.tv_sec = IOMGR_MAXWAITTIME;
546 iomgr_timeout.tv_usec = 0;
551 /* We do this also for the DOS-box Win95 client, since
552 NCB calls don't interrupt a select, but we want to catch them
553 in a reasonable amount of time (say, half a second). */
554 iomgr_timeout.tv_sec = 0;
555 iomgr_timeout.tv_usec = IOMGR_WIN95WAITTIME;
558 /* Check one last time for a signal delivery. If one comes after
559 this, the signal handler will set iomgr_timeout to zero, causing
560 the select to return immediately. The timer package won't return
561 a zero timeval because all of those guys were handled above.
563 I'm assuming that the kernel masks signals while it's picking up
564 the parameters to select. This may a bad assumption. -DN */
565 if (anySigsDelivered)
566 continue; /* go to the top and handle them. */
569 if (IOMGR_CheckNCB()) /* check for completed netbios requests */
570 LWP_DispatchProcess();
571 #endif /* AFS_DJGPP_ENV */
574 if (IOMGR_readfds.fd_count == 0 && IOMGR_writefds.fd_count == 0
575 && IOMGR_exceptfds.fd_count == 0) {
578 if (iomgr_timeout.tv_sec || iomgr_timeout.tv_usec) {
579 stime = iomgr_timeout.tv_sec * 1000
580 + iomgr_timeout.tv_usec/1000;
588 { /* select runs much faster if 0's are passed instead of &0s */
589 code = select(IOMGR_nfds,
590 (FDSetEmpty(IOMGR_nfds, &IOMGR_readfds)) ?
591 (fd_set*)0 : &IOMGR_readfds,
592 (FDSetEmpty(IOMGR_nfds, &IOMGR_writefds)) ?
593 (fd_set*)0 : &IOMGR_writefds,
594 (FDSetEmpty(IOMGR_nfds, &IOMGR_exceptfds)) ?
595 (fd_set*)0 : &IOMGR_exceptfds,
602 #if defined(AFS_SUN_ENV)
603 /* Tape drives on Sun boxes do not support select and return ENXIO */
604 if (errno == ENXIO) e=0, code=1;
606 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_AIX32_ENV)
607 /* For SGI and SVR4 - poll & select can return EAGAIN ... */
608 if (errno == EAGAIN) e=0;
610 #if defined(AFS_SUN5_ENV)
611 /* On sun4x_55, select doesn't block signal. It could be
612 interupted by a signal that changes iomgr_timeout, and
613 then select returns with EINVAL. In this case, we need
616 if (errno==EINVAL && anySigsDelivered)
618 #endif /* AFS_SUN5_ENV */
620 if ((errno != EINTR) && e) {
623 for(i=0; i<FD_SETSIZE; i++) {
624 if (fcntl(i, F_GETFD, 0) < 0 && errno == EBADF)
625 FD_SET(i, &openMask);
633 /* See what happened */
635 /* Action -- wake up everyone involved */
636 SignalIO(IOMGR_nfds, &IOMGR_readfds, &IOMGR_writefds,
637 &IOMGR_exceptfds, code);
640 && (iomgr_timeout.tv_sec != 0 || iomgr_timeout.tv_usec != 0)) {
641 /* Real timeout only if signal handler hasn't set
642 iomgr_timeout to zero. */
644 #if defined(AFS_NT40_ENV) || defined(AFS_LINUX24_ENV)
645 /* On NT, real timeout only if above and if iomgr_timeout
646 * interval is equal to timeout interval (i.e., not adjusted
647 * to check for pseudo-signals).
649 /* And also for Linux as above */
650 if (iomgr_timeout.tv_sec != timeout.tv_sec ||
651 iomgr_timeout.tv_usec != timeout.tv_usec) {
652 /* signal check interval timed out; not real timeout */
655 #endif /* AFS_NT40_ENV */
656 #ifndef AFS_DJGPP_ENV
657 FT_GetTimeOfDay(&junk, 0);
659 SignalTimeout(code, &timeout);
663 #endif /* AFS_DJGPP_ENV */
665 LWP_DispatchProcess();
667 return -1; /* keeps compilers happy. */
670 /************************\
672 * Signalling routines *
674 \************************/
676 static void SignalIO(int fds, fd_set *readfds, fd_set *writefds,
677 fd_set *exceptfds, int code)
680 /* Look at everyone who's bit mask was affected */
681 FOR_ALL_ELTS(r, Requests, {
682 register struct IoRequest *req;
683 register PROCESS pid;
684 req = (struct IoRequest *) r -> BackPointer;
685 nfds = MIN(fds, req->nfds);
686 if (FDSetCmp(nfds, req->readfds, readfds) ||
687 FDSetCmp(nfds, req->writefds, writefds) ||
688 FDSetCmp(nfds, req->exceptfds, exceptfds)) {
689 /* put ready fd's into request. */
690 FDSetAnd(nfds, req->readfds, readfds);
691 FDSetAnd(nfds, req->writefds, writefds);
692 FDSetAnd(nfds, req->exceptfds, exceptfds);
693 req -> result = code;
694 TM_Remove(Requests, &req->timeout);
695 LWP_QSignal(pid=req->pid);
696 pid->iomgrRequest = 0;
701 static void SignalTimeout(int code, struct timeval *timeout)
703 /* Find everyone who has specified timeout */
704 FOR_ALL_ELTS(r, Requests, {
705 register struct IoRequest *req;
706 register PROCESS pid;
707 req = (struct IoRequest *) r -> BackPointer;
708 if (TM_eql(&r->TimeLeft, timeout)) {
709 req -> result = code;
710 TM_Remove(Requests, &req->timeout);
711 LWP_QSignal(pid=req->pid);
712 pid->iomgrRequest = 0;
718 /*****************************************************\
720 * Signal handling routine (not to be confused with *
721 * signalling routines, above). *
723 \*****************************************************/
724 static void SigHandler (signo)
727 if (badsig(signo) || (sigsHandled & mysigmask(signo)) == 0)
728 return; /* can't happen. */
729 sigDelivered[signo] = TRUE;
730 anySigsDelivered = TRUE;
731 /* Make sure that the IOMGR process doesn't pause on the select. */
732 iomgr_timeout.tv_sec = 0;
733 iomgr_timeout.tv_usec = 0;
736 /* Alright, this is the signal signalling routine. It delivers LWP signals
737 to LWPs waiting on Unix signals. NOW ALSO CAN YIELD!! */
738 static int SignalSignals (void)
745 anySigsDelivered = FALSE;
747 /* handle software signals */
748 stackSize = (AFS_LWP_MINSTACKSIZE < lwp_MaxStackSeen? lwp_MaxStackSeen : AFS_LWP_MINSTACKSIZE);
749 for (i=0; i < NSOFTSIG; i++) {
751 if (p=sigProc[i]) /* This yields!!! */
752 LWP_CreateProcess2(p, stackSize, LWP_NORMAL_PRIORITY,
753 (void *) sigRock[i], "SignalHandler", &pid);
757 for (i = 1; i <= NSIG; ++i) /* forall !badsig(i) */
758 if ((sigsHandled & mysigmask(i)) && sigDelivered[i] == TRUE) {
759 sigDelivered[i] = FALSE;
760 LWP_NoYieldSignal (sigEvents[i]);
767 /***************************\
769 * User-callable routines *
771 \***************************/
774 /* Keep IOMGR process id */
775 static PROCESS IOMGR_Id = NULL;
777 int IOMGR_SoftSig(aproc, arock)
781 for (i=0;i<NSOFTSIG;i++) {
782 if (sigProc[i] == 0) {
786 anySigsDelivered = TRUE;
787 iomgr_timeout.tv_sec = 0;
788 iomgr_timeout.tv_usec = 0;
796 unsigned char allOnes[100];
798 int IOMGR_Initialize(void)
800 extern int TM_Init();
803 /* If lready initialized, just return */
804 if (IOMGR_Id != NULL) return LWP_SUCCESS;
806 /* Init LWP if someone hasn't yet. */
807 if (LWP_InitializeProcessSupport (LWP_NORMAL_PRIORITY, &pid) != LWP_SUCCESS)
810 /* Initialize request lists */
811 if (TM_Init(&Requests) < 0) return -1;
813 /* Initialize signal handling stuff. */
815 anySigsDelivered = TRUE; /* A soft signal may have happened before
816 IOMGR_Initialize: so force a check for signals regardless */
817 memset(allOnes, 0xff, sizeof(allOnes));
820 install_ncb_handler();
821 #endif /* AFS_DJGPP_ENV */
823 return LWP_CreateProcess(IOMGR, AFS_LWP_MINSTACKSIZE, 0, (void *) 0,
824 "IO MANAGER", &IOMGR_Id);
833 status = LWP_DestroyProcess(IOMGR_Id);
838 /* signal I/O for anyone who is waiting for a FD or a timeout; not too cheap,
839 * since forces select and timeofday check */
840 int IOMGR_Poll(void) {
841 fd_set *readfds, *writefds, *exceptfds;
846 FT_GetTimeOfDay(&tv, 0); /* force accurate time check */
849 register struct IoRequest *req;
850 struct TM_Elem *expired;
851 expired = TM_GetExpired(Requests);
852 if (expired == NULL) break;
853 req = (struct IoRequest *) expired -> BackPointer;
855 if (lwp_debug != 0) puts("[Polling SELECT]");
858 if (req->readfds) FD_N_ZERO(req->nfds, req->readfds);
859 if (req->writefds) FD_N_ZERO(req->nfds, req->writefds);
860 if (req->exceptfds) FD_N_ZERO(req->nfds, req->exceptfds);
862 req->result = 0; /* no fds ready */
863 TM_Remove(Requests, &req->timeout);
865 req -> timeout.Next = (struct TM_Elem *) 2;
866 req -> timeout.Prev = (struct TM_Elem *) 2;
868 LWP_QSignal(req->pid);
869 req->pid->iomgrRequest = 0;
872 /* Collect requests & update times */
873 readfds = IOMGR_AllocFDSet();
874 writefds = IOMGR_AllocFDSet();
875 exceptfds = IOMGR_AllocFDSet();
876 if (!(readfds && writefds && exceptfds)) {
877 fprintf(stderr, "IOMGR_Poll: Could not malloc space for fd_sets.\n");
883 FOR_ALL_ELTS(r, Requests, {
884 register struct IoRequest *req;
885 req = (struct IoRequest *) r -> BackPointer;
886 FDSetSet(req->nfds, readfds, req->readfds);
887 FDSetSet(req->nfds, writefds, req->writefds);
888 FDSetSet(req->nfds, exceptfds, req->exceptfds);
897 if (readfds->fd_count == 0 && writefds->fd_count == 0
898 && exceptfds->fd_count == 0)
900 code = select(fds, readfds, writefds, exceptfds, &tv);
902 SignalIO(fds, readfds, writefds, exceptfds, code);
905 if (readfds) IOMGR_FreeFDSet(readfds);
906 if (writefds) IOMGR_FreeFDSet(writefds);
907 if (exceptfds) IOMGR_FreeFDSet(exceptfds);
910 LWP_DispatchProcess(); /* make sure others run */
911 LWP_DispatchProcess();
915 int IOMGR_Select(fds, readfds, writefds, exceptfds, timeout)
917 fd_set *readfds, *writefds, *exceptfds;
918 struct timeval *timeout;
920 register struct IoRequest *request;
924 if(fds > FD_SETSIZE) {
925 fprintf(stderr, "IOMGR_Select: fds=%d, more than max %d\n",
932 /* See if polling request. If so, handle right here */
933 if (timeout != NULL) {
934 if (timeout->tv_sec == 0 && timeout->tv_usec == 0) {
937 if (lwp_debug != 0) puts("[Polling SELECT]");
940 code = select(fds, readfds, writefds, exceptfds, timeout);
941 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_AIX32_ENV)
943 * For SGI and SVR4 - poll & select can return EAGAIN ...
946 * this is basically for SGI, but I believe stock SVR4 (Solaris?)
947 * can also get this error return
949 if (code < 0 && errno == EAGAIN)
953 if (code == SOCKET_ERROR) {
954 if (WSAGetLastError() == WSAEINPROGRESS)
960 return (code > 1 ? 1 : code);
964 /* Construct request block & insert */
965 request = NewRequest(); /* zeroes fd_set's */
966 if (readfds && !FDSetEmpty(fds, readfds))
967 request->readfds = readfds;
968 if (writefds && !FDSetEmpty(fds, writefds))
969 request->writefds = writefds;
970 if (exceptfds && !FDSetEmpty(fds, exceptfds))
971 request->exceptfds = exceptfds;
974 if (timeout == NULL) {
975 request -> timeout.TotalTime.tv_sec = -1;
976 request -> timeout.TotalTime.tv_usec = -1;
978 request -> timeout.TotalTime = *timeout;
979 /* check for bad request */
980 if (timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec > 999999) {
982 iomgr_badtv = *timeout;
983 iomgr_badpid = LWP_ActiveProcess;
984 /* now fixup request */
985 if(request->timeout.TotalTime.tv_sec < 0)
986 request->timeout.TotalTime.tv_sec = 1;
987 request->timeout.TotalTime.tv_usec = 100000;
991 request -> timeout.BackPointer = (char *) request;
993 /* Insert my PID in case of IOMGR_Cancel */
994 request -> pid = LWP_ActiveProcess;
995 LWP_ActiveProcess -> iomgrRequest = request;
998 request -> timeout.Next = (struct TM_Elem *) 1;
999 request -> timeout.Prev = (struct TM_Elem *) 1;
1001 TM_Insert(Requests, &request->timeout);
1003 /* Wait for action */
1006 /* Update parameters & return */
1007 result = request -> result;
1009 FreeRequest(request);
1010 return (result > 1 ? 1 : result);
1013 int IOMGR_Cancel(PROCESS pid)
1015 register struct IoRequest *request;
1017 if ((request = pid->iomgrRequest) == 0) return -1; /* Pid not found */
1019 if (request->readfds) FD_N_ZERO(request->nfds, request->readfds);
1020 if (request->writefds) FD_N_ZERO(request->nfds, request->writefds);
1021 if (request->exceptfds) FD_N_ZERO(request->nfds, request->exceptfds);
1024 request -> result = -2;
1025 TM_Remove(Requests, &request->timeout);
1027 request -> timeout.Next = (struct TM_Elem *) 5;
1028 request -> timeout.Prev = (struct TM_Elem *) 5;
1030 LWP_QSignal(request->pid);
1031 pid->iomgrRequest = 0;
1036 #ifndef AFS_NT40_ENV
1037 /* Cause delivery of signal signo to result in a LWP_SignalProcess of
1039 int IOMGR_Signal (int signo, char *event)
1041 struct sigaction sa;
1046 return LWP_EBADEVENT;
1047 sa.sa_handler = SigHandler;
1048 sa.sa_mask = *((sigset_t *) allOnes); /* mask all signals */
1050 sigsHandled |= mysigmask(signo);
1051 sigEvents[signo] = event;
1052 sigDelivered[signo] = FALSE;
1053 if (sigaction (signo, &sa, &oldActions[signo]) == -1)
1058 /* Stop handling occurrences of signo. */
1059 int IOMGR_CancelSignal (int signo)
1061 if (badsig(signo) || (sigsHandled & mysigmask(signo)) == 0)
1063 sigaction (signo, &oldActions[signo], NULL);
1064 sigsHandled &= ~mysigmask(signo);
1067 #endif /* AFS_NT40_ENV */
1068 /* This routine calls select is a fashion that simulates the standard sleep routine */
1069 void IOMGR_Sleep (int seconds)
1071 #ifndef AFS_DJGPP_ENV
1072 struct timeval timeout;
1074 timeout.tv_sec = seconds;
1075 timeout.tv_usec = 0;
1076 IOMGR_Select(0, 0, 0, 0, &timeout);
1078 struct timeval timeout;
1083 s = socket(AF_INET,SOCK_STREAM,0);
1086 timeout.tv_sec = seconds;
1087 timeout.tv_usec = 0;
1088 IOMGR_Select(1,&set,&empty,&empty,&timeout);
1092 #endif /* USE_PTHREADS */
1095 #ifdef AFS_DJGPP_ENV
1097 /* Netbios code for djgpp port */
1099 int IOMGR_NCBSelect(NCB *ncbp, dos_ptr dos_ncb, struct timeval *timeout)
1101 struct IoRequest *request;
1104 if (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1107 if (ncbp->ncb_event != NULL)
1113 if (get_dos_member_b(NCB, dos_ncb, ncb_cmd_cplt) != 0xff)
1122 /* Construct request block & insert */
1123 request = NewRequest();
1124 request->ncbp = ncbp;
1125 request->dos_ncb = dos_ncb;
1127 if (timeout == NULL)
1129 request->timeout.TotalTime.tv_sec = -1;
1130 request->timeout.TotalTime.tv_usec = -1;
1134 request -> timeout.TotalTime = *timeout;
1135 /* check for bad request */
1136 if (timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec > 999999)
1139 iomgr_badtv = *timeout;
1140 iomgr_badpid = LWP_ActiveProcess;
1141 /* now fixup request */
1142 if(request->timeout.TotalTime.tv_sec < 0)
1143 request->timeout.TotalTime.tv_sec = 1;
1144 request->timeout.TotalTime.tv_usec = 100000;
1148 request->timeout.BackPointer = (char *)request;
1150 /* Insert my PID in case of IOMGR_Cancel */
1151 request -> pid = LWP_ActiveProcess;
1152 LWP_ActiveProcess -> iomgrRequest = request;
1155 request -> timeout.Next = (struct TM_Elem *) 1;
1156 request -> timeout.Prev = (struct TM_Elem *) 1;
1158 TM_Insert(Requests, &request->timeout);
1160 if (ncbp->ncb_event != NULL)
1162 /* since we were given an event, we can return immediately and just
1163 signal the event once the request completes. */
1168 /* Wait for action */
1172 /* Update parameters & return */
1173 result = request -> result;
1175 FreeRequest(request);
1176 return (result > 1 ? 1 : result);
1180 int IOMGR_CheckNCB(void)
1182 int woke_someone = FALSE;
1186 anyNCBComplete = FALSE;
1187 FOR_ALL_ELTS(r, Requests, {
1188 register struct IoRequest *req;
1189 req = (struct IoRequest *) r -> BackPointer;
1191 if (req->dos_ncb && get_dos_member_b(NCB, req->dos_ncb, ncb_cmd_cplt) != 0xff)
1193 /* this NCB has completed */
1194 TM_Remove(Requests, &req->timeout);
1196 /* copy out NCB from DOS to virtual space */
1197 dosmemget(req->dos_ncb, sizeof(NCB), (char *) req->ncbp);
1199 if (ev = req->ncbp->ncb_event)
1205 woke_someone = TRUE;
1206 LWP_QSignal(pid=req->pid);
1207 pid->iomgrRequest = 0;
1211 return woke_someone;
1214 int ncb_handler(__dpmi_regs *r)
1216 anyNCBComplete = TRUE; /* NCB completed */
1217 /* Make sure that the IOMGR process doesn't pause on the select. */
1218 iomgr_timeout.tv_sec = 0;
1219 iomgr_timeout.tv_usec = 0;
1223 int install_ncb_handler(void)
1225 callback_info.pm_offset = (long) ncb_handler;
1226 if (_go32_dpmi_allocate_real_mode_callback_retf(&callback_info,
1229 fprintf(stderr, "error, allocate_real_mode_callback_retf failed\n");
1233 handler_seg = callback_info.rm_segment;
1234 handler_off = callback_info.rm_offset;
1236 /*printf("NCB handler_seg=0x%x, off=0x%x\n", handler_seg, handler_off);*/
1238 #endif /* AFS_DJGPP_ENV */