blob: 5e40261e6a7edcab1645f4f35dbf75d4314bcfe4 [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>
25
26#include "thread.h"
27#include "memory.h"
28#include "log.h"
paule04ab742003-01-17 23:47:00 +000029#include "hash.h"
Christian Franke4becea72013-11-19 14:11:42 +000030#include "pqueue.h"
paule04ab742003-01-17 23:47:00 +000031#include "command.h"
paul05c447d2004-07-22 19:14:27 +000032#include "sigevent.h"
Vincent Bernatd6be5fb2012-05-24 09:44:43 +020033
34#if defined HAVE_SNMP && defined SNMP_AGENTX
35#include <net-snmp/net-snmp-config.h>
36#include <net-snmp/net-snmp-includes.h>
37#include <net-snmp/agent/net-snmp-agent-includes.h>
38#include <net-snmp/agent/snmp_vars.h>
39
40extern int agentx_enabled;
41#endif
42
Hasso Tepper3b96b782012-10-11 11:31:54 +000043#if defined(__APPLE__)
44#include <mach/mach.h>
45#include <mach/mach_time.h>
46#endif
47
David Lamparter6b0655a2014-06-04 06:53:35 +020048
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;
528
paule04ab742003-01-17 23:47:00 +0000529 if (cpu_record == NULL)
paul8cc41982005-05-06 21:25:49 +0000530 cpu_record
Stephen Hemminger90645f52013-01-04 22:29:21 +0000531 = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
532 (int (*) (const void *, const void *))cpu_record_hash_cmp);
Christian Franke4becea72013-11-19 14:11:42 +0000533
534 rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master));
535
536 /* Initialize the timer queues */
537 rv->timer = pqueue_create();
538 rv->background = pqueue_create();
539 rv->timer->cmp = rv->background->cmp = thread_timer_cmp;
540 rv->timer->update = rv->background->update = thread_timer_update;
541
542 return rv;
paul718e3742002-12-13 20:15:29 +0000543}
544
545/* Add a new thread to the list. */
546static void
547thread_list_add (struct thread_list *list, struct thread *thread)
548{
549 thread->next = NULL;
550 thread->prev = list->tail;
551 if (list->tail)
552 list->tail->next = thread;
553 else
554 list->head = thread;
555 list->tail = thread;
556 list->count++;
557}
558
paul718e3742002-12-13 20:15:29 +0000559/* Delete a thread from the list. */
560static struct thread *
561thread_list_delete (struct thread_list *list, struct thread *thread)
562{
563 if (thread->next)
564 thread->next->prev = thread->prev;
565 else
566 list->tail = thread->prev;
567 if (thread->prev)
568 thread->prev->next = thread->next;
569 else
570 list->head = thread->next;
571 thread->next = thread->prev = NULL;
572 list->count--;
573 return thread;
574}
575
576/* Move thread to unuse list. */
577static void
578thread_add_unuse (struct thread_master *m, struct thread *thread)
579{
paula48b4e62005-04-22 00:43:47 +0000580 assert (m != NULL && thread != NULL);
paul718e3742002-12-13 20:15:29 +0000581 assert (thread->next == NULL);
582 assert (thread->prev == NULL);
583 assert (thread->type == THREAD_UNUSED);
584 thread_list_add (&m->unuse, thread);
585}
586
587/* Free all unused thread. */
588static void
589thread_list_free (struct thread_master *m, struct thread_list *list)
590{
591 struct thread *t;
592 struct thread *next;
593
594 for (t = list->head; t; t = next)
595 {
596 next = t->next;
597 XFREE (MTYPE_THREAD, t);
598 list->count--;
599 m->alloc--;
600 }
601}
602
Christian Franke4becea72013-11-19 14:11:42 +0000603static void
604thread_queue_free (struct thread_master *m, struct pqueue *queue)
605{
606 int i;
607
608 for (i = 0; i < queue->size; i++)
609 XFREE(MTYPE_THREAD, queue->array[i]);
610
611 m->alloc -= queue->size;
612 pqueue_delete(queue);
613}
614
paul718e3742002-12-13 20:15:29 +0000615/* Stop thread scheduler. */
616void
617thread_master_free (struct thread_master *m)
618{
619 thread_list_free (m, &m->read);
620 thread_list_free (m, &m->write);
Christian Franke4becea72013-11-19 14:11:42 +0000621 thread_queue_free (m, m->timer);
paul718e3742002-12-13 20:15:29 +0000622 thread_list_free (m, &m->event);
623 thread_list_free (m, &m->ready);
624 thread_list_free (m, &m->unuse);
Christian Franke4becea72013-11-19 14:11:42 +0000625 thread_queue_free (m, m->background);
paula48b4e62005-04-22 00:43:47 +0000626
paul718e3742002-12-13 20:15:29 +0000627 XFREE (MTYPE_THREAD_MASTER, m);
Chris Caputo228da422009-07-18 05:44:03 +0000628
629 if (cpu_record)
630 {
631 hash_clean (cpu_record, cpu_record_hash_free);
632 hash_free (cpu_record);
633 cpu_record = NULL;
634 }
paul718e3742002-12-13 20:15:29 +0000635}
636
paul8cc41982005-05-06 21:25:49 +0000637/* Thread list is empty or not. */
Paul Jakmaf63f06d2011-04-08 12:44:43 +0100638static int
paul8cc41982005-05-06 21:25:49 +0000639thread_empty (struct thread_list *list)
640{
641 return list->head ? 0 : 1;
642}
643
paul718e3742002-12-13 20:15:29 +0000644/* Delete top of the list and return it. */
645static struct thread *
646thread_trim_head (struct thread_list *list)
647{
paul8cc41982005-05-06 21:25:49 +0000648 if (!thread_empty (list))
paul718e3742002-12-13 20:15:29 +0000649 return thread_list_delete (list, list->head);
650 return NULL;
651}
652
paul718e3742002-12-13 20:15:29 +0000653/* Return remain time in second. */
654unsigned long
655thread_timer_remain_second (struct thread *thread)
656{
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000657 quagga_get_relative (NULL);
658
659 if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
660 return thread->u.sands.tv_sec - relative_time.tv_sec;
paul718e3742002-12-13 20:15:29 +0000661 else
662 return 0;
663}
664
Christian Franke76fbc642015-11-10 18:04:41 +0100665struct timeval
666thread_timer_remain(struct thread *thread)
667{
668 quagga_get_relative(NULL);
669
670 return timeval_subtract(thread->u.sands, relative_time);
671}
672
David Lamparter3493b772013-11-18 23:04:27 +0100673#define debugargdef const char *funcname, const char *schedfrom, int fromln
674#define debugargpass funcname, schedfrom, fromln
paule04ab742003-01-17 23:47:00 +0000675
paul718e3742002-12-13 20:15:29 +0000676/* Get new thread. */
677static struct thread *
678thread_get (struct thread_master *m, u_char type,
David Lamparter3493b772013-11-18 23:04:27 +0100679 int (*func) (struct thread *), void *arg, debugargdef)
paul718e3742002-12-13 20:15:29 +0000680{
Jorge Boncompte [DTI2]64018322012-05-07 16:53:13 +0000681 struct thread *thread = thread_trim_head (&m->unuse);
paul718e3742002-12-13 20:15:29 +0000682
Jorge Boncompte [DTI2]22714f92012-05-07 16:53:14 +0000683 if (! thread)
paul718e3742002-12-13 20:15:29 +0000684 {
685 thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
686 m->alloc++;
687 }
688 thread->type = type;
paule04ab742003-01-17 23:47:00 +0000689 thread->add_type = type;
paul718e3742002-12-13 20:15:29 +0000690 thread->master = m;
691 thread->func = func;
692 thread->arg = arg;
Christian Franke4becea72013-11-19 14:11:42 +0000693 thread->index = -1;
694
David Lamparter3493b772013-11-18 23:04:27 +0100695 thread->funcname = funcname;
696 thread->schedfrom = schedfrom;
697 thread->schedfrom_line = fromln;
paule04ab742003-01-17 23:47:00 +0000698
paul718e3742002-12-13 20:15:29 +0000699 return thread;
700}
701
702/* Add new read thread. */
703struct thread *
paule04ab742003-01-17 23:47:00 +0000704funcname_thread_add_read (struct thread_master *m,
David Lamparter3493b772013-11-18 23:04:27 +0100705 int (*func) (struct thread *), void *arg, int fd,
706 debugargdef)
paul718e3742002-12-13 20:15:29 +0000707{
708 struct thread *thread;
709
710 assert (m != NULL);
711
712 if (FD_ISSET (fd, &m->readfd))
713 {
714 zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
715 return NULL;
716 }
717
David Lamparter3493b772013-11-18 23:04:27 +0100718 thread = thread_get (m, THREAD_READ, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000719 FD_SET (fd, &m->readfd);
720 thread->u.fd = fd;
721 thread_list_add (&m->read, thread);
722
723 return thread;
724}
725
726/* Add new write thread. */
727struct thread *
paule04ab742003-01-17 23:47:00 +0000728funcname_thread_add_write (struct thread_master *m,
David Lamparter3493b772013-11-18 23:04:27 +0100729 int (*func) (struct thread *), void *arg, int fd,
730 debugargdef)
paul718e3742002-12-13 20:15:29 +0000731{
732 struct thread *thread;
733
734 assert (m != NULL);
735
736 if (FD_ISSET (fd, &m->writefd))
737 {
738 zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
739 return NULL;
740 }
741
David Lamparter3493b772013-11-18 23:04:27 +0100742 thread = thread_get (m, THREAD_WRITE, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000743 FD_SET (fd, &m->writefd);
744 thread->u.fd = fd;
745 thread_list_add (&m->write, thread);
746
747 return thread;
748}
749
paul98c91ac2004-10-05 14:57:50 +0000750static struct thread *
751funcname_thread_add_timer_timeval (struct thread_master *m,
752 int (*func) (struct thread *),
paula48b4e62005-04-22 00:43:47 +0000753 int type,
paul98c91ac2004-10-05 14:57:50 +0000754 void *arg,
David Lamparter3493b772013-11-18 23:04:27 +0100755 struct timeval *time_relative,
756 debugargdef)
paul718e3742002-12-13 20:15:29 +0000757{
paul718e3742002-12-13 20:15:29 +0000758 struct thread *thread;
Christian Franke4becea72013-11-19 14:11:42 +0000759 struct pqueue *queue;
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000760 struct timeval alarm_time;
paul718e3742002-12-13 20:15:29 +0000761
762 assert (m != NULL);
763
ajs8b70d0b2005-04-28 01:31:13 +0000764 assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
paula48b4e62005-04-22 00:43:47 +0000765 assert (time_relative);
766
Christian Franke4becea72013-11-19 14:11:42 +0000767 queue = ((type == THREAD_TIMER) ? m->timer : m->background);
David Lamparter3493b772013-11-18 23:04:27 +0100768 thread = thread_get (m, type, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000769
770 /* Do we need jitter here? */
Joakim Tjernlundb8192762008-11-10 09:33:30 +0100771 quagga_get_relative (NULL);
Paul Jakmadb9c0df2006-08-27 06:44:02 +0000772 alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
773 alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
ajs8b70d0b2005-04-28 01:31:13 +0000774 thread->u.sands = timeval_adjust(alarm_time);
paul718e3742002-12-13 20:15:29 +0000775
Christian Franke4becea72013-11-19 14:11:42 +0000776 pqueue_enqueue(thread, queue);
paul718e3742002-12-13 20:15:29 +0000777 return thread;
778}
779
paul98c91ac2004-10-05 14:57:50 +0000780
781/* Add timer event thread. */
jardin9e867fe2003-12-23 08:56:18 +0000782struct thread *
paul98c91ac2004-10-05 14:57:50 +0000783funcname_thread_add_timer (struct thread_master *m,
784 int (*func) (struct thread *),
David Lamparter3493b772013-11-18 23:04:27 +0100785 void *arg, long timer,
786 debugargdef)
jardin9e867fe2003-12-23 08:56:18 +0000787{
paul98c91ac2004-10-05 14:57:50 +0000788 struct timeval trel;
jardin9e867fe2003-12-23 08:56:18 +0000789
790 assert (m != NULL);
791
paul9076fbd2004-10-11 09:40:58 +0000792 trel.tv_sec = timer;
paul98c91ac2004-10-05 14:57:50 +0000793 trel.tv_usec = 0;
794
paula48b4e62005-04-22 00:43:47 +0000795 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
David Lamparter3493b772013-11-18 23:04:27 +0100796 &trel, debugargpass);
paul98c91ac2004-10-05 14:57:50 +0000797}
798
799/* Add timer event thread with "millisecond" resolution */
800struct thread *
801funcname_thread_add_timer_msec (struct thread_master *m,
802 int (*func) (struct thread *),
David Lamparter3493b772013-11-18 23:04:27 +0100803 void *arg, long timer,
804 debugargdef)
paul98c91ac2004-10-05 14:57:50 +0000805{
806 struct timeval trel;
807
808 assert (m != NULL);
jardin9e867fe2003-12-23 08:56:18 +0000809
ajsaf04bd72004-12-28 17:00:12 +0000810 trel.tv_sec = timer / 1000;
811 trel.tv_usec = 1000*(timer % 1000);
jardin9e867fe2003-12-23 08:56:18 +0000812
paula48b4e62005-04-22 00:43:47 +0000813 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
David Lamparter3493b772013-11-18 23:04:27 +0100814 arg, &trel, debugargpass);
paula48b4e62005-04-22 00:43:47 +0000815}
816
817/* Add a background thread, with an optional millisec delay */
818struct thread *
819funcname_thread_add_background (struct thread_master *m,
820 int (*func) (struct thread *),
David Lamparter3493b772013-11-18 23:04:27 +0100821 void *arg, long delay,
822 debugargdef)
paula48b4e62005-04-22 00:43:47 +0000823{
824 struct timeval trel;
825
826 assert (m != NULL);
827
828 if (delay)
829 {
830 trel.tv_sec = delay / 1000;
831 trel.tv_usec = 1000*(delay % 1000);
832 }
833 else
834 {
835 trel.tv_sec = 0;
836 trel.tv_usec = 0;
837 }
838
839 return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
David Lamparter3493b772013-11-18 23:04:27 +0100840 arg, &trel, debugargpass);
jardin9e867fe2003-12-23 08:56:18 +0000841}
842
paul718e3742002-12-13 20:15:29 +0000843/* Add simple event thread. */
844struct thread *
paule04ab742003-01-17 23:47:00 +0000845funcname_thread_add_event (struct thread_master *m,
David Lamparter3493b772013-11-18 23:04:27 +0100846 int (*func) (struct thread *), void *arg, int val,
847 debugargdef)
paul718e3742002-12-13 20:15:29 +0000848{
849 struct thread *thread;
850
851 assert (m != NULL);
852
David Lamparter3493b772013-11-18 23:04:27 +0100853 thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
paul718e3742002-12-13 20:15:29 +0000854 thread->u.val = val;
855 thread_list_add (&m->event, thread);
856
857 return thread;
858}
859
860/* Cancel thread from scheduler. */
861void
862thread_cancel (struct thread *thread)
863{
Christian Franke4becea72013-11-19 14:11:42 +0000864 struct thread_list *list = NULL;
865 struct pqueue *queue = NULL;
paula48b4e62005-04-22 00:43:47 +0000866
paul718e3742002-12-13 20:15:29 +0000867 switch (thread->type)
868 {
869 case THREAD_READ:
870 assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
871 FD_CLR (thread->u.fd, &thread->master->readfd);
paula48b4e62005-04-22 00:43:47 +0000872 list = &thread->master->read;
paul718e3742002-12-13 20:15:29 +0000873 break;
874 case THREAD_WRITE:
875 assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
876 FD_CLR (thread->u.fd, &thread->master->writefd);
paula48b4e62005-04-22 00:43:47 +0000877 list = &thread->master->write;
paul718e3742002-12-13 20:15:29 +0000878 break;
879 case THREAD_TIMER:
Christian Franke4becea72013-11-19 14:11:42 +0000880 queue = thread->master->timer;
paul718e3742002-12-13 20:15:29 +0000881 break;
882 case THREAD_EVENT:
paula48b4e62005-04-22 00:43:47 +0000883 list = &thread->master->event;
paul718e3742002-12-13 20:15:29 +0000884 break;
885 case THREAD_READY:
paula48b4e62005-04-22 00:43:47 +0000886 list = &thread->master->ready;
paul718e3742002-12-13 20:15:29 +0000887 break;
paula48b4e62005-04-22 00:43:47 +0000888 case THREAD_BACKGROUND:
Christian Franke4becea72013-11-19 14:11:42 +0000889 queue = thread->master->background;
ajs8b70d0b2005-04-28 01:31:13 +0000890 break;
paul718e3742002-12-13 20:15:29 +0000891 default:
paula48b4e62005-04-22 00:43:47 +0000892 return;
paul718e3742002-12-13 20:15:29 +0000893 break;
894 }
Christian Franke4becea72013-11-19 14:11:42 +0000895
896 if (queue)
897 {
898 assert(thread->index >= 0);
899 assert(thread == queue->array[thread->index]);
900 pqueue_remove_at(thread->index, queue);
901 }
902 else if (list)
903 {
904 thread_list_delete (list, thread);
905 }
906 else
907 {
908 assert(!"Thread should be either in queue or list!");
909 }
910
paul718e3742002-12-13 20:15:29 +0000911 thread->type = THREAD_UNUSED;
912 thread_add_unuse (thread->master, thread);
913}
914
915/* Delete all events which has argument value arg. */
pauldc818072005-05-19 01:30:53 +0000916unsigned int
paul718e3742002-12-13 20:15:29 +0000917thread_cancel_event (struct thread_master *m, void *arg)
918{
pauldc818072005-05-19 01:30:53 +0000919 unsigned int ret = 0;
paul718e3742002-12-13 20:15:29 +0000920 struct thread *thread;
921
922 thread = m->event.head;
923 while (thread)
924 {
925 struct thread *t;
926
927 t = thread;
928 thread = t->next;
929
930 if (t->arg == arg)
paula48b4e62005-04-22 00:43:47 +0000931 {
pauldc818072005-05-19 01:30:53 +0000932 ret++;
paula48b4e62005-04-22 00:43:47 +0000933 thread_list_delete (&m->event, t);
934 t->type = THREAD_UNUSED;
935 thread_add_unuse (m, t);
936 }
paul718e3742002-12-13 20:15:29 +0000937 }
Jorge Boncompte [DTI2]1b79fcb2012-05-07 15:17:31 +0000938
939 /* thread can be on the ready list too */
940 thread = m->ready.head;
941 while (thread)
942 {
943 struct thread *t;
944
945 t = thread;
946 thread = t->next;
947
948 if (t->arg == arg)
949 {
950 ret++;
951 thread_list_delete (&m->ready, t);
952 t->type = THREAD_UNUSED;
953 thread_add_unuse (m, t);
954 }
955 }
pauldc818072005-05-19 01:30:53 +0000956 return ret;
paul718e3742002-12-13 20:15:29 +0000957}
958
paula48b4e62005-04-22 00:43:47 +0000959static struct timeval *
Christian Franke4becea72013-11-19 14:11:42 +0000960thread_timer_wait (struct pqueue *queue, struct timeval *timer_val)
paul718e3742002-12-13 20:15:29 +0000961{
Christian Franke4becea72013-11-19 14:11:42 +0000962 if (queue->size)
paul718e3742002-12-13 20:15:29 +0000963 {
Christian Franke4becea72013-11-19 14:11:42 +0000964 struct thread *next_timer = queue->array[0];
965 *timer_val = timeval_subtract (next_timer->u.sands, relative_time);
paul718e3742002-12-13 20:15:29 +0000966 return timer_val;
967 }
968 return NULL;
969}
paul718e3742002-12-13 20:15:29 +0000970
paul8cc41982005-05-06 21:25:49 +0000971static struct thread *
paul718e3742002-12-13 20:15:29 +0000972thread_run (struct thread_master *m, struct thread *thread,
973 struct thread *fetch)
974{
975 *fetch = *thread;
976 thread->type = THREAD_UNUSED;
977 thread_add_unuse (m, thread);
978 return fetch;
979}
980
paula48b4e62005-04-22 00:43:47 +0000981static int
982thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
paul718e3742002-12-13 20:15:29 +0000983{
984 struct thread *thread;
985 struct thread *next;
986 int ready = 0;
paula48b4e62005-04-22 00:43:47 +0000987
988 assert (list);
989
paul718e3742002-12-13 20:15:29 +0000990 for (thread = list->head; thread; thread = next)
991 {
992 next = thread->next;
993
994 if (FD_ISSET (THREAD_FD (thread), fdset))
paula48b4e62005-04-22 00:43:47 +0000995 {
996 assert (FD_ISSET (THREAD_FD (thread), mfdset));
997 FD_CLR(THREAD_FD (thread), mfdset);
998 thread_list_delete (list, thread);
999 thread_list_add (&thread->master->ready, thread);
1000 thread->type = THREAD_READY;
1001 ready++;
1002 }
paul718e3742002-12-13 20:15:29 +00001003 }
1004 return ready;
1005}
1006
ajs8b70d0b2005-04-28 01:31:13 +00001007/* Add all timers that have popped to the ready list. */
paula48b4e62005-04-22 00:43:47 +00001008static unsigned int
Christian Franke4becea72013-11-19 14:11:42 +00001009thread_timer_process (struct pqueue *queue, struct timeval *timenow)
paula48b4e62005-04-22 00:43:47 +00001010{
1011 struct thread *thread;
1012 unsigned int ready = 0;
1013
Christian Franke4becea72013-11-19 14:11:42 +00001014 while (queue->size)
ajs8b70d0b2005-04-28 01:31:13 +00001015 {
Christian Franke4becea72013-11-19 14:11:42 +00001016 thread = queue->array[0];
ajs8b70d0b2005-04-28 01:31:13 +00001017 if (timeval_cmp (*timenow, thread->u.sands) < 0)
1018 return ready;
Christian Franke4becea72013-11-19 14:11:42 +00001019 pqueue_dequeue(queue);
ajs8b70d0b2005-04-28 01:31:13 +00001020 thread->type = THREAD_READY;
1021 thread_list_add (&thread->master->ready, thread);
1022 ready++;
1023 }
paula48b4e62005-04-22 00:43:47 +00001024 return ready;
1025}
1026
Paul Jakma2613abe2010-01-11 16:33:07 +00001027/* process a list en masse, e.g. for event thread lists */
1028static unsigned int
1029thread_process (struct thread_list *list)
1030{
1031 struct thread *thread;
Paul Jakmab5043aa2012-02-28 18:32:56 +00001032 struct thread *next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001033 unsigned int ready = 0;
1034
Paul Jakmab5043aa2012-02-28 18:32:56 +00001035 for (thread = list->head; thread; thread = next)
Paul Jakma2613abe2010-01-11 16:33:07 +00001036 {
Paul Jakmab5043aa2012-02-28 18:32:56 +00001037 next = thread->next;
Paul Jakma2613abe2010-01-11 16:33:07 +00001038 thread_list_delete (list, thread);
1039 thread->type = THREAD_READY;
1040 thread_list_add (&thread->master->ready, thread);
1041 ready++;
1042 }
1043 return ready;
1044}
1045
1046
paul718e3742002-12-13 20:15:29 +00001047/* Fetch next ready thread. */
1048struct thread *
1049thread_fetch (struct thread_master *m, struct thread *fetch)
1050{
paul718e3742002-12-13 20:15:29 +00001051 struct thread *thread;
1052 fd_set readfd;
1053 fd_set writefd;
1054 fd_set exceptfd;
Paul Jakma2613abe2010-01-11 16:33:07 +00001055 struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
paula48b4e62005-04-22 00:43:47 +00001056 struct timeval timer_val_bg;
Paul Jakma2613abe2010-01-11 16:33:07 +00001057 struct timeval *timer_wait = &timer_val;
paula48b4e62005-04-22 00:43:47 +00001058 struct timeval *timer_wait_bg;
paul718e3742002-12-13 20:15:29 +00001059
1060 while (1)
1061 {
paula48b4e62005-04-22 00:43:47 +00001062 int num = 0;
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001063#if defined HAVE_SNMP && defined SNMP_AGENTX
1064 struct timeval snmp_timer_wait;
1065 int snmpblock = 0;
1066 int fdsetsize;
1067#endif
paula48b4e62005-04-22 00:43:47 +00001068
Paul Jakma2613abe2010-01-11 16:33:07 +00001069 /* Signals pre-empt everything */
paul05c447d2004-07-22 19:14:27 +00001070 quagga_sigevent_process ();
1071
Paul Jakma2613abe2010-01-11 16:33:07 +00001072 /* Drain the ready queue of already scheduled jobs, before scheduling
1073 * more.
paula48b4e62005-04-22 00:43:47 +00001074 */
paul718e3742002-12-13 20:15:29 +00001075 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001076 return thread_run (m, thread, fetch);
paula48b4e62005-04-22 00:43:47 +00001077
Paul Jakma2613abe2010-01-11 16:33:07 +00001078 /* To be fair to all kinds of threads, and avoid starvation, we
1079 * need to be careful to consider all thread types for scheduling
1080 * in each quanta. I.e. we should not return early from here on.
1081 */
1082
1083 /* Normal event are the next highest priority. */
1084 thread_process (&m->event);
1085
paul718e3742002-12-13 20:15:29 +00001086 /* Structure copy. */
1087 readfd = m->readfd;
1088 writefd = m->writefd;
1089 exceptfd = m->exceptfd;
paula48b4e62005-04-22 00:43:47 +00001090
1091 /* Calculate select wait timer if nothing else to do */
Paul Jakma2613abe2010-01-11 16:33:07 +00001092 if (m->ready.count == 0)
1093 {
1094 quagga_get_relative (NULL);
Christian Franke4becea72013-11-19 14:11:42 +00001095 timer_wait = thread_timer_wait (m->timer, &timer_val);
1096 timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg);
Paul Jakma2613abe2010-01-11 16:33:07 +00001097
1098 if (timer_wait_bg &&
1099 (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
1100 timer_wait = timer_wait_bg;
1101 }
paula48b4e62005-04-22 00:43:47 +00001102
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001103#if defined HAVE_SNMP && defined SNMP_AGENTX
1104 /* When SNMP is enabled, we may have to select() on additional
1105 FD. snmp_select_info() will add them to `readfd'. The trick
1106 with this function is its last argument. We need to set it to
1107 0 if timer_wait is not NULL and we need to use the provided
1108 new timer only if it is still set to 0. */
1109 if (agentx_enabled)
1110 {
1111 fdsetsize = FD_SETSIZE;
1112 snmpblock = 1;
1113 if (timer_wait)
1114 {
1115 snmpblock = 0;
1116 memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval));
1117 }
1118 snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock);
1119 if (snmpblock == 0)
1120 timer_wait = &snmp_timer_wait;
1121 }
1122#endif
paul718e3742002-12-13 20:15:29 +00001123 num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
paula48b4e62005-04-22 00:43:47 +00001124
1125 /* Signals should get quick treatment */
paul718e3742002-12-13 20:15:29 +00001126 if (num < 0)
paul05c447d2004-07-22 19:14:27 +00001127 {
1128 if (errno == EINTR)
paula48b4e62005-04-22 00:43:47 +00001129 continue; /* signal received - process it */
ajs6099b3b2004-11-20 02:06:59 +00001130 zlog_warn ("select() error: %s", safe_strerror (errno));
paul05c447d2004-07-22 19:14:27 +00001131 return NULL;
1132 }
ajs8b70d0b2005-04-28 01:31:13 +00001133
Vincent Bernatd6be5fb2012-05-24 09:44:43 +02001134#if defined HAVE_SNMP && defined SNMP_AGENTX
1135 if (agentx_enabled)
1136 {
1137 if (num > 0)
1138 snmp_read(&readfd);
1139 else if (num == 0)
1140 {
1141 snmp_timeout();
1142 run_alarms();
1143 }
1144 netsnmp_check_outstanding_agent_requests();
1145 }
1146#endif
1147
ajs8b70d0b2005-04-28 01:31:13 +00001148 /* Check foreground timers. Historically, they have had higher
1149 priority than I/O threads, so let's push them onto the ready
1150 list in front of the I/O threads. */
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001151 quagga_get_relative (NULL);
Christian Franke4becea72013-11-19 14:11:42 +00001152 thread_timer_process (m->timer, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001153
1154 /* Got IO, process it */
1155 if (num > 0)
1156 {
1157 /* Normal priority read thead. */
ajs8b70d0b2005-04-28 01:31:13 +00001158 thread_process_fd (&m->read, &readfd, &m->readfd);
paula48b4e62005-04-22 00:43:47 +00001159 /* Write thead. */
ajs8b70d0b2005-04-28 01:31:13 +00001160 thread_process_fd (&m->write, &writefd, &m->writefd);
paula48b4e62005-04-22 00:43:47 +00001161 }
ajs8b70d0b2005-04-28 01:31:13 +00001162
1163#if 0
1164 /* If any threads were made ready above (I/O or foreground timer),
1165 perhaps we should avoid adding background timers to the ready
1166 list at this time. If this is code is uncommented, then background
1167 timer threads will not run unless there is nothing else to do. */
1168 if ((thread = thread_trim_head (&m->ready)) != NULL)
1169 return thread_run (m, thread, fetch);
1170#endif
1171
paula48b4e62005-04-22 00:43:47 +00001172 /* Background timer/events, lowest priority */
Christian Franke4becea72013-11-19 14:11:42 +00001173 thread_timer_process (m->background, &relative_time);
paula48b4e62005-04-22 00:43:47 +00001174
ajs8b70d0b2005-04-28 01:31:13 +00001175 if ((thread = thread_trim_head (&m->ready)) != NULL)
paul05c447d2004-07-22 19:14:27 +00001176 return thread_run (m, thread, fetch);
paul718e3742002-12-13 20:15:29 +00001177 }
1178}
1179
ajs924b9222005-04-16 17:11:24 +00001180unsigned long
ajs8b70d0b2005-04-28 01:31:13 +00001181thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
paul718e3742002-12-13 20:15:29 +00001182{
paul718e3742002-12-13 20:15:29 +00001183#ifdef HAVE_RUSAGE
1184 /* This is 'user + sys' time. */
ajs8b70d0b2005-04-28 01:31:13 +00001185 *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
1186 timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
paul718e3742002-12-13 20:15:29 +00001187#else
ajs8b70d0b2005-04-28 01:31:13 +00001188 *cputime = 0;
paul718e3742002-12-13 20:15:29 +00001189#endif /* HAVE_RUSAGE */
ajs8b70d0b2005-04-28 01:31:13 +00001190 return timeval_elapsed (now->real, start->real);
paul718e3742002-12-13 20:15:29 +00001191}
1192
ajs8b70d0b2005-04-28 01:31:13 +00001193/* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
1194 Note: we are using real (wall clock) time for this calculation.
1195 It could be argued that CPU time may make more sense in certain
1196 contexts. The things to consider are whether the thread may have
1197 blocked (in which case wall time increases, but CPU time does not),
1198 or whether the system is heavily loaded with other processes competing
1199 for CPU time. On balance, wall clock time seems to make sense.
1200 Plus it has the added benefit that gettimeofday should be faster
1201 than calling getrusage. */
paul718e3742002-12-13 20:15:29 +00001202int
1203thread_should_yield (struct thread *thread)
1204{
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001205 quagga_get_relative (NULL);
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001206 return (timeval_elapsed(relative_time, thread->real) >
ajs8b70d0b2005-04-28 01:31:13 +00001207 THREAD_YIELD_TIME_SLOT);
paul718e3742002-12-13 20:15:29 +00001208}
1209
Paul Jakmadb9c0df2006-08-27 06:44:02 +00001210void
1211thread_getrusage (RUSAGE_T *r)
1212{
1213 quagga_get_relative (NULL);
1214#ifdef HAVE_RUSAGE
1215 getrusage(RUSAGE_SELF, &(r->cpu));
1216#endif
1217 r->real = relative_time;
1218
1219#ifdef HAVE_CLOCK_MONOTONIC
1220 /* quagga_get_relative() only updates recent_time if gettimeofday
1221 * based, not when using CLOCK_MONOTONIC. As we export recent_time
1222 * and guarantee to update it before threads are run...
1223 */
1224 quagga_gettimeofday(&recent_time);
1225#endif /* HAVE_CLOCK_MONOTONIC */
1226}
1227
David Lamparter615f9f12013-11-18 23:52:02 +01001228struct thread *thread_current = NULL;
1229
paul718e3742002-12-13 20:15:29 +00001230/* We check thread consumed time. If the system has getrusage, we'll
ajs8b70d0b2005-04-28 01:31:13 +00001231 use that to get in-depth stats on the performance of the thread in addition
1232 to wall clock time stats from gettimeofday. */
paul718e3742002-12-13 20:15:29 +00001233void
1234thread_call (struct thread *thread)
1235{
ajs8b70d0b2005-04-28 01:31:13 +00001236 unsigned long realtime, cputime;
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001237 RUSAGE_T before, after;
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001238
1239 /* Cache a pointer to the relevant cpu history thread, if the thread
1240 * does not have it yet.
1241 *
1242 * Callers submitting 'dummy threads' hence must take care that
1243 * thread->cpu is NULL
1244 */
1245 if (!thread->hist)
1246 {
1247 struct cpu_thread_history tmp;
1248
1249 tmp.func = thread->func;
David Lamparter3493b772013-11-18 23:04:27 +01001250 tmp.funcname = thread->funcname;
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001251
1252 thread->hist = hash_get (cpu_record, &tmp,
1253 (void * (*) (void *))cpu_record_hash_alloc);
1254 }
paul718e3742002-12-13 20:15:29 +00001255
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001256 GETRUSAGE (&before);
1257 thread->real = before.real;
paul718e3742002-12-13 20:15:29 +00001258
David Lamparter615f9f12013-11-18 23:52:02 +01001259 thread_current = thread;
paul718e3742002-12-13 20:15:29 +00001260 (*thread->func) (thread);
David Lamparter615f9f12013-11-18 23:52:02 +01001261 thread_current = NULL;
paul718e3742002-12-13 20:15:29 +00001262
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001263 GETRUSAGE (&after);
paul718e3742002-12-13 20:15:29 +00001264
Jorge Boncompte [DTI2]41af3382012-05-07 16:53:12 +00001265 realtime = thread_consumed_time (&after, &before, &cputime);
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001266 thread->hist->real.total += realtime;
1267 if (thread->hist->real.max < realtime)
1268 thread->hist->real.max = realtime;
ajs8b70d0b2005-04-28 01:31:13 +00001269#ifdef HAVE_RUSAGE
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001270 thread->hist->cpu.total += cputime;
1271 if (thread->hist->cpu.max < cputime)
1272 thread->hist->cpu.max = cputime;
ajs8b70d0b2005-04-28 01:31:13 +00001273#endif
paule04ab742003-01-17 23:47:00 +00001274
Paul Jakmacc8b13a2006-07-25 20:40:40 +00001275 ++(thread->hist->total_calls);
1276 thread->hist->types |= (1 << thread->add_type);
paul718e3742002-12-13 20:15:29 +00001277
ajs924b9222005-04-16 17:11:24 +00001278#ifdef CONSUMED_TIME_CHECK
ajs8b70d0b2005-04-28 01:31:13 +00001279 if (realtime > CONSUMED_TIME_CHECK)
paul718e3742002-12-13 20:15:29 +00001280 {
1281 /*
1282 * We have a CPU Hog on our hands.
1283 * Whinge about it now, so we're aware this is yet another task
1284 * to fix.
1285 */
ajs8b70d0b2005-04-28 01:31:13 +00001286 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
ajs924b9222005-04-16 17:11:24 +00001287 thread->funcname,
1288 (unsigned long) thread->func,
ajs8b70d0b2005-04-28 01:31:13 +00001289 realtime/1000, cputime/1000);
paul718e3742002-12-13 20:15:29 +00001290 }
ajs924b9222005-04-16 17:11:24 +00001291#endif /* CONSUMED_TIME_CHECK */
paul718e3742002-12-13 20:15:29 +00001292}
1293
1294/* Execute thread */
1295struct thread *
paule04ab742003-01-17 23:47:00 +00001296funcname_thread_execute (struct thread_master *m,
paul718e3742002-12-13 20:15:29 +00001297 int (*func)(struct thread *),
1298 void *arg,
paule04ab742003-01-17 23:47:00 +00001299 int val,
David Lamparter3493b772013-11-18 23:04:27 +01001300 debugargdef)
paul718e3742002-12-13 20:15:29 +00001301{
1302 struct thread dummy;
1303
1304 memset (&dummy, 0, sizeof (struct thread));
1305
1306 dummy.type = THREAD_EVENT;
paule04ab742003-01-17 23:47:00 +00001307 dummy.add_type = THREAD_EXECUTE;
paul718e3742002-12-13 20:15:29 +00001308 dummy.master = NULL;
1309 dummy.func = func;
1310 dummy.arg = arg;
1311 dummy.u.val = val;
David Lamparter3493b772013-11-18 23:04:27 +01001312
1313 dummy.funcname = funcname;
1314 dummy.schedfrom = schedfrom;
1315 dummy.schedfrom_line = fromln;
1316
paul718e3742002-12-13 20:15:29 +00001317 thread_call (&dummy);
1318
paul718e3742002-12-13 20:15:29 +00001319 return NULL;
1320}