2 ****************************************************************************
3 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
5 * Permission to use, copy, modify, and distribute this software and its *
6 * documentation for any purpose and without fee is hereby granted, *
7 * provided that the above copyright notice appear in all copies and *
8 * that both that copyright notice and this permission notice appear in *
9 * supporting documentation, and that the name of IBM not be used in *
10 * advertising or publicity pertaining to distribution of the software *
11 * without specific, written prior permission. *
13 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
15 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
16 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
17 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
18 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
19 ****************************************************************************
22 /*******************************************************************\
24 * Information Technology Center *
25 * Carnegie-Mellon University *
29 \*******************************************************************/
33 * IO Manager routines & server process for VICE server.
56 static void SignalIO(int, fd_set
*, fd_set
*, fd_set
*) ;
57 static void SignalTimeout(int fds
, struct timeval
*timeout
) ;
58 static int SignalSignals (void);
60 int FT_GetTimeOfDay(struct timeval
*, struct timezone
*);
62 /********************************\
64 * Stuff for managing IoRequests *
66 \********************************/
70 /* Pid of process making request (for use in IOMGR_Cancel) */
73 /* Descriptor masks for requests */
84 struct TM_Elem timeout
;
86 /* Result of select call */
88 struct IoRequest
*next
;
91 /********************************\
93 * Stuff for managing signals *
95 \********************************/
97 #define badsig(signo) (((signo) <= 0) || ((signo) >= NSIG))
98 #define mysigmask(signo) (1 << ((signo)-1))
100 static long openMask
; /* mask of open files on an IOMGR abort */
101 static long sigsHandled
; /* sigmask(signo) is on if we handle signo */
102 static int anySigsDelivered
; /* true if any have been delivered. */
103 #ifdef AFS_POSIX_SIGNALS
104 static struct sigaction oldVecs
[NSIG
]; /* the old signal vectors */
106 static struct sigvec oldVecs
[NSIG
]; /* the old signal vectors */
108 static char *sigEvents
[NSIG
]; /* the event to do an LWP signal on */
109 static int sigDelivered
[NSIG
]; /*
110 * True for signals delivered so far.
111 * This is an int array to make sure
112 * there are no conflicts when trying
115 /* software 'signals' */
117 static void (*sigProc
[NSOFTSIG
])();
118 static char *sigRock
[NSOFTSIG
];
121 static struct IoRequest
*iorFreeList
= 0;
123 static struct TM_Elem
*Requests
; /* List of requests */
124 static struct timeval iomgr_timeout
; /* global so signal handler can zap it */
126 /* stuff for debugging */
127 static int iomgr_errno
;
128 static struct timeval iomgr_badtv
;
129 static PROCESS iomgr_badpid
;
132 FreeRequest(struct IoRequest
*req
)
134 req
->next
= iorFreeList
;
138 /* stuff for handling select fd_sets */
141 #define FD_COPY(f, t) memcpy((t), (f), sizeof(*(f)))
145 * FD_OR - bitwise or of two fd_sets
146 * The result goes into set1
149 FD_OR(fd_set
*set1
, fd_set
*set2
)
154 unsigned long *s1
= (unsigned long *)set1
;
155 unsigned long *s2
= (unsigned long *)set2
;
157 for (i
= 0; i
< sizeof(fd_set
)/sizeof(unsigned long); i
++)
160 for (i
= 0; i
< FD_SETSIZE
; i
++)
161 if (FD_ISSET(i
, set1
) || FD_ISSET(i
, set2
))
167 * FD_AND - bitwise and of two fd_sets
168 * The result goes into set1
171 FD_AND(fd_set
*set1
, fd_set
*set2
)
176 unsigned long *s1
= (unsigned long *)set1
;
177 unsigned long *s2
= (unsigned long *)set2
;
179 for(i
= 0; i
< sizeof(fd_set
)/sizeof(unsigned long); i
++)
182 for(i
= 0; i
< FD_SETSIZE
; i
++)
183 if (FD_ISSET(i
, set1
) && FD_ISSET(i
, set2
))
189 * FD_LOGAND - "logical" and of two fd_sets
190 * returns 0 if there are no fds that are the same in both fd_sets
191 * otherwise it returns 1
194 FD_LOGAND(fd_set
*set1
, fd_set
*set2
)
199 unsigned long *s1
= (unsigned long *)set1
;
200 unsigned long *s2
= (unsigned long *)set2
;
202 for(i
= 0; i
< sizeof(fd_set
)/sizeof(unsigned long); i
++)
203 if ((s1
[i
] & s2
[i
]) != 0)
212 return !FD_ISZERO(&tmp
);
216 static struct IoRequest
*
219 struct IoRequest
*request
;
221 if ((request
= iorFreeList
) != NULL
)
222 iorFreeList
= request
->next
;
224 request
= (struct IoRequest
*) malloc(sizeof(struct IoRequest
));
229 #define Purge(list) FOR_ALL_ELTS(req, list, { free(req->BackPointer); })
232 /* The IOMGR process */
235 * Important invariant: process->iomgrRequest is null iff request not in
236 * timer queue also, request->pid is valid while request is in queue, also,
237 * don't signal selector while request in queue, since selector free's request.
246 fd_set readfds
, writefds
, exceptfds
;
247 fd_set
*rfds
, *wfds
, *efds
;
248 struct TM_Elem
*earliest
;
249 struct timeval timeout
, junk
;
253 * Wake up anyone who has expired or who has received a
254 * Unix signal between executions. Keep going until we
258 woke_someone
= FALSE
;
259 /* Wake up anyone waiting on signals. */
260 /* Note: SignalSignals() may yield! */
261 if (anySigsDelivered
&& SignalSignals ())
265 struct IoRequest
*req
;
266 struct TM_Elem
*expired
;
267 expired
= TM_GetExpired(Requests
);
268 if (expired
== NULL
) break;
270 req
= (struct IoRequest
*) expired
-> BackPointer
;
272 if (lwp_debug
!= 0) puts("[Polling SELECT]");
274 FD_ZERO(&req
->readfds
);
275 FD_ZERO(&req
->writefds
);
276 FD_ZERO(&req
->exceptfds
);
279 req
->rfds
= req
->wfds
= req
->efds
= NULL
;
284 TM_Remove(Requests
, &req
->timeout
);
286 req
-> timeout
.Next
= (struct TM_Elem
*) 2;
287 req
-> timeout
.Prev
= (struct TM_Elem
*) 2;
289 LWP_QSignal(req
->pid
);
290 req
->pid
->iomgrRequest
= 0;
292 if (woke_someone
) LWP_DispatchProcess();
293 } while (woke_someone
);
296 /* Collect requests & update times */
297 FD_ZERO(&readfds
); /* XXX - should not be needed */
301 rfds
= wfds
= efds
= NULL
;
302 FOR_ALL_ELTS(r
, Requests
, {
303 struct IoRequest
*req
;
304 req
= (struct IoRequest
*) r
-> BackPointer
;
307 FD_OR(rfds
, req
->rfds
);
310 FD_COPY(req
->rfds
, rfds
);
316 FD_OR(wfds
, req
->wfds
);
319 FD_COPY(req
->wfds
, wfds
);
325 FD_OR(efds
, req
->efds
);
328 FD_COPY(req
->efds
, efds
);
331 nfds
= max(nfds
, req
->nfds
);
333 earliest
= TM_GetEarliest(Requests
);
334 if (earliest
!= NULL
) {
335 timeout
= earliest
-> TimeLeft
;
339 if (lwp_debug
!= 0) {
340 printf("[select(%d, %p, %p, %p, ", nfds
,
342 if (timeout
.tv_sec
== -1 && timeout
.tv_usec
== -1)
345 printf("<%ld, %lu>)]\n",
346 (long)timeout
.tv_sec
,
347 (unsigned long)timeout
.tv_usec
);
350 iomgr_timeout
= timeout
;
351 if (timeout
.tv_sec
== -1 && timeout
.tv_usec
== -1) {
352 /* infinite, sort of */
353 iomgr_timeout
.tv_sec
= 100000000;
354 iomgr_timeout
.tv_usec
= 0;
357 * Check one last time for a signal delivery. If one comes after
358 * this, the signal handler will set iomgr_timeout to zero,
359 * causing the select to return immediately. The timer package
360 * won't return a zero timeval because all of those guys were
363 * I'm assuming that the kernel masks signals while it's picking up
364 * the parameters to select. This may a bad assumption. -DN
366 if (anySigsDelivered
)
367 continue; /* go to the top and handle them. */
370 * select runs much faster if NULL's are passed instead of &0s
373 fds
= select(nfds
, rfds
, wfds
, efds
, &iomgr_timeout
);
376 * For SGI and SVR4 - poll & select can return EAGAIN ...
379 && errno
!= EINTR
&& errno
!= EAGAIN
&& errno
!= ENOMEM
) {
381 for(fds
= 0; fds
< FD_SETSIZE
; fds
++) {
382 if (fcntl(fds
, F_GETFD
, 0) < 0 && errno
== EBADF
)
383 openMask
|= (1<<fds
);
388 /* force a new gettimeofday call so FT_AGetTimeOfDay calls work */
389 FT_GetTimeOfDay(&junk
, 0);
391 /* See what happened */
393 /* Action -- wake up everyone involved */
394 SignalIO(fds
, rfds
, wfds
, efds
);
396 && (iomgr_timeout
.tv_sec
!= 0 || iomgr_timeout
.tv_usec
!= 0))
397 /* Real timeout only if signal handler hasn't set
398 iomgr_timeout to zero. */
399 SignalTimeout(fds
, &timeout
);
402 LWP_DispatchProcess();
406 /************************\
408 * Signalling routines *
410 \************************/
413 SignalIO(int fds
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*efds
)
415 /* Look at everyone who's bit mask was affected */
416 FOR_ALL_ELTS(r
, Requests
, {
417 struct IoRequest
*req
;
420 req
= (struct IoRequest
*) r
-> BackPointer
;
422 if (rfds
&& req
->rfds
&& FD_LOGAND(req
->rfds
, rfds
)) {
423 FD_AND(req
->rfds
, rfds
);
426 if (wfds
&& req
->wfds
&& FD_LOGAND(req
->wfds
, wfds
)) {
427 FD_AND(req
->wfds
, wfds
);
430 if (efds
&& req
->efds
&& FD_LOGAND(req
->efds
, efds
)) {
431 FD_AND(req
->efds
, efds
);
437 TM_Remove(Requests
, &req
->timeout
);
438 LWP_QSignal(pid
=req
->pid
);
439 pid
->iomgrRequest
= 0;
446 SignalTimeout(int fds
, struct timeval
*timeout
)
448 /* Find everyone who has specified timeout */
449 FOR_ALL_ELTS(r
, Requests
, {
450 struct IoRequest
*req
;
452 req
= (struct IoRequest
*) r
-> BackPointer
;
453 if (TM_eql(&r
->TimeLeft
, timeout
)) {
455 TM_Remove(Requests
, &req
->timeout
);
456 LWP_QSignal(pid
=req
->pid
);
457 pid
->iomgrRequest
= 0;
463 /*****************************************************\
465 * Signal handling routine (not to be confused with *
466 * signalling routines, above). *
468 \*****************************************************/
470 SigHandler (int signo
)
472 if (badsig(signo
) || (sigsHandled
& mysigmask(signo
)) == 0)
473 return; /* can't happen. */
474 sigDelivered
[signo
] = TRUE
;
475 anySigsDelivered
= TRUE
;
476 /* Make sure that the IOMGR process doesn't pause on the select. */
477 iomgr_timeout
.tv_sec
= 0;
478 iomgr_timeout
.tv_usec
= 0;
481 /* Alright, this is the signal signalling routine. It delivers LWP signals
482 to LWPs waiting on Unix signals. NOW ALSO CAN YIELD!! */
491 anySigsDelivered
= FALSE
;
493 /* handle software signals */
494 stackSize
= (AFS_LWP_MINSTACKSIZE
< lwp_MaxStackSeen
?
495 lwp_MaxStackSeen
: AFS_LWP_MINSTACKSIZE
);
496 for (i
=0; i
< NSOFTSIG
; i
++) {
498 if ((p
= sigProc
[i
]) != NULL
) /* This yields!!! */
499 LWP_CreateProcess(p
, stackSize
, LWP_NORMAL_PRIORITY
, sigRock
[i
],
500 "SignalHandler", &pid
);
504 for (i
= 1; i
<= NSIG
; ++i
) /* forall !badsig(i) */
505 if ((sigsHandled
& mysigmask(i
)) && sigDelivered
[i
] == TRUE
) {
506 sigDelivered
[i
] = FALSE
;
507 LWP_NoYieldSignal (sigEvents
[i
]);
514 /***************************\
516 * User-callable routines *
518 \***************************/
521 /* Keep IOMGR process id */
522 static PROCESS IOMGR_Id
= NULL
;
525 IOMGR_SoftSig(void (*aproc
)(), char *arock
)
528 for (i
=0;i
<NSOFTSIG
;i
++) {
529 if (sigProc
[i
] == 0) {
533 anySigsDelivered
= TRUE
;
534 iomgr_timeout
.tv_sec
= 0;
535 iomgr_timeout
.tv_usec
= 0;
544 IOMGR_Initialize(void)
548 /* If lready initialized, just return */
549 if (IOMGR_Id
!= NULL
) return LWP_SUCCESS
;
551 /* Init LWP if someone hasn't yet. */
552 if (LWP_InitializeProcessSupport (LWP_NORMAL_PRIORITY
, &pid
)
556 /* Initialize request lists */
557 if (TM_Init(&Requests
) < 0) return -1;
559 /* Initialize signal handling stuff. */
561 anySigsDelivered
= TRUE
; /*
562 * A soft signal may have happened before
563 * IOMGR_Initialize: so force a check for
567 return LWP_CreateProcess(IOMGR
, AFS_LWP_MINSTACKSIZE
, 0, 0,
568 "IO MANAGER", &IOMGR_Id
);
578 status
= LWP_DestroyProcess(IOMGR_Id
);
584 * signal I/O for anyone who is waiting for a FD or a timeout;
585 * not too cheap, since forces select and timeofday check
590 fd_set readfds
, writefds
, exceptfds
;
591 fd_set
*rfds
, *wfds
, *efds
;
596 FT_GetTimeOfDay(&tv
, 0); /* force accurate time check */
599 struct IoRequest
*req
;
600 struct TM_Elem
*expired
;
601 expired
= TM_GetExpired(Requests
);
602 if (expired
== NULL
) break;
603 req
= (struct IoRequest
*) expired
-> BackPointer
;
605 if (lwp_debug
!= 0) puts("[Polling SELECT]");
609 FD_ZERO(&req
->readfds
);
610 FD_ZERO(&req
->writefds
);
611 FD_ZERO(&req
->exceptfds
);
614 req
->rfds
= req
->wfds
= req
->efds
= NULL
;
616 req
->result
= 0; /* no fds ready */
617 TM_Remove(Requests
, &req
->timeout
);
619 req
-> timeout
.Next
= (struct TM_Elem
*) 2;
620 req
-> timeout
.Prev
= (struct TM_Elem
*) 2;
622 LWP_QSignal(req
->pid
);
623 req
->pid
->iomgrRequest
= 0;
626 /* Collect requests & update times */
627 FD_ZERO(&readfds
); /* XXX - should not be needed */
630 rfds
= wfds
= efds
= NULL
;
632 FOR_ALL_ELTS(r
, Requests
, {
633 struct IoRequest
*req
;
634 req
= (struct IoRequest
*) r
-> BackPointer
;
638 FD_OR(rfds
, req
->rfds
);
641 FD_COPY(req
->rfds
, rfds
);
647 FD_OR(wfds
, req
->wfds
);
650 FD_COPY(req
->wfds
, wfds
);
656 FD_OR(efds
, req
->efds
);
659 FD_COPY(req
->efds
, efds
);
662 nfds
= max(nfds
, req
->nfds
);
667 code
= select(nfds
, rfds
, wfds
, efds
, &tv
);
670 SignalIO(code
, rfds
, wfds
, efds
);
673 LWP_DispatchProcess(); /* make sure others run */
674 LWP_DispatchProcess();
679 IOMGR_Select(int nfds
, fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
680 struct timeval
*timeout
)
682 struct IoRequest
*request
;
685 /* See if polling request. If so, handle right here */
686 if (timeout
!= NULL
) {
687 if (timeout
->tv_sec
== 0 && timeout
->tv_usec
== 0) {
690 if (lwp_debug
!= 0) puts("[Polling SELECT]");
695 timeout
->tv_usec
= 0;
696 fds
= select(nfds
, readfds
, writefds
, exceptfds
,
698 } while (fds
< 0 && errno
== EAGAIN
);
700 return (fds
> 1 ? 1 : fds
);
704 /* Construct request block & insert */
705 request
= NewRequest();
707 request
->rfds
= NULL
;
709 request
->rfds
= &request
->readfds
;
710 FD_COPY(readfds
, request
->rfds
);
713 if (writefds
== NULL
)
714 request
->wfds
= NULL
;
716 request
->wfds
= &request
->writefds
;
717 FD_COPY(writefds
, request
->wfds
);
720 if (exceptfds
== NULL
)
721 request
->efds
= NULL
;
723 request
->efds
= &request
->exceptfds
;
724 FD_COPY(exceptfds
, request
->efds
);
727 request
->nfds
= nfds
;
729 if (timeout
== NULL
) {
730 request
-> timeout
.TotalTime
.tv_sec
= -1;
731 request
-> timeout
.TotalTime
.tv_usec
= -1;
733 request
-> timeout
.TotalTime
= *timeout
;
734 /* check for bad request */
735 if (timeout
->tv_sec
< 0 ||
736 timeout
->tv_usec
< 0 ||
737 timeout
->tv_usec
> 999999) {
739 iomgr_badtv
= *timeout
;
740 iomgr_badpid
= LWP_ActiveProcess
;
741 /* now fixup request */
742 if(request
->timeout
.TotalTime
.tv_sec
< 0)
743 request
->timeout
.TotalTime
.tv_sec
= 1;
744 request
->timeout
.TotalTime
.tv_usec
= 100000;
748 request
-> timeout
.BackPointer
= (char *) request
;
750 /* Insert my PID in case of IOMGR_Cancel */
751 request
-> pid
= LWP_ActiveProcess
;
752 LWP_ActiveProcess
-> iomgrRequest
= request
;
755 request
-> timeout
.Next
= (struct TM_Elem
*) 1;
756 request
-> timeout
.Prev
= (struct TM_Elem
*) 1;
758 TM_Insert(Requests
, &request
->timeout
);
760 /* Wait for action */
763 /* Update parameters & return */
764 if (readfds
!= NULL
) FD_COPY(&request
->readfds
, readfds
);
765 if (writefds
!= NULL
) FD_COPY(&request
->writefds
, writefds
);
766 if (exceptfds
!= NULL
) FD_COPY(&request
->exceptfds
, exceptfds
);
767 result
= request
-> result
;
768 FreeRequest(request
);
769 return (result
> 1 ? 1 : result
);
773 IOMGR_Cancel(PROCESS pid
)
775 struct IoRequest
*request
;
777 if ((request
= pid
->iomgrRequest
) == 0) return -1; /* Pid not found */
779 FD_ZERO(&request
->readfds
);
780 FD_ZERO(&request
->writefds
);
781 FD_ZERO(&request
->exceptfds
);
782 request
->rfds
= request
->wfds
= request
->efds
= NULL
;
785 request
-> result
= -2;
786 TM_Remove(Requests
, &request
->timeout
);
788 request
-> timeout
.Next
= (struct TM_Elem
*) 5;
789 request
-> timeout
.Prev
= (struct TM_Elem
*) 5;
791 LWP_QSignal(request
->pid
);
792 pid
->iomgrRequest
= 0;
798 * Cause delivery of signal signo to result in a LWP_SignalProcess of
802 IOMGR_Signal (int signo
, char *event
)
804 #ifdef AFS_POSIX_SIGNALS
813 return LWP_EBADEVENT
;
814 #ifdef AFS_POSIX_SIGNALS
815 sa
.sa_handler
= SigHandler
;
816 sigfillset(&sa
.sa_mask
);
819 sv
.sv_handler
= SigHandler
;
820 sv
.sv_mask
= ~0; /* mask all signals */
823 sigsHandled
|= mysigmask(signo
);
824 sigEvents
[signo
] = event
;
825 sigDelivered
[signo
] = FALSE
;
826 #ifdef AFS_POSIX_SIGNALS
827 if (sigaction (signo
, &sa
, &oldVecs
[signo
]) == -1)
830 if (sigvec (signo
, &sv
, &oldVecs
[signo
]) == -1)
836 /* Stop handling occurances of signo. */
838 IOMGR_CancelSignal (int signo
)
840 if (badsig(signo
) || (sigsHandled
& mysigmask(signo
)) == 0)
842 #ifdef AFS_POSIX_SIGNALS
843 sigaction (signo
, &oldVecs
[signo
], (struct sigaction
*)0);
845 sigvec (signo
, &oldVecs
[signo
], (struct sigvec
*)0);
847 sigsHandled
&= ~mysigmask(signo
);
852 * This routine calls select is a fashion that simulates the standard
856 IOMGR_Sleep (unsigned int seconds
)
858 struct timeval timeout
;
860 timeout
.tv_sec
= seconds
;
862 IOMGR_Select(0, NULL
, NULL
, NULL
, &timeout
);