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