summaryrefslogtreecommitdiff
path: root/lib/thread.c
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2017-04-24 22:33:25 +0000
committerQuentin Young <qlyoung@cumulusnetworks.com>2017-05-09 20:44:19 +0000
commitffa2c8986d204f4a3e7204258fd6906af4a57c93 (patch)
tree6242b8634bc2a264339a05dcfb20b94f63c252f4 /lib/thread.c
parent7a78dea34d20e44539ccabb1b97e029003be4b40 (diff)
*: remove THREAD_ON macros, add nullity check
The way thread.c is written, a caller who wishes to be able to cancel a thread or avoid scheduling it twice must keep a reference to the thread. Typically this is done with a long lived pointer whose value is checked for null in order to know if the thread is currently scheduled. The check-and-schedule idiom is so common that several wrapper macros in thread.h existed solely to provide it. This patch removes those macros and adds a new parameter to all thread_add_* functions which is a pointer to the struct thread * to store the result of a scheduling call. If the value passed is non-null, the thread will only be scheduled if the value is null. This helps with consistency. A Coccinelle spatch has been used to transform code of the form: if (t == NULL) t = thread_add_* (...) to the form thread_add_* (..., &t) The THREAD_ON macros have also been transformed to the underlying thread.c calls. Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
Diffstat (limited to 'lib/thread.c')
-rw-r--r--lib/thread.c79
1 files changed, 50 insertions, 29 deletions
diff --git a/lib/thread.c b/lib/thread.c
index 3fb28bce26..37a71824d7 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -725,6 +725,7 @@ fd_select (struct thread_master *m, int size, thread_fd_set *read, thread_fd_set
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;
@@ -776,13 +777,19 @@ fd_clear_read_write (struct thread *thread)
/* Add new read thread. */
struct thread *
funcname_thread_add_read_write (int dir, struct thread_master *m,
- int (*func) (struct thread *), void *arg, int fd,
- debugargdef)
+ int (*func) (struct thread *), void *arg, int fd, struct thread **t_ptr,
+ debugargdef)
{
struct thread *thread = NULL;
pthread_mutex_lock (&m->mtx);
{
+ if (t_ptr && *t_ptr) // thread is already scheduled; don't reschedule
+ {
+ pthread_mutex_unlock (&m->mtx);
+ return NULL;
+ }
+
#if defined (HAVE_POLL_CALL)
thread = generic_thread_add(m, func, arg, fd, dir, debugargpass);
#else
@@ -822,6 +829,9 @@ funcname_thread_add_read_write (int dir, struct thread_master *m,
}
pthread_mutex_unlock (&thread->mtx);
}
+
+ if (t_ptr)
+ *t_ptr = thread;
}
pthread_mutex_unlock (&m->mtx);
@@ -830,11 +840,8 @@ funcname_thread_add_read_write (int dir, struct thread_master *m,
static struct thread *
funcname_thread_add_timer_timeval (struct thread_master *m,
- int (*func) (struct thread *),
- int type,
- void *arg,
- struct timeval *time_relative,
- debugargdef)
+ int (*func) (struct thread *), int type, void *arg,
+ struct timeval *time_relative, struct thread **t_ptr, debugargdef)
{
struct thread *thread;
struct pqueue *queue;
@@ -846,6 +853,12 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
pthread_mutex_lock (&m->mtx);
{
+ if (t_ptr && *t_ptr) // thread is already scheduled; don't reschedule
+ {
+ pthread_mutex_unlock (&m->mtx);
+ return NULL;
+ }
+
queue = ((type == THREAD_TIMER) ? m->timer : m->background);
thread = thread_get (m, type, func, arg, debugargpass);
@@ -856,6 +869,9 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
pqueue_enqueue(thread, queue);
}
pthread_mutex_unlock (&thread->mtx);
+
+ if (t_ptr)
+ *t_ptr = thread;
}
pthread_mutex_unlock (&m->mtx);
@@ -866,9 +882,8 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
/* Add timer event thread. */
struct thread *
funcname_thread_add_timer (struct thread_master *m,
- int (*func) (struct thread *),
- void *arg, long timer,
- debugargdef)
+ int (*func) (struct thread *), void *arg, long timer,
+ struct thread **t_ptr, debugargdef)
{
struct timeval trel;
@@ -877,16 +892,15 @@ funcname_thread_add_timer (struct thread_master *m,
trel.tv_sec = timer;
trel.tv_usec = 0;
- return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
- &trel, debugargpass);
+ return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, &trel,
+ t_ptr, debugargpass);
}
/* Add timer event thread with "millisecond" resolution */
struct thread *
funcname_thread_add_timer_msec (struct thread_master *m,
- int (*func) (struct thread *),
- void *arg, long timer,
- debugargdef)
+ int (*func) (struct thread *), void *arg, long timer,
+ struct thread **t_ptr, debugargdef)
{
struct timeval trel;
@@ -895,27 +909,25 @@ funcname_thread_add_timer_msec (struct thread_master *m,
trel.tv_sec = timer / 1000;
trel.tv_usec = 1000*(timer % 1000);
- return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
- arg, &trel, debugargpass);
+ return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, &trel,
+ t_ptr, debugargpass);
}
/* Add timer event thread with "millisecond" resolution */
struct thread *
funcname_thread_add_timer_tv (struct thread_master *m,
- int (*func) (struct thread *),
- void *arg, struct timeval *tv,
- debugargdef)
+ int (*func) (struct thread *), void *arg, struct timeval *tv,
+ struct thread **t_ptr, debugargdef)
{
- return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
- arg, tv, debugargpass);
+ return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, tv,
+ t_ptr, debugargpass);
}
/* Add a background thread, with an optional millisec delay */
struct thread *
funcname_thread_add_background (struct thread_master *m,
- int (*func) (struct thread *),
- void *arg, long delay,
- debugargdef)
+ int (*func) (struct thread *), void *arg, long delay,
+ struct thread **t_ptr, debugargdef)
{
struct timeval trel;
@@ -932,15 +944,15 @@ funcname_thread_add_background (struct thread_master *m,
trel.tv_usec = 0;
}
- return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
- arg, &trel, debugargpass);
+ return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND, arg,
+ &trel, t_ptr, debugargpass);
}
/* Add simple event thread. */
struct thread *
funcname_thread_add_event (struct thread_master *m,
- int (*func) (struct thread *), void *arg, int val,
- debugargdef)
+ int (*func) (struct thread *), void *arg, int val,
+ struct thread **t_ptr, debugargdef)
{
struct thread *thread;
@@ -948,6 +960,12 @@ funcname_thread_add_event (struct thread_master *m,
pthread_mutex_lock (&m->mtx);
{
+ if (t_ptr && *t_ptr) // thread is already scheduled; don't reschedule
+ {
+ pthread_mutex_unlock (&m->mtx);
+ return NULL;
+ }
+
thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
pthread_mutex_lock (&thread->mtx);
{
@@ -955,6 +973,9 @@ funcname_thread_add_event (struct thread_master *m,
thread_list_add (&m->event, thread);
}
pthread_mutex_unlock (&thread->mtx);
+
+ if (t_ptr)
+ *t_ptr = thread;
}
pthread_mutex_unlock (&m->mtx);