1 /* Thread management routine
2 * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
3 *
4 * This file is part of GNU Zebra.
5 *
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
9 * later version.
10 *
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.
15 *
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
19 * 02111-1307, USA.
20 */
21
22 #include "pmacct.h"
23 #include "isis.h"
24
25 #include "thread.h"
26 #include "hash.h"
27
28 /* Recent absolute time of day */
29 struct timeval recent_time;
30 static struct timeval last_recent_time;
31 /* Relative time, since startup */
32 static struct timeval relative_time;
33 static struct timeval relative_time_base;
34 /* init flag */
35 static unsigned short timers_inited;
36
37 static struct hash *cpu_record = NULL;
38
39 /* Struct timeval's tv_usec one second value. */
40 #define TIMER_SECOND_MICRO 1000000L
41
42 /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
43 And change negative values to 0. */
44 static struct timeval
timeval_adjust(struct timeval a)45 timeval_adjust (struct timeval a)
46 {
47 while (a.tv_usec >= TIMER_SECOND_MICRO)
48 {
49 a.tv_usec -= TIMER_SECOND_MICRO;
50 a.tv_sec++;
51 }
52
53 while (a.tv_usec < 0)
54 {
55 a.tv_usec += TIMER_SECOND_MICRO;
56 a.tv_sec--;
57 }
58
59 if (a.tv_sec < 0)
60 /* Change negative timeouts to 0. */
61 a.tv_sec = a.tv_usec = 0;
62
63 return a;
64 }
65
66 static struct timeval
timeval_subtract(struct timeval a,struct timeval b)67 timeval_subtract (struct timeval a, struct timeval b)
68 {
69 struct timeval ret;
70
71 ret.tv_usec = a.tv_usec - b.tv_usec;
72 ret.tv_sec = a.tv_sec - b.tv_sec;
73
74 return timeval_adjust (ret);
75 }
76
77 static long
isis_timeval_cmp(struct timeval a,struct timeval b)78 isis_timeval_cmp (struct timeval a, struct timeval b)
79 {
80 return (a.tv_sec == b.tv_sec
81 ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
82 }
83
84 static unsigned long
timeval_elapsed(struct timeval a,struct timeval b)85 timeval_elapsed (struct timeval a, struct timeval b)
86 {
87 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
88 + (a.tv_usec - b.tv_usec));
89 }
90
91 #ifndef HAVE_CLOCK_MONOTONIC
92 static void
quagga_gettimeofday_relative_adjust(void)93 quagga_gettimeofday_relative_adjust (void)
94 {
95 struct timeval diff;
96 if (isis_timeval_cmp (recent_time, last_recent_time) < 0)
97 {
98 relative_time.tv_sec++;
99 relative_time.tv_usec = 0;
100 }
101 else
102 {
103 diff = timeval_subtract (recent_time, last_recent_time);
104 relative_time.tv_sec += diff.tv_sec;
105 relative_time.tv_usec += diff.tv_usec;
106 relative_time = timeval_adjust (relative_time);
107 }
108 last_recent_time = recent_time;
109 }
110 #endif /* !HAVE_CLOCK_MONOTONIC */
111
112 /* gettimeofday wrapper, to keep recent_time updated */
113 static int
quagga_gettimeofday(struct timeval * tv)114 quagga_gettimeofday (struct timeval *tv)
115 {
116 int ret;
117
118 assert (tv);
119
120 if (!(ret = gettimeofday (&recent_time, NULL)))
121 {
122 /* init... */
123 if (!timers_inited)
124 {
125 relative_time_base = last_recent_time = recent_time;
126 timers_inited = 1;
127 }
128 /* avoid copy if user passed recent_time pointer.. */
129 if (tv != &recent_time)
130 *tv = recent_time;
131 return 0;
132 }
133 return ret;
134 }
135
136 static int
quagga_get_relative(struct timeval * tv)137 quagga_get_relative (struct timeval *tv)
138 {
139 int ret;
140
141 #ifdef HAVE_CLOCK_MONOTONIC
142 {
143 struct timespec tp;
144 if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
145 {
146 relative_time.tv_sec = tp.tv_sec;
147 relative_time.tv_usec = tp.tv_nsec / 1000;
148 }
149 }
150 #else /* !HAVE_CLOCK_MONOTONIC */
151 if (!(ret = quagga_gettimeofday (&recent_time)))
152 quagga_gettimeofday_relative_adjust();
153 #endif /* HAVE_CLOCK_MONOTONIC */
154
155 if (tv)
156 *tv = relative_time;
157
158 return ret;
159 }
160
161 /* Get absolute time stamp, but in terms of the internal timer
162 * Could be wrong, but at least won't go back.
163 */
164 static void
quagga_real_stabilised(struct timeval * tv)165 quagga_real_stabilised (struct timeval *tv)
166 {
167 *tv = relative_time_base;
168 tv->tv_sec += relative_time.tv_sec;
169 tv->tv_usec += relative_time.tv_usec;
170 *tv = timeval_adjust (*tv);
171 }
172
173 /* Exported Quagga timestamp function.
174 * Modelled on POSIX clock_gettime.
175 */
176 int
quagga_gettime(enum quagga_clkid clkid,struct timeval * tv)177 quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
178 {
179 switch (clkid)
180 {
181 case QUAGGA_CLK_REALTIME:
182 return quagga_gettimeofday (tv);
183 case QUAGGA_CLK_MONOTONIC:
184 return quagga_get_relative (tv);
185 case QUAGGA_CLK_REALTIME_STABILISED:
186 quagga_real_stabilised (tv);
187 return 0;
188 default:
189 errno = EINVAL;
190 return -1;
191 }
192 }
193
194 /* time_t value in terms of stabilised absolute time.
195 * replacement for POSIX time()
196 */
197 time_t
quagga_time(time_t * t)198 quagga_time (time_t *t)
199 {
200 struct timeval tv;
201 quagga_real_stabilised (&tv);
202 if (t)
203 *t = tv.tv_sec;
204 return tv.tv_sec;
205 }
206
207 /* Public export of recent_relative_time by value */
208 struct timeval
recent_relative_time(void)209 recent_relative_time (void)
210 {
211 return relative_time;
212 }
213
214 static unsigned int
cpu_record_hash_key(struct cpu_thread_history * a)215 cpu_record_hash_key (struct cpu_thread_history *a)
216 {
217 return (uintptr_t) a->func;
218 }
219
220 static int
cpu_record_hash_cmp(const struct cpu_thread_history * a,const struct cpu_thread_history * b)221 cpu_record_hash_cmp (const struct cpu_thread_history *a,
222 const struct cpu_thread_history *b)
223 {
224 return a->func == b->func;
225 }
226
227 static void *
cpu_record_hash_alloc(struct cpu_thread_history * a)228 cpu_record_hash_alloc (struct cpu_thread_history *a)
229 {
230 struct cpu_thread_history *new;
231 new = calloc(1, sizeof (struct cpu_thread_history));
232 new->func = a->func;
233 new->funcname = strdup(a->funcname);
234 return new;
235 }
236
237 static void
cpu_record_hash_free(void * a)238 cpu_record_hash_free (void *a)
239 {
240 struct cpu_thread_history *hist = a;
241
242 free(hist->funcname);
243 free(hist);
244 }
245
246 /* Allocate new thread master. */
247 struct thread_master *
thread_master_create()248 thread_master_create ()
249 {
250 if (cpu_record == NULL)
251 cpu_record
252 = isis_hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key,
253 (int (*) (const void *, const void *))cpu_record_hash_cmp);
254
255 return (struct thread_master *) calloc(1, sizeof (struct thread_master));
256 }
257
258 /* Add a new thread to the list. */
259 static void
thread_list_add(struct thread_list * list,struct thread * thread)260 thread_list_add (struct thread_list *list, struct thread *thread)
261 {
262 thread->next = NULL;
263 thread->prev = list->tail;
264 if (list->tail)
265 list->tail->next = thread;
266 else
267 list->head = thread;
268 list->tail = thread;
269 list->count++;
270 }
271
272 /* Add a new thread just before the point. */
273 static void
thread_list_add_before(struct thread_list * list,struct thread * point,struct thread * thread)274 thread_list_add_before (struct thread_list *list,
275 struct thread *point,
276 struct thread *thread)
277 {
278 thread->next = point;
279 thread->prev = point->prev;
280 if (point->prev)
281 point->prev->next = thread;
282 else
283 list->head = thread;
284 point->prev = thread;
285 list->count++;
286 }
287
288 /* Delete a thread from the list. */
289 static struct thread *
thread_list_delete(struct thread_list * list,struct thread * thread)290 thread_list_delete (struct thread_list *list, struct thread *thread)
291 {
292 if (thread->next)
293 thread->next->prev = thread->prev;
294 else
295 list->tail = thread->prev;
296 if (thread->prev)
297 thread->prev->next = thread->next;
298 else
299 list->head = thread->next;
300 thread->next = thread->prev = NULL;
301 list->count--;
302 return thread;
303 }
304
305 /* Move thread to unuse list. */
306 static void
thread_add_unuse(struct thread_master * m,struct thread * thread)307 thread_add_unuse (struct thread_master *m, struct thread *thread)
308 {
309 assert (m != NULL && thread != NULL);
310 assert (thread->next == NULL);
311 assert (thread->prev == NULL);
312 assert (thread->type == THREAD_UNUSED);
313 thread_list_add (&m->unuse, thread);
314 /* XXX: Should we deallocate funcname here? */
315 }
316
317 /* Free all unused thread. */
318 static void
thread_list_free(struct thread_master * m,struct thread_list * list)319 thread_list_free (struct thread_master *m, struct thread_list *list)
320 {
321 struct thread *t;
322 struct thread *next;
323
324 for (t = list->head; t; t = next)
325 {
326 next = t->next;
327 if (t->funcname)
328 free(t->funcname);
329 free(t);
330 list->count--;
331 m->alloc--;
332 }
333 }
334
335 /* Stop thread scheduler. */
336 void
thread_master_free(struct thread_master * m)337 thread_master_free (struct thread_master *m)
338 {
339 thread_list_free (m, &m->read);
340 thread_list_free (m, &m->write);
341 thread_list_free (m, &m->timer);
342 thread_list_free (m, &m->event);
343 thread_list_free (m, &m->ready);
344 thread_list_free (m, &m->unuse);
345 thread_list_free (m, &m->background);
346
347 free(m);
348
349 if (cpu_record)
350 {
351 isis_hash_clean (cpu_record, cpu_record_hash_free);
352 isis_hash_free (cpu_record);
353 cpu_record = NULL;
354 }
355 }
356
357 /* Thread list is empty or not. */
358 static inline int
thread_empty(struct thread_list * list)359 thread_empty (struct thread_list *list)
360 {
361 return list->head ? 0 : 1;
362 }
363
364 /* Delete top of the list and return it. */
365 static struct thread *
thread_trim_head(struct thread_list * list)366 thread_trim_head (struct thread_list *list)
367 {
368 if (!thread_empty (list))
369 return thread_list_delete (list, list->head);
370 return NULL;
371 }
372
373 /* Return remain time in second. */
374 unsigned long
thread_timer_remain_second(struct thread * thread)375 thread_timer_remain_second (struct thread *thread)
376 {
377 quagga_get_relative (NULL);
378
379 if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
380 return thread->u.sands.tv_sec - relative_time.tv_sec;
381 else
382 return 0;
383 }
384
385 /* Trim blankspace and "()"s */
386 static char *
strip_funcname(const char * funcname)387 strip_funcname (const char *funcname)
388 {
389 char buff[100];
390 char tmp, *ret, *e, *b = buff;
391
392 strncpy(buff, funcname, sizeof(buff));
393 buff[ sizeof(buff) -1] = '\0';
394 e = buff +strlen(buff) -1;
395
396 /* Wont work for funcname == "Word (explanation)" */
397
398 while (*b == ' ' || *b == '(')
399 ++b;
400 while (*e == ' ' || *e == ')')
401 --e;
402 e++;
403
404 tmp = *e;
405 *e = '\0';
406 ret = strdup(b);
407 *e = tmp;
408
409 return ret;
410 }
411
412 /* Get new thread. */
413 static struct thread *
thread_get(struct thread_master * m,u_char type,int (* func)(struct thread *),void * arg,const char * funcname)414 thread_get (struct thread_master *m, u_char type,
415 int (*func) (struct thread *), void *arg, const char* funcname)
416 {
417 struct thread *thread;
418
419 if (!thread_empty (&m->unuse))
420 {
421 thread = thread_trim_head (&m->unuse);
422 if (thread->funcname)
423 free(thread->funcname);
424 }
425 else
426 {
427 thread = calloc(1, sizeof (struct thread));
428 m->alloc++;
429 }
430 thread->type = type;
431 thread->add_type = type;
432 thread->master = m;
433 thread->func = func;
434 thread->arg = arg;
435
436 thread->funcname = strip_funcname(funcname);
437
438 return thread;
439 }
440
441 /* Add new read thread. */
442 struct thread *
funcname_thread_add_read(struct thread_master * m,int (* func)(struct thread *),void * arg,int fd,const char * funcname)443 funcname_thread_add_read (struct thread_master *m,
444 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
445 {
446 struct thread *thread;
447
448 assert (m != NULL);
449
450 if (FD_ISSET (fd, &m->readfd))
451 {
452 Log(LOG_WARNING, "WARN ( %s/core/ISIS ): There is already read fd [%d]\n", config.name, fd);
453 return NULL;
454 }
455
456 thread = thread_get (m, THREAD_READ, func, arg, funcname);
457 FD_SET (fd, &m->readfd);
458 thread->u.fd = fd;
459 thread_list_add (&m->read, thread);
460
461 return thread;
462 }
463
464 /* Add new write thread. */
465 struct thread *
funcname_thread_add_write(struct thread_master * m,int (* func)(struct thread *),void * arg,int fd,const char * funcname)466 funcname_thread_add_write (struct thread_master *m,
467 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
468 {
469 struct thread *thread;
470
471 assert (m != NULL);
472
473 if (FD_ISSET (fd, &m->writefd))
474 {
475 Log(LOG_WARNING, "WARN ( %s/core/ISIS ): There is already write fd [%d]\n", config.name, fd);
476 return NULL;
477 }
478
479 thread = thread_get (m, THREAD_WRITE, func, arg, funcname);
480 FD_SET (fd, &m->writefd);
481 thread->u.fd = fd;
482 thread_list_add (&m->write, thread);
483
484 return thread;
485 }
486
487 static struct thread *
funcname_thread_add_timer_timeval(struct thread_master * m,int (* func)(struct thread *),int type,void * arg,struct timeval * time_relative,const char * funcname)488 funcname_thread_add_timer_timeval (struct thread_master *m,
489 int (*func) (struct thread *),
490 int type,
491 void *arg,
492 struct timeval *time_relative,
493 const char* funcname)
494 {
495 struct thread *thread;
496 struct thread_list *list;
497 struct timeval alarm_time;
498 struct thread *tt;
499
500 assert (m != NULL);
501
502 assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
503 assert (time_relative);
504
505 list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
506 thread = thread_get (m, type, func, arg, funcname);
507
508 /* Do we need jitter here? */
509 quagga_get_relative (NULL);
510 alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
511 alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
512 thread->u.sands = timeval_adjust(alarm_time);
513
514 /* Sort by timeval. */
515 for (tt = list->head; tt; tt = tt->next)
516 if (isis_timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
517 break;
518
519 if (tt)
520 thread_list_add_before (list, tt, thread);
521 else
522 thread_list_add (list, thread);
523
524 return thread;
525 }
526
527
528 /* Add timer event thread. */
529 struct thread *
funcname_thread_add_timer(struct thread_master * m,int (* func)(struct thread *),void * arg,long timer,const char * funcname)530 funcname_thread_add_timer (struct thread_master *m,
531 int (*func) (struct thread *),
532 void *arg, long timer, const char* funcname)
533 {
534 struct timeval trel;
535
536 assert (m != NULL);
537
538 trel.tv_sec = timer;
539 trel.tv_usec = 0;
540
541 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
542 &trel, funcname);
543 }
544
545 /* Add timer event thread with "millisecond" resolution */
546 struct thread *
funcname_thread_add_timer_msec(struct thread_master * m,int (* func)(struct thread *),void * arg,long timer,const char * funcname)547 funcname_thread_add_timer_msec (struct thread_master *m,
548 int (*func) (struct thread *),
549 void *arg, long timer, const char* funcname)
550 {
551 struct timeval trel;
552
553 assert (m != NULL);
554
555 trel.tv_sec = timer / 1000;
556 trel.tv_usec = 1000*(timer % 1000);
557
558 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
559 arg, &trel, funcname);
560 }
561
562 /* Add a background thread, with an optional millisec delay */
563 struct thread *
funcname_thread_add_background(struct thread_master * m,int (* func)(struct thread *),void * arg,long delay,const char * funcname)564 funcname_thread_add_background (struct thread_master *m,
565 int (*func) (struct thread *),
566 void *arg, long delay,
567 const char *funcname)
568 {
569 struct timeval trel;
570
571 assert (m != NULL);
572
573 if (delay)
574 {
575 trel.tv_sec = delay / 1000;
576 trel.tv_usec = 1000*(delay % 1000);
577 }
578 else
579 {
580 trel.tv_sec = 0;
581 trel.tv_usec = 0;
582 }
583
584 return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
585 arg, &trel, funcname);
586 }
587
588 /* Add simple event thread. */
589 struct thread *
funcname_thread_add_event(struct thread_master * m,int (* func)(struct thread *),void * arg,int val,const char * funcname)590 funcname_thread_add_event (struct thread_master *m,
591 int (*func) (struct thread *), void *arg, int val, const char* funcname)
592 {
593 struct thread *thread;
594
595 assert (m != NULL);
596
597 thread = thread_get (m, THREAD_EVENT, func, arg, funcname);
598 thread->u.val = val;
599 thread_list_add (&m->event, thread);
600
601 return thread;
602 }
603
604 /* Cancel thread from scheduler. */
605 void
thread_cancel(struct thread * thread)606 thread_cancel (struct thread *thread)
607 {
608 struct thread_list *list;
609
610 switch (thread->type)
611 {
612 case THREAD_READ:
613 assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
614 FD_CLR (thread->u.fd, &thread->master->readfd);
615 list = &thread->master->read;
616 break;
617 case THREAD_WRITE:
618 assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
619 FD_CLR (thread->u.fd, &thread->master->writefd);
620 list = &thread->master->write;
621 break;
622 case THREAD_TIMER:
623 list = &thread->master->timer;
624 break;
625 case THREAD_EVENT:
626 list = &thread->master->event;
627 break;
628 case THREAD_READY:
629 list = &thread->master->ready;
630 break;
631 case THREAD_BACKGROUND:
632 list = &thread->master->background;
633 break;
634 default:
635 return;
636 break;
637 }
638 thread_list_delete (list, thread);
639 thread->type = THREAD_UNUSED;
640 thread_add_unuse (thread->master, thread);
641 }
642
643 /* Delete all events which has argument value arg. */
644 unsigned int
thread_cancel_event(struct thread_master * m,void * arg)645 thread_cancel_event (struct thread_master *m, void *arg)
646 {
647 unsigned int ret = 0;
648 struct thread *thread;
649
650 thread = m->event.head;
651 while (thread)
652 {
653 struct thread *t;
654
655 t = thread;
656 thread = t->next;
657
658 if (t->arg == arg)
659 {
660 ret++;
661 thread_list_delete (&m->event, t);
662 t->type = THREAD_UNUSED;
663 thread_add_unuse (m, t);
664 }
665 }
666 return ret;
667 }
668
669 static struct timeval *
thread_timer_wait(struct thread_list * tlist,struct timeval * timer_val)670 thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
671 {
672 if (!thread_empty (tlist))
673 {
674 *timer_val = timeval_subtract (tlist->head->u.sands, relative_time);
675 return timer_val;
676 }
677 return NULL;
678 }
679
680 static struct thread *
thread_run(struct thread_master * m,struct thread * thread,struct thread * fetch)681 thread_run (struct thread_master *m, struct thread *thread,
682 struct thread *fetch)
683 {
684 *fetch = *thread;
685 thread->type = THREAD_UNUSED;
686 thread->funcname = NULL; /* thread_call will free fetch's copied pointer */
687 thread_add_unuse (m, thread);
688 return fetch;
689 }
690
691 static int
thread_process_fd(struct thread_list * list,fd_set * fdset,fd_set * mfdset)692 thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
693 {
694 struct thread *thread;
695 struct thread *next;
696 int ready = 0;
697
698 assert (list);
699
700 for (thread = list->head; thread; thread = next)
701 {
702 next = thread->next;
703
704 if (FD_ISSET (THREAD_FD (thread), fdset))
705 {
706 assert (FD_ISSET (THREAD_FD (thread), mfdset));
707 FD_CLR(THREAD_FD (thread), mfdset);
708 thread_list_delete (list, thread);
709 thread_list_add (&thread->master->ready, thread);
710 thread->type = THREAD_READY;
711 ready++;
712 }
713 }
714 return ready;
715 }
716
717 /* Add all timers that have popped to the ready list. */
718 static unsigned int
thread_timer_process(struct thread_list * list,struct timeval * timenow)719 thread_timer_process (struct thread_list *list, struct timeval *timenow)
720 {
721 struct thread *thread;
722 unsigned int ready = 0;
723
724 for (thread = list->head; thread; thread = thread->next)
725 {
726 if (isis_timeval_cmp (*timenow, thread->u.sands) < 0)
727 return ready;
728 thread_list_delete (list, thread);
729 thread->type = THREAD_READY;
730 thread_list_add (&thread->master->ready, thread);
731 ready++;
732 }
733 return ready;
734 }
735
736 /* process a list en masse, e.g. for event thread lists */
737 static unsigned int
thread_process(struct thread_list * list)738 thread_process (struct thread_list *list)
739 {
740 struct thread *thread;
741 unsigned int ready = 0;
742
743 for (thread = list->head; thread; thread = thread->next)
744 {
745 thread_list_delete (list, thread);
746 thread->type = THREAD_READY;
747 thread_list_add (&thread->master->ready, thread);
748 ready++;
749 }
750 return ready;
751 }
752
753
754 /* Fetch next ready thread. */
755 struct thread *
thread_fetch(struct thread_master * m,struct thread * fetch)756 thread_fetch (struct thread_master *m, struct thread *fetch)
757 {
758 struct thread *thread;
759 fd_set readfd;
760 fd_set writefd;
761 fd_set exceptfd;
762 struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
763 struct timeval timer_val_bg;
764 struct timeval *timer_wait = &timer_val;
765 struct timeval *timer_wait_bg;
766
767 while (1)
768 {
769 int num = 0;
770
771 /* Signals pre-empt everything */
772 // quagga_sigevent_process ();
773
774 /* Drain the ready queue of already scheduled jobs, before scheduling
775 * more.
776 */
777 if ((thread = thread_trim_head (&m->ready)) != NULL)
778 return thread_run (m, thread, fetch);
779
780 /* To be fair to all kinds of threads, and avoid starvation, we
781 * need to be careful to consider all thread types for scheduling
782 * in each quanta. I.e. we should not return early from here on.
783 */
784
785 /* Normal event are the next highest priority. */
786 thread_process (&m->event);
787
788 /* Structure copy. */
789 readfd = m->readfd;
790 writefd = m->writefd;
791 exceptfd = m->exceptfd;
792
793 /* Calculate select wait timer if nothing else to do */
794 if (m->ready.count == 0)
795 {
796 quagga_get_relative (NULL);
797 timer_wait = thread_timer_wait (&m->timer, &timer_val);
798 timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
799
800 if (timer_wait_bg &&
801 (!timer_wait || (isis_timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
802 timer_wait = timer_wait_bg;
803 }
804
805 num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
806
807 /* Signals should get quick treatment */
808 if (num < 0)
809 {
810 if (errno == EINTR)
811 continue; /* signal received - process it */
812 Log(LOG_WARNING, "WARN ( %s/core/ISIS ): select() error: %s\n", config.name, strerror (errno));
813 return NULL;
814 }
815
816 /* Check foreground timers. Historically, they have had higher
817 priority than I/O threads, so let's push them onto the ready
818 list in front of the I/O threads. */
819 quagga_get_relative (NULL);
820 thread_timer_process (&m->timer, &relative_time);
821
822 /* Got IO, process it */
823 if (num > 0)
824 {
825 /* Normal priority read thead. */
826 thread_process_fd (&m->read, &readfd, &m->readfd);
827 /* Write thead. */
828 thread_process_fd (&m->write, &writefd, &m->writefd);
829 }
830
831 #if 0
832 /* If any threads were made ready above (I/O or foreground timer),
833 perhaps we should avoid adding background timers to the ready
834 list at this time. If this is code is uncommented, then background
835 timer threads will not run unless there is nothing else to do. */
836 if ((thread = thread_trim_head (&m->ready)) != NULL)
837 return thread_run (m, thread, fetch);
838 #endif
839
840 /* Background timer/events, lowest priority */
841 thread_timer_process (&m->background, &relative_time);
842
843 if ((thread = thread_trim_head (&m->ready)) != NULL)
844 return thread_run (m, thread, fetch);
845 }
846 }
847
848 unsigned long
thread_consumed_time(RUSAGE_T * now,RUSAGE_T * start,unsigned long * cputime)849 thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
850 {
851 *cputime = 0;
852 return timeval_elapsed (now->real, start->real);
853 }
854
855 /* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
856 Note: we are using real (wall clock) time for this calculation.
857 It could be argued that CPU time may make more sense in certain
858 contexts. The things to consider are whether the thread may have
859 blocked (in which case wall time increases, but CPU time does not),
860 or whether the system is heavily loaded with other processes competing
861 for CPU time. On balance, wall clock time seems to make sense.
862 Plus it has the added benefit that gettimeofday should be faster
863 than calling getrusage. */
864 int
thread_should_yield(struct thread * thread)865 thread_should_yield (struct thread *thread)
866 {
867 quagga_get_relative (NULL);
868 return (timeval_elapsed(relative_time, thread->ru.real) >
869 THREAD_YIELD_TIME_SLOT);
870 }
871
872 void
thread_getrusage(RUSAGE_T * r)873 thread_getrusage (RUSAGE_T *r)
874 {
875 quagga_get_relative (NULL);
876 r->real = relative_time;
877
878 #ifdef HAVE_CLOCK_MONOTONIC
879 /* quagga_get_relative() only updates recent_time if gettimeofday
880 * based, not when using CLOCK_MONOTONIC. As we export recent_time
881 * and guarantee to update it before threads are run...
882 */
883 quagga_gettimeofday(&recent_time);
884 #endif /* HAVE_CLOCK_MONOTONIC */
885 }
886
887 /* We check thread consumed time. If the system has getrusage, we'll
888 use that to get in-depth stats on the performance of the thread in addition
889 to wall clock time stats from gettimeofday. */
890 void
thread_call(struct thread * thread)891 thread_call (struct thread *thread)
892 {
893 unsigned long realtime, cputime;
894 RUSAGE_T ru;
895
896 /* Cache a pointer to the relevant cpu history thread, if the thread
897 * does not have it yet.
898 *
899 * Callers submitting 'dummy threads' hence must take care that
900 * thread->cpu is NULL
901 */
902 if (!thread->hist)
903 {
904 struct cpu_thread_history tmp;
905
906 tmp.func = thread->func;
907 tmp.funcname = thread->funcname;
908
909 thread->hist = isis_hash_get (cpu_record, &tmp,
910 (void * (*) (void *))cpu_record_hash_alloc);
911 }
912
913 GETRUSAGE (&thread->ru);
914
915 (*thread->func) (thread);
916
917 GETRUSAGE (&ru);
918
919 realtime = thread_consumed_time (&ru, &thread->ru, &cputime);
920 thread->hist->real.total += realtime;
921 if (thread->hist->real.max < realtime)
922 thread->hist->real.max = realtime;
923
924 ++(thread->hist->total_calls);
925 thread->hist->types |= (1 << thread->add_type);
926
927 free(thread->funcname);
928 }
929
930 /* Execute thread */
931 struct thread *
funcname_thread_execute(struct thread_master * m,int (* func)(struct thread *),void * arg,int val,const char * funcname)932 funcname_thread_execute (struct thread_master *m,
933 int (*func)(struct thread *),
934 void *arg,
935 int val,
936 const char* funcname)
937 {
938 struct thread dummy;
939
940 memset (&dummy, 0, sizeof (struct thread));
941
942 dummy.type = THREAD_EVENT;
943 dummy.add_type = THREAD_EXECUTE;
944 dummy.master = NULL;
945 dummy.func = func;
946 dummy.arg = arg;
947 dummy.u.val = val;
948 dummy.funcname = strip_funcname (funcname);
949 thread_call (&dummy);
950
951 free(dummy.funcname);
952
953 return NULL;
954 }
955