blob: 39e79ad8c9cc576ec22b93386e201765792449e4 [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
Paul Jakmadb9c0df2006-08-27 06:44:02 +000049/* Recent absolute time of day */
ajs8b70d0b2005-04-28 01:31:13 +000050struct timeval recent_time;
Paul Jakmadb9c0df2006-08-27 06:44:02 +000051static struct timeval last_recent_time;
52/* Relative time, since startup */
53static struct timeval relative_time;
54static struct timeval relative_time_base;
55/* init flag */
56static unsigned short timers_inited;
David Lamparter6b0655a2014-06-04 06:53:35 +020057
paule04ab742003-01-17 23:47:00 +000058static struct hash *cpu_record = NULL;
David Lamparter6b0655a2014-06-04 06:53:35 +020059
paul718e3742002-12-13 20:15:29 +000060/* Struct timeval's tv_usec one second value. */
61#define TIMER_SECOND_MICRO 1000000L
62
ajs8b70d0b2005-04-28 01:31:13 +000063/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
64 And change negative values to 0. */
paula48b4e62005-04-22 00:43:47 +000065static struct timeval
paul718e3742002-12-13 20:15:29 +000066timeval_adjust (struct timeval a)
67{
68 while (a.tv_usec >= TIMER_SECOND_MICRO)
69 {
70 a.tv_usec -= TIMER_SECOND_MICRO;
71 a.tv_sec++;
72 }
73
74 while (a.tv_usec < 0)
75 {
76 a.tv_usec += TIMER_SECOND_MICRO;
77 a.tv_sec--;
78 }
79
80 if (a.tv_sec < 0)
ajs8b70d0b2005-04-28 01:31:13 +000081 /* Change negative timeouts to 0. */
82 a.tv_sec = a.tv_usec = 0;
paul718e3742002-12-13 20:15:29 +000083
84 return a;
85}
86
87static struct timeval
88timeval_subtract (struct timeval a, struct timeval b)
89{
90 struct timeval ret;
91
92 ret.tv_usec = a.tv_usec - b.tv_usec;
93 ret.tv_sec = a.tv_sec - b.tv_sec;
94
95 return timeval_adjust (ret);
96}
97
ajs8b70d0b2005-04-28 01:31:13 +000098static long
paul718e3742002-12-13 20:15:29 +000099timeval_cmp (struct timeval a, struct timeval b)
100{
101 return (a.tv_sec == b.tv_sec
102 ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
103}
104
Dinesh G Dutt50f38b32014-09-30 12:53:28 -0700105unsigned long
paul718e3742002-12-13 20:15:29 +0000106timeval_elapsed (struct timeval a, struct timeval b)
107{
108 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
109 + (a.tv_usec - b.tv_usec));
110}
David Lamparter6b0655a2014-06-04 06:53:35 +0200111
Hasso Tepper3b96b782012-10-11 11:31:54 +0000112#if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__)
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000113static void
114quagga_gettimeofday_relative_adjust (void)
115{
116 struct timeval diff;
117 if (timeval_cmp (recent_time, last_recent_time) < 0)
118 {
119 relative_time.tv_sec++;
120 relative_time.tv_usec = 0;
121 }
122 else
123 {
124 diff = timeval_subtract (recent_time, last_recent_time);
125 relative_time.tv_sec += diff.tv_sec;
126 relative_time.tv_usec += diff.tv_usec;
127 relative_time = timeval_adjust (relative_time);
128 }
129 last_recent_time = recent_time;
130}
Hasso Tepper3b96b782012-10-11 11:31:54 +0000131#endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000132
133/* gettimeofday wrapper, to keep recent_time updated */
134static int
135quagga_gettimeofday (struct timeval *tv)
136{
137 int ret;
138
139 assert (tv);
140
141 if (!(ret = gettimeofday (&recent_time, NULL)))
142 {
143 /* init... */
144 if (!timers_inited)
145 {
146 relative_time_base = last_recent_time = recent_time;
147 timers_inited = 1;
148 }
149 /* avoid copy if user passed recent_time pointer.. */
150 if (tv != &recent_time)
151 *tv = recent_time;
152 return 0;
153 }
154 return ret;
155}
156
157static int
158quagga_get_relative (struct timeval *tv)
159{
160 int ret;
161
162#ifdef HAVE_CLOCK_MONOTONIC
163 {
164 struct timespec tp;
165 if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
166 {
167 relative_time.tv_sec = tp.tv_sec;
168 relative_time.tv_usec = tp.tv_nsec / 1000;
169 }
170 }
Hasso Tepper3b96b782012-10-11 11:31:54 +0000171#elif defined(__APPLE__)
172 {
173 uint64_t ticks;
174 uint64_t useconds;
175 static mach_timebase_info_data_t timebase_info;
176
177 ticks = mach_absolute_time();
178 if (timebase_info.denom == 0)
179 mach_timebase_info(&timebase_info);
180
181 useconds = ticks * timebase_info.numer / timebase_info.denom / 1000;
182 relative_time.tv_sec = useconds / 1000000;
183 relative_time.tv_usec = useconds % 1000000;
184
185 return 0;
186 }
187#else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000188 if (!(ret = quagga_gettimeofday (&recent_time)))
189 quagga_gettimeofday_relative_adjust();
190#endif /* HAVE_CLOCK_MONOTONIC */
191
192 if (tv)
193 *tv = relative_time;
194
195 return ret;
196}
197
198/* Get absolute time stamp, but in terms of the internal timer
199 * Could be wrong, but at least won't go back.
200 */
201static void
202quagga_real_stabilised (struct timeval *tv)
203{
204 *tv = relative_time_base;
205 tv->tv_sec += relative_time.tv_sec;
206 tv->tv_usec += relative_time.tv_usec;
207 *tv = timeval_adjust (*tv);
208}
209
210/* Exported Quagga timestamp function.
211 * Modelled on POSIX clock_gettime.
212 */
213int
214quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
215{
216 switch (clkid)
217 {
218 case QUAGGA_CLK_REALTIME:
219 return quagga_gettimeofday (tv);
220 case QUAGGA_CLK_MONOTONIC:
221 return quagga_get_relative (tv);
222 case QUAGGA_CLK_REALTIME_STABILISED:
223 quagga_real_stabilised (tv);
224 return 0;
225 default:
226 errno = EINVAL;
227 return -1;
228 }
229}
230
231/* time_t value in terms of stabilised absolute time.
232 * replacement for POSIX time()
233 */
234time_t
235quagga_time (time_t *t)
236{
237 struct timeval tv;
238 quagga_real_stabilised (&tv);
239 if (t)
240 *t = tv.tv_sec;
241 return tv.tv_sec;
242}
243
244/* Public export of recent_relative_time by value */
245struct timeval
246recent_relative_time (void)
247{
248 return relative_time;
249}
David Lamparter6b0655a2014-06-04 06:53:35 +0200250
paula48b4e62005-04-22 00:43:47 +0000251static unsigned int
paule04ab742003-01-17 23:47:00 +0000252cpu_record_hash_key (struct cpu_thread_history *a)
253{
paul8cc41982005-05-06 21:25:49 +0000254 return (uintptr_t) a->func;
paule04ab742003-01-17 23:47:00 +0000255}
256
257static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100258cpu_record_hash_cmp (const struct cpu_thread_history *a,
259 const struct cpu_thread_history *b)
paule04ab742003-01-17 23:47:00 +0000260{
261 return a->func == b->func;
262}
263
paul8cc41982005-05-06 21:25:49 +0000264static void *
paule04ab742003-01-17 23:47:00 +0000265cpu_record_hash_alloc (struct cpu_thread_history *a)
266{
267 struct cpu_thread_history *new;
paul039b9572004-10-31 16:43:17 +0000268 new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
paule04ab742003-01-17 23:47:00 +0000269 new->func = a->func;
David Lamparter3493b772013-11-18 23:04:27 +0100270 new->funcname = a->funcname;
paule04ab742003-01-17 23:47:00 +0000271 return new;
272}
273
Chris Caputo228da422009-07-18 05:44:03 +0000274static void
275cpu_record_hash_free (void *a)
276{
277 struct cpu_thread_history *hist = a;
278
Chris Caputo228da422009-07-18 05:44:03 +0000279 XFREE (MTYPE_THREAD_STATS, hist);
280}
281
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100282static void
paule04ab742003-01-17 23:47:00 +0000283vty_out_cpu_thread_history(struct vty* vty,
284 struct cpu_thread_history *a)
285{
ajs8b70d0b2005-04-28 01:31:13 +0000286#ifdef HAVE_RUSAGE
287 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
288 a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
289 a->cpu.total/a->total_calls, a->cpu.max,
290 a->real.total/a->total_calls, a->real.max);
291#else
292 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld",
293 a->real.total/1000, a->real.total%1000, a->total_calls,
294 a->real.total/a->total_calls, a->real.max);
295#endif
296 vty_out(vty, " %c%c%c%c%c%c %s%s",
paule04ab742003-01-17 23:47:00 +0000297 a->types & (1 << THREAD_READ) ? 'R':' ',
298 a->types & (1 << THREAD_WRITE) ? 'W':' ',
299 a->types & (1 << THREAD_TIMER) ? 'T':' ',
300 a->types & (1 << THREAD_EVENT) ? 'E':' ',
301 a->types & (1 << THREAD_EXECUTE) ? 'X':' ',
paula48b4e62005-04-22 00:43:47 +0000302 a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
paule04ab742003-01-17 23:47:00 +0000303 a->funcname, VTY_NEWLINE);
304}
305
306static void
307cpu_record_hash_print(struct hash_backet *bucket,
308 void *args[])
309{
310 struct cpu_thread_history *totals = args[0];
311 struct vty *vty = args[1];
Paul Jakma41b23732009-06-30 16:12:49 +0100312 thread_type *filter = args[2];
paule04ab742003-01-17 23:47:00 +0000313 struct cpu_thread_history *a = bucket->data;
paula48b4e62005-04-22 00:43:47 +0000314
paule04ab742003-01-17 23:47:00 +0000315 a = bucket->data;
316 if ( !(a->types & *filter) )
317 return;
318 vty_out_cpu_thread_history(vty,a);
paule04ab742003-01-17 23:47:00 +0000319 totals->total_calls += a->total_calls;
ajs8b70d0b2005-04-28 01:31:13 +0000320 totals->real.total += a->real.total;
321 if (totals->real.max < a->real.max)
322 totals->real.max = a->real.max;
323#ifdef HAVE_RUSAGE
324 totals->cpu.total += a->cpu.total;
325 if (totals->cpu.max < a->cpu.max)
326 totals->cpu.max = a->cpu.max;
327#endif
paule04ab742003-01-17 23:47:00 +0000328}
329
330static void
Paul Jakma41b23732009-06-30 16:12:49 +0100331cpu_record_print(struct vty *vty, thread_type filter)
paule04ab742003-01-17 23:47:00 +0000332{
333 struct cpu_thread_history tmp;
334 void *args[3] = {&tmp, vty, &filter};
335
336 memset(&tmp, 0, sizeof tmp);
David Lamparter3493b772013-11-18 23:04:27 +0100337 tmp.funcname = "TOTAL";
paule04ab742003-01-17 23:47:00 +0000338 tmp.types = filter;
339
ajs8b70d0b2005-04-28 01:31:13 +0000340#ifdef HAVE_RUSAGE
341 vty_out(vty, "%21s %18s %18s%s",
342 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE);
343#endif
344 vty_out(vty, "Runtime(ms) Invoked Avg uSec Max uSecs");
345#ifdef HAVE_RUSAGE
346 vty_out(vty, " Avg uSec Max uSecs");
347#endif
348 vty_out(vty, " Type Thread%s", VTY_NEWLINE);
paule04ab742003-01-17 23:47:00 +0000349 hash_iterate(cpu_record,
350 (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
351 args);
352
353 if (tmp.total_calls > 0)
354 vty_out_cpu_thread_history(vty, &tmp);
355}
356
357DEFUN(show_thread_cpu,
358 show_thread_cpu_cmd,
359 "show thread cpu [FILTER]",
360 SHOW_STR
361 "Thread information\n"
362 "Thread CPU usage\n"
paula48b4e62005-04-22 00:43:47 +0000363 "Display filter (rwtexb)\n")
paule04ab742003-01-17 23:47:00 +0000364{
365 int i = 0;
Paul Jakma41b23732009-06-30 16:12:49 +0100366 thread_type filter = (thread_type) -1U;
paule04ab742003-01-17 23:47:00 +0000367
368 if (argc > 0)
369 {
370 filter = 0;
371 while (argv[0][i] != '\0')
372 {
373 switch ( argv[0][i] )
374 {
375 case 'r':
376 case 'R':
377 filter |= (1 << THREAD_READ);
378 break;
379 case 'w':
380 case 'W':
381 filter |= (1 << THREAD_WRITE);
382 break;
383 case 't':
384 case 'T':
385 filter |= (1 << THREAD_TIMER);
386 break;
387 case 'e':
388 case 'E':
389 filter |= (1 << THREAD_EVENT);
390 break;
391 case 'x':
392 case 'X':
393 filter |= (1 << THREAD_EXECUTE);
394 break;
paula48b4e62005-04-22 00:43:47 +0000395 case 'b':
396 case 'B':
397 filter |= (1 << THREAD_BACKGROUND);
398 break;
paule04ab742003-01-17 23:47:00 +0000399 default:
400 break;
401 }
402 ++i;
403 }
404 if (filter == 0)
405 {
paula48b4e62005-04-22 00:43:47 +0000406 vty_out(vty, "Invalid filter \"%s\" specified,"
407 " must contain at least one of 'RWTEXB'%s",
paule04ab742003-01-17 23:47:00 +0000408 argv[0], VTY_NEWLINE);
409 return CMD_WARNING;
410 }
411 }
412
413 cpu_record_print(vty, filter);
414 return CMD_SUCCESS;
415}
Paul Jakmae276eb82010-01-09 16:15:00 +0000416
417static void
418cpu_record_hash_clear (struct hash_backet *bucket,
419 void *args)
420{
421 thread_type *filter = args;
422 struct cpu_thread_history *a = bucket->data;
423
424 a = bucket->data;
425 if ( !(a->types & *filter) )
426 return;
427
428 hash_release (cpu_record, bucket->data);
429}
430
431static void
432cpu_record_clear (thread_type filter)
433{
434 thread_type *tmp = &filter;
435 hash_iterate (cpu_record,
436 (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
437 tmp);
438}
439
440DEFUN(clear_thread_cpu,
441 clear_thread_cpu_cmd,
442 "clear thread cpu [FILTER]",
443 "Clear stored data\n"
444 "Thread information\n"
445 "Thread CPU usage\n"
446 "Display filter (rwtexb)\n")
447{
448 int i = 0;
449 thread_type filter = (thread_type) -1U;
450
451 if (argc > 0)
452 {
453 filter = 0;
454 while (argv[0][i] != '\0')
455 {
456 switch ( argv[0][i] )
457 {
458 case 'r':
459 case 'R':
460 filter |= (1 << THREAD_READ);
461 break;
462 case 'w':
463 case 'W':
464 filter |= (1 << THREAD_WRITE);
465 break;
466 case 't':
467 case 'T':
468 filter |= (1 << THREAD_TIMER);
469 break;
470 case 'e':
471 case 'E':
472 filter |= (1 << THREAD_EVENT);
473 break;
474 case 'x':
475 case 'X':
476 filter |= (1 << THREAD_EXECUTE);
477 break;
478 case 'b':
479 case 'B':
480 filter |= (1 << THREAD_BACKGROUND);
481 break;
482 default:
483 break;
484 }
485 ++i;
486 }
487 if (filter == 0)
488 {
489 vty_out(vty, "Invalid filter \"%s\" specified,"
490 " must contain at least one of 'RWTEXB'%s",
491 argv[0], VTY_NEWLINE);
492 return CMD_WARNING;
493 }
494 }
495
496 cpu_record_clear (filter);
497 return CMD_SUCCESS;
498}
David Lamparter6b0655a2014-06-04 06:53:35 +0200499
Christian Franke4becea72013-11-19 14:11:42 +0000500static int
501thread_timer_cmp(void *a, void *b)
502{
503 struct thread *thread_a = a;
504 struct thread *thread_b = b;
505
506 long cmp = timeval_cmp(thread_a->u.sands, thread_b->u.sands);
507
508 if (cmp < 0)
509 return -1;
510 if (cmp > 0)
511 return 1;
512 return 0;
513}
514
515static void
516thread_timer_update(void *node, int actual_position)
517{
518 struct thread *thread = node;
519
520 thread->index = actual_position;
521}
522
paul718e3742002-12-13 20:15:29 +0000523/* Allocate new thread master. */
524struct thread_master *
525thread_master_create ()
526{
Christian Franke4becea72013-11-19 14:11:42 +0000527 struct thread_master *rv;
Denil Vira4ab273b2016-03-04 15:28:54 -0500528 struct rlimit limit;
529
530 getrlimit(RLIMIT_NOFILE, &limit);
Christian Franke4becea72013-11-19 14:11:42 +0000531
paule04ab742003-01-17 23:47:00 +0000532 if (cpu_record == NULL)
paul8cc41982005-05-06 21:25:49 +0000533 cpu_record
Stephen Hemminger90645f52013-01-04 22:29:21 +0000534 = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
535 (int (*) (const void *, const void *))cpu_record_hash_cmp);
Christian Franke4becea72013-11-19 14:11:42 +0000536
537 rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master));
Denil Vira4ab273b2016-03-04 15:28:54 -0500538 if (rv == NULL)
539 {
540 return NULL;
541 }
542
543 rv->fd_limit = (int)limit.rlim_cur;
544 rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit);
545 if (rv->read == NULL)
546 {
547 XFREE (MTYPE_THREAD_MASTER, rv);
548 return NULL;
549 }
550
551 rv->write = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit);
552 if (rv->write == NULL)
553 {
554 XFREE (MTYPE_THREAD, rv->read);
555 XFREE (MTYPE_THREAD_MASTER, rv);
556 return NULL;
557 }
Christian Franke4becea72013-11-19 14:11:42 +0000558
559 /* Initialize the timer queues */
560 rv->timer = pqueue_create();
561 rv->background = pqueue_create();
562 rv->timer->cmp = rv->background->cmp = thread_timer_cmp;
563 rv->timer->update = rv->background->update = thread_timer_update;
564
565 return rv;
paul718e3742002-12-13 20:15:29 +0000566}
567
568/* Add a new thread to the list. */
569static void
570thread_list_add (struct thread_list *list, struct thread *thread)
571{
572 thread->next = NULL;
573 thread->prev = list->tail;
574 if (list->tail)
575 list->tail->next = thread;
576 else
577 list->head = thread;
578 list->tail = thread;
579 list->count++;
580}
581
paul718e3742002-12-13 20:15:29 +0000582/* Delete a thread from the list. */
583static struct thread *
584thread_list_delete (struct thread_list *list, struct thread *thread)
585{
586 if (thread->next)
587 thread->next->prev = thread->prev;
588 else
589 list->tail = thread->prev;
590 if (thread->prev)
591 thread->prev->next = thread->next;
592 else
593 list->head = thread->next;
594 thread->next = thread->prev = NULL;
595 list->count--;
596 return thread;
597}
598
Denil Vira4ab273b2016-03-04 15:28:54 -0500599static void
600thread_delete_fd (struct thread **thread_array, struct thread *thread)
601{
602 thread_array[thread->u.fd] = NULL;
603}
604
605static void
606thread_add_fd (struct thread **thread_array, struct thread *thread)
607{
608 thread_array[thread->u.fd] = thread;
609}
610
paul718e3742002-12-13 20:15:29 +0000611/* Move thread to unuse list. */
612static void
613thread_add_unuse (struct thread_master *m, struct thread *thread)
614{
paula48b4e62005-04-22 00:43:47 +0000615 assert (m != NULL && thread != NULL);
paul718e3742002-12-13 20:15:29 +0000616 assert (thread->next == NULL);
617 assert (thread->prev == NULL);
618 assert (thread->type == THREAD_UNUSED);
619 thread_list_add (&m->unuse, thread);
620}
621
622/* Free all unused thread. */
623static void
624thread_list_free (struct thread_master *m, struct thread_list *list)
625{
626 struct thread *t;
627 struct thread *next;
628
629 for (t = list->head; t; t = next)
630 {
631 next = t->next;
632 XFREE (MTYPE_THREAD, t);
633 list->count--;
634 m->alloc--;
635 }
636}
637
Christian Franke4becea72013-11-19 14:11:42 +0000638static void
Denil Vira4ab273b2016-03-04 15:28:54 -0500639thread_array_free (struct thread_master *m, struct thread **thread_array)
640{
641 struct thread *t;
642 int index;
643
644 for (index = 0; index < m->fd_limit; ++index)
645 {
646 t = thread_array[index];
647 if (t)
648 {
649 thread_array[index] = NULL;
650 XFREE (MTYPE_THREAD, t);
651 m->alloc--;
652 }
653 }
654 XFREE (MTYPE_THREAD, thread_array);
655}
656
657static void
Christian Franke4becea72013-11-19 14:11:42 +0000658thread_queue_free (struct thread_master *m, struct pqueue *queue)
659{
660 int i;
661
662 for (i = 0; i < queue->size; i++)
663 XFREE(MTYPE_THREAD, queue->array[i]);
664
665 m->alloc -= queue->size;
666 pqueue_delete(queue);
667}
668
paul718e3742002-12-13 20:15:29 +0000669/* Stop thread scheduler. */
670void
671thread_master_free (struct thread_master *m)
672{
Denil Vira4ab273b2016-03-04 15:28:54 -0500673 thread_array_free (m, m->read);
674 thread_array_free (m, m->write);
Christian Franke4becea72013-11-19 14:11:42 +0000675 thread_queue_free (m, m->timer);
paul718e3742002-12-13 20:15:29 +0000676 thread_list_free (m, &m->event);
677 thread_list_free (m, &m->ready);
678 thread_list_free (m, &m->unuse);
Christian Franke4becea72013-11-19 14:11:42 +0000679 thread_queue_free (m, m->background);
paula48b4e62005-04-22 00:43:47 +0000680
paul718e3742002-12-13 20:15:29 +0000681 XFREE (MTYPE_THREAD_MASTER, m);
Chris Caputo228da422009-07-18 05:44:03 +0000682
683 if (cpu_record)
684 {
685 hash_clean (cpu_record, cpu_record_hash_free);
686 hash_free (cpu_record);
687 cpu_record = NULL;
688 }
paul718e3742002-12-13 20:15:29 +0000689}
690
paul8cc41982005-05-06 21:25:49 +0000691/* Thread list is empty or not. */
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100692static int
paul8cc41982005-05-06 21:25:49 +0000693thread_empty (struct thread_list *list)
694{
695 return list->head ? 0 : 1;
696}
697
paul718e3742002-12-13 20:15:29 +0000698/* Delete top of the list and return it. */
699static struct thread *
700thread_trim_head (struct thread_list *list)
701{
paul8cc41982005-05-06 21:25:49 +0000702 if (!thread_empty (list))
paul718e3742002-12-13 20:15:29 +0000703 return thread_list_delete (list, list->head);
704 return NULL;
705}
706
paul718e3742002-12-13 20:15:29 +0000707/* Return remain time in second. */
708unsigned long
709thread_timer_remain_second (struct thread *thread)
710{
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000711 quagga_get_relative (NULL);
712
713 if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
714 return thread->u.sands.tv_sec - relative_time.tv_sec;
paul718e3742002-12-13 20:15:29 +0000715 else
716 return 0;
717}
718
Christian Franke76fbc642015-11-10 18:04:41 +0100719struct timeval
720thread_timer_remain(struct thread *thread)
721{
722 quagga_get_relative(NULL);
723
724 return timeval_subtract(thread->u.sands, relative_time);
725}
726
David Lamparter3493b772013-11-18 23:04:27 +0100727#define debugargdef const char *funcname, const char *schedfrom, int fromln
728#define debugargpass funcname, schedfrom, fromln
paule04ab742003-01-17 23:47:00 +0000729
paul718e3742002-12-13 20:15:29 +0000730/* Get new thread. */
731static struct thread *
732thread_get (struct thread_master *m, u_char type,
David Lamparter3493b772013-11-18 23:04:27 +0100733 int (*func) (struct thread *), void *arg, debugargdef)
paul718e3742002-12-13 20:15:29 +0000734{
Jorge Boncompte [DTI2]64018322012-05-07 16:53:13 +0000735 struct thread *thread = thread_trim_head (&m->unuse);
paul718e3742002-12-13 20:15:29 +0000736
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000737 if (! thread)
paul718e3742002-12-13 20:15:29 +0000738 {
739 thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
740 m->alloc++;
741 }
742 thread->type = type;
paule04ab742003-01-17 23:47:00 +0000743 thread->add_type = type;
paul718e3742002-12-13 20:15:29 +0000744 thread->master = m;
745 thread->func = func;
746 thread->arg = arg;
Christian Franke4becea72013-11-19 14:11:42 +0000747 thread->index = -1;
748
David Lamparter3493b772013-11-18 23:04:27 +0100749 thread->funcname = funcname;
750 thread->schedfrom = schedfrom;
751 thread->schedfrom_line = fromln;
paule04ab742003-01-17 23:47:00 +0000752
paul718e3742002-12-13 20:15:29 +0000753 return thread;
754}
755
Donald Sharp19be18a2016-03-04 15:28:55 -0500756#define fd_copy_fd_set(X) (X)
757
758static int
759fd_select (int size, thread_fd_set *read, thread_fd_set *write, thread_fd_set *except, struct timeval *t)
760{
761 return(select(size, read, write, except, t));
762}
763
764static int
765fd_is_set (int fd, thread_fd_set *fdset)
766{
767 return FD_ISSET (fd, fdset);
768}
769
770static int
Donald Sharp19be18a2016-03-04 15:28:55 -0500771fd_clear_read_write (int fd, thread_fd_set *fdset)
772{
773 if (!FD_ISSET (fd, fdset))
774 return 0;
775
776 FD_CLR (fd, fdset);
777 return 1;
778}
779
Donald Sharpe0b83242016-03-04 15:28:56 -0500780static struct thread *
781funcname_thread_add_read_write (int dir, struct thread_master *m,
782 int (*func) (struct thread *), void *arg, int fd,
783 debugargdef)
784{
785 struct thread *thread = NULL;
786 thread_fd_set *fdset = NULL;
787
788 if (dir == THREAD_READ)
789 fdset = &m->readfd;
790 else
791 fdset = &m->writefd;
792
Donald Sharp1ad00b02016-07-13 11:02:38 -0400793 if (FD_ISSET (fd, fdset))
Donald Sharpe0b83242016-03-04 15:28:56 -0500794 {
795 zlog (NULL, LOG_WARNING, "There is already %s fd [%d]",
796 (dir = THREAD_READ) ? "read" : "write", fd);
797 return NULL;
798 }
799
800 FD_SET (fd, fdset);
801
802 thread = thread_get (m, dir, func, arg, debugargpass);
803 thread->u.fd = fd;
804 if (dir == THREAD_READ)
805 thread_add_fd (m->read, thread);
806 else
807 thread_add_fd (m->write, thread);
808
809 return thread;
810}
811
paul718e3742002-12-13 20:15:29 +0000812/* Add new read thread. */
813struct thread *
paule04ab742003-01-17 23:47:00 +0000814funcname_thread_add_read (struct thread_master *m,
David Lamparter3493b772013-11-18 23:04:27 +0100815 int (*func) (struct thread *), void *arg, int fd,
816 debugargdef)
paul718e3742002-12-13 20:15:29 +0000817{
Donald Sharpe0b83242016-03-04 15:28:56 -0500818 return funcname_thread_add_read_write (THREAD_READ, m, func,
819 arg, fd, debugargpass);
paul718e3742002-12-13 20:15:29 +0000820}
821
822/* Add new write thread. */
823struct thread *
paule04ab742003-01-17 23:47:00 +0000824funcname_thread_add_write (struct thread_master *m,
David Lamparter3493b772013-11-18 23:04:27 +0100825 int (*func) (struct thread *), void *arg, int fd,
826 debugargdef)
paul718e3742002-12-13 20:15:29 +0000827{
Donald Sharpe0b83242016-03-04 15:28:56 -0500828 return funcname_thread_add_read_write (THREAD_WRITE, m, func,
829 arg, fd, debugargpass);
paul718e3742002-12-13 20:15:29 +0000830}
831
paul98c91ac2004-10-05 14:57:50 +0000832static struct thread *
833funcname_thread_add_timer_timeval (struct thread_master *m,
834 int (*func) (struct thread *),
paula48b4e62005-04-22 00:43:47 +0000835 int type,
paul98c91ac2004-10-05 14:57:50 +0000836 void *arg,
David Lamparter3493b772013-11-18 23:04:27 +0100837 struct timeval *time_relative,
838 debugargdef)
paul718e3742002-12-13 20:15:29 +0000839{
paul718e3742002-12-13 20:15:29 +0000840 struct thread *thread;
Christian Franke4becea72013-11-19 14:11:42 +0000841 struct pqueue *queue;
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000842 struct timeval alarm_time;
paul718e3742002-12-13 20:15:29 +0000843
844 assert (m != NULL);
845
ajs8b70d0b2005-04-28 01:31:13 +0000846 assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
paula48b4e62005-04-22 00:43:47 +0000847 assert (time_relative);
848
Christian Franke4becea72013-11-19 14:11:42 +0000849 queue = ((type == THREAD_TIMER) ? m->timer : m->background);
David Lamparter3493b772013-11-18 23:04:27 +0100850 thread = thread_get (m, type, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000851
852 /* Do we need jitter here? */
Joakim Tjernlundb8192762008-11-10 09:33:30 +0100853 quagga_get_relative (NULL);
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000854 alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
855 alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
ajs8b70d0b2005-04-28 01:31:13 +0000856 thread->u.sands = timeval_adjust(alarm_time);
paul718e3742002-12-13 20:15:29 +0000857
Christian Franke4becea72013-11-19 14:11:42 +0000858 pqueue_enqueue(thread, queue);
paul718e3742002-12-13 20:15:29 +0000859 return thread;
860}
861
paul98c91ac2004-10-05 14:57:50 +0000862
863/* Add timer event thread. */
jardin9e867fe2003-12-23 08:56:18 +0000864struct thread *
paul98c91ac2004-10-05 14:57:50 +0000865funcname_thread_add_timer (struct thread_master *m,
866 int (*func) (struct thread *),
David Lamparter3493b772013-11-18 23:04:27 +0100867 void *arg, long timer,
868 debugargdef)
jardin9e867fe2003-12-23 08:56:18 +0000869{
paul98c91ac2004-10-05 14:57:50 +0000870 struct timeval trel;
jardin9e867fe2003-12-23 08:56:18 +0000871
872 assert (m != NULL);
873
paul9076fbd2004-10-11 09:40:58 +0000874 trel.tv_sec = timer;
paul98c91ac2004-10-05 14:57:50 +0000875 trel.tv_usec = 0;
876
paula48b4e62005-04-22 00:43:47 +0000877 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
David Lamparter3493b772013-11-18 23:04:27 +0100878 &trel, debugargpass);
paul98c91ac2004-10-05 14:57:50 +0000879}
880
881/* Add timer event thread with "millisecond" resolution */
882struct thread *
883funcname_thread_add_timer_msec (struct thread_master *m,
884 int (*func) (struct thread *),
David Lamparter3493b772013-11-18 23:04:27 +0100885 void *arg, long timer,
886 debugargdef)
paul98c91ac2004-10-05 14:57:50 +0000887{
888 struct timeval trel;
889
890 assert (m != NULL);
jardin9e867fe2003-12-23 08:56:18 +0000891
ajsaf04bd72004-12-28 17:00:12 +0000892 trel.tv_sec = timer / 1000;
893 trel.tv_usec = 1000*(timer % 1000);
jardin9e867fe2003-12-23 08:56:18 +0000894
paula48b4e62005-04-22 00:43:47 +0000895 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
David Lamparter3493b772013-11-18 23:04:27 +0100896 arg, &trel, debugargpass);
paula48b4e62005-04-22 00:43:47 +0000897}
898
David Lamparter47fb0a82016-06-13 17:29:13 +0200899/* Add timer event thread with "millisecond" resolution */
900struct thread *
901funcname_thread_add_timer_tv (struct thread_master *m,
902 int (*func) (struct thread *),
903 void *arg, struct timeval *tv,
904 debugargdef)
905{
906 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
907 arg, tv, debugargpass);
908}
909
paula48b4e62005-04-22 00:43:47 +0000910/* Add a background thread, with an optional millisec delay */
911struct thread *
912funcname_thread_add_background (struct thread_master *m,
913 int (*func) (struct thread *),
David Lamparter3493b772013-11-18 23:04:27 +0100914 void *arg, long delay,
915 debugargdef)
paula48b4e62005-04-22 00:43:47 +0000916{
917 struct timeval trel;
918
919 assert (m != NULL);
920
921 if (delay)
922 {
923 trel.tv_sec = delay / 1000;
924 trel.tv_usec = 1000*(delay % 1000);
925 }
926 else
927 {
928 trel.tv_sec = 0;
929 trel.tv_usec = 0;
930 }
931
932 return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
David Lamparter3493b772013-11-18 23:04:27 +0100933 arg, &trel, debugargpass);
jardin9e867fe2003-12-23 08:56:18 +0000934}
935
paul718e3742002-12-13 20:15:29 +0000936/* Add simple event thread. */
937struct thread *
paule04ab742003-01-17 23:47:00 +0000938funcname_thread_add_event (struct thread_master *m,
David Lamparter3493b772013-11-18 23:04:27 +0100939 int (*func) (struct thread *), void *arg, int val,
940 debugargdef)
paul718e3742002-12-13 20:15:29 +0000941{
942 struct thread *thread;
943
944 assert (m != NULL);
945
David Lamparter3493b772013-11-18 23:04:27 +0100946 thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000947 thread->u.val = val;
948 thread_list_add (&m->event, thread);
949
950 return thread;
951}
952
953/* Cancel thread from scheduler. */
954void
955thread_cancel (struct thread *thread)
956{
Christian Franke4becea72013-11-19 14:11:42 +0000957 struct thread_list *list = NULL;
958 struct pqueue *queue = NULL;
Denil Vira4ab273b2016-03-04 15:28:54 -0500959 struct thread **thread_array = NULL;
paula48b4e62005-04-22 00:43:47 +0000960
paul718e3742002-12-13 20:15:29 +0000961 switch (thread->type)
962 {
963 case THREAD_READ:
Donald Sharp19be18a2016-03-04 15:28:55 -0500964 assert (fd_clear_read_write (thread->u.fd, &thread->master->readfd));
Denil Vira4ab273b2016-03-04 15:28:54 -0500965 thread_array = thread->master->read;
paul718e3742002-12-13 20:15:29 +0000966 break;
967 case THREAD_WRITE:
Donald Sharp19be18a2016-03-04 15:28:55 -0500968 assert (fd_clear_read_write (thread->u.fd, &thread->master->writefd));
Denil Vira4ab273b2016-03-04 15:28:54 -0500969 thread_array = thread->master->write;
paul718e3742002-12-13 20:15:29 +0000970 break;
971 case THREAD_TIMER:
Christian Franke4becea72013-11-19 14:11:42 +0000972 queue = thread->master->timer;
paul718e3742002-12-13 20:15:29 +0000973 break;
974 case THREAD_EVENT:
paula48b4e62005-04-22 00:43:47 +0000975 list = &thread->master->event;
paul718e3742002-12-13 20:15:29 +0000976 break;
977 case THREAD_READY:
paula48b4e62005-04-22 00:43:47 +0000978 list = &thread->master->ready;
paul718e3742002-12-13 20:15:29 +0000979 break;
paula48b4e62005-04-22 00:43:47 +0000980 case THREAD_BACKGROUND:
Christian Franke4becea72013-11-19 14:11:42 +0000981 queue = thread->master->background;
ajs8b70d0b2005-04-28 01:31:13 +0000982 break;
paul718e3742002-12-13 20:15:29 +0000983 default:
paula48b4e62005-04-22 00:43:47 +0000984 return;
paul718e3742002-12-13 20:15:29 +0000985 break;
986 }
Christian Franke4becea72013-11-19 14:11:42 +0000987
988 if (queue)
989 {
990 assert(thread->index >= 0);
991 assert(thread == queue->array[thread->index]);
992 pqueue_remove_at(thread->index, queue);
993 }
994 else if (list)
995 {
996 thread_list_delete (list, thread);
997 }
Denil Vira4ab273b2016-03-04 15:28:54 -0500998 else if (thread_array)
999 {
1000 thread_delete_fd (thread_array, thread);
1001 }
Christian Franke4becea72013-11-19 14:11:42 +00001002 else
1003 {
Denil Vira4ab273b2016-03-04 15:28:54 -05001004 assert(!"Thread should be either in queue or list or array!");
Christian Franke4becea72013-11-19 14:11:42 +00001005 }
1006
paul718e3742002-12-13 20:15:29 +00001007 thread->type = THREAD_UNUSED;
1008 thread_add_unuse (thread->master, thread);
1009}
1010
1011/* Delete all events which has argument value arg. */
pauldc818072005-05-19 01:30:53 +00001012unsigned int
paul718e3742002-12-13 20:15:29 +00001013thread_cancel_event (struct thread_master *m, void *arg)
1014{
pauldc818072005-05-19 01:30:53 +00001015 unsigned int ret = 0;
paul718e3742002-12-13 20:15:29 +00001016 struct thread *thread;
1017
1018 thread = m->event.head;
1019 while (thread)
1020 {
1021 struct thread *t;
1022
1023 t = thread;
1024 thread = t->next;
1025
1026 if (t->arg == arg)
paula48b4e62005-04-22 00:43:47 +00001027 {
pauldc818072005-05-19 01:30:53 +00001028 ret++;
paula48b4e62005-04-22 00:43:47 +00001029 thread_list_delete (&m->event, t);
1030 t->type = THREAD_UNUSED;
1031 thread_add_unuse (m, t);
1032 }
paul718e3742002-12-13 20:15:29 +00001033 }
Jorge Boncompte [DTI2]1b79fcb2012-05-07 15:17:31 +00001034
1035 /* thread can be on the ready list too */
1036 thread = m->ready.head;
1037 while (thread)
1038 {
1039 struct thread *t;
1040
1041 t = thread;
1042 thread = t->next;
1043
1044 if (t->arg == arg)
1045 {
1046 ret++;
1047 thread_list_delete (&m->ready, t);
1048 t->type = THREAD_UNUSED;
1049 thread_add_unuse (m, t);
1050 }
1051 }
pauldc818072005-05-19 01:30:53 +00001052 return ret;
paul718e3742002-12-13 20:15:29 +00001053}
1054
paula48b4e62005-04-22 00:43:47 +00001055static struct timeval *
Christian Franke4becea72013-11-19 14:11:42 +00001056thread_timer_wait (struct pqueue *queue, struct timeval *timer_val)
paul718e3742002-12-13 20:15:29 +00001057{
Christian Franke4becea72013-11-19 14:11:42 +00001058 if (queue->size)
paul718e3742002-12-13 20:15:29 +00001059 {
Christian Franke4becea72013-11-19 14:11:42 +00001060 struct thread *next_timer = queue->array[0];
1061 *timer_val = timeval_subtract (next_timer->u.sands, relative_time);
paul718e3742002-12-13 20:15:29 +00001062 return timer_val;
1063 }
1064 return NULL;
1065}
paul718e3742002-12-13 20:15:29 +00001066
paul8cc41982005-05-06 21:25:49 +00001067static struct thread *
paul718e3742002-12-13 20:15:29 +00001068thread_run (struct thread_master *m, struct thread *thread,
1069 struct thread *fetch)
1070{
1071 *fetch = *thread;
1072 thread->type = THREAD_UNUSED;
1073 thread_add_unuse (m, thread);
1074 return fetch;
1075}
1076
paula48b4e62005-04-22 00:43:47 +00001077static int
Donald Sharp54406ac2016-03-04 15:28:57 -05001078thread_process_fds_helper (struct thread_master *m, struct thread *thread, thread_fd_set *fdset)
paul718e3742002-12-13 20:15:29 +00001079{
Donald Sharp54406ac2016-03-04 15:28:57 -05001080 thread_fd_set *mfdset = NULL;
1081 struct thread **thread_array;
1082
1083 if (!thread)
1084 return 0;
1085
1086 if (thread->type == THREAD_READ)
1087 {
1088 mfdset = &m->readfd;
1089 thread_array = m->read;
1090 }
1091 else
1092 {
1093 mfdset = &m->writefd;
1094 thread_array = m->write;
1095 }
1096
1097 if (fd_is_set (THREAD_FD (thread), fdset))
1098 {
1099 fd_clear_read_write (THREAD_FD (thread), mfdset);
1100 thread_delete_fd (thread_array, thread);
1101 thread_list_add (&m->ready, thread);
1102 thread->type = THREAD_READY;
1103 return 1;
1104 }
1105 return 0;
1106}
1107
1108static int
1109thread_process_fds (struct thread_master *m, thread_fd_set *rset, thread_fd_set *wset, int num)
1110{
Denil Vira4ab273b2016-03-04 15:28:54 -05001111 int ready = 0, index;
paul718e3742002-12-13 20:15:29 +00001112
Donald Sharp54406ac2016-03-04 15:28:57 -05001113 for (index = 0; index < m->fd_limit && ready < num; ++index)
Denil Vira4ab273b2016-03-04 15:28:54 -05001114 {
Donald Sharp54406ac2016-03-04 15:28:57 -05001115 ready += thread_process_fds_helper (m, m->read[index], rset);
1116 ready += thread_process_fds_helper (m, m->write[index], wset);
paul718e3742002-12-13 20:15:29 +00001117 }
Denil Vira4ab273b2016-03-04 15:28:54 -05001118 return num - ready;
paul718e3742002-12-13 20:15:29 +00001119}
1120
ajs8b70d0b2005-04-28 01:31:13 +00001121/* Add all timers that have popped to the ready list. */
paula48b4e62005-04-22 00:43:47 +00001122static unsigned int
Christian Franke4becea72013-11-19 14:11:42 +00001123thread_timer_process (struct pqueue *queue, struct timeval *timenow)
paula48b4e62005-04-22 00:43:47 +00001124{
1125 struct thread *thread;
1126 unsigned int ready = 0;
1127
Christian Franke4becea72013-11-19 14:11:42 +00001128 while (queue->size)
ajs8b70d0b2005-04-28 01:31:13 +00001129 {
Christian Franke4becea72013-11-19 14:11:42 +00001130 thread = queue->array[0];
ajs8b70d0b2005-04-28 01:31:13 +00001131 if (timeval_cmp (*timenow, thread->u.sands) < 0)
1132 return ready;
Christian Franke4becea72013-11-19 14:11:42 +00001133 pqueue_dequeue(queue);
ajs8b70d0b2005-04-28 01:31:13 +00001134 thread->type = THREAD_READY;
1135 thread_list_add (&thread->master->ready, thread);
1136 ready++;
1137 }
paula48b4e62005-04-22 00:43:47 +00001138 return ready;
1139}
1140
Paul Jakma2613abe2010-01-11 16:33:07 +00001141/* process a list en masse, e.g. for event thread lists */
1142static unsigned int
1143thread_process (struct thread_list *list)
1144{
1145 struct thread *thread;
Paul Jakmab5043aa2012-02-28 18:32:56 +00001146 struct thread *next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001147 unsigned int ready = 0;
1148
Paul Jakmab5043aa2012-02-28 18:32:56 +00001149 for (thread = list->head; thread; thread = next)
Paul Jakma2613abe2010-01-11 16:33:07 +00001150 {
Paul Jakmab5043aa2012-02-28 18:32:56 +00001151 next = thread->next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001152 thread_list_delete (list, thread);
1153 thread->type = THREAD_READY;
1154 thread_list_add (&thread->master->ready, thread);
1155 ready++;
1156 }
1157 return ready;
1158}
1159
1160
paul718e3742002-12-13 20:15:29 +00001161/* Fetch next ready thread. */
1162struct thread *
1163thread_fetch (struct thread_master *m, struct thread *fetch)
1164{
paul718e3742002-12-13 20:15:29 +00001165 struct thread *thread;
Donald Sharp19be18a2016-03-04 15:28:55 -05001166 thread_fd_set readfd;
1167 thread_fd_set writefd;
1168 thread_fd_set exceptfd;
Paul Jakma2613abe2010-01-11 16:33:07 +00001169 struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
paula48b4e62005-04-22 00:43:47 +00001170 struct timeval timer_val_bg;
Paul Jakma2613abe2010-01-11 16:33:07 +00001171 struct timeval *timer_wait = &timer_val;
paula48b4e62005-04-22 00:43:47 +00001172 struct timeval *timer_wait_bg;
paul718e3742002-12-13 20:15:29 +00001173
1174 while (1)
1175 {
paula48b4e62005-04-22 00:43:47 +00001176 int num = 0;
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001177#if defined HAVE_SNMP && defined SNMP_AGENTX
1178 struct timeval snmp_timer_wait;
1179 int snmpblock = 0;
1180 int fdsetsize;
1181#endif
paula48b4e62005-04-22 00:43:47 +00001182
Paul Jakma2613abe2010-01-11 16:33:07 +00001183 /* Signals pre-empt everything */
paul05c447d2004-07-22 19:14:27 +00001184 quagga_sigevent_process ();
1185
Paul Jakma2613abe2010-01-11 16:33:07 +00001186 /* Drain the ready queue of already scheduled jobs, before scheduling
1187 * more.
paula48b4e62005-04-22 00:43:47 +00001188 */
paul718e3742002-12-13 20:15:29 +00001189 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001190 return thread_run (m, thread, fetch);
paula48b4e62005-04-22 00:43:47 +00001191
Paul Jakma2613abe2010-01-11 16:33:07 +00001192 /* To be fair to all kinds of threads, and avoid starvation, we
1193 * need to be careful to consider all thread types for scheduling
1194 * in each quanta. I.e. we should not return early from here on.
1195 */
1196
1197 /* Normal event are the next highest priority. */
1198 thread_process (&m->event);
1199
paul718e3742002-12-13 20:15:29 +00001200 /* Structure copy. */
Donald Sharp19be18a2016-03-04 15:28:55 -05001201 readfd = fd_copy_fd_set(m->readfd);
1202 writefd = fd_copy_fd_set(m->writefd);
1203 exceptfd = fd_copy_fd_set(m->exceptfd);
paula48b4e62005-04-22 00:43:47 +00001204
1205 /* Calculate select wait timer if nothing else to do */
Paul Jakma2613abe2010-01-11 16:33:07 +00001206 if (m->ready.count == 0)
1207 {
1208 quagga_get_relative (NULL);
Christian Franke4becea72013-11-19 14:11:42 +00001209 timer_wait = thread_timer_wait (m->timer, &timer_val);
1210 timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg);
Paul Jakma2613abe2010-01-11 16:33:07 +00001211
1212 if (timer_wait_bg &&
1213 (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
1214 timer_wait = timer_wait_bg;
1215 }
paula48b4e62005-04-22 00:43:47 +00001216
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001217#if defined HAVE_SNMP && defined SNMP_AGENTX
1218 /* When SNMP is enabled, we may have to select() on additional
1219 FD. snmp_select_info() will add them to `readfd'. The trick
1220 with this function is its last argument. We need to set it to
1221 0 if timer_wait is not NULL and we need to use the provided
1222 new timer only if it is still set to 0. */
1223 if (agentx_enabled)
1224 {
1225 fdsetsize = FD_SETSIZE;
1226 snmpblock = 1;
1227 if (timer_wait)
1228 {
1229 snmpblock = 0;
1230 memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval));
1231 }
1232 snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock);
1233 if (snmpblock == 0)
1234 timer_wait = &snmp_timer_wait;
1235 }
1236#endif
Donald Sharp19be18a2016-03-04 15:28:55 -05001237 num = fd_select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
paula48b4e62005-04-22 00:43:47 +00001238
1239 /* Signals should get quick treatment */
paul718e3742002-12-13 20:15:29 +00001240 if (num < 0)
paul05c447d2004-07-22 19:14:27 +00001241 {
1242 if (errno == EINTR)
paula48b4e62005-04-22 00:43:47 +00001243 continue; /* signal received - process it */
ajs6099b3b2004-11-20 02:06:59 +00001244 zlog_warn ("select() error: %s", safe_strerror (errno));
Donald Sharp54406ac2016-03-04 15:28:57 -05001245 return NULL;
paul05c447d2004-07-22 19:14:27 +00001246 }
ajs8b70d0b2005-04-28 01:31:13 +00001247
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001248#if defined HAVE_SNMP && defined SNMP_AGENTX
1249 if (agentx_enabled)
1250 {
1251 if (num > 0)
1252 snmp_read(&readfd);
1253 else if (num == 0)
1254 {
1255 snmp_timeout();
1256 run_alarms();
1257 }
1258 netsnmp_check_outstanding_agent_requests();
1259 }
1260#endif
1261
ajs8b70d0b2005-04-28 01:31:13 +00001262 /* Check foreground timers. Historically, they have had higher
1263 priority than I/O threads, so let's push them onto the ready
1264 list in front of the I/O threads. */
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001265 quagga_get_relative (NULL);
Christian Franke4becea72013-11-19 14:11:42 +00001266 thread_timer_process (m->timer, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001267
1268 /* Got IO, process it */
1269 if (num > 0)
Donald Sharp54406ac2016-03-04 15:28:57 -05001270 thread_process_fds (m, &readfd, &writefd, num);
ajs8b70d0b2005-04-28 01:31:13 +00001271
1272#if 0
1273 /* If any threads were made ready above (I/O or foreground timer),
1274 perhaps we should avoid adding background timers to the ready
1275 list at this time. If this is code is uncommented, then background
1276 timer threads will not run unless there is nothing else to do. */
1277 if ((thread = thread_trim_head (&m->ready)) != NULL)
1278 return thread_run (m, thread, fetch);
1279#endif
1280
paula48b4e62005-04-22 00:43:47 +00001281 /* Background timer/events, lowest priority */
Christian Franke4becea72013-11-19 14:11:42 +00001282 thread_timer_process (m->background, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001283
ajs8b70d0b2005-04-28 01:31:13 +00001284 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001285 return thread_run (m, thread, fetch);
paul718e3742002-12-13 20:15:29 +00001286 }
1287}
1288
ajs924b9222005-04-16 17:11:24 +00001289unsigned long
ajs8b70d0b2005-04-28 01:31:13 +00001290thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
paul718e3742002-12-13 20:15:29 +00001291{
paul718e3742002-12-13 20:15:29 +00001292#ifdef HAVE_RUSAGE
1293 /* This is 'user + sys' time. */
ajs8b70d0b2005-04-28 01:31:13 +00001294 *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
1295 timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
paul718e3742002-12-13 20:15:29 +00001296#else
ajs8b70d0b2005-04-28 01:31:13 +00001297 *cputime = 0;
paul718e3742002-12-13 20:15:29 +00001298#endif /* HAVE_RUSAGE */
ajs8b70d0b2005-04-28 01:31:13 +00001299 return timeval_elapsed (now->real, start->real);
paul718e3742002-12-13 20:15:29 +00001300}
1301
ajs8b70d0b2005-04-28 01:31:13 +00001302/* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1303 Note: we are using real (wall clock) time for this calculation.
1304 It could be argued that CPU time may make more sense in certain
1305 contexts. The things to consider are whether the thread may have
1306 blocked (in which case wall time increases, but CPU time does not),
1307 or whether the system is heavily loaded with other processes competing
1308 for CPU time. On balance, wall clock time seems to make sense.
1309 Plus it has the added benefit that gettimeofday should be faster
1310 than calling getrusage. */
paul718e3742002-12-13 20:15:29 +00001311int
1312thread_should_yield (struct thread *thread)
1313{
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001314 quagga_get_relative (NULL);
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001315 return (timeval_elapsed(relative_time, thread->real) >
ajs8b70d0b2005-04-28 01:31:13 +00001316 THREAD_YIELD_TIME_SLOT);
paul718e3742002-12-13 20:15:29 +00001317}
1318
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001319void
1320thread_getrusage (RUSAGE_T *r)
1321{
1322 quagga_get_relative (NULL);
1323#ifdef HAVE_RUSAGE
1324 getrusage(RUSAGE_SELF, &(r->cpu));
1325#endif
1326 r->real = relative_time;
1327
1328#ifdef HAVE_CLOCK_MONOTONIC
1329 /* quagga_get_relative() only updates recent_time if gettimeofday
1330 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1331 * and guarantee to update it before threads are run...
1332 */
1333 quagga_gettimeofday(&recent_time);
1334#endif /* HAVE_CLOCK_MONOTONIC */
1335}
1336
David Lamparter615f9f12013-11-18 23:52:02 +01001337struct thread *thread_current = NULL;
1338
paul718e3742002-12-13 20:15:29 +00001339/* We check thread consumed time. If the system has getrusage, we'll
ajs8b70d0b2005-04-28 01:31:13 +00001340 use that to get in-depth stats on the performance of the thread in addition
1341 to wall clock time stats from gettimeofday. */
paul718e3742002-12-13 20:15:29 +00001342void
1343thread_call (struct thread *thread)
1344{
ajs8b70d0b2005-04-28 01:31:13 +00001345 unsigned long realtime, cputime;
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001346 RUSAGE_T before, after;
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001347
1348 /* Cache a pointer to the relevant cpu history thread, if the thread
1349 * does not have it yet.
1350 *
1351 * Callers submitting 'dummy threads' hence must take care that
1352 * thread->cpu is NULL
1353 */
1354 if (!thread->hist)
1355 {
1356 struct cpu_thread_history tmp;
1357
1358 tmp.func = thread->func;
David Lamparter3493b772013-11-18 23:04:27 +01001359 tmp.funcname = thread->funcname;
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001360
1361 thread->hist = hash_get (cpu_record, &tmp,
1362 (void * (*) (void *))cpu_record_hash_alloc);
1363 }
paul718e3742002-12-13 20:15:29 +00001364
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001365 GETRUSAGE (&before);
1366 thread->real = before.real;
paul718e3742002-12-13 20:15:29 +00001367
David Lamparter615f9f12013-11-18 23:52:02 +01001368 thread_current = thread;
paul718e3742002-12-13 20:15:29 +00001369 (*thread->func) (thread);
David Lamparter615f9f12013-11-18 23:52:02 +01001370 thread_current = NULL;
paul718e3742002-12-13 20:15:29 +00001371
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001372 GETRUSAGE (&after);
paul718e3742002-12-13 20:15:29 +00001373
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001374 realtime = thread_consumed_time (&after, &before, &cputime);
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001375 thread->hist->real.total += realtime;
1376 if (thread->hist->real.max < realtime)
1377 thread->hist->real.max = realtime;
ajs8b70d0b2005-04-28 01:31:13 +00001378#ifdef HAVE_RUSAGE
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001379 thread->hist->cpu.total += cputime;
1380 if (thread->hist->cpu.max < cputime)
1381 thread->hist->cpu.max = cputime;
ajs8b70d0b2005-04-28 01:31:13 +00001382#endif
paule04ab742003-01-17 23:47:00 +00001383
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001384 ++(thread->hist->total_calls);
1385 thread->hist->types |= (1 << thread->add_type);
paul718e3742002-12-13 20:15:29 +00001386
ajs924b9222005-04-16 17:11:24 +00001387#ifdef CONSUMED_TIME_CHECK
ajs8b70d0b2005-04-28 01:31:13 +00001388 if (realtime > CONSUMED_TIME_CHECK)
paul718e3742002-12-13 20:15:29 +00001389 {
1390 /*
1391 * We have a CPU Hog on our hands.
1392 * Whinge about it now, so we're aware this is yet another task
1393 * to fix.
1394 */
ajs8b70d0b2005-04-28 01:31:13 +00001395 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
ajs924b9222005-04-16 17:11:24 +00001396 thread->funcname,
1397 (unsigned long) thread->func,
ajs8b70d0b2005-04-28 01:31:13 +00001398 realtime/1000, cputime/1000);
paul718e3742002-12-13 20:15:29 +00001399 }
ajs924b9222005-04-16 17:11:24 +00001400#endif /* CONSUMED_TIME_CHECK */
paul718e3742002-12-13 20:15:29 +00001401}
1402
1403/* Execute thread */
1404struct thread *
paule04ab742003-01-17 23:47:00 +00001405funcname_thread_execute (struct thread_master *m,
paul718e3742002-12-13 20:15:29 +00001406 int (*func)(struct thread *),
1407 void *arg,
paule04ab742003-01-17 23:47:00 +00001408 int val,
David Lamparter3493b772013-11-18 23:04:27 +01001409 debugargdef)
paul718e3742002-12-13 20:15:29 +00001410{
1411 struct thread dummy;
1412
1413 memset (&dummy, 0, sizeof (struct thread));
1414
1415 dummy.type = THREAD_EVENT;
paule04ab742003-01-17 23:47:00 +00001416 dummy.add_type = THREAD_EXECUTE;
paul718e3742002-12-13 20:15:29 +00001417 dummy.master = NULL;
1418 dummy.func = func;
1419 dummy.arg = arg;
1420 dummy.u.val = val;
David Lamparter3493b772013-11-18 23:04:27 +01001421
1422 dummy.funcname = funcname;
1423 dummy.schedfrom = schedfrom;
1424 dummy.schedfrom_line = fromln;
1425
paul718e3742002-12-13 20:15:29 +00001426 thread_call (&dummy);
1427
paul718e3742002-12-13 20:15:29 +00001428 return NULL;
1429}