summaryrefslogtreecommitdiff
path: root/lib/thread.c
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2017-04-28 22:45:59 +0000
committerQuentin Young <qlyoung@cumulusnetworks.com>2017-04-30 23:06:14 +0000
commit705f21797e348a02660a638b6d1b2751ef37372e (patch)
tree181a9b3d635fb4df4eb7b2a79542a47213089721 /lib/thread.c
parent98f14af8bf8340115049e0df4888b6acc8701ea5 (diff)
lib: allow nonblocking thread_fetch()
This change adds three fields to thread_master and associated code to use them. The fields are: * long selectpoll_timeout This is a millisecond value that, if nonzero, will override the internally calculated timeout for select()/poll(). -1 indicates nonblocking while a positive value indicates the desired timeout in milliseconds. * bool spin This indicates whether a call to thread_fetch() should result in a loop until work is available. By default this is set to true, in order to keep the default behavior. In this case a return value of NULL indicates that a fatal signal was received in select() or poll(). If it is set to false, thread_fetch() will return immediately. NULL is then an acceptable return value if there is no work to be done. * bool handle_signals This indicates whether or not the pthread that owns the thread master is responsible for handling signals (since this is an MT-unsafe operation, it is best to have just the root thread do it). It is set to true by default. Non-root pthreads should set this to false. Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
Diffstat (limited to 'lib/thread.c')
-rw-r--r--lib/thread.c48
1 files changed, 42 insertions, 6 deletions
diff --git a/lib/thread.c b/lib/thread.c
index 6cd3b9676f..d4ed5d1a08 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -376,6 +376,8 @@ thread_master_create (void)
rv->background = pqueue_create();
rv->timer->cmp = rv->background->cmp = thread_timer_cmp;
rv->timer->update = rv->background->update = thread_timer_update;
+ rv->spin = true;
+ rv->handle_signals = true;
#if defined(HAVE_POLL)
rv->handler.pfdsize = rv->fd_limit;
@@ -696,15 +698,45 @@ static int
fd_select (struct thread_master *m, int size, thread_fd_set *read, thread_fd_set *write, thread_fd_set *except, struct timeval *timer_wait)
{
int num;
+
+ /* If timer_wait is null here, that means either select() or poll() should
+ * block indefinitely, unless the thread_master has overriden it. select()
+ * and poll() differ in the timeout values they interpret as an indefinite
+ * block; select() requires a null pointer, while poll takes a millisecond
+ * value of -1.
+ *
+ * The thread_master owner has the option of overriding the default behavior
+ * by setting ->selectpoll_timeout. If the value is positive, it specifies
+ * the maximum number of milliseconds to wait. If the timeout is -1, it
+ * specifies that we should never wait and always return immediately even if
+ * no event is detected. If the value is zero, the behavior is default.
+ */
+
#if defined(HAVE_POLL)
- /* recalc timeout for poll. Attention NULL pointer is no timeout with
- select, where with poll no timeount is -1 */
int timeout = -1;
- if (timer_wait != NULL)
+
+ if (timer_wait != NULL && m->selectpoll_timeout == 0) // use the default value
timeout = (timer_wait->tv_sec*1000) + (timer_wait->tv_usec/1000);
+ else if (m->selectpoll_timeout > 0) // use the user's timeout
+ timeout = m->selectpoll_timeout;
+ else if (m->selectpoll_timeout < 0) // effect a poll (return immediately)
+ timeout = 0;
num = poll (m->handler.pfds, m->handler.pfdcount + m->handler.pfdcountsnmp, timeout);
#else
+ struct timeval timeout;
+ if (m->selectpoll_timeout > 0) // use the user's timeout
+ {
+ timeout.tv_sec = m->selectpoll_timeout / 1000;
+ timeout.tv_usec = (m->selectpoll_timeout % 1000) * 1000;
+ timer_wait = &timeout;
+ }
+ else if (m->selectpoll_timeout < 0) // effect a poll (return immediately)
+ {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ timer_wait = &timeout;
+ }
num = select (size, read, write, except, timer_wait);
#endif
@@ -1232,12 +1264,13 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
struct timeval *timer_wait = &timer_val;
struct timeval *timer_wait_bg;
- while (1)
+ do
{
int num = 0;
/* Signals pre-empt everything */
- quagga_sigevent_process ();
+ if (m->handle_signals)
+ quagga_sigevent_process ();
pthread_mutex_lock (&m->mtx);
/* Drain the ready queue of already scheduled jobs, before scheduling
@@ -1331,7 +1364,10 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
}
pthread_mutex_unlock (&m->mtx);
- }
+
+ } while (m->spin);
+
+ return NULL;
}
unsigned long