1 /* Thread management routine
2 * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
30 /* Struct timeval's tv_usec one second value. */
31 #define TIMER_SECOND_MICRO 1000000L
34 timeval_subtract (struct timeval a, struct timeval b)
38 ret.tv_usec = a.tv_usec - b.tv_usec;
39 ret.tv_sec = a.tv_sec - b.tv_sec;
41 while (ret.tv_usec < 0)
43 ret.tv_usec += TIMER_SECOND_MICRO;
51 timeval_cmp (struct timeval a, struct timeval b)
53 return (a.tv_sec == b.tv_sec
54 ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
58 timeval_elapsed (struct timeval a, struct timeval b)
60 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
61 + (a.tv_usec - b.tv_usec));
65 /* List allocation and head/tail print out. */
67 thread_list_debug (struct thread_list *list)
69 printf ("count [%d] head [%p] tail [%p]\n",
70 list->count, list->head, list->tail);
73 /* Debug print for thread_master. */
75 thread_master_debug (struct thread_master *m)
77 printf ("-----------\n");
78 printf ("readlist : ");
79 thread_list_debug (&m->read);
80 printf ("writelist : ");
81 thread_list_debug (&m->write);
82 printf ("timerlist : ");
83 thread_list_debug (&m->timer);
84 printf ("eventlist : ");
85 thread_list_debug (&m->event);
86 printf ("unuselist : ");
87 thread_list_debug (&m->unuse);
88 printf ("total alloc: [%ld]\n", m->alloc);
89 printf ("-----------\n");
91 #endif /* #ifdef BRCM_RIP_DEBUG */
93 /* Allocate new thread master. */
94 struct thread_master *
95 thread_master_create ()
97 return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
98 sizeof (struct thread_master));
101 /* Add a new thread to the list. */
103 thread_list_add (struct thread_list *list, struct thread *thread)
106 thread->prev = list->tail;
108 list->tail->next = thread;
115 /* Add a new thread just before the point. */
117 thread_list_add_before (struct thread_list *list,
118 struct thread *point,
119 struct thread *thread)
121 thread->next = point;
122 thread->prev = point->prev;
124 point->prev->next = thread;
127 point->prev = thread;
131 /* Delete a thread from the list. */
132 static struct thread *
133 thread_list_delete (struct thread_list *list, struct thread *thread)
136 thread->next->prev = thread->prev;
138 list->tail = thread->prev;
140 thread->prev->next = thread->next;
142 list->head = thread->next;
143 thread->next = thread->prev = NULL;
148 /* Move thread to unuse list. */
150 thread_add_unuse (struct thread_master *m, struct thread *thread)
153 assert (thread->next == NULL);
154 assert (thread->prev == NULL);
155 assert (thread->type == THREAD_UNUSED);
156 thread_list_add (&m->unuse, thread);
159 /* Free all unused thread. */
161 thread_list_free (struct thread_master *m, struct thread_list *list)
166 for (t = list->head; t; t = next)
169 XFREE (MTYPE_THREAD, t);
175 /* Stop thread scheduler. */
177 thread_master_free (struct thread_master *m)
179 thread_list_free (m, &m->read);
180 thread_list_free (m, &m->write);
181 thread_list_free (m, &m->timer);
182 thread_list_free (m, &m->event);
183 thread_list_free (m, &m->ready);
184 thread_list_free (m, &m->unuse);
186 XFREE (MTYPE_THREAD_MASTER, m);
189 /* Delete top of the list and return it. */
190 static struct thread *
191 thread_trim_head (struct thread_list *list)
194 return thread_list_delete (list, list->head);
198 /* Thread list is empty or not. */
200 thread_empty (struct thread_list *list)
202 return list->head ? 0 : 1;
205 /* Return remain time in second. */
207 thread_timer_remain_second (struct thread *thread)
209 struct timeval timer_now;
211 gettimeofday (&timer_now, NULL);
213 if (thread->u.sands.tv_sec - timer_now.tv_sec > 0)
214 return thread->u.sands.tv_sec - timer_now.tv_sec;
218 #endif /* #ifdef BRCM_SUPPORT */
220 /* Get new thread. */
221 static struct thread *
222 thread_get (struct thread_master *m, u_char type,
223 int (*func) (struct thread *), void *arg)
225 struct thread *thread;
228 thread = thread_trim_head (&m->unuse);
231 thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
242 /* Add new read thread. */
244 thread_add_read (struct thread_master *m,
245 int (*func) (struct thread *), void *arg, int fd)
247 struct thread *thread;
251 if (FD_ISSET (fd, &m->readfd))
253 #ifdef BRCM_RIP_DEBUG
254 zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
259 thread = thread_get (m, THREAD_READ, func, arg);
260 FD_SET (fd, &m->readfd);
262 thread_list_add (&m->read, thread);
267 /* Add new write thread. */
269 thread_add_write (struct thread_master *m,
270 int (*func) (struct thread *), void *arg, int fd)
272 struct thread *thread;
276 if (FD_ISSET (fd, &m->writefd))
278 #ifdef BRCM_RIP_DEBUG
279 zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
284 thread = thread_get (m, THREAD_WRITE, func, arg);
285 FD_SET (fd, &m->writefd);
287 thread_list_add (&m->write, thread);
292 /* Add timer event thread. */
294 thread_add_timer (struct thread_master *m,
295 int (*func) (struct thread *), void *arg, long timer)
297 struct timeval timer_now;
298 struct thread *thread;
299 #ifndef TIMER_NO_SORT
301 #endif /* TIMER_NO_SORT */
305 thread = thread_get (m, THREAD_TIMER, func, arg);
307 /* Do we need jitter here? */
308 gettimeofday (&timer_now, NULL);
309 timer_now.tv_sec += timer;
310 thread->u.sands = timer_now;
312 /* Sort by timeval. */
314 thread_list_add (&m->timer, thread);
316 for (tt = m->timer.head; tt; tt = tt->next)
317 if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
321 thread_list_add_before (&m->timer, tt, thread);
323 thread_list_add (&m->timer, thread);
324 #endif /* TIMER_NO_SORT */
329 /* Add simple event thread. */
331 thread_add_event (struct thread_master *m,
332 int (*func) (struct thread *), void *arg, int val)
334 struct thread *thread;
338 thread = thread_get (m, THREAD_EVENT, func, arg);
340 thread_list_add (&m->event, thread);
345 /* Cancel thread from scheduler. */
347 thread_cancel (struct thread *thread)
349 switch (thread->type)
352 assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
353 FD_CLR (thread->u.fd, &thread->master->readfd);
354 thread_list_delete (&thread->master->read, thread);
357 assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
358 FD_CLR (thread->u.fd, &thread->master->writefd);
359 thread_list_delete (&thread->master->write, thread);
362 thread_list_delete (&thread->master->timer, thread);
365 thread_list_delete (&thread->master->event, thread);
368 thread_list_delete (&thread->master->ready, thread);
373 thread->type = THREAD_UNUSED;
374 thread_add_unuse (thread->master, thread);
377 /* Delete all events which has argument value arg. */
379 thread_cancel_event (struct thread_master *m, void *arg)
381 struct thread *thread;
383 thread = m->event.head;
393 thread_list_delete (&m->event, t);
394 t->type = THREAD_UNUSED;
395 thread_add_unuse (m, t);
402 thread_timer_wait (struct thread_master *m, struct timeval *timer_val)
404 struct timeval timer_now;
405 struct timeval timer_min;
406 struct timeval *timer_wait;
408 gettimeofday (&timer_now, NULL);
411 for (thread = m->timer.head; thread; thread = thread->next)
414 timer_wait = &thread->u.sands;
415 else if (timeval_cmp (thread->u.sands, *timer_wait) < 0)
416 timer_wait = &thread->u.sands;
421 timer_min = *timer_wait;
422 timer_min = timeval_subtract (timer_min, timer_now);
423 if (timer_min.tv_sec < 0)
425 timer_min.tv_sec = 0;
426 timer_min.tv_usec = 10;
428 timer_wait = &timer_min;
435 *timer_val = timer_wait;
440 #else /* ! TIMER_NO_SORT */
442 thread_timer_wait (struct thread_master *m, struct timeval *timer_val)
444 struct timeval timer_now;
445 struct timeval timer_min;
449 gettimeofday (&timer_now, NULL);
450 timer_min = m->timer.head->u.sands;
451 timer_min = timeval_subtract (timer_min, timer_now);
452 if (timer_min.tv_sec < 0)
454 timer_min.tv_sec = 0;
455 timer_min.tv_usec = 10;
457 *timer_val = timer_min;
462 #endif /* TIMER_NO_SORT */
465 thread_run (struct thread_master *m, struct thread *thread,
466 struct thread *fetch)
469 thread->type = THREAD_UNUSED;
470 thread_add_unuse (m, thread);
475 thread_process_fd (struct thread_master *m, struct thread_list *list,
476 fd_set *fdset, fd_set *mfdset)
478 struct thread *thread;
482 for (thread = list->head; thread; thread = next)
486 if (FD_ISSET (THREAD_FD (thread), fdset))
488 assert (FD_ISSET (THREAD_FD (thread), mfdset));
489 FD_CLR(THREAD_FD (thread), mfdset);
490 thread_list_delete (list, thread);
491 thread_list_add (&m->ready, thread);
492 thread->type = THREAD_READY;
499 /* Fetch next ready thread. */
501 thread_fetch (struct thread_master *m, struct thread *fetch)
505 struct thread *thread;
509 struct timeval timer_now;
510 struct timeval timer_val;
511 struct timeval *timer_wait;
512 struct timeval timer_nowait;
514 timer_nowait.tv_sec = 0;
515 timer_nowait.tv_usec = 0;
519 /* Normal event is the highest priority. */
520 if ((thread = thread_trim_head (&m->event)) != NULL)
521 return thread_run (m, thread, fetch);
524 gettimeofday (&timer_now, NULL);
526 for (thread = m->timer.head; thread; thread = thread->next)
527 if (timeval_cmp (timer_now, thread->u.sands) >= 0)
529 thread_list_delete (&m->timer, thread);
530 return thread_run (m, thread, fetch);
533 /* If there are any ready threads, process top of them. */
534 if ((thread = thread_trim_head (&m->ready)) != NULL)
535 return thread_run (m, thread, fetch);
537 /* Structure copy. */
539 writefd = m->writefd;
540 exceptfd = m->exceptfd;
542 /* Calculate select wait timer. */
543 timer_wait = thread_timer_wait (m, &timer_val);
545 num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
554 #ifdef BRCM_RIP_DEBUG
555 zlog_warn ("select() error: %s", strerror (errno));
560 /* Normal priority read thead. */
561 ready = thread_process_fd (m, &m->read, &readfd, &m->readfd);
564 ready = thread_process_fd (m, &m->write, &writefd, &m->writefd);
566 if ((thread = thread_trim_head (&m->ready)) != NULL)
567 return thread_run (m, thread, fetch);
572 thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start)
574 unsigned long thread_time;
577 /* This is 'user + sys' time. */
578 thread_time = timeval_elapsed (now->ru_utime, start->ru_utime);
579 thread_time += timeval_elapsed (now->ru_stime, start->ru_stime);
581 /* When rusage is not available, simple elapsed time is used. */
582 thread_time = timeval_elapsed (*now, *start);
583 #endif /* HAVE_RUSAGE */
588 /* We should aim to yield after THREAD_YIELD_TIME_SLOT
591 thread_should_yield (struct thread *thread)
597 if (thread_consumed_time (&ru, &thread->ru) > THREAD_YIELD_TIME_SLOT)
602 #endif /* #ifdef BRCM_SUPPORT*/
604 /* We check thread consumed time. If the system has getrusage, we'll
605 use that to get indepth stats on the performance of the thread. If
606 not - we'll use gettimeofday for some guestimation. */
608 thread_call (struct thread *thread)
610 unsigned long thread_time;
613 GETRUSAGE (&thread->ru);
615 (*thread->func) (thread);
619 thread_time = thread_consumed_time (&ru, &thread->ru);
621 #ifdef THREAD_CONSUMED_TIME_CHECK
622 if (thread_time > 200000L)
625 * We have a CPU Hog on our hands.
626 * Whinge about it now, so we're aware this is yet another task
629 #ifdef BRCM_RIP_DEBUG
630 zlog_err ("CPU HOG task %lx ran for %ldms",
631 /* FIXME: report the name of the function somehow */
632 (unsigned long) thread->func,
633 thread_time / 1000L);
636 #endif /* THREAD_CONSUMED_TIME_CHECK */
641 thread_execute (struct thread_master *m,
642 int (*func)(struct thread *),
648 memset (&dummy, 0, sizeof (struct thread));
650 dummy.type = THREAD_EVENT;
655 thread_call (&dummy);