blob: 6c2b0b0ba4526b54ebb3642135e5fc4987516061 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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/* #define DEBUG */
23
24#include <zebra.h>
Denil Vira4ab273b2016-03-04 15:28:54 -050025#include <sys/resource.h>
paul718e3742002-12-13 20:15:29 +000026
27#include "thread.h"
28#include "memory.h"
29#include "log.h"
paule04ab742003-01-17 23:47:00 +000030#include "hash.h"
Christian Franke4becea72013-11-19 14:11:42 +000031#include "pqueue.h"
paule04ab742003-01-17 23:47:00 +000032#include "command.h"
paul05c447d2004-07-22 19:14:27 +000033#include "sigevent.h"
Vincent Bernatd6be5fb2012-05-24 09:44:43 +020034
35#if defined HAVE_SNMP && defined SNMP_AGENTX
36#include <net-snmp/net-snmp-config.h>
37#include <net-snmp/net-snmp-includes.h>
38#include <net-snmp/agent/net-snmp-agent-includes.h>
39#include <net-snmp/agent/snmp_vars.h>
40
41extern int agentx_enabled;
42#endif
43
Hasso Tepper3b96b782012-10-11 11:31:54 +000044#if defined(__APPLE__)
45#include <mach/mach.h>
46#include <mach/mach_time.h>
47#endif
48
David Lamparter6b0655a2014-06-04 06:53:35 +020049
Paul Jakmadb9c0df2006-08-27 06:44:02 +000050/* Recent absolute time of day */
ajs8b70d0b2005-04-28 01:31:13 +000051struct timeval recent_time;
Paul Jakmadb9c0df2006-08-27 06:44:02 +000052static struct timeval last_recent_time;
53/* Relative time, since startup */
54static struct timeval relative_time;
55static struct timeval relative_time_base;
56/* init flag */
57static unsigned short timers_inited;
David Lamparter6b0655a2014-06-04 06:53:35 +020058
paule04ab742003-01-17 23:47:00 +000059static struct hash *cpu_record = NULL;
David Lamparter6b0655a2014-06-04 06:53:35 +020060
paul718e3742002-12-13 20:15:29 +000061/* Struct timeval's tv_usec one second value. */
62#define TIMER_SECOND_MICRO 1000000L
63
ajs8b70d0b2005-04-28 01:31:13 +000064/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
65 And change negative values to 0. */
paula48b4e62005-04-22 00:43:47 +000066static struct timeval
paul718e3742002-12-13 20:15:29 +000067timeval_adjust (struct timeval a)
68{
69 while (a.tv_usec >= TIMER_SECOND_MICRO)
70 {
71 a.tv_usec -= TIMER_SECOND_MICRO;
72 a.tv_sec++;
73 }
74
75 while (a.tv_usec < 0)
76 {
77 a.tv_usec += TIMER_SECOND_MICRO;
78 a.tv_sec--;
79 }
80
81 if (a.tv_sec < 0)
ajs8b70d0b2005-04-28 01:31:13 +000082 /* Change negative timeouts to 0. */
83 a.tv_sec = a.tv_usec = 0;
paul718e3742002-12-13 20:15:29 +000084
85 return a;
86}
87
88static struct timeval
89timeval_subtract (struct timeval a, struct timeval b)
90{
91 struct timeval ret;
92
93 ret.tv_usec = a.tv_usec - b.tv_usec;
94 ret.tv_sec = a.tv_sec - b.tv_sec;
95
96 return timeval_adjust (ret);
97}
98
ajs8b70d0b2005-04-28 01:31:13 +000099static long
paul718e3742002-12-13 20:15:29 +0000100timeval_cmp (struct timeval a, struct timeval b)
101{
102 return (a.tv_sec == b.tv_sec
103 ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
104}
105
Dinesh G Dutt50f38b32014-09-30 12:53:28 -0700106unsigned long
paul718e3742002-12-13 20:15:29 +0000107timeval_elapsed (struct timeval a, struct timeval b)
108{
109 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
110 + (a.tv_usec - b.tv_usec));
111}
David Lamparter6b0655a2014-06-04 06:53:35 +0200112
Hasso Tepper3b96b782012-10-11 11:31:54 +0000113#if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__)
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000114static void
115quagga_gettimeofday_relative_adjust (void)
116{
117 struct timeval diff;
118 if (timeval_cmp (recent_time, last_recent_time) < 0)
119 {
120 relative_time.tv_sec++;
121 relative_time.tv_usec = 0;
122 }
123 else
124 {
125 diff = timeval_subtract (recent_time, last_recent_time);
126 relative_time.tv_sec += diff.tv_sec;
127 relative_time.tv_usec += diff.tv_usec;
128 relative_time = timeval_adjust (relative_time);
129 }
130 last_recent_time = recent_time;
131}
Hasso Tepper3b96b782012-10-11 11:31:54 +0000132#endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000133
134/* gettimeofday wrapper, to keep recent_time updated */
135static int
136quagga_gettimeofday (struct timeval *tv)
137{
138 int ret;
139
140 assert (tv);
141
142 if (!(ret = gettimeofday (&recent_time, NULL)))
143 {
144 /* init... */
145 if (!timers_inited)
146 {
147 relative_time_base = last_recent_time = recent_time;
148 timers_inited = 1;
149 }
150 /* avoid copy if user passed recent_time pointer.. */
151 if (tv != &recent_time)
152 *tv = recent_time;
153 return 0;
154 }
155 return ret;
156}
157
158static int
159quagga_get_relative (struct timeval *tv)
160{
161 int ret;
162
163#ifdef HAVE_CLOCK_MONOTONIC
164 {
165 struct timespec tp;
166 if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
167 {
168 relative_time.tv_sec = tp.tv_sec;
169 relative_time.tv_usec = tp.tv_nsec / 1000;
170 }
171 }
Hasso Tepper3b96b782012-10-11 11:31:54 +0000172#elif defined(__APPLE__)
173 {
174 uint64_t ticks;
175 uint64_t useconds;
176 static mach_timebase_info_data_t timebase_info;
177
178 ticks = mach_absolute_time();
179 if (timebase_info.denom == 0)
180 mach_timebase_info(&timebase_info);
181
182 useconds = ticks * timebase_info.numer / timebase_info.denom / 1000;
183 relative_time.tv_sec = useconds / 1000000;
184 relative_time.tv_usec = useconds % 1000000;
185
186 return 0;
187 }
188#else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000189 if (!(ret = quagga_gettimeofday (&recent_time)))
190 quagga_gettimeofday_relative_adjust();
191#endif /* HAVE_CLOCK_MONOTONIC */
192
193 if (tv)
194 *tv = relative_time;
195
196 return ret;
197}
198
199/* Get absolute time stamp, but in terms of the internal timer
200 * Could be wrong, but at least won't go back.
201 */
202static void
203quagga_real_stabilised (struct timeval *tv)
204{
205 *tv = relative_time_base;
206 tv->tv_sec += relative_time.tv_sec;
207 tv->tv_usec += relative_time.tv_usec;
208 *tv = timeval_adjust (*tv);
209}
210
211/* Exported Quagga timestamp function.
212 * Modelled on POSIX clock_gettime.
213 */
214int
215quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
216{
217 switch (clkid)
218 {
219 case QUAGGA_CLK_REALTIME:
220 return quagga_gettimeofday (tv);
221 case QUAGGA_CLK_MONOTONIC:
222 return quagga_get_relative (tv);
223 case QUAGGA_CLK_REALTIME_STABILISED:
224 quagga_real_stabilised (tv);
225 return 0;
226 default:
227 errno = EINVAL;
228 return -1;
229 }
230}
231
232/* time_t value in terms of stabilised absolute time.
233 * replacement for POSIX time()
234 */
235time_t
236quagga_time (time_t *t)
237{
238 struct timeval tv;
239 quagga_real_stabilised (&tv);
240 if (t)
241 *t = tv.tv_sec;
242 return tv.tv_sec;
243}
244
245/* Public export of recent_relative_time by value */
246struct timeval
247recent_relative_time (void)
248{
249 return relative_time;
250}
David Lamparter6b0655a2014-06-04 06:53:35 +0200251
paula48b4e62005-04-22 00:43:47 +0000252static unsigned int
paule04ab742003-01-17 23:47:00 +0000253cpu_record_hash_key (struct cpu_thread_history *a)
254{
paul8cc41982005-05-06 21:25:49 +0000255 return (uintptr_t) a->func;
paule04ab742003-01-17 23:47:00 +0000256}
257
258static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100259cpu_record_hash_cmp (const struct cpu_thread_history *a,
260 const struct cpu_thread_history *b)
paule04ab742003-01-17 23:47:00 +0000261{
262 return a->func == b->func;
263}
264
paul8cc41982005-05-06 21:25:49 +0000265static void *
paule04ab742003-01-17 23:47:00 +0000266cpu_record_hash_alloc (struct cpu_thread_history *a)
267{
268 struct cpu_thread_history *new;
paul039b9572004-10-31 16:43:17 +0000269 new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
paule04ab742003-01-17 23:47:00 +0000270 new->func = a->func;
David Lamparter3493b772013-11-18 23:04:27 +0100271 new->funcname = a->funcname;
paule04ab742003-01-17 23:47:00 +0000272 return new;
273}
274
Chris Caputo228da422009-07-18 05:44:03 +0000275static void
276cpu_record_hash_free (void *a)
277{
278 struct cpu_thread_history *hist = a;
279
Chris Caputo228da422009-07-18 05:44:03 +0000280 XFREE (MTYPE_THREAD_STATS, hist);
281}
282
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100283static void
paule04ab742003-01-17 23:47:00 +0000284vty_out_cpu_thread_history(struct vty* vty,
285 struct cpu_thread_history *a)
286{
ajs8b70d0b2005-04-28 01:31:13 +0000287#ifdef HAVE_RUSAGE
288 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
289 a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
290 a->cpu.total/a->total_calls, a->cpu.max,
291 a->real.total/a->total_calls, a->real.max);
292#else
293 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld",
294 a->real.total/1000, a->real.total%1000, a->total_calls,
295 a->real.total/a->total_calls, a->real.max);
296#endif
297 vty_out(vty, " %c%c%c%c%c%c %s%s",
paule04ab742003-01-17 23:47:00 +0000298 a->types & (1 << THREAD_READ) ? 'R':' ',
299 a->types & (1 << THREAD_WRITE) ? 'W':' ',
300 a->types & (1 << THREAD_TIMER) ? 'T':' ',
301 a->types & (1 << THREAD_EVENT) ? 'E':' ',
302 a->types & (1 << THREAD_EXECUTE) ? 'X':' ',
paula48b4e62005-04-22 00:43:47 +0000303 a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
paule04ab742003-01-17 23:47:00 +0000304 a->funcname, VTY_NEWLINE);
305}
306
307static void
308cpu_record_hash_print(struct hash_backet *bucket,
309 void *args[])
310{
311 struct cpu_thread_history *totals = args[0];
312 struct vty *vty = args[1];
Paul Jakma41b23732009-06-30 16:12:49 +0100313 thread_type *filter = args[2];
paule04ab742003-01-17 23:47:00 +0000314 struct cpu_thread_history *a = bucket->data;
paula48b4e62005-04-22 00:43:47 +0000315
paule04ab742003-01-17 23:47:00 +0000316 a = bucket->data;
317 if ( !(a->types & *filter) )
318 return;
319 vty_out_cpu_thread_history(vty,a);
paule04ab742003-01-17 23:47:00 +0000320 totals->total_calls += a->total_calls;
ajs8b70d0b2005-04-28 01:31:13 +0000321 totals->real.total += a->real.total;
322 if (totals->real.max < a->real.max)
323 totals->real.max = a->real.max;
324#ifdef HAVE_RUSAGE
325 totals->cpu.total += a->cpu.total;
326 if (totals->cpu.max < a->cpu.max)
327 totals->cpu.max = a->cpu.max;
328#endif
paule04ab742003-01-17 23:47:00 +0000329}
330
331static void
Paul Jakma41b23732009-06-30 16:12:49 +0100332cpu_record_print(struct vty *vty, thread_type filter)
paule04ab742003-01-17 23:47:00 +0000333{
334 struct cpu_thread_history tmp;
335 void *args[3] = {&tmp, vty, &filter};
336
337 memset(&tmp, 0, sizeof tmp);
David Lamparter3493b772013-11-18 23:04:27 +0100338 tmp.funcname = "TOTAL";
paule04ab742003-01-17 23:47:00 +0000339 tmp.types = filter;
340
ajs8b70d0b2005-04-28 01:31:13 +0000341#ifdef HAVE_RUSAGE
342 vty_out(vty, "%21s %18s %18s%s",
343 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE);
344#endif
345 vty_out(vty, "Runtime(ms) Invoked Avg uSec Max uSecs");
346#ifdef HAVE_RUSAGE
347 vty_out(vty, " Avg uSec Max uSecs");
348#endif
349 vty_out(vty, " Type Thread%s", VTY_NEWLINE);
paule04ab742003-01-17 23:47:00 +0000350 hash_iterate(cpu_record,
351 (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
352 args);
353
354 if (tmp.total_calls > 0)
355 vty_out_cpu_thread_history(vty, &tmp);
356}
357
358DEFUN(show_thread_cpu,
359 show_thread_cpu_cmd,
360 "show thread cpu [FILTER]",
361 SHOW_STR
362 "Thread information\n"
363 "Thread CPU usage\n"
paula48b4e62005-04-22 00:43:47 +0000364 "Display filter (rwtexb)\n")
paule04ab742003-01-17 23:47:00 +0000365{
366 int i = 0;
Paul Jakma41b23732009-06-30 16:12:49 +0100367 thread_type filter = (thread_type) -1U;
paule04ab742003-01-17 23:47:00 +0000368
369 if (argc > 0)
370 {
371 filter = 0;
372 while (argv[0][i] != '\0')
373 {
374 switch ( argv[0][i] )
375 {
376 case 'r':
377 case 'R':
378 filter |= (1 << THREAD_READ);
379 break;
380 case 'w':
381 case 'W':
382 filter |= (1 << THREAD_WRITE);
383 break;
384 case 't':
385 case 'T':
386 filter |= (1 << THREAD_TIMER);
387 break;
388 case 'e':
389 case 'E':
390 filter |= (1 << THREAD_EVENT);
391 break;
392 case 'x':
393 case 'X':
394 filter |= (1 << THREAD_EXECUTE);
395 break;
paula48b4e62005-04-22 00:43:47 +0000396 case 'b':
397 case 'B':
398 filter |= (1 << THREAD_BACKGROUND);
399 break;
paule04ab742003-01-17 23:47:00 +0000400 default:
401 break;
402 }
403 ++i;
404 }
405 if (filter == 0)
406 {
paula48b4e62005-04-22 00:43:47 +0000407 vty_out(vty, "Invalid filter \"%s\" specified,"
408 " must contain at least one of 'RWTEXB'%s",
paule04ab742003-01-17 23:47:00 +0000409 argv[0], VTY_NEWLINE);
410 return CMD_WARNING;
411 }
412 }
413
414 cpu_record_print(vty, filter);
415 return CMD_SUCCESS;
416}
Paul Jakmae276eb82010-01-09 16:15:00 +0000417
418static void
419cpu_record_hash_clear (struct hash_backet *bucket,
420 void *args)
421{
422 thread_type *filter = args;
423 struct cpu_thread_history *a = bucket->data;
424
425 a = bucket->data;
426 if ( !(a->types & *filter) )
427 return;
428
429 hash_release (cpu_record, bucket->data);
430}
431
432static void
433cpu_record_clear (thread_type filter)
434{
435 thread_type *tmp = &filter;
436 hash_iterate (cpu_record,
437 (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
438 tmp);
439}
440
441DEFUN(clear_thread_cpu,
442 clear_thread_cpu_cmd,
443 "clear thread cpu [FILTER]",
444 "Clear stored data\n"
445 "Thread information\n"
446 "Thread CPU usage\n"
447 "Display filter (rwtexb)\n")
448{
449 int i = 0;
450 thread_type filter = (thread_type) -1U;
451
452 if (argc > 0)
453 {
454 filter = 0;
455 while (argv[0][i] != '\0')
456 {
457 switch ( argv[0][i] )
458 {
459 case 'r':
460 case 'R':
461 filter |= (1 << THREAD_READ);
462 break;
463 case 'w':
464 case 'W':
465 filter |= (1 << THREAD_WRITE);
466 break;
467 case 't':
468 case 'T':
469 filter |= (1 << THREAD_TIMER);
470 break;
471 case 'e':
472 case 'E':
473 filter |= (1 << THREAD_EVENT);
474 break;
475 case 'x':
476 case 'X':
477 filter |= (1 << THREAD_EXECUTE);
478 break;
479 case 'b':
480 case 'B':
481 filter |= (1 << THREAD_BACKGROUND);
482 break;
483 default:
484 break;
485 }
486 ++i;
487 }
488 if (filter == 0)
489 {
490 vty_out(vty, "Invalid filter \"%s\" specified,"
491 " must contain at least one of 'RWTEXB'%s",
492 argv[0], VTY_NEWLINE);
493 return CMD_WARNING;
494 }
495 }
496
497 cpu_record_clear (filter);
498 return CMD_SUCCESS;
499}
David Lamparter6b0655a2014-06-04 06:53:35 +0200500
Christian Franke4becea72013-11-19 14:11:42 +0000501static int
502thread_timer_cmp(void *a, void *b)
503{
504 struct thread *thread_a = a;
505 struct thread *thread_b = b;
506
507 long cmp = timeval_cmp(thread_a->u.sands, thread_b->u.sands);
508
509 if (cmp < 0)
510 return -1;
511 if (cmp > 0)
512 return 1;
513 return 0;
514}
515
516static void
517thread_timer_update(void *node, int actual_position)
518{
519 struct thread *thread = node;
520
521 thread->index = actual_position;
522}
523
paul718e3742002-12-13 20:15:29 +0000524/* Allocate new thread master. */
525struct thread_master *
526thread_master_create ()
527{
Christian Franke4becea72013-11-19 14:11:42 +0000528 struct thread_master *rv;
Denil Vira4ab273b2016-03-04 15:28:54 -0500529 struct rlimit limit;
530
531 getrlimit(RLIMIT_NOFILE, &limit);
Christian Franke4becea72013-11-19 14:11:42 +0000532
paule04ab742003-01-17 23:47:00 +0000533 if (cpu_record == NULL)
paul8cc41982005-05-06 21:25:49 +0000534 cpu_record
Stephen Hemminger90645f52013-01-04 22:29:21 +0000535 = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
536 (int (*) (const void *, const void *))cpu_record_hash_cmp);
Christian Franke4becea72013-11-19 14:11:42 +0000537
538 rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master));
Denil Vira4ab273b2016-03-04 15:28:54 -0500539 if (rv == NULL)
540 {
541 return NULL;
542 }
543
544 rv->fd_limit = (int)limit.rlim_cur;
545 rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit);
546 if (rv->read == NULL)
547 {
548 XFREE (MTYPE_THREAD_MASTER, rv);
549 return NULL;
550 }
551
552 rv->write = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit);
553 if (rv->write == NULL)
554 {
555 XFREE (MTYPE_THREAD, rv->read);
556 XFREE (MTYPE_THREAD_MASTER, rv);
557 return NULL;
558 }
Christian Franke4becea72013-11-19 14:11:42 +0000559
560 /* Initialize the timer queues */
561 rv->timer = pqueue_create();
562 rv->background = pqueue_create();
563 rv->timer->cmp = rv->background->cmp = thread_timer_cmp;
564 rv->timer->update = rv->background->update = thread_timer_update;
565
566 return rv;
paul718e3742002-12-13 20:15:29 +0000567}
568
569/* Add a new thread to the list. */
570static void
571thread_list_add (struct thread_list *list, struct thread *thread)
572{
573 thread->next = NULL;
574 thread->prev = list->tail;
575 if (list->tail)
576 list->tail->next = thread;
577 else
578 list->head = thread;
579 list->tail = thread;
580 list->count++;
581}
582
paul718e3742002-12-13 20:15:29 +0000583/* Delete a thread from the list. */
584static struct thread *
585thread_list_delete (struct thread_list *list, struct thread *thread)
586{
587 if (thread->next)
588 thread->next->prev = thread->prev;
589 else
590 list->tail = thread->prev;
591 if (thread->prev)
592 thread->prev->next = thread->next;
593 else
594 list->head = thread->next;
595 thread->next = thread->prev = NULL;
596 list->count--;
597 return thread;
598}
599
Denil Vira4ab273b2016-03-04 15:28:54 -0500600static void
601thread_delete_fd (struct thread **thread_array, struct thread *thread)
602{
603 thread_array[thread->u.fd] = NULL;
604}
605
606static void
607thread_add_fd (struct thread **thread_array, struct thread *thread)
608{
609 thread_array[thread->u.fd] = thread;
610}
611
paul718e3742002-12-13 20:15:29 +0000612/* Move thread to unuse list. */
613static void
614thread_add_unuse (struct thread_master *m, struct thread *thread)
615{
paula48b4e62005-04-22 00:43:47 +0000616 assert (m != NULL && thread != NULL);
paul718e3742002-12-13 20:15:29 +0000617 assert (thread->next == NULL);
618 assert (thread->prev == NULL);
619 assert (thread->type == THREAD_UNUSED);
620 thread_list_add (&m->unuse, thread);
621}
622
623/* Free all unused thread. */
624static void
625thread_list_free (struct thread_master *m, struct thread_list *list)
626{
627 struct thread *t;
628 struct thread *next;
629
630 for (t = list->head; t; t = next)
631 {
632 next = t->next;
633 XFREE (MTYPE_THREAD, t);
634 list->count--;
635 m->alloc--;
636 }
637}
638
Christian Franke4becea72013-11-19 14:11:42 +0000639static void
Denil Vira4ab273b2016-03-04 15:28:54 -0500640thread_array_free (struct thread_master *m, struct thread **thread_array)
641{
642 struct thread *t;
643 int index;
644
645 for (index = 0; index < m->fd_limit; ++index)
646 {
647 t = thread_array[index];
648 if (t)
649 {
650 thread_array[index] = NULL;
651 XFREE (MTYPE_THREAD, t);
652 m->alloc--;
653 }
654 }
655 XFREE (MTYPE_THREAD, thread_array);
656}
657
658static void
Christian Franke4becea72013-11-19 14:11:42 +0000659thread_queue_free (struct thread_master *m, struct pqueue *queue)
660{
661 int i;
662
663 for (i = 0; i < queue->size; i++)
664 XFREE(MTYPE_THREAD, queue->array[i]);
665
666 m->alloc -= queue->size;
667 pqueue_delete(queue);
668}
669
paul718e3742002-12-13 20:15:29 +0000670/* Stop thread scheduler. */
671void
672thread_master_free (struct thread_master *m)
673{
Denil Vira4ab273b2016-03-04 15:28:54 -0500674 thread_array_free (m, m->read);
675 thread_array_free (m, m->write);
Christian Franke4becea72013-11-19 14:11:42 +0000676 thread_queue_free (m, m->timer);
paul718e3742002-12-13 20:15:29 +0000677 thread_list_free (m, &m->event);
678 thread_list_free (m, &m->ready);
679 thread_list_free (m, &m->unuse);
Christian Franke4becea72013-11-19 14:11:42 +0000680 thread_queue_free (m, m->background);
paula48b4e62005-04-22 00:43:47 +0000681
paul718e3742002-12-13 20:15:29 +0000682 XFREE (MTYPE_THREAD_MASTER, m);
Chris Caputo228da422009-07-18 05:44:03 +0000683
684 if (cpu_record)
685 {
686 hash_clean (cpu_record, cpu_record_hash_free);
687 hash_free (cpu_record);
688 cpu_record = NULL;
689 }
paul718e3742002-12-13 20:15:29 +0000690}
691
paul8cc41982005-05-06 21:25:49 +0000692/* Thread list is empty or not. */
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100693static int
paul8cc41982005-05-06 21:25:49 +0000694thread_empty (struct thread_list *list)
695{
696 return list->head ? 0 : 1;
697}
698
paul718e3742002-12-13 20:15:29 +0000699/* Delete top of the list and return it. */
700static struct thread *
701thread_trim_head (struct thread_list *list)
702{
paul8cc41982005-05-06 21:25:49 +0000703 if (!thread_empty (list))
paul718e3742002-12-13 20:15:29 +0000704 return thread_list_delete (list, list->head);
705 return NULL;
706}
707
paul718e3742002-12-13 20:15:29 +0000708/* Return remain time in second. */
709unsigned long
710thread_timer_remain_second (struct thread *thread)
711{
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000712 quagga_get_relative (NULL);
713
714 if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
715 return thread->u.sands.tv_sec - relative_time.tv_sec;
paul718e3742002-12-13 20:15:29 +0000716 else
717 return 0;
718}
719
Christian Franke76fbc642015-11-10 18:04:41 +0100720struct timeval
721thread_timer_remain(struct thread *thread)
722{
723 quagga_get_relative(NULL);
724
725 return timeval_subtract(thread->u.sands, relative_time);
726}
727
David Lamparter3493b772013-11-18 23:04:27 +0100728#define debugargdef const char *funcname, const char *schedfrom, int fromln
729#define debugargpass funcname, schedfrom, fromln
paule04ab742003-01-17 23:47:00 +0000730
paul718e3742002-12-13 20:15:29 +0000731/* Get new thread. */
732static struct thread *
733thread_get (struct thread_master *m, u_char type,
David Lamparter3493b772013-11-18 23:04:27 +0100734 int (*func) (struct thread *), void *arg, debugargdef)
paul718e3742002-12-13 20:15:29 +0000735{
Jorge Boncompte [DTI2]64018322012-05-07 16:53:13 +0000736 struct thread *thread = thread_trim_head (&m->unuse);
paul718e3742002-12-13 20:15:29 +0000737
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000738 if (! thread)
paul718e3742002-12-13 20:15:29 +0000739 {
740 thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
741 m->alloc++;
742 }
743 thread->type = type;
paule04ab742003-01-17 23:47:00 +0000744 thread->add_type = type;
paul718e3742002-12-13 20:15:29 +0000745 thread->master = m;
746 thread->func = func;
747 thread->arg = arg;
Christian Franke4becea72013-11-19 14:11:42 +0000748 thread->index = -1;
749
David Lamparter3493b772013-11-18 23:04:27 +0100750 thread->funcname = funcname;
751 thread->schedfrom = schedfrom;
752 thread->schedfrom_line = fromln;
paule04ab742003-01-17 23:47:00 +0000753
paul718e3742002-12-13 20:15:29 +0000754 return thread;
755}
756
757/* Add new read thread. */
758struct thread *
paule04ab742003-01-17 23:47:00 +0000759funcname_thread_add_read (struct thread_master *m,
David Lamparter3493b772013-11-18 23:04:27 +0100760 int (*func) (struct thread *), void *arg, int fd,
761 debugargdef)
paul718e3742002-12-13 20:15:29 +0000762{
763 struct thread *thread;
764
765 assert (m != NULL);
766
767 if (FD_ISSET (fd, &m->readfd))
768 {
769 zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
770 return NULL;
771 }
772
David Lamparter3493b772013-11-18 23:04:27 +0100773 thread = thread_get (m, THREAD_READ, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000774 FD_SET (fd, &m->readfd);
775 thread->u.fd = fd;
Denil Vira4ab273b2016-03-04 15:28:54 -0500776 thread_add_fd (m->read, thread);
paul718e3742002-12-13 20:15:29 +0000777
778 return thread;
779}
780
781/* Add new write thread. */
782struct thread *
paule04ab742003-01-17 23:47:00 +0000783funcname_thread_add_write (struct thread_master *m,
David Lamparter3493b772013-11-18 23:04:27 +0100784 int (*func) (struct thread *), void *arg, int fd,
785 debugargdef)
paul718e3742002-12-13 20:15:29 +0000786{
787 struct thread *thread;
788
789 assert (m != NULL);
790
791 if (FD_ISSET (fd, &m->writefd))
792 {
793 zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
794 return NULL;
795 }
796
David Lamparter3493b772013-11-18 23:04:27 +0100797 thread = thread_get (m, THREAD_WRITE, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000798 FD_SET (fd, &m->writefd);
799 thread->u.fd = fd;
Denil Vira4ab273b2016-03-04 15:28:54 -0500800 thread_add_fd (m->write, thread);
paul718e3742002-12-13 20:15:29 +0000801
802 return thread;
803}
804
paul98c91ac2004-10-05 14:57:50 +0000805static struct thread *
806funcname_thread_add_timer_timeval (struct thread_master *m,
807 int (*func) (struct thread *),
paula48b4e62005-04-22 00:43:47 +0000808 int type,
paul98c91ac2004-10-05 14:57:50 +0000809 void *arg,
David Lamparter3493b772013-11-18 23:04:27 +0100810 struct timeval *time_relative,
811 debugargdef)
paul718e3742002-12-13 20:15:29 +0000812{
paul718e3742002-12-13 20:15:29 +0000813 struct thread *thread;
Christian Franke4becea72013-11-19 14:11:42 +0000814 struct pqueue *queue;
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000815 struct timeval alarm_time;
paul718e3742002-12-13 20:15:29 +0000816
817 assert (m != NULL);
818
ajs8b70d0b2005-04-28 01:31:13 +0000819 assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
paula48b4e62005-04-22 00:43:47 +0000820 assert (time_relative);
821
Christian Franke4becea72013-11-19 14:11:42 +0000822 queue = ((type == THREAD_TIMER) ? m->timer : m->background);
David Lamparter3493b772013-11-18 23:04:27 +0100823 thread = thread_get (m, type, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000824
825 /* Do we need jitter here? */
Joakim Tjernlundb8192762008-11-10 09:33:30 +0100826 quagga_get_relative (NULL);
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000827 alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
828 alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
ajs8b70d0b2005-04-28 01:31:13 +0000829 thread->u.sands = timeval_adjust(alarm_time);
paul718e3742002-12-13 20:15:29 +0000830
Christian Franke4becea72013-11-19 14:11:42 +0000831 pqueue_enqueue(thread, queue);
paul718e3742002-12-13 20:15:29 +0000832 return thread;
833}
834
paul98c91ac2004-10-05 14:57:50 +0000835
836/* Add timer event thread. */
jardin9e867fe2003-12-23 08:56:18 +0000837struct thread *
paul98c91ac2004-10-05 14:57:50 +0000838funcname_thread_add_timer (struct thread_master *m,
839 int (*func) (struct thread *),
David Lamparter3493b772013-11-18 23:04:27 +0100840 void *arg, long timer,
841 debugargdef)
jardin9e867fe2003-12-23 08:56:18 +0000842{
paul98c91ac2004-10-05 14:57:50 +0000843 struct timeval trel;
jardin9e867fe2003-12-23 08:56:18 +0000844
845 assert (m != NULL);
846
paul9076fbd2004-10-11 09:40:58 +0000847 trel.tv_sec = timer;
paul98c91ac2004-10-05 14:57:50 +0000848 trel.tv_usec = 0;
849
paula48b4e62005-04-22 00:43:47 +0000850 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
David Lamparter3493b772013-11-18 23:04:27 +0100851 &trel, debugargpass);
paul98c91ac2004-10-05 14:57:50 +0000852}
853
854/* Add timer event thread with "millisecond" resolution */
855struct thread *
856funcname_thread_add_timer_msec (struct thread_master *m,
857 int (*func) (struct thread *),
David Lamparter3493b772013-11-18 23:04:27 +0100858 void *arg, long timer,
859 debugargdef)
paul98c91ac2004-10-05 14:57:50 +0000860{
861 struct timeval trel;
862
863 assert (m != NULL);
jardin9e867fe2003-12-23 08:56:18 +0000864
ajsaf04bd72004-12-28 17:00:12 +0000865 trel.tv_sec = timer / 1000;
866 trel.tv_usec = 1000*(timer % 1000);
jardin9e867fe2003-12-23 08:56:18 +0000867
paula48b4e62005-04-22 00:43:47 +0000868 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
David Lamparter3493b772013-11-18 23:04:27 +0100869 arg, &trel, debugargpass);
paula48b4e62005-04-22 00:43:47 +0000870}
871
872/* Add a background thread, with an optional millisec delay */
873struct thread *
874funcname_thread_add_background (struct thread_master *m,
875 int (*func) (struct thread *),
David Lamparter3493b772013-11-18 23:04:27 +0100876 void *arg, long delay,
877 debugargdef)
paula48b4e62005-04-22 00:43:47 +0000878{
879 struct timeval trel;
880
881 assert (m != NULL);
882
883 if (delay)
884 {
885 trel.tv_sec = delay / 1000;
886 trel.tv_usec = 1000*(delay % 1000);
887 }
888 else
889 {
890 trel.tv_sec = 0;
891 trel.tv_usec = 0;
892 }
893
894 return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
David Lamparter3493b772013-11-18 23:04:27 +0100895 arg, &trel, debugargpass);
jardin9e867fe2003-12-23 08:56:18 +0000896}
897
paul718e3742002-12-13 20:15:29 +0000898/* Add simple event thread. */
899struct thread *
paule04ab742003-01-17 23:47:00 +0000900funcname_thread_add_event (struct thread_master *m,
David Lamparter3493b772013-11-18 23:04:27 +0100901 int (*func) (struct thread *), void *arg, int val,
902 debugargdef)
paul718e3742002-12-13 20:15:29 +0000903{
904 struct thread *thread;
905
906 assert (m != NULL);
907
David Lamparter3493b772013-11-18 23:04:27 +0100908 thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000909 thread->u.val = val;
910 thread_list_add (&m->event, thread);
911
912 return thread;
913}
914
915/* Cancel thread from scheduler. */
916void
917thread_cancel (struct thread *thread)
918{
Christian Franke4becea72013-11-19 14:11:42 +0000919 struct thread_list *list = NULL;
920 struct pqueue *queue = NULL;
Denil Vira4ab273b2016-03-04 15:28:54 -0500921 struct thread **thread_array = NULL;
paula48b4e62005-04-22 00:43:47 +0000922
paul718e3742002-12-13 20:15:29 +0000923 switch (thread->type)
924 {
925 case THREAD_READ:
926 assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
927 FD_CLR (thread->u.fd, &thread->master->readfd);
Denil Vira4ab273b2016-03-04 15:28:54 -0500928 thread_array = thread->master->read;
paul718e3742002-12-13 20:15:29 +0000929 break;
930 case THREAD_WRITE:
931 assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
932 FD_CLR (thread->u.fd, &thread->master->writefd);
Denil Vira4ab273b2016-03-04 15:28:54 -0500933 thread_array = thread->master->write;
paul718e3742002-12-13 20:15:29 +0000934 break;
935 case THREAD_TIMER:
Christian Franke4becea72013-11-19 14:11:42 +0000936 queue = thread->master->timer;
paul718e3742002-12-13 20:15:29 +0000937 break;
938 case THREAD_EVENT:
paula48b4e62005-04-22 00:43:47 +0000939 list = &thread->master->event;
paul718e3742002-12-13 20:15:29 +0000940 break;
941 case THREAD_READY:
paula48b4e62005-04-22 00:43:47 +0000942 list = &thread->master->ready;
paul718e3742002-12-13 20:15:29 +0000943 break;
paula48b4e62005-04-22 00:43:47 +0000944 case THREAD_BACKGROUND:
Christian Franke4becea72013-11-19 14:11:42 +0000945 queue = thread->master->background;
ajs8b70d0b2005-04-28 01:31:13 +0000946 break;
paul718e3742002-12-13 20:15:29 +0000947 default:
paula48b4e62005-04-22 00:43:47 +0000948 return;
paul718e3742002-12-13 20:15:29 +0000949 break;
950 }
Christian Franke4becea72013-11-19 14:11:42 +0000951
952 if (queue)
953 {
954 assert(thread->index >= 0);
955 assert(thread == queue->array[thread->index]);
956 pqueue_remove_at(thread->index, queue);
957 }
958 else if (list)
959 {
960 thread_list_delete (list, thread);
961 }
Denil Vira4ab273b2016-03-04 15:28:54 -0500962 else if (thread_array)
963 {
964 thread_delete_fd (thread_array, thread);
965 }
Christian Franke4becea72013-11-19 14:11:42 +0000966 else
967 {
Denil Vira4ab273b2016-03-04 15:28:54 -0500968 assert(!"Thread should be either in queue or list or array!");
Christian Franke4becea72013-11-19 14:11:42 +0000969 }
970
paul718e3742002-12-13 20:15:29 +0000971 thread->type = THREAD_UNUSED;
972 thread_add_unuse (thread->master, thread);
973}
974
975/* Delete all events which has argument value arg. */
pauldc818072005-05-19 01:30:53 +0000976unsigned int
paul718e3742002-12-13 20:15:29 +0000977thread_cancel_event (struct thread_master *m, void *arg)
978{
pauldc818072005-05-19 01:30:53 +0000979 unsigned int ret = 0;
paul718e3742002-12-13 20:15:29 +0000980 struct thread *thread;
981
982 thread = m->event.head;
983 while (thread)
984 {
985 struct thread *t;
986
987 t = thread;
988 thread = t->next;
989
990 if (t->arg == arg)
paula48b4e62005-04-22 00:43:47 +0000991 {
pauldc818072005-05-19 01:30:53 +0000992 ret++;
paula48b4e62005-04-22 00:43:47 +0000993 thread_list_delete (&m->event, t);
994 t->type = THREAD_UNUSED;
995 thread_add_unuse (m, t);
996 }
paul718e3742002-12-13 20:15:29 +0000997 }
Jorge Boncompte [DTI2]1b79fcb2012-05-07 15:17:31 +0000998
999 /* thread can be on the ready list too */
1000 thread = m->ready.head;
1001 while (thread)
1002 {
1003 struct thread *t;
1004
1005 t = thread;
1006 thread = t->next;
1007
1008 if (t->arg == arg)
1009 {
1010 ret++;
1011 thread_list_delete (&m->ready, t);
1012 t->type = THREAD_UNUSED;
1013 thread_add_unuse (m, t);
1014 }
1015 }
pauldc818072005-05-19 01:30:53 +00001016 return ret;
paul718e3742002-12-13 20:15:29 +00001017}
1018
paula48b4e62005-04-22 00:43:47 +00001019static struct timeval *
Christian Franke4becea72013-11-19 14:11:42 +00001020thread_timer_wait (struct pqueue *queue, struct timeval *timer_val)
paul718e3742002-12-13 20:15:29 +00001021{
Christian Franke4becea72013-11-19 14:11:42 +00001022 if (queue->size)
paul718e3742002-12-13 20:15:29 +00001023 {
Christian Franke4becea72013-11-19 14:11:42 +00001024 struct thread *next_timer = queue->array[0];
1025 *timer_val = timeval_subtract (next_timer->u.sands, relative_time);
paul718e3742002-12-13 20:15:29 +00001026 return timer_val;
1027 }
1028 return NULL;
1029}
paul718e3742002-12-13 20:15:29 +00001030
paul8cc41982005-05-06 21:25:49 +00001031static struct thread *
paul718e3742002-12-13 20:15:29 +00001032thread_run (struct thread_master *m, struct thread *thread,
1033 struct thread *fetch)
1034{
1035 *fetch = *thread;
1036 thread->type = THREAD_UNUSED;
1037 thread_add_unuse (m, thread);
1038 return fetch;
1039}
1040
paula48b4e62005-04-22 00:43:47 +00001041static int
Denil Vira4ab273b2016-03-04 15:28:54 -05001042thread_process_fd (struct thread **thread_array, fd_set *fdset, fd_set *mfdset, int num, int fd_limit)
paul718e3742002-12-13 20:15:29 +00001043{
1044 struct thread *thread;
Denil Vira4ab273b2016-03-04 15:28:54 -05001045 int ready = 0, index;
paul718e3742002-12-13 20:15:29 +00001046
Denil Vira4ab273b2016-03-04 15:28:54 -05001047 assert (thread_array);
1048
1049 for (index = 0; index < fd_limit && ready < num; ++index)
1050 {
1051 thread = thread_array[index];
1052 if (thread && FD_ISSET (THREAD_FD (thread), fdset))
paula48b4e62005-04-22 00:43:47 +00001053 {
1054 assert (FD_ISSET (THREAD_FD (thread), mfdset));
1055 FD_CLR(THREAD_FD (thread), mfdset);
Denil Vira4ab273b2016-03-04 15:28:54 -05001056 thread_delete_fd (thread_array, thread);
paula48b4e62005-04-22 00:43:47 +00001057 thread_list_add (&thread->master->ready, thread);
1058 thread->type = THREAD_READY;
1059 ready++;
1060 }
paul718e3742002-12-13 20:15:29 +00001061 }
Denil Vira4ab273b2016-03-04 15:28:54 -05001062 return num - ready;
paul718e3742002-12-13 20:15:29 +00001063}
1064
ajs8b70d0b2005-04-28 01:31:13 +00001065/* Add all timers that have popped to the ready list. */
paula48b4e62005-04-22 00:43:47 +00001066static unsigned int
Christian Franke4becea72013-11-19 14:11:42 +00001067thread_timer_process (struct pqueue *queue, struct timeval *timenow)
paula48b4e62005-04-22 00:43:47 +00001068{
1069 struct thread *thread;
1070 unsigned int ready = 0;
1071
Christian Franke4becea72013-11-19 14:11:42 +00001072 while (queue->size)
ajs8b70d0b2005-04-28 01:31:13 +00001073 {
Christian Franke4becea72013-11-19 14:11:42 +00001074 thread = queue->array[0];
ajs8b70d0b2005-04-28 01:31:13 +00001075 if (timeval_cmp (*timenow, thread->u.sands) < 0)
1076 return ready;
Christian Franke4becea72013-11-19 14:11:42 +00001077 pqueue_dequeue(queue);
ajs8b70d0b2005-04-28 01:31:13 +00001078 thread->type = THREAD_READY;
1079 thread_list_add (&thread->master->ready, thread);
1080 ready++;
1081 }
paula48b4e62005-04-22 00:43:47 +00001082 return ready;
1083}
1084
Paul Jakma2613abe2010-01-11 16:33:07 +00001085/* process a list en masse, e.g. for event thread lists */
1086static unsigned int
1087thread_process (struct thread_list *list)
1088{
1089 struct thread *thread;
Paul Jakmab5043aa2012-02-28 18:32:56 +00001090 struct thread *next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001091 unsigned int ready = 0;
1092
Paul Jakmab5043aa2012-02-28 18:32:56 +00001093 for (thread = list->head; thread; thread = next)
Paul Jakma2613abe2010-01-11 16:33:07 +00001094 {
Paul Jakmab5043aa2012-02-28 18:32:56 +00001095 next = thread->next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001096 thread_list_delete (list, thread);
1097 thread->type = THREAD_READY;
1098 thread_list_add (&thread->master->ready, thread);
1099 ready++;
1100 }
1101 return ready;
1102}
1103
1104
paul718e3742002-12-13 20:15:29 +00001105/* Fetch next ready thread. */
1106struct thread *
1107thread_fetch (struct thread_master *m, struct thread *fetch)
1108{
paul718e3742002-12-13 20:15:29 +00001109 struct thread *thread;
1110 fd_set readfd;
1111 fd_set writefd;
1112 fd_set exceptfd;
Paul Jakma2613abe2010-01-11 16:33:07 +00001113 struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
paula48b4e62005-04-22 00:43:47 +00001114 struct timeval timer_val_bg;
Paul Jakma2613abe2010-01-11 16:33:07 +00001115 struct timeval *timer_wait = &timer_val;
paula48b4e62005-04-22 00:43:47 +00001116 struct timeval *timer_wait_bg;
paul718e3742002-12-13 20:15:29 +00001117
1118 while (1)
1119 {
paula48b4e62005-04-22 00:43:47 +00001120 int num = 0;
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001121#if defined HAVE_SNMP && defined SNMP_AGENTX
1122 struct timeval snmp_timer_wait;
1123 int snmpblock = 0;
1124 int fdsetsize;
1125#endif
paula48b4e62005-04-22 00:43:47 +00001126
Paul Jakma2613abe2010-01-11 16:33:07 +00001127 /* Signals pre-empt everything */
paul05c447d2004-07-22 19:14:27 +00001128 quagga_sigevent_process ();
1129
Paul Jakma2613abe2010-01-11 16:33:07 +00001130 /* Drain the ready queue of already scheduled jobs, before scheduling
1131 * more.
paula48b4e62005-04-22 00:43:47 +00001132 */
paul718e3742002-12-13 20:15:29 +00001133 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001134 return thread_run (m, thread, fetch);
paula48b4e62005-04-22 00:43:47 +00001135
Paul Jakma2613abe2010-01-11 16:33:07 +00001136 /* To be fair to all kinds of threads, and avoid starvation, we
1137 * need to be careful to consider all thread types for scheduling
1138 * in each quanta. I.e. we should not return early from here on.
1139 */
1140
1141 /* Normal event are the next highest priority. */
1142 thread_process (&m->event);
1143
paul718e3742002-12-13 20:15:29 +00001144 /* Structure copy. */
1145 readfd = m->readfd;
1146 writefd = m->writefd;
1147 exceptfd = m->exceptfd;
paula48b4e62005-04-22 00:43:47 +00001148
1149 /* Calculate select wait timer if nothing else to do */
Paul Jakma2613abe2010-01-11 16:33:07 +00001150 if (m->ready.count == 0)
1151 {
1152 quagga_get_relative (NULL);
Christian Franke4becea72013-11-19 14:11:42 +00001153 timer_wait = thread_timer_wait (m->timer, &timer_val);
1154 timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg);
Paul Jakma2613abe2010-01-11 16:33:07 +00001155
1156 if (timer_wait_bg &&
1157 (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
1158 timer_wait = timer_wait_bg;
1159 }
paula48b4e62005-04-22 00:43:47 +00001160
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001161#if defined HAVE_SNMP && defined SNMP_AGENTX
1162 /* When SNMP is enabled, we may have to select() on additional
1163 FD. snmp_select_info() will add them to `readfd'. The trick
1164 with this function is its last argument. We need to set it to
1165 0 if timer_wait is not NULL and we need to use the provided
1166 new timer only if it is still set to 0. */
1167 if (agentx_enabled)
1168 {
1169 fdsetsize = FD_SETSIZE;
1170 snmpblock = 1;
1171 if (timer_wait)
1172 {
1173 snmpblock = 0;
1174 memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval));
1175 }
1176 snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock);
1177 if (snmpblock == 0)
1178 timer_wait = &snmp_timer_wait;
1179 }
1180#endif
paul718e3742002-12-13 20:15:29 +00001181 num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
paula48b4e62005-04-22 00:43:47 +00001182
1183 /* Signals should get quick treatment */
paul718e3742002-12-13 20:15:29 +00001184 if (num < 0)
paul05c447d2004-07-22 19:14:27 +00001185 {
1186 if (errno == EINTR)
paula48b4e62005-04-22 00:43:47 +00001187 continue; /* signal received - process it */
ajs6099b3b2004-11-20 02:06:59 +00001188 zlog_warn ("select() error: %s", safe_strerror (errno));
paul05c447d2004-07-22 19:14:27 +00001189 return NULL;
1190 }
ajs8b70d0b2005-04-28 01:31:13 +00001191
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001192#if defined HAVE_SNMP && defined SNMP_AGENTX
1193 if (agentx_enabled)
1194 {
1195 if (num > 0)
1196 snmp_read(&readfd);
1197 else if (num == 0)
1198 {
1199 snmp_timeout();
1200 run_alarms();
1201 }
1202 netsnmp_check_outstanding_agent_requests();
1203 }
1204#endif
1205
ajs8b70d0b2005-04-28 01:31:13 +00001206 /* Check foreground timers. Historically, they have had higher
1207 priority than I/O threads, so let's push them onto the ready
1208 list in front of the I/O threads. */
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001209 quagga_get_relative (NULL);
Christian Franke4becea72013-11-19 14:11:42 +00001210 thread_timer_process (m->timer, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001211
1212 /* Got IO, process it */
1213 if (num > 0)
1214 {
Denil Vira4ab273b2016-03-04 15:28:54 -05001215 /* Normal priority read thread. */
1216 num = thread_process_fd (m->read, &readfd, &m->readfd, num, m->fd_limit);
1217 /* Write thread. */
1218 num = thread_process_fd (m->write, &writefd, &m->writefd, num, m->fd_limit);
paula48b4e62005-04-22 00:43:47 +00001219 }
ajs8b70d0b2005-04-28 01:31:13 +00001220
1221#if 0
1222 /* If any threads were made ready above (I/O or foreground timer),
1223 perhaps we should avoid adding background timers to the ready
1224 list at this time. If this is code is uncommented, then background
1225 timer threads will not run unless there is nothing else to do. */
1226 if ((thread = thread_trim_head (&m->ready)) != NULL)
1227 return thread_run (m, thread, fetch);
1228#endif
1229
paula48b4e62005-04-22 00:43:47 +00001230 /* Background timer/events, lowest priority */
Christian Franke4becea72013-11-19 14:11:42 +00001231 thread_timer_process (m->background, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001232
ajs8b70d0b2005-04-28 01:31:13 +00001233 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001234 return thread_run (m, thread, fetch);
paul718e3742002-12-13 20:15:29 +00001235 }
1236}
1237
ajs924b9222005-04-16 17:11:24 +00001238unsigned long
ajs8b70d0b2005-04-28 01:31:13 +00001239thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
paul718e3742002-12-13 20:15:29 +00001240{
paul718e3742002-12-13 20:15:29 +00001241#ifdef HAVE_RUSAGE
1242 /* This is 'user + sys' time. */
ajs8b70d0b2005-04-28 01:31:13 +00001243 *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
1244 timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
paul718e3742002-12-13 20:15:29 +00001245#else
ajs8b70d0b2005-04-28 01:31:13 +00001246 *cputime = 0;
paul718e3742002-12-13 20:15:29 +00001247#endif /* HAVE_RUSAGE */
ajs8b70d0b2005-04-28 01:31:13 +00001248 return timeval_elapsed (now->real, start->real);
paul718e3742002-12-13 20:15:29 +00001249}
1250
ajs8b70d0b2005-04-28 01:31:13 +00001251/* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1252 Note: we are using real (wall clock) time for this calculation.
1253 It could be argued that CPU time may make more sense in certain
1254 contexts. The things to consider are whether the thread may have
1255 blocked (in which case wall time increases, but CPU time does not),
1256 or whether the system is heavily loaded with other processes competing
1257 for CPU time. On balance, wall clock time seems to make sense.
1258 Plus it has the added benefit that gettimeofday should be faster
1259 than calling getrusage. */
paul718e3742002-12-13 20:15:29 +00001260int
1261thread_should_yield (struct thread *thread)
1262{
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001263 quagga_get_relative (NULL);
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001264 return (timeval_elapsed(relative_time, thread->real) >
ajs8b70d0b2005-04-28 01:31:13 +00001265 THREAD_YIELD_TIME_SLOT);
paul718e3742002-12-13 20:15:29 +00001266}
1267
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001268void
1269thread_getrusage (RUSAGE_T *r)
1270{
1271 quagga_get_relative (NULL);
1272#ifdef HAVE_RUSAGE
1273 getrusage(RUSAGE_SELF, &(r->cpu));
1274#endif
1275 r->real = relative_time;
1276
1277#ifdef HAVE_CLOCK_MONOTONIC
1278 /* quagga_get_relative() only updates recent_time if gettimeofday
1279 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1280 * and guarantee to update it before threads are run...
1281 */
1282 quagga_gettimeofday(&recent_time);
1283#endif /* HAVE_CLOCK_MONOTONIC */
1284}
1285
David Lamparter615f9f12013-11-18 23:52:02 +01001286struct thread *thread_current = NULL;
1287
paul718e3742002-12-13 20:15:29 +00001288/* We check thread consumed time. If the system has getrusage, we'll
ajs8b70d0b2005-04-28 01:31:13 +00001289 use that to get in-depth stats on the performance of the thread in addition
1290 to wall clock time stats from gettimeofday. */
paul718e3742002-12-13 20:15:29 +00001291void
1292thread_call (struct thread *thread)
1293{
ajs8b70d0b2005-04-28 01:31:13 +00001294 unsigned long realtime, cputime;
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001295 RUSAGE_T before, after;
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001296
1297 /* Cache a pointer to the relevant cpu history thread, if the thread
1298 * does not have it yet.
1299 *
1300 * Callers submitting 'dummy threads' hence must take care that
1301 * thread->cpu is NULL
1302 */
1303 if (!thread->hist)
1304 {
1305 struct cpu_thread_history tmp;
1306
1307 tmp.func = thread->func;
David Lamparter3493b772013-11-18 23:04:27 +01001308 tmp.funcname = thread->funcname;
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001309
1310 thread->hist = hash_get (cpu_record, &tmp,
1311 (void * (*) (void *))cpu_record_hash_alloc);
1312 }
paul718e3742002-12-13 20:15:29 +00001313
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001314 GETRUSAGE (&before);
1315 thread->real = before.real;
paul718e3742002-12-13 20:15:29 +00001316
David Lamparter615f9f12013-11-18 23:52:02 +01001317 thread_current = thread;
paul718e3742002-12-13 20:15:29 +00001318 (*thread->func) (thread);
David Lamparter615f9f12013-11-18 23:52:02 +01001319 thread_current = NULL;
paul718e3742002-12-13 20:15:29 +00001320
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001321 GETRUSAGE (&after);
paul718e3742002-12-13 20:15:29 +00001322
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001323 realtime = thread_consumed_time (&after, &before, &cputime);
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001324 thread->hist->real.total += realtime;
1325 if (thread->hist->real.max < realtime)
1326 thread->hist->real.max = realtime;
ajs8b70d0b2005-04-28 01:31:13 +00001327#ifdef HAVE_RUSAGE
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001328 thread->hist->cpu.total += cputime;
1329 if (thread->hist->cpu.max < cputime)
1330 thread->hist->cpu.max = cputime;
ajs8b70d0b2005-04-28 01:31:13 +00001331#endif
paule04ab742003-01-17 23:47:00 +00001332
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001333 ++(thread->hist->total_calls);
1334 thread->hist->types |= (1 << thread->add_type);
paul718e3742002-12-13 20:15:29 +00001335
ajs924b9222005-04-16 17:11:24 +00001336#ifdef CONSUMED_TIME_CHECK
ajs8b70d0b2005-04-28 01:31:13 +00001337 if (realtime > CONSUMED_TIME_CHECK)
paul718e3742002-12-13 20:15:29 +00001338 {
1339 /*
1340 * We have a CPU Hog on our hands.
1341 * Whinge about it now, so we're aware this is yet another task
1342 * to fix.
1343 */
ajs8b70d0b2005-04-28 01:31:13 +00001344 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
ajs924b9222005-04-16 17:11:24 +00001345 thread->funcname,
1346 (unsigned long) thread->func,
ajs8b70d0b2005-04-28 01:31:13 +00001347 realtime/1000, cputime/1000);
paul718e3742002-12-13 20:15:29 +00001348 }
ajs924b9222005-04-16 17:11:24 +00001349#endif /* CONSUMED_TIME_CHECK */
paul718e3742002-12-13 20:15:29 +00001350}
1351
1352/* Execute thread */
1353struct thread *
paule04ab742003-01-17 23:47:00 +00001354funcname_thread_execute (struct thread_master *m,
paul718e3742002-12-13 20:15:29 +00001355 int (*func)(struct thread *),
1356 void *arg,
paule04ab742003-01-17 23:47:00 +00001357 int val,
David Lamparter3493b772013-11-18 23:04:27 +01001358 debugargdef)
paul718e3742002-12-13 20:15:29 +00001359{
1360 struct thread dummy;
1361
1362 memset (&dummy, 0, sizeof (struct thread));
1363
1364 dummy.type = THREAD_EVENT;
paule04ab742003-01-17 23:47:00 +00001365 dummy.add_type = THREAD_EXECUTE;
paul718e3742002-12-13 20:15:29 +00001366 dummy.master = NULL;
1367 dummy.func = func;
1368 dummy.arg = arg;
1369 dummy.u.val = val;
David Lamparter3493b772013-11-18 23:04:27 +01001370
1371 dummy.funcname = funcname;
1372 dummy.schedfrom = schedfrom;
1373 dummy.schedfrom_line = fromln;
1374
paul718e3742002-12-13 20:15:29 +00001375 thread_call (&dummy);
1376
paul718e3742002-12-13 20:15:29 +00001377 return NULL;
1378}