1 #include <lha_internal.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 /*
5  * Substitute poll(2) function using POSIX real time signals.
6  *
7  * The poll(2) system call often has significant latencies and realtime
8  * impacts (probably because of its variable length argument list).
9  *
10  * These functions let us use real time signals and sigtimedwait(2) instead
11  * of poll - for those files which work with real time signals.
12  * In the 2.4 series of Linux kernels, this does *not* include FIFOs.
13  *
14  * NOTE:  We (have to) grab the SIGPOLL signal for our own purposes.
15  *		Hope that's OK with you...
16  *
17  * Special caution:  We can only incompletely simulate the difference between
18  * the level-triggered interface of poll(2) and the edge-triggered behavior
19  * of I/O signals.  As a result you *must* read all previously-indicated
20  * incoming data before calling cl_poll() again.  Otherwise you may miss
21  * some incoming data (and possibly hang).
22  *
23  *
24  * Copyright (C) 2003 IBM Corporation
25  *
26  * Author:	<alanr@unix.sh>
27  *
28  * This software licensed under the GNU LGPL.
29  *
30  *
31  * This library is free software; you can redistribute it and/or
32  * modify it under the terms of version 2.1 of the GNU Lesser General Public
33  * License as published by the Free Software Foundation.
34  *
35  * This library is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
38  * Lesser General Public License for more details.
39  *
40  * You should have received a copy of the GNU Lesser General Public
41  * License along with this library; if not, write to the Free Software
42  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
43  *
44  **************************************************************************/
45 
46 
47 #define	__USE_GNU	1
48 #	include <fcntl.h>
49 #undef	__USE_GNU
50 
51 #include <errno.h>
52 #include <string.h>
53 #include <glib.h>
54 #include <clplumbing/cl_log.h>
55 #include <clplumbing/cl_poll.h>
56 #include <clplumbing/cl_signal.h>
57 
58 
59 
60 /* Turn on to log odd realtime behavior */
61 
62 #define	TIME_CALLS	1
63 #ifdef	TIME_CALLS
64 #	include <clplumbing/longclock.h>
65 #	include <clplumbing/cl_log.h>
66 #endif
67 
68 static int	debug = 0;
69 
70 int	/* Slightly sleazy... */
cl_glibpoll(GPollFD * ufds,guint nfsd,gint timeout)71 cl_glibpoll(GPollFD* ufds, guint nfsd, gint timeout)
72 {
73 	(void)debug;
74 	return cl_poll((struct pollfd*)ufds, nfsd, timeout);
75 }
76 
77 #if defined (F_SETSIG) && defined(F_SETOWN) && defined (O_ASYNC)
78 #	define HAVE_FCNTL_F_SETSIG
79 #endif
80 
81 #ifndef HAVE_FCNTL_F_SETSIG
82 
83 /*
84  * Dummy cl_poll() and cl_poll_ignore() functions for systems where
85  * we don't have all the support we need.
86  */
87 
88 int
cl_poll(struct pollfd * fds,unsigned int nfds,int timeout)89 cl_poll(struct pollfd *fds, unsigned int nfds, int timeout)
90 {
91 	return poll(fds, (nfds_t)nfds, timeout);
92 }
93 
94 int
cl_poll_ignore(int fd)95 cl_poll_ignore(int fd)
96 {
97 	return 0;
98 }
99 
100 #else /* HAVE_FCNTL_F_SETSIG */
101 static void dump_fd_info(struct pollfd *fds, unsigned int nfds, int timeoutms);
102 static void check_fd_info(struct pollfd *fds, unsigned int nfds);
103 static void cl_real_poll_fd(int fd);
104 static void cl_poll_sigpoll_overflow_sigaction(int nsig, siginfo_t* , void*);
105 static void cl_poll_sigpoll_overflow(void);
106 static int cl_poll_get_sigqlimit(void);
107 typedef	unsigned char poll_bool;
108 
109 /*
110  *	Here's our strategy:
111  *	We have a set of signals which we use for these file descriptors,
112  *	and we use sigtimedwait(2) to wait on information from these various
113  *	signals.
114  *
115  *	If we are ever asked to wait for a particular signal, then we will
116  *	enable signals for that file descriptor, and post the events in
117  *	our own cache.  The next time you include that signal in a call
118  *	to cl_poll(), you will get the information delivered
119  *	to you in your cl_poll() call.
120  *
121  *	If you want to stop monitoring a particular file descriptor, use
122  *	cl_poll_ignore() for that purpose.  Doing this is a good idea, but
123  *	not fatal if omitted...
124  */
125 
126 /* Information about a file descriptor we're monitoring */
127 
128 typedef struct poll_fd_info_s {
129 	short		nsig;		/* Which signal goes with it? */
130 	short		pendevents;	/* Pending events */
131 }poll_info_t;
132 
133 static int		max_allocated = 0;
134 static poll_bool*	is_monitored = NULL;	/* Sized by max_allocated */
135 static poll_info_t*	monitorinfo = NULL;	/* Sized by max_allocated */
136 static int		cl_nsig = 0;
137 static gboolean		SigQOverflow = FALSE;
138 
139 static int	cl_init_poll_sig(struct pollfd *fds, unsigned int nfds);
140 static short	cl_poll_assignsig(int fd);
141 static void	cl_poll_sigaction(int nsig, siginfo_t* info, void* v);
142 static int	cl_poll_prepsig(int nsig);
143 
144 
145 /*
146  *	SignalSet is the set of all file descriptors we're monitoring.
147  *
148  *	We monitor a file descriptor forever, unless you tell us not to
149  *	by calling cl_poll_ignore(), or you (mistakenly) give it to
150  *	us to look at in another poll call after you've closed it.
151  */
152 
153 static sigset_t	SignalSet;
154 
155 /* Select the signal you want us to use (must be a RT signal) */
156 int
cl_poll_setsig(int nsig)157 cl_poll_setsig(int nsig)
158 {
159 	if (nsig < SIGRTMIN || nsig >= SIGRTMAX) {
160 		errno = EINVAL;
161 		return -1;
162 	}
163 	if (cl_poll_prepsig(nsig) < 0) {
164 		return -1;
165 	}
166 	cl_nsig = nsig;
167 	return 0;
168 }
169 
170 /*
171  *	It's harmless to call us multiple times on the same signal.
172  */
173 static int
cl_poll_prepsig(int nsig)174 cl_poll_prepsig(int nsig)
175 {
176 	static gboolean	setinityet=FALSE;
177 
178 	if (!setinityet) {
179 		CL_SIGEMPTYSET(&SignalSet);
180 		cl_signal_set_simple_action(SIGPOLL
181 		,	cl_poll_sigpoll_overflow_sigaction
182 		,	NULL);
183 		setinityet = TRUE;
184 	}
185 	if (CL_SIGINTERRUPT(nsig, FALSE) < 0) {
186 		cl_perror("sig_interrupt(%d, FALSE)", nsig);
187 		return -1;
188 	}
189 	if (CL_SIGADDSET(&SignalSet, nsig) < 0) {
190 		cl_perror("sig_addset(&SignalSet, %d)", nsig);
191 		return -1;
192 	}
193 	if (CL_SIGPROCMASK(SIG_BLOCK, &SignalSet, NULL) < 0) {
194 		cl_perror("sig_sigprocmask(SIG_BLOCK, sig %d)", nsig);
195 		return -1;
196 	}
197 	if (debug) {
198 		cl_log(LOG_DEBUG
199 		,	"Signal %d belongs to us...", nsig);
200 		cl_log(LOG_DEBUG, "cl_poll_prepsig(%d) succeeded.", nsig);
201 	}
202 
203 	return 0;
204 }
205 
206 #define	FD_CHUNKSIZE	64
207 
208 /* Set of events everyone must monitor whether they want to or not ;-) */
209 #define	CONSTEVENTS	(POLLHUP|POLLERR|POLLNVAL)
210 
211 #define	RECORDFDEVENT(fd, flags) (monitorinfo[fd].pendevents |= (flags))
212 
213 /*
214  * Initialized our poll-simulation data structures.
215  * This means (among other things) registering any monitored
216  * file descriptors.
217  */
218 static int
cl_init_poll_sig(struct pollfd * fds,unsigned int nfds)219 cl_init_poll_sig(struct pollfd *fds, unsigned int nfds)
220 {
221 	unsigned	j;
222 	int		maxmonfd = -1;
223 	int		nmatch = 0;
224 
225 
226 	if (cl_nsig == 0) {
227 		cl_nsig = ((SIGRTMIN+SIGRTMAX)/2);
228 		if (cl_poll_setsig(cl_nsig) < 0) {
229 			return -1;
230 		}
231 	}
232 	for (j=0; j < nfds; ++j) {
233 		const int fd = fds[j].fd;
234 
235 		if (fd > maxmonfd) {
236 			maxmonfd = fd;
237 		}
238 	}
239 
240 	/* See if we need to malloc/realloc our data structures */
241 
242 	if (maxmonfd >= max_allocated) {
243 		int	newsize;
244 		int	growthamount;
245 
246 		newsize = ((maxmonfd + FD_CHUNKSIZE)/FD_CHUNKSIZE)
247 		*	FD_CHUNKSIZE;
248 		growthamount = newsize - max_allocated;
249 
250 		/* This can't happen ;-) */
251 		if (growthamount <= 0 || newsize <= maxmonfd) {
252 			errno = EINVAL;
253 			return -1;
254 		}
255 
256 		/* Allocate (more) memory! */
257 
258 		if ((is_monitored = (poll_bool*)realloc(is_monitored
259 		,	newsize * sizeof(poll_bool))) == NULL
260 		||	(monitorinfo = (poll_info_t*) realloc(monitorinfo
261 		,	newsize * sizeof(poll_info_t))) == NULL) {
262 
263 			if (is_monitored) {
264 				free(is_monitored);
265 				is_monitored = NULL;
266 			}
267 			if (monitorinfo) {
268 				free(monitorinfo);
269 				monitorinfo = NULL;
270 			}
271 			max_allocated = 0;
272 			errno = ENOMEM;
273 			return -1;
274 		}
275 		memset(monitorinfo+max_allocated, 0
276 		,	growthamount * sizeof(monitorinfo[0]));
277 		memset(is_monitored+max_allocated, FALSE
278 		,	growthamount*sizeof(is_monitored[0]));
279 		max_allocated = newsize;
280 	}
281 
282 	if (fds->events != 0 && debug) {
283 		cl_log(LOG_DEBUG
284 		,	"Current event mask for fd [0] {%d} 0x%x"
285 		,	fds->fd, fds->events);
286 	}
287 	/*
288 	 * Examine each fd for the following things:
289 	 *	Is it already monitored?
290 	 *		if not, set it up for monitoring.
291 	 *	Do we have events for it?
292 	 *		if so, post events...
293 	 */
294 
295 	for (j=0; j < nfds; ++j) {
296 		const int	fd = fds[j].fd;
297 		poll_info_t*	moni = monitorinfo+fd;
298 		short		nsig;
299 		int		badfd = FALSE;
300 
301 		is_monitored[fd] = TRUE;
302 
303 		if (moni->nsig <= 0) {
304 			nsig = cl_poll_assignsig(fd);
305 			if (nsig < 0) {
306 				RECORDFDEVENT(fd, POLLERR);
307 				badfd = TRUE;
308 			}else{
309 				/* Use real poll(2) to get initial
310 				 * event status
311 				 */
312 				moni->nsig = nsig;
313 				cl_real_poll_fd(fd);
314 			}
315 		}else if (fcntl(fd, F_GETFD) < 0) {
316 			cl_log(LOG_ERR, "bad fd(%d)", fd);
317 			RECORDFDEVENT(fd, POLLNVAL);
318 			badfd = TRUE;
319 		}
320 
321 		/* Look for pending events... */
322 
323 		fds[j].revents = (moni->pendevents
324 		&	(fds[j].events|CONSTEVENTS));
325 
326 		if (fds[j].revents) {
327 			++nmatch;
328 			moni->pendevents &= ~(fds[j].revents);
329 			if (debug) {
330 				cl_log(LOG_DEBUG
331 				,	"revents for fd %d: 0x%x"
332 				,	fds[j].fd, fds[j].revents);
333 				cl_log(LOG_DEBUG
334 				,	"events for fd %d: 0x%x"
335 				,	fds[j].fd, fds[j].events);
336 			}
337 		}else if (fds[j].events && debug) {
338 			cl_log(LOG_DEBUG
339 			,	"pendevents for fd %d: 0x%x"
340 			,	fds[j].fd, moni->pendevents);
341 		}
342 		if (badfd) {
343 			cl_poll_ignore(fd);
344 		}
345 	}
346 	if (nmatch != 0 && debug) {
347 		cl_log(LOG_DEBUG, "Returning %d events from cl_init_poll_sig()"
348 		,	nmatch);
349 	}
350 	return nmatch;
351 }
352 
353 /*
354  * Initialize our current state of the world with info from the
355  * real poll(2) call.
356  *
357  * We call this when we first see a particular fd, and after a signal
358  * queue overflow.
359  */
360 static void
cl_real_poll_fd(int fd)361 cl_real_poll_fd(int fd)
362 {
363 	struct pollfd	pfd[1];
364 
365 	if (fd >= max_allocated || !is_monitored[fd]) {
366 		return;
367 	}
368 
369 	if (debug) {
370 		cl_log(LOG_DEBUG
371 		,	"Calling poll(2) on fd %d", fd);
372 	}
373 	/* Get the current state of affaris from poll(2) */
374 	pfd[0].fd = fd;
375 	pfd[0].revents = 0;
376 	pfd[0].events = ~0;
377 	if (poll(pfd, 1, 0) >= 0) {
378 		RECORDFDEVENT(fd, pfd[0].revents);
379 		if (pfd[0].revents & (POLLNVAL|POLLERR)) {
380 			cl_log(LOG_INFO, "cl_poll_real_fd(%d): error in revents [%d]"
381 			,	fd, pfd[0].revents);
382 		}
383 		if (debug) {
384 			cl_log(LOG_DEBUG
385 			,	"Old news from poll(2) for fd %d: 0x%x"
386 			,	fd, pfd[0].revents);
387 		}
388 	}else{
389 		if (fcntl(fd, F_GETFL) < 0) {
390 			cl_perror("cl_poll_real_fd(%d): F_GETFL failure"
391 			,	fd);
392 			RECORDFDEVENT(fd, POLLNVAL);
393 		}else{
394 			RECORDFDEVENT(fd, POLLERR);
395 		}
396 	}
397 }
398 
399 /*
400  * Assign a signal for monitoring the given file descriptor
401  */
402 
403 static short
cl_poll_assignsig(int fd)404 cl_poll_assignsig(int fd)
405 {
406 	int		flags;
407 
408 
409 	if (debug) {
410 		cl_log(LOG_DEBUG
411 		,	"Signal %d monitors fd %d...", cl_nsig, fd);
412 	}
413 
414 	/* Test to see if the file descriptor is good */
415 	if ((flags = fcntl(fd, F_GETFL)) < 0) {
416 		cl_perror("cl_poll_assignsig(%d) F_GETFL failure"
417 		,	fd);
418 		return -1;
419 	}
420 
421 	/* Associate the right signal with the fd */
422 
423 	if (fcntl(fd, F_SETSIG, cl_nsig) < 0) {
424 		cl_perror("cl_poll_assignsig(%d) F_SETSIG failure"
425 		,	fd);
426 		return -1;
427 	}
428 
429 	/* Direct the signals to us */
430 	if (fcntl(fd, F_SETOWN, getpid()) < 0) {
431 		cl_perror("cl_poll_assignsig(%d) F_SETOWN failure", fd);
432 		return -1;
433 	}
434 
435 	/* OK... Go ahead and send us signals! */
436 
437 	if (fcntl(fd, F_SETFL, flags|O_ASYNC) < 0) {
438 		cl_perror("cl_poll_assignsig(%d) F_SETFL(O_ASYNC) failure"
439 		,	fd);
440 		return -1;
441 	}
442 
443 	return cl_nsig;
444 }
445 
446 
447 /*
448  *	This is a function we call as a (fake) signal handler.
449  *
450  *	It records events to our "monitorinfo" structure.
451  *
452  *	Except for the cl_log() call, it could be called in a signal
453  *	context.
454  */
455 
456 static void
cl_poll_sigaction(int nsig,siginfo_t * info,void * v)457 cl_poll_sigaction(int nsig, siginfo_t* info, void* v)
458 {
459 	int	fd;
460 
461 	/* What do you suppose all the various si_code values mean? */
462 
463 	fd = info->si_fd;
464 	if (debug) {
465 		cl_log(LOG_DEBUG
466 		,	"cl_poll_sigaction(nsig=%d fd=%d"
467 		", si_code=%d si_band=0x%lx)"
468 		,	nsig, fd, info->si_code
469 		,	(unsigned long)info->si_band);
470 	}
471 
472 	if (fd <= 0) {
473 		return;
474 	}
475 
476 
477 	if (fd >= max_allocated || !is_monitored[fd]) {
478 		return;
479 	}
480 
481 	/* We should not call logging functions in (real) signal handlers */
482 	if (nsig != monitorinfo[fd].nsig) {
483 		cl_log(LOG_ERR, "cl_poll_sigaction called with signal %d/%d"
484 		,	nsig, monitorinfo[fd].nsig);
485 	}
486 
487 	/* Record everything as a pending event. */
488 	RECORDFDEVENT(fd, info->si_band);
489 }
490 
491 
492 
493 /*
494  *	This is called whenever a file descriptor shouldn't be
495  *	monitored any more.
496  */
497 int
cl_poll_ignore(int fd)498 cl_poll_ignore(int fd)
499 {
500 	int	flags;
501 
502 	if (debug) {
503 		cl_log(LOG_DEBUG
504 		,	"cl_poll_ignore(%d)", fd);
505 	}
506 	if (fd <  0 || fd >= max_allocated) {
507 		errno = EINVAL;
508 		return -1;
509 	}
510 	if (!is_monitored[fd]) {
511 		return 0;
512 	}
513 
514 	is_monitored[fd] = FALSE;
515 	memset(monitorinfo+fd, 0, sizeof(monitorinfo[0]));
516 
517 	if ((flags = fcntl(fd, F_GETFL)) >= 0) {
518 		flags &= ~O_ASYNC;
519 		if (fcntl(fd, F_SETFL, flags) < 0) {
520 			return -1;
521 		}
522 	}else{
523 		return flags;
524 	}
525 	return 0;
526 }
527 
528 
529 /*
530  * cl_poll: fake poll routine based on POSIX realtime signals.
531  *
532  * We want to emulate poll as exactly as possible, but poll has a couple
533  * of problems:  scaleability, and it tends to sleep in the kernel
534  * because the first argument is an argument of arbitrary size, and
535  * generally requires allocating memory.
536  *
537  * The challenge is that poll is level-triggered, but the POSIX
538  * signals (and sigtimedwait(2)) are edge triggered.  This is
539  * one of the reasons why we have the cl_real_poll_fd() function
540  * - to get the current "level" before we start.
541  * Once we have this level we can compute something like the current
542  * level
543  */
544 
545 int
cl_poll(struct pollfd * fds,unsigned int nfds,int timeoutms)546 cl_poll(struct pollfd *fds, unsigned int nfds, int timeoutms)
547 {
548 	int				nready;
549 	struct	timespec		ts;
550 	static const struct timespec	zerotime = {0L, 0L};
551 	const struct timespec*		itertime = &ts;
552 	siginfo_t			info;
553 	int				eventcount = 0;
554 	unsigned int			j;
555 	int				savederrno = errno;
556 	int				stw_errno;
557 	int				rc;
558 	longclock_t			starttime;
559 	longclock_t			endtime;
560 	const int			msfudge
561 	=				2* 1000/hz_longclock();
562 	int				mselapsed = 0;
563 
564 	/* Do we have any old news to report? */
565 	if ((nready=cl_init_poll_sig(fds, nfds)) != 0) {
566 		/* Return error or old news to report */
567 		if (debug) {
568 			cl_log(LOG_DEBUG, "cl_poll: early return(%d)", nready);
569 		}
570 		return nready;
571 	}
572 
573 	/* Nothing to report yet... */
574 
575 	/* So, we'll do a sigtimedwait(2) to wait for signals
576 	 * and see if we can find something to report...
577 	 *
578 	 * cl_init_poll() prepared a set of file signals to watch...
579 	 */
580 
581 recalcandwaitagain:
582 	if (timeoutms >= 0) {
583 		ts.tv_sec = timeoutms / 1000;
584 		ts.tv_nsec = (((unsigned long)timeoutms) % 1000UL)*1000000UL;
585 	}else{
586 		ts.tv_sec = G_MAXLONG;
587 		ts.tv_nsec = 99999999UL;
588 	}
589 
590 	/*
591 	 * Perform a timed wait for any of our signals...
592 	 *
593 	 * We shouldn't sleep for any call but (possibly) the first one.
594 	 * Subsequent calls should just pick up other events without
595 	 * sleeping.
596 	 */
597 
598 	starttime = time_longclock();
599 	/*
600 	 * Wait up to the prescribed time for a signal.
601 	 * If we get a signal, then loop grabbing all other
602 	 * pending signals. Note that subsequent iterations will
603 	 * use &zerotime to get the minimum wait time.
604 	 */
605 	if (debug) {
606 		check_fd_info(fds, nfds);
607 		dump_fd_info(fds, nfds, timeoutms);
608 	}
609 waitagain:
610 	while (sigtimedwait(&SignalSet, &info, itertime) >= 0) {
611 		int		nsig = info.si_signo;
612 
613 		/* Call signal handler to simulate signal reception */
614 
615 		cl_poll_sigaction(nsig, &info, NULL);
616 		itertime = &zerotime;
617 	}
618 	stw_errno=errno; /* Save errno for later use */
619 	endtime = time_longclock();
620 	mselapsed = longclockto_ms(sub_longclock(endtime, starttime));
621 
622 #ifdef TIME_CALLS
623 	if (timeoutms >= 0 && mselapsed > timeoutms + msfudge) {
624 		/* We slept too long... */
625 		cl_log(LOG_WARNING
626 		,	"sigtimedwait() sequence for %d ms took %d ms"
627 		,	timeoutms, mselapsed);
628 	}
629 #endif
630 
631 	if (SigQOverflow) {
632 		/* OOPS!  Better recover from this! */
633 		/* This will use poll(2) to correct our current status */
634 		cl_poll_sigpoll_overflow();
635 	}
636 
637 	/* Post observed events and count them... */
638 
639 	for (j=0; j < nfds; ++j) {
640 		int	fd = fds[j].fd;
641 		poll_info_t*	moni = monitorinfo+fd;
642 		fds[j].revents = (moni->pendevents
643 		&	(fds[j].events|CONSTEVENTS));
644 		if (fds[j].revents) {
645 			++eventcount;
646 			moni->pendevents &= ~(fds[j].revents);
647 			/* Make POLLHUP persistent */
648 			if (fds[j].revents & POLLHUP) {
649 				moni->pendevents |= POLLHUP;
650 				/* Don't lose input events at EOF */
651 				if (fds[j].events & POLLIN) {
652 					cl_real_poll_fd(fds[j].fd);
653 				}
654 			}
655 		}
656 	}
657 	if (eventcount == 0 && stw_errno == EAGAIN && timeoutms != 0) {
658 		/* We probably saw an event the user didn't ask to see. */
659 		/* Consquently, we may have more waiting to do */
660 		if (timeoutms < 0) {
661 			/* Restore our infinite wait time */
662 			itertime = &ts;
663 			goto waitagain;
664 		}else if (timeoutms > 0) {
665 			if (mselapsed < timeoutms) {
666 				timeoutms -= mselapsed;
667 				goto recalcandwaitagain;
668 			}
669 		}
670 	}
671 	rc = (eventcount > 0 ? eventcount : (stw_errno == EAGAIN ? 0 : -1));
672 
673 	if (rc >= 0) {
674 		errno = savederrno;
675 	}
676 	return rc;
677 }
678 /*
679  * Debugging routine for printing current poll arguments, etc.
680  */
681 static void
dump_fd_info(struct pollfd * fds,unsigned int nfds,int timeoutms)682 dump_fd_info(struct pollfd *fds, unsigned int nfds, int timeoutms)
683 {
684 	unsigned	j;
685 
686 	cl_log(LOG_DEBUG, "timeout: %d milliseconds", timeoutms);
687 	for (j=0; j < nfds; ++j) {
688 		int	fd = fds[j].fd;
689 		poll_info_t*	moni = monitorinfo+fd;
690 
691 		cl_log(LOG_DEBUG, "fd %d flags: 0%o, signal: %d, events: 0x%x"
692 		", revents: 0x%x, pendevents: 0x%x"
693 		,	fd, fcntl(fd, F_GETFL), moni->nsig
694 		,	fds[j].events, fds[j].revents, moni->pendevents);
695 	}
696 	for (j=SIGRTMIN; j < (unsigned)SIGRTMAX; ++j) {
697 		if (!sigismember(&SignalSet, j)) {
698 			continue;
699 		}
700 		cl_log(LOG_DEBUG, "Currently monitoring RT signal %d", j);
701 	}
702 }
703 
704 /*
705  * Debugging routine for auditing our file descriptors, etc.
706  */
707 static void
check_fd_info(struct pollfd * fds,unsigned int nfds)708 check_fd_info(struct pollfd *fds, unsigned int nfds)
709 {
710 	unsigned	j;
711 
712 	for (j=0; j < nfds; ++j) {
713 		int	fd = fds[j].fd;
714 		poll_info_t*	moni = monitorinfo+fd;
715 
716 		if (!sigismember(&SignalSet, moni->nsig)) {
717 			cl_log(LOG_ERR, "SIGNAL %d not in monitored SignalSet"
718 			,	moni->nsig);
719 		}
720 	}
721 	for (j=0; j < 10; ++j) {
722 		int	sig;
723 		int	flags;
724 		int	pid;
725 		if ((flags = fcntl(j, F_GETFL)) < 0 || (flags & O_ASYNC) ==0){
726 			continue;
727 		}
728 		sig = fcntl(j, F_GETSIG);
729 		if (sig == 0) {
730 			cl_log(LOG_ERR, "FD %d will get SIGIO", j);
731 		}
732 		if (!sigismember(&SignalSet, sig)) {
733 			cl_log(LOG_ERR, "FD %d (signal %d) is not in SignalSet"
734 			,	j, sig);
735 		}
736 		if (sig < SIGRTMIN || sig >= SIGRTMAX) {
737 			cl_log(LOG_ERR, "FD %d (signal %d) is not RealTime"
738 			,	j, sig);
739 		}
740 		pid = fcntl(j, F_GETOWN);
741 		if (pid != getpid()) {
742 			cl_log(LOG_ERR, "FD %d (signal %d) owner is pid %d"
743 			,	j, sig, pid);
744 		}
745 	}
746 }
747 
748 /* Note that the kernel signalled an event queue overflow */
749 static void
cl_poll_sigpoll_overflow_sigaction(int nsig,siginfo_t * info,void * v)750 cl_poll_sigpoll_overflow_sigaction(int nsig, siginfo_t* info, void* v)
751 {
752 	SigQOverflow = TRUE;
753 }
754 
755 #define	MAXQNAME	"rtsig-max"
756 /*
757  * Called when signal queue overflow is suspected.
758  * We then use poll(2) to get the current data.  It's slow, but it
759  * should work quite nicely.
760  */
761 static void
cl_poll_sigpoll_overflow(void)762 cl_poll_sigpoll_overflow(void)
763 {
764 	int	fd;
765 	int	limit;
766 
767 	if (!SigQOverflow) {
768 		return;
769 	}
770 	cl_log(LOG_WARNING, "System signal queue overflow.");
771 	limit = cl_poll_get_sigqlimit();
772 	if (limit > 0) {
773 		cl_log(LOG_WARNING, "Increase '%s'. Current limit is %d"
774 		" (see sysctl(8)).", MAXQNAME, limit);
775 	}
776 
777 	SigQOverflow = FALSE;
778 
779 	for (fd = 0; fd < max_allocated; ++fd) {
780 		if (is_monitored[fd]) {
781 			cl_real_poll_fd(fd);
782 		}
783 	}
784 }
785 
786 #define	PSK	"/proc/sys/kernel/"
787 
788 /* Get current kernel signal queue limit */
789 /* This only works on Linux - but that's not a big problem... */
790 static int
cl_poll_get_sigqlimit(void)791 cl_poll_get_sigqlimit(void)
792 {
793 	int	limit = -1;
794 	int	pfd;
795 	char	result[32];
796 
797 	pfd = open(PSK MAXQNAME, O_RDONLY);
798 	if (pfd >= 0 && read(pfd, result, sizeof(result)) > 1) {
799 		limit = atoi(result);
800 		if (limit < 1) {
801 			limit = -1;
802 		}
803 	}
804 	if (pfd >= 0) {
805 		close(pfd);
806 	}
807 	return limit;
808 }
809 #endif /* HAVE_FCNTL_F_SETSIG */
810