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