summaryrefslogtreecommitdiffstats
path: root/lib/qpselect.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/qpselect.c')
-rw-r--r--lib/qpselect.c154
1 files changed, 126 insertions, 28 deletions
diff --git a/lib/qpselect.c b/lib/qpselect.c
index bcd2e2c9..3fb80daf 100644
--- a/lib/qpselect.c
+++ b/lib/qpselect.c
@@ -18,6 +18,7 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+#include "misc.h"
#include <signal.h>
#include <string.h>
@@ -30,18 +31,32 @@
#include "vector.h"
/*------------------------------------------------------------------------------
- * Sort out any debug setting
+ * Sort out QPSELECT_DEBUG.
+ *
+ * Set to 1 if defined, but blank.
+ * Set to QDEBUG if not defined.
+ *
+ * Force to 0 if VTY_NO_DEBUG is defined and not zero.
+ *
+ * So: defaults to same as QDEBUG, but no matter what QDEBUG is set to:
+ *
+ * * can set QPSELECT_DEBUG == 0 to turn off debug
+ * * or set QPSELECT_DEBUG != 0 to turn on debug
+ * * or set QPSELECT_NO_DEBUG != to force debug off
*/
-#ifdef QPSELECT_DEBUG /* Can be forced from outside */
-# if QPSELECT_DEBUG
-# define QPSELECT_DEBUG 1 /* Force 1 or 0 */
-#else
-# define QPSELECT_DEBUG 0
+
+#ifdef QPSELECT_DEBUG /* If defined, make it 1 or 0 */
+# if IS_BLANK_OPTION(QPSELECT_DEBUG)
+# undef QPSELECT_DEBUG
+# define QPSELECT_DEBUG 1
# endif
-#else
-# ifdef QDEBUG
-# define QPSELECT_DEBUG 1 /* Follow QDEBUG */
-#else
+#else /* If not defined, follow QDEBUG */
+# define QPSELECT_DEBUG QDEBUG
+#endif
+
+#ifdef QPSELECT_NO_DEBUG /* Override, if defined */
+# if IS_NOT_ZERO_OPTION(QPSELECT_NO_DEBUG)
+# undef QPSELECT_DEBUG
# define QPSELECT_DEBUG 0
# endif
#endif
@@ -283,29 +298,18 @@ qps_selection_ream(qps_selection qps, int free_structure)
/*------------------------------------------------------------------------------
* Set the signal mask for the selection.
*
- * This supports the unmasking of a single signal for the duration of the
+ * This supports the unmasking of one or more signals for the duration of the
* pselect operation.
*
- * It is assumed that the set of signals generally masked by a thread is
- * essentially static. So this function is passed that set. (So the sigmask
- * argument must have the signum signal masked.)
- *
- * If the set of signals masked by the thread changes, then this function
+ * * If the set of signals masked by the thread changes, then this function
* should be called again.
*
- * Setting a signum == 0 turns OFF the use of the sigmask.
+ * Setting a sigmask == NULL turns OFF the use of the sigmask.
*/
-void
-qps_set_signal(qps_selection qps, int signum, sigset_t sigmask)
+extern void
+qps_set_signal(qps_selection qps, const sigset_t* sigmask)
{
- qps->signum = signum ;
-
- if (signum != 0)
- {
- assert(sigismember(&sigmask, signum)) ;
- sigdelset(&sigmask, signum) ;
- qps->sigmask = sigmask ;
- } ;
+ qps->sigmask = sigmask ;
} ;
/*------------------------------------------------------------------------------
@@ -377,7 +381,7 @@ qps_pselect(qps_selection qps, qtime_t max_wait)
p_fds[qps_write_mnum],
p_fds[qps_error_mnum],
qtime2timespec(&ts, max_wait),
- (qps->signum != 0) ? &qps->sigmask : NULL) ;
+ qps->sigmask) ;
/* If have something, set and return the pending count. */
if (n > 0)
@@ -1423,3 +1427,97 @@ qps_selection_validate(qps_selection qps)
if (n != qps->pend_count)
zabort("Non-empty bit vector where tried count == 0") ;
} ;
+
+/*==============================================================================
+ * Miniature pselect -- for where want to wait for a small number of things.
+ */
+
+/*------------------------------------------------------------------------------
+ * Initialise a qps_mini and set one fd in the given mode.
+ *
+ * If the fd is < 0, sets nothing (returns empty qps_mini).
+ *
+ * Zero timeout is an indefinite wait !
+ */
+extern qps_mini
+qps_mini_set(qps_mini qm, int fd, qps_mnum_t mode, uint timeout)
+{
+ qps_super_set_zero(qm->sets, qps_mnum_count) ;
+ qm->fd_last = -1 ;
+
+ qm->interval = QTIME(timeout) ; /* convert from time in seconds */
+ qm->end_time = qt_add_monotonic(qm->interval) ;
+
+ qps_mini_add(qm, fd, mode) ;
+
+ return qm ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Add given fd in the given mode to the given qps_mini.
+ *
+ * If the fd is < 0, adds nothing (returns qps_mini unchanged).
+ */
+extern qps_mini
+qps_mini_add(qps_mini qm, int fd, qps_mnum_t mode)
+{
+ if (fd >= 0)
+ {
+ FD_SET(fd, &(qm->sets[mode].fdset)) ;
+ if (fd > qm->fd_last)
+ qm->fd_last = fd ;
+ } ;
+
+ return qm ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Wait for a qps_mini -- with given timeout, in seconds.
+ *
+ * If !signal, loops on EINTR, so will not exit until gets ready state or a
+ * timeout.
+ *
+ * If signal, will exit on EINTR. Can call this again after an EINTR return,
+ * and will continue to wait the *remainder* of the timeout interval.
+ *
+ * Returns what pselect returns: > 0 number of bits set
+ * == 0 no bits set <=> timed out
+ * < 0 EINTR (iff signal)
+ */
+extern int
+qps_mini_wait(qps_mini qm, const sigset_t* sigmask, bool signal)
+{
+ while (1)
+ {
+ struct timespec ts[1] ;
+ int n ;
+
+ n = pselect(qm->fd_last + 1,
+ &(qm->sets[qps_read_mnum].fdset),
+ &(qm->sets[qps_write_mnum].fdset),
+ &(qm->sets[qps_error_mnum].fdset),
+ (qm->interval > 0) ? qtime2timespec(ts, qm->interval)
+ : NULL,
+ sigmask) ;
+ if (n >= 0)
+ return n ;
+
+ if (errno != EINTR)
+ break ;
+
+ if (qm->interval > 0)
+ {
+ /* set new interval, in case comes back */
+ qm->interval = qm->end_time - qt_get_monotonic() ;
+ if (qm->interval < 0)
+ return 0 ;
+ } ;
+
+ if (signal)
+ return -1 ; /* signal EINTR */
+ } ;
+
+ zabort_errno("Failed in pselect") ;
+} ;
+
+