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