From: Denil Vira <de...@cumulusnetworks.com> With arrays, a thread corresponding to given fd is looked up in constant time versus the linear time taken for list traversals.
Signed-off-by: Denil Vira <de...@cumulusnetworks.com> Signed-off-by: Donald Sharp <sha...@cumulusnetworks.com> --- lib/thread.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++------------- lib/thread.h | 5 +-- 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/lib/thread.c b/lib/thread.c index 5e40261..6c2b0b0 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -22,6 +22,7 @@ /* #define DEBUG */ #include <zebra.h> +#include <sys/resource.h> #include "thread.h" #include "memory.h" @@ -525,6 +526,9 @@ struct thread_master * thread_master_create () { struct thread_master *rv; + struct rlimit limit; + + getrlimit(RLIMIT_NOFILE, &limit); if (cpu_record == NULL) cpu_record @@ -532,6 +536,26 @@ thread_master_create () (int (*) (const void *, const void *))cpu_record_hash_cmp); rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); + if (rv == NULL) + { + return NULL; + } + + rv->fd_limit = (int)limit.rlim_cur; + rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit); + if (rv->read == NULL) + { + XFREE (MTYPE_THREAD_MASTER, rv); + return NULL; + } + + rv->write = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit); + if (rv->write == NULL) + { + XFREE (MTYPE_THREAD, rv->read); + XFREE (MTYPE_THREAD_MASTER, rv); + return NULL; + } /* Initialize the timer queues */ rv->timer = pqueue_create(); @@ -573,6 +597,18 @@ thread_list_delete (struct thread_list *list, struct thread *thread) return thread; } +static void +thread_delete_fd (struct thread **thread_array, struct thread *thread) +{ + thread_array[thread->u.fd] = NULL; +} + +static void +thread_add_fd (struct thread **thread_array, struct thread *thread) +{ + thread_array[thread->u.fd] = thread; +} + /* Move thread to unuse list. */ static void thread_add_unuse (struct thread_master *m, struct thread *thread) @@ -601,6 +637,25 @@ thread_list_free (struct thread_master *m, struct thread_list *list) } static void +thread_array_free (struct thread_master *m, struct thread **thread_array) +{ + struct thread *t; + int index; + + for (index = 0; index < m->fd_limit; ++index) + { + t = thread_array[index]; + if (t) + { + thread_array[index] = NULL; + XFREE (MTYPE_THREAD, t); + m->alloc--; + } + } + XFREE (MTYPE_THREAD, thread_array); +} + +static void thread_queue_free (struct thread_master *m, struct pqueue *queue) { int i; @@ -616,8 +671,8 @@ thread_queue_free (struct thread_master *m, struct pqueue *queue) void thread_master_free (struct thread_master *m) { - thread_list_free (m, &m->read); - thread_list_free (m, &m->write); + thread_array_free (m, m->read); + thread_array_free (m, m->write); thread_queue_free (m, m->timer); thread_list_free (m, &m->event); thread_list_free (m, &m->ready); @@ -718,7 +773,7 @@ funcname_thread_add_read (struct thread_master *m, thread = thread_get (m, THREAD_READ, func, arg, debugargpass); FD_SET (fd, &m->readfd); thread->u.fd = fd; - thread_list_add (&m->read, thread); + thread_add_fd (m->read, thread); return thread; } @@ -742,7 +797,7 @@ funcname_thread_add_write (struct thread_master *m, thread = thread_get (m, THREAD_WRITE, func, arg, debugargpass); FD_SET (fd, &m->writefd); thread->u.fd = fd; - thread_list_add (&m->write, thread); + thread_add_fd (m->write, thread); return thread; } @@ -863,18 +918,19 @@ thread_cancel (struct thread *thread) { struct thread_list *list = NULL; struct pqueue *queue = NULL; + struct thread **thread_array = NULL; switch (thread->type) { case THREAD_READ: assert (FD_ISSET (thread->u.fd, &thread->master->readfd)); FD_CLR (thread->u.fd, &thread->master->readfd); - list = &thread->master->read; + thread_array = thread->master->read; break; case THREAD_WRITE: assert (FD_ISSET (thread->u.fd, &thread->master->writefd)); FD_CLR (thread->u.fd, &thread->master->writefd); - list = &thread->master->write; + thread_array = thread->master->write; break; case THREAD_TIMER: queue = thread->master->timer; @@ -903,9 +959,13 @@ thread_cancel (struct thread *thread) { thread_list_delete (list, thread); } + else if (thread_array) + { + thread_delete_fd (thread_array, thread); + } else { - assert(!"Thread should be either in queue or list!"); + assert(!"Thread should be either in queue or list or array!"); } thread->type = THREAD_UNUSED; @@ -979,29 +1039,27 @@ thread_run (struct thread_master *m, struct thread *thread, } static int -thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset) +thread_process_fd (struct thread **thread_array, fd_set *fdset, fd_set *mfdset, int num, int fd_limit) { struct thread *thread; - struct thread *next; - int ready = 0; - - assert (list); + int ready = 0, index; + + assert (thread_array); - for (thread = list->head; thread; thread = next) + for (index = 0; index < fd_limit && ready < num; ++index) { - next = thread->next; - - if (FD_ISSET (THREAD_FD (thread), fdset)) + thread = thread_array[index]; + if (thread && FD_ISSET (THREAD_FD (thread), fdset)) { assert (FD_ISSET (THREAD_FD (thread), mfdset)); FD_CLR(THREAD_FD (thread), mfdset); - thread_list_delete (list, thread); + thread_delete_fd (thread_array, thread); thread_list_add (&thread->master->ready, thread); thread->type = THREAD_READY; ready++; } } - return ready; + return num - ready; } /* Add all timers that have popped to the ready list. */ @@ -1154,10 +1212,10 @@ thread_fetch (struct thread_master *m, struct thread *fetch) /* Got IO, process it */ if (num > 0) { - /* Normal priority read thead. */ - thread_process_fd (&m->read, &readfd, &m->readfd); - /* Write thead. */ - thread_process_fd (&m->write, &writefd, &m->writefd); + /* Normal priority read thread. */ + num = thread_process_fd (m->read, &readfd, &m->readfd, num, m->fd_limit); + /* Write thread. */ + num = thread_process_fd (m->write, &writefd, &m->writefd, num, m->fd_limit); } #if 0 diff --git a/lib/thread.h b/lib/thread.h index 5bc756c..5a3bf7d 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -48,13 +48,14 @@ struct pqueue; /* Master of the theads. */ struct thread_master { - struct thread_list read; - struct thread_list write; + struct thread **read; + struct thread **write; struct pqueue *timer; struct thread_list event; struct thread_list ready; struct thread_list unuse; struct pqueue *background; + int fd_limit; fd_set readfd; fd_set writefd; fd_set exceptfd; -- 1.9.1 _______________________________________________ Quagga-dev mailing list Quagga-dev@lists.quagga.net https://lists.quagga.net/mailman/listinfo/quagga-dev