]> git.proxmox.com Git - mirror_frr.git/blame - lib/thread.c
ospf: Fix segfault if compiled with DEBUG
[mirror_frr.git] / lib / thread.c
CommitLineData
718e3744 1/* Thread management routine
2 * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
896014f4
DL
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
718e3744 19 */
20
21/* #define DEBUG */
22
23#include <zebra.h>
308d14ae 24#include <sys/resource.h>
718e3744 25
26#include "thread.h"
27#include "memory.h"
28#include "log.h"
e04ab74d 29#include "hash.h"
4becea72 30#include "pqueue.h"
e04ab74d 31#include "command.h"
05c447dd 32#include "sigevent.h"
3bf2673b 33#include "network.h"
d6be5fb9 34
d62a17ae 35DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread")
4a1ab8e4 36DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master")
d62a17ae 37DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
4a1ab8e4 38
3b96b781
HT
39#if defined(__APPLE__)
40#include <mach/mach.h>
41#include <mach/mach_time.h>
42#endif
43
d62a17ae 44#define AWAKEN(m) \
45 do { \
46 static unsigned char wakebyte = 0x01; \
47 write(m->io_pipe[1], &wakebyte, 1); \
48 } while (0);
3bf2673b 49
d764d2cc
QY
50/* max # of thread_fetch() calls before we force a poll() */
51#define MAX_TICK_IO 1000
52
62f44022 53/* control variable for initializer */
e0bebc7c 54pthread_once_t init_once = PTHREAD_ONCE_INIT;
e0bebc7c 55pthread_key_t thread_current;
6b0655a2 56
62f44022
QY
57pthread_mutex_t masters_mtx = PTHREAD_MUTEX_INITIALIZER;
58static struct list *masters;
59
6b0655a2 60
62f44022 61/* CLI start ---------------------------------------------------------------- */
d62a17ae 62static unsigned int cpu_record_hash_key(struct cpu_thread_history *a)
e04ab74d 63{
d62a17ae 64 return (uintptr_t)a->func;
e04ab74d 65}
66
d62a17ae 67static int cpu_record_hash_cmp(const struct cpu_thread_history *a,
68 const struct cpu_thread_history *b)
e04ab74d 69{
d62a17ae 70 return a->func == b->func;
e04ab74d 71}
72
d62a17ae 73static void *cpu_record_hash_alloc(struct cpu_thread_history *a)
e04ab74d 74{
d62a17ae 75 struct cpu_thread_history *new;
76 new = XCALLOC(MTYPE_THREAD_STATS, sizeof(struct cpu_thread_history));
77 new->func = a->func;
78 new->funcname = a->funcname;
79 return new;
e04ab74d 80}
81
d62a17ae 82static void cpu_record_hash_free(void *a)
228da428 83{
d62a17ae 84 struct cpu_thread_history *hist = a;
85
86 XFREE(MTYPE_THREAD_STATS, hist);
228da428
CC
87}
88
d62a17ae 89static void vty_out_cpu_thread_history(struct vty *vty,
90 struct cpu_thread_history *a)
e04ab74d 91{
d62a17ae 92 vty_out(vty, "%5d %10ld.%03ld %9d %8ld %9ld %8ld %9ld", a->total_active,
93 a->cpu.total / 1000, a->cpu.total % 1000, a->total_calls,
94 a->cpu.total / a->total_calls, a->cpu.max,
95 a->real.total / a->total_calls, a->real.max);
96 vty_out(vty, " %c%c%c%c%c %s\n",
97 a->types & (1 << THREAD_READ) ? 'R' : ' ',
98 a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
99 a->types & (1 << THREAD_TIMER) ? 'T' : ' ',
100 a->types & (1 << THREAD_EVENT) ? 'E' : ' ',
101 a->types & (1 << THREAD_EXECUTE) ? 'X' : ' ', a->funcname);
e04ab74d 102}
103
d62a17ae 104static void cpu_record_hash_print(struct hash_backet *bucket, void *args[])
e04ab74d 105{
d62a17ae 106 struct cpu_thread_history *totals = args[0];
107 struct vty *vty = args[1];
108 thread_type *filter = args[2];
109
110 struct cpu_thread_history *a = bucket->data;
111
112 if (!(a->types & *filter))
113 return;
114 vty_out_cpu_thread_history(vty, a);
115 totals->total_active += a->total_active;
116 totals->total_calls += a->total_calls;
117 totals->real.total += a->real.total;
118 if (totals->real.max < a->real.max)
119 totals->real.max = a->real.max;
120 totals->cpu.total += a->cpu.total;
121 if (totals->cpu.max < a->cpu.max)
122 totals->cpu.max = a->cpu.max;
e04ab74d 123}
124
d62a17ae 125static void cpu_record_print(struct vty *vty, thread_type filter)
e04ab74d 126{
d62a17ae 127 struct cpu_thread_history tmp;
128 void *args[3] = {&tmp, vty, &filter};
129 struct thread_master *m;
130 struct listnode *ln;
131
132 memset(&tmp, 0, sizeof tmp);
133 tmp.funcname = "TOTAL";
134 tmp.types = filter;
135
136 pthread_mutex_lock(&masters_mtx);
137 {
138 for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
139 const char *name = m->name ? m->name : "main";
140
141 char underline[strlen(name) + 1];
142 memset(underline, '-', sizeof(underline));
143 underline[sizeof(underline)] = '\0';
144
145 vty_out(vty, "\n");
146 vty_out(vty, "Showing statistics for pthread %s\n",
147 name);
148 vty_out(vty, "-------------------------------%s\n",
149 underline);
150 vty_out(vty, "%21s %18s %18s\n", "",
151 "CPU (user+system):", "Real (wall-clock):");
152 vty_out(vty,
153 "Active Runtime(ms) Invoked Avg uSec Max uSecs");
154 vty_out(vty, " Avg uSec Max uSecs");
155 vty_out(vty, " Type Thread\n");
156
157 if (m->cpu_record->count)
158 hash_iterate(
159 m->cpu_record,
160 (void (*)(struct hash_backet *,
161 void *))cpu_record_hash_print,
162 args);
163 else
164 vty_out(vty, "No data to display yet.\n");
165
166 vty_out(vty, "\n");
167 }
168 }
169 pthread_mutex_unlock(&masters_mtx);
170
171 vty_out(vty, "\n");
172 vty_out(vty, "Total thread statistics\n");
173 vty_out(vty, "-------------------------\n");
174 vty_out(vty, "%21s %18s %18s\n", "",
175 "CPU (user+system):", "Real (wall-clock):");
176 vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs");
177 vty_out(vty, " Avg uSec Max uSecs");
178 vty_out(vty, " Type Thread\n");
179
180 if (tmp.total_calls > 0)
181 vty_out_cpu_thread_history(vty, &tmp);
e04ab74d 182}
183
d62a17ae 184static void cpu_record_hash_clear(struct hash_backet *bucket, void *args[])
e276eb82 185{
d62a17ae 186 thread_type *filter = args[0];
187 struct hash *cpu_record = args[1];
188
189 struct cpu_thread_history *a = bucket->data;
62f44022 190
d62a17ae 191 if (!(a->types & *filter))
192 return;
f48f65d2 193
d62a17ae 194 hash_release(cpu_record, bucket->data);
e276eb82
PJ
195}
196
d62a17ae 197static void cpu_record_clear(thread_type filter)
e276eb82 198{
d62a17ae 199 thread_type *tmp = &filter;
200 struct thread_master *m;
201 struct listnode *ln;
202
203 pthread_mutex_lock(&masters_mtx);
204 {
205 for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
206 pthread_mutex_lock(&m->mtx);
207 {
208 void *args[2] = {tmp, m->cpu_record};
209 hash_iterate(
210 m->cpu_record,
211 (void (*)(struct hash_backet *,
212 void *))cpu_record_hash_clear,
213 args);
214 }
215 pthread_mutex_unlock(&m->mtx);
216 }
217 }
218 pthread_mutex_unlock(&masters_mtx);
62f44022
QY
219}
220
d62a17ae 221static thread_type parse_filter(const char *filterstr)
62f44022 222{
d62a17ae 223 int i = 0;
224 int filter = 0;
225
226 while (filterstr[i] != '\0') {
227 switch (filterstr[i]) {
228 case 'r':
229 case 'R':
230 filter |= (1 << THREAD_READ);
231 break;
232 case 'w':
233 case 'W':
234 filter |= (1 << THREAD_WRITE);
235 break;
236 case 't':
237 case 'T':
238 filter |= (1 << THREAD_TIMER);
239 break;
240 case 'e':
241 case 'E':
242 filter |= (1 << THREAD_EVENT);
243 break;
244 case 'x':
245 case 'X':
246 filter |= (1 << THREAD_EXECUTE);
247 break;
248 default:
249 break;
250 }
251 ++i;
252 }
253 return filter;
62f44022
QY
254}
255
256DEFUN (show_thread_cpu,
257 show_thread_cpu_cmd,
258 "show thread cpu [FILTER]",
259 SHOW_STR
260 "Thread information\n"
261 "Thread CPU usage\n"
262 "Display filter (rwtexb)\n")
263{
d62a17ae 264 thread_type filter = (thread_type)-1U;
265 int idx = 0;
266
267 if (argv_find(argv, argc, "FILTER", &idx)) {
268 filter = parse_filter(argv[idx]->arg);
269 if (!filter) {
270 vty_out(vty,
271 "Invalid filter \"%s\" specified; must contain at least"
272 "one of 'RWTEXB'\n",
273 argv[idx]->arg);
274 return CMD_WARNING;
275 }
276 }
277
278 cpu_record_print(vty, filter);
279 return CMD_SUCCESS;
e276eb82
PJ
280}
281
49d41a26
DS
282DEFUN (clear_thread_cpu,
283 clear_thread_cpu_cmd,
284 "clear thread cpu [FILTER]",
62f44022 285 "Clear stored data in all pthreads\n"
49d41a26
DS
286 "Thread information\n"
287 "Thread CPU usage\n"
288 "Display filter (rwtexb)\n")
e276eb82 289{
d62a17ae 290 thread_type filter = (thread_type)-1U;
291 int idx = 0;
292
293 if (argv_find(argv, argc, "FILTER", &idx)) {
294 filter = parse_filter(argv[idx]->arg);
295 if (!filter) {
296 vty_out(vty,
297 "Invalid filter \"%s\" specified; must contain at least"
298 "one of 'RWTEXB'\n",
299 argv[idx]->arg);
300 return CMD_WARNING;
301 }
302 }
303
304 cpu_record_clear(filter);
305 return CMD_SUCCESS;
e276eb82 306}
6b0655a2 307
d62a17ae 308void thread_cmd_init(void)
0b84f294 309{
d62a17ae 310 install_element(VIEW_NODE, &show_thread_cpu_cmd);
311 install_element(ENABLE_NODE, &clear_thread_cpu_cmd);
0b84f294 312}
62f44022
QY
313/* CLI end ------------------------------------------------------------------ */
314
0b84f294 315
d62a17ae 316static int thread_timer_cmp(void *a, void *b)
4becea72 317{
d62a17ae 318 struct thread *thread_a = a;
319 struct thread *thread_b = b;
320
321 if (timercmp(&thread_a->u.sands, &thread_b->u.sands, <))
322 return -1;
323 if (timercmp(&thread_a->u.sands, &thread_b->u.sands, >))
324 return 1;
325 return 0;
4becea72
CF
326}
327
d62a17ae 328static void thread_timer_update(void *node, int actual_position)
4becea72 329{
d62a17ae 330 struct thread *thread = node;
4becea72 331
d62a17ae 332 thread->index = actual_position;
4becea72
CF
333}
334
d62a17ae 335static void cancelreq_del(void *cr)
63ccb9cb 336{
d62a17ae 337 XFREE(MTYPE_TMP, cr);
63ccb9cb
QY
338}
339
e0bebc7c 340/* initializer, only ever called once */
d62a17ae 341static void initializer()
e0bebc7c 342{
d62a17ae 343 pthread_key_create(&thread_current, NULL);
e0bebc7c
QY
344}
345
718e3744 346/* Allocate new thread master. */
d62a17ae 347struct thread_master *thread_master_create(const char *name)
718e3744 348{
d62a17ae 349 struct thread_master *rv;
350 struct rlimit limit;
351
352 pthread_once(&init_once, &initializer);
353
354 rv = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct thread_master));
355 if (rv == NULL)
356 return NULL;
357
358 /* Initialize master mutex */
359 pthread_mutex_init(&rv->mtx, NULL);
360 pthread_cond_init(&rv->cancel_cond, NULL);
361
362 /* Set name */
363 rv->name = name ? XSTRDUP(MTYPE_THREAD_MASTER, name) : NULL;
364
365 /* Initialize I/O task data structures */
366 getrlimit(RLIMIT_NOFILE, &limit);
367 rv->fd_limit = (int)limit.rlim_cur;
368 rv->read =
369 XCALLOC(MTYPE_THREAD, sizeof(struct thread *) * rv->fd_limit);
370 if (rv->read == NULL) {
371 XFREE(MTYPE_THREAD_MASTER, rv);
372 return NULL;
373 }
374 rv->write =
375 XCALLOC(MTYPE_THREAD, sizeof(struct thread *) * rv->fd_limit);
376 if (rv->write == NULL) {
377 XFREE(MTYPE_THREAD, rv->read);
378 XFREE(MTYPE_THREAD_MASTER, rv);
379 return NULL;
380 }
381
382 rv->cpu_record = hash_create(
383 (unsigned int (*)(void *))cpu_record_hash_key,
384 (int (*)(const void *, const void *))cpu_record_hash_cmp, NULL);
385
386
387 /* Initialize the timer queues */
388 rv->timer = pqueue_create();
389 rv->timer->cmp = thread_timer_cmp;
390 rv->timer->update = thread_timer_update;
391
392 /* Initialize thread_fetch() settings */
393 rv->spin = true;
394 rv->handle_signals = true;
395
396 /* Set pthread owner, should be updated by actual owner */
397 rv->owner = pthread_self();
398 rv->cancel_req = list_new();
399 rv->cancel_req->del = cancelreq_del;
400 rv->canceled = true;
401
402 /* Initialize pipe poker */
403 pipe(rv->io_pipe);
404 set_nonblocking(rv->io_pipe[0]);
405 set_nonblocking(rv->io_pipe[1]);
406
407 /* Initialize data structures for poll() */
408 rv->handler.pfdsize = rv->fd_limit;
409 rv->handler.pfdcount = 0;
410 rv->handler.pfds = XCALLOC(MTYPE_THREAD_MASTER,
411 sizeof(struct pollfd) * rv->handler.pfdsize);
412 rv->handler.copy = XCALLOC(MTYPE_THREAD_MASTER,
413 sizeof(struct pollfd) * rv->handler.pfdsize);
414
eff09c66 415 /* add to list of threadmasters */
d62a17ae 416 pthread_mutex_lock(&masters_mtx);
417 {
eff09c66
QY
418 if (!masters)
419 masters = list_new();
420
d62a17ae 421 listnode_add(masters, rv);
422 }
423 pthread_mutex_unlock(&masters_mtx);
424
425 return rv;
718e3744 426}
427
428/* Add a new thread to the list. */
d62a17ae 429static void thread_list_add(struct thread_list *list, struct thread *thread)
718e3744 430{
d62a17ae 431 thread->next = NULL;
432 thread->prev = list->tail;
433 if (list->tail)
434 list->tail->next = thread;
435 else
436 list->head = thread;
437 list->tail = thread;
438 list->count++;
718e3744 439}
440
718e3744 441/* Delete a thread from the list. */
d62a17ae 442static struct thread *thread_list_delete(struct thread_list *list,
443 struct thread *thread)
718e3744 444{
d62a17ae 445 if (thread->next)
446 thread->next->prev = thread->prev;
447 else
448 list->tail = thread->prev;
449 if (thread->prev)
450 thread->prev->next = thread->next;
451 else
452 list->head = thread->next;
453 thread->next = thread->prev = NULL;
454 list->count--;
455 return thread;
718e3744 456}
457
495f0b13 458/* Thread list is empty or not. */
d62a17ae 459static int thread_empty(struct thread_list *list)
495f0b13 460{
d62a17ae 461 return list->head ? 0 : 1;
495f0b13
DS
462}
463
464/* Delete top of the list and return it. */
d62a17ae 465static struct thread *thread_trim_head(struct thread_list *list)
495f0b13 466{
d62a17ae 467 if (!thread_empty(list))
468 return thread_list_delete(list, list->head);
469 return NULL;
495f0b13
DS
470}
471
718e3744 472/* Move thread to unuse list. */
d62a17ae 473static void thread_add_unuse(struct thread_master *m, struct thread *thread)
718e3744 474{
d62a17ae 475 assert(m != NULL && thread != NULL);
476 assert(thread->next == NULL);
477 assert(thread->prev == NULL);
478 thread->ref = NULL;
479
480 thread->type = THREAD_UNUSED;
481 thread->hist->total_active--;
482 thread_list_add(&m->unuse, thread);
718e3744 483}
484
485/* Free all unused thread. */
d62a17ae 486static void thread_list_free(struct thread_master *m, struct thread_list *list)
718e3744 487{
d62a17ae 488 struct thread *t;
489 struct thread *next;
490
491 for (t = list->head; t; t = next) {
492 next = t->next;
493 XFREE(MTYPE_THREAD, t);
494 list->count--;
495 m->alloc--;
496 }
718e3744 497}
498
d62a17ae 499static void thread_array_free(struct thread_master *m,
500 struct thread **thread_array)
308d14ae 501{
d62a17ae 502 struct thread *t;
503 int index;
504
505 for (index = 0; index < m->fd_limit; ++index) {
506 t = thread_array[index];
507 if (t) {
508 thread_array[index] = NULL;
509 XFREE(MTYPE_THREAD, t);
510 m->alloc--;
511 }
512 }
513 XFREE(MTYPE_THREAD, thread_array);
308d14ae
DV
514}
515
d62a17ae 516static void thread_queue_free(struct thread_master *m, struct pqueue *queue)
4becea72 517{
d62a17ae 518 int i;
4becea72 519
d62a17ae 520 for (i = 0; i < queue->size; i++)
521 XFREE(MTYPE_THREAD, queue->array[i]);
4becea72 522
d62a17ae 523 m->alloc -= queue->size;
524 pqueue_delete(queue);
4becea72
CF
525}
526
495f0b13
DS
527/*
528 * thread_master_free_unused
529 *
530 * As threads are finished with they are put on the
531 * unuse list for later reuse.
532 * If we are shutting down, Free up unused threads
533 * So we can see if we forget to shut anything off
534 */
d62a17ae 535void thread_master_free_unused(struct thread_master *m)
495f0b13 536{
d62a17ae 537 pthread_mutex_lock(&m->mtx);
538 {
539 struct thread *t;
540 while ((t = thread_trim_head(&m->unuse)) != NULL) {
541 pthread_mutex_destroy(&t->mtx);
542 XFREE(MTYPE_THREAD, t);
543 }
544 }
545 pthread_mutex_unlock(&m->mtx);
495f0b13
DS
546}
547
718e3744 548/* Stop thread scheduler. */
d62a17ae 549void thread_master_free(struct thread_master *m)
718e3744 550{
d62a17ae 551 pthread_mutex_lock(&masters_mtx);
552 {
553 listnode_delete(masters, m);
eff09c66
QY
554 if (masters->count == 0) {
555 list_free (masters);
556 masters = NULL;
557 }
d62a17ae 558 }
559 pthread_mutex_unlock(&masters_mtx);
560
561 thread_array_free(m, m->read);
562 thread_array_free(m, m->write);
563 thread_queue_free(m, m->timer);
564 thread_list_free(m, &m->event);
565 thread_list_free(m, &m->ready);
566 thread_list_free(m, &m->unuse);
567 pthread_mutex_destroy(&m->mtx);
568 close(m->io_pipe[0]);
569 close(m->io_pipe[1]);
570 list_delete(m->cancel_req);
571
572 hash_clean(m->cpu_record, cpu_record_hash_free);
573 hash_free(m->cpu_record);
574 m->cpu_record = NULL;
575
576 XFREE(MTYPE_THREAD_MASTER, m->handler.pfds);
577 XFREE(MTYPE_THREAD_MASTER, m->handler.copy);
578 XFREE(MTYPE_THREAD_MASTER, m);
718e3744 579}
580
718e3744 581/* Return remain time in second. */
d62a17ae 582unsigned long thread_timer_remain_second(struct thread *thread)
718e3744 583{
d62a17ae 584 int64_t remain;
1189d95f 585
d62a17ae 586 pthread_mutex_lock(&thread->mtx);
587 {
588 remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
589 }
590 pthread_mutex_unlock(&thread->mtx);
1189d95f 591
d62a17ae 592 return remain < 0 ? 0 : remain;
718e3744 593}
594
9c7753e4
DL
595#define debugargdef const char *funcname, const char *schedfrom, int fromln
596#define debugargpass funcname, schedfrom, fromln
e04ab74d 597
d62a17ae 598struct timeval thread_timer_remain(struct thread *thread)
6ac44687 599{
d62a17ae 600 struct timeval remain;
601 pthread_mutex_lock(&thread->mtx);
602 {
603 monotime_until(&thread->u.sands, &remain);
604 }
605 pthread_mutex_unlock(&thread->mtx);
606 return remain;
6ac44687
CF
607}
608
718e3744 609/* Get new thread. */
d62a17ae 610static struct thread *thread_get(struct thread_master *m, u_char type,
611 int (*func)(struct thread *), void *arg,
612 debugargdef)
718e3744 613{
d62a17ae 614 struct thread *thread = thread_trim_head(&m->unuse);
615 struct cpu_thread_history tmp;
616
617 if (!thread) {
618 thread = XCALLOC(MTYPE_THREAD, sizeof(struct thread));
619 /* mutex only needs to be initialized at struct creation. */
620 pthread_mutex_init(&thread->mtx, NULL);
621 m->alloc++;
622 }
623
624 thread->type = type;
625 thread->add_type = type;
626 thread->master = m;
627 thread->arg = arg;
628 thread->index = -1;
629 thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
630 thread->ref = NULL;
631
632 /*
633 * So if the passed in funcname is not what we have
634 * stored that means the thread->hist needs to be
635 * updated. We keep the last one around in unused
636 * under the assumption that we are probably
637 * going to immediately allocate the same
638 * type of thread.
639 * This hopefully saves us some serious
640 * hash_get lookups.
641 */
642 if (thread->funcname != funcname || thread->func != func) {
643 tmp.func = func;
644 tmp.funcname = funcname;
645 thread->hist =
646 hash_get(m->cpu_record, &tmp,
647 (void *(*)(void *))cpu_record_hash_alloc);
648 }
649 thread->hist->total_active++;
650 thread->func = func;
651 thread->funcname = funcname;
652 thread->schedfrom = schedfrom;
653 thread->schedfrom_line = fromln;
654
655 return thread;
718e3744 656}
657
d62a17ae 658static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
659 nfds_t count, const struct timeval *timer_wait)
209a72a6 660{
d62a17ae 661 /* If timer_wait is null here, that means poll() should block
662 * indefinitely,
663 * unless the thread_master has overriden it by setting
664 * ->selectpoll_timeout.
665 * If the value is positive, it specifies the maximum number of
666 * milliseconds
667 * to wait. If the timeout is -1, it specifies that we should never wait
668 * and
669 * always return immediately even if no event is detected. If the value
670 * is
671 * zero, the behavior is default. */
672 int timeout = -1;
673
674 /* number of file descriptors with events */
675 int num;
676
677 if (timer_wait != NULL
678 && m->selectpoll_timeout == 0) // use the default value
679 timeout = (timer_wait->tv_sec * 1000)
680 + (timer_wait->tv_usec / 1000);
681 else if (m->selectpoll_timeout > 0) // use the user's timeout
682 timeout = m->selectpoll_timeout;
683 else if (m->selectpoll_timeout
684 < 0) // effect a poll (return immediately)
685 timeout = 0;
686
687 /* add poll pipe poker */
688 assert(count + 1 < pfdsize);
689 pfds[count].fd = m->io_pipe[0];
690 pfds[count].events = POLLIN;
691 pfds[count].revents = 0x00;
692
693 num = poll(pfds, count + 1, timeout);
694
695 unsigned char trash[64];
696 if (num > 0 && pfds[count].revents != 0 && num--)
697 while (read(m->io_pipe[0], &trash, sizeof(trash)) > 0)
698 ;
699
700 return num;
209a72a6
DS
701}
702
718e3744 703/* Add new read thread. */
d62a17ae 704struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
705 int (*func)(struct thread *),
706 void *arg, int fd,
707 struct thread **t_ptr,
708 debugargdef)
718e3744 709{
d62a17ae 710 struct thread *thread = NULL;
711
712 pthread_mutex_lock(&m->mtx);
713 {
714 if (t_ptr
715 && *t_ptr) // thread is already scheduled; don't reschedule
716 {
717 pthread_mutex_unlock(&m->mtx);
718 return NULL;
719 }
720
721 /* default to a new pollfd */
722 nfds_t queuepos = m->handler.pfdcount;
723
724 /* if we already have a pollfd for our file descriptor, find and
725 * use it */
726 for (nfds_t i = 0; i < m->handler.pfdcount; i++)
727 if (m->handler.pfds[i].fd == fd) {
728 queuepos = i;
729 break;
730 }
731
732 /* make sure we have room for this fd + pipe poker fd */
733 assert(queuepos + 1 < m->handler.pfdsize);
734
735 thread = thread_get(m, dir, func, arg, debugargpass);
736
737 m->handler.pfds[queuepos].fd = fd;
738 m->handler.pfds[queuepos].events |=
739 (dir == THREAD_READ ? POLLIN : POLLOUT);
740
741 if (queuepos == m->handler.pfdcount)
742 m->handler.pfdcount++;
743
744 if (thread) {
745 pthread_mutex_lock(&thread->mtx);
746 {
747 thread->u.fd = fd;
748 if (dir == THREAD_READ)
749 m->read[thread->u.fd] = thread;
750 else
751 m->write[thread->u.fd] = thread;
752 }
753 pthread_mutex_unlock(&thread->mtx);
754
755 if (t_ptr) {
756 *t_ptr = thread;
757 thread->ref = t_ptr;
758 }
759 }
760
761 AWAKEN(m);
762 }
763 pthread_mutex_unlock(&m->mtx);
764
765 return thread;
718e3744 766}
767
56a94b36 768static struct thread *
d62a17ae 769funcname_thread_add_timer_timeval(struct thread_master *m,
770 int (*func)(struct thread *), int type,
771 void *arg, struct timeval *time_relative,
772 struct thread **t_ptr, debugargdef)
718e3744 773{
d62a17ae 774 struct thread *thread;
775 struct pqueue *queue;
776
777 assert(m != NULL);
778
779 assert(type == THREAD_TIMER);
780 assert(time_relative);
781
782 pthread_mutex_lock(&m->mtx);
783 {
784 if (t_ptr
785 && *t_ptr) // thread is already scheduled; don't reschedule
786 {
787 pthread_mutex_unlock(&m->mtx);
788 return NULL;
789 }
790
791 queue = m->timer;
792 thread = thread_get(m, type, func, arg, debugargpass);
793
794 pthread_mutex_lock(&thread->mtx);
795 {
796 monotime(&thread->u.sands);
797 timeradd(&thread->u.sands, time_relative,
798 &thread->u.sands);
799 pqueue_enqueue(thread, queue);
800 if (t_ptr) {
801 *t_ptr = thread;
802 thread->ref = t_ptr;
803 }
804 }
805 pthread_mutex_unlock(&thread->mtx);
806
807 AWAKEN(m);
808 }
809 pthread_mutex_unlock(&m->mtx);
810
811 return thread;
9e867fe6 812}
813
98c91ac6 814
815/* Add timer event thread. */
d62a17ae 816struct thread *funcname_thread_add_timer(struct thread_master *m,
817 int (*func)(struct thread *),
818 void *arg, long timer,
819 struct thread **t_ptr, debugargdef)
9e867fe6 820{
d62a17ae 821 struct timeval trel;
9e867fe6 822
d62a17ae 823 assert(m != NULL);
9e867fe6 824
d62a17ae 825 trel.tv_sec = timer;
826 trel.tv_usec = 0;
9e867fe6 827
d62a17ae 828 return funcname_thread_add_timer_timeval(m, func, THREAD_TIMER, arg,
829 &trel, t_ptr, debugargpass);
98c91ac6 830}
9e867fe6 831
98c91ac6 832/* Add timer event thread with "millisecond" resolution */
d62a17ae 833struct thread *funcname_thread_add_timer_msec(struct thread_master *m,
834 int (*func)(struct thread *),
835 void *arg, long timer,
836 struct thread **t_ptr,
837 debugargdef)
98c91ac6 838{
d62a17ae 839 struct timeval trel;
9e867fe6 840
d62a17ae 841 assert(m != NULL);
718e3744 842
d62a17ae 843 trel.tv_sec = timer / 1000;
844 trel.tv_usec = 1000 * (timer % 1000);
98c91ac6 845
d62a17ae 846 return funcname_thread_add_timer_timeval(m, func, THREAD_TIMER, arg,
847 &trel, t_ptr, debugargpass);
a48b4e6d 848}
849
d03c4cbd 850/* Add timer event thread with "millisecond" resolution */
d62a17ae 851struct thread *funcname_thread_add_timer_tv(struct thread_master *m,
852 int (*func)(struct thread *),
853 void *arg, struct timeval *tv,
854 struct thread **t_ptr, debugargdef)
d03c4cbd 855{
d62a17ae 856 return funcname_thread_add_timer_timeval(m, func, THREAD_TIMER, arg, tv,
857 t_ptr, debugargpass);
d03c4cbd
DL
858}
859
718e3744 860/* Add simple event thread. */
d62a17ae 861struct thread *funcname_thread_add_event(struct thread_master *m,
862 int (*func)(struct thread *),
863 void *arg, int val,
864 struct thread **t_ptr, debugargdef)
718e3744 865{
d62a17ae 866 struct thread *thread;
867
868 assert(m != NULL);
869
870 pthread_mutex_lock(&m->mtx);
871 {
872 if (t_ptr
873 && *t_ptr) // thread is already scheduled; don't reschedule
874 {
875 pthread_mutex_unlock(&m->mtx);
876 return NULL;
877 }
878
879 thread = thread_get(m, THREAD_EVENT, func, arg, debugargpass);
880 pthread_mutex_lock(&thread->mtx);
881 {
882 thread->u.val = val;
883 thread_list_add(&m->event, thread);
884 }
885 pthread_mutex_unlock(&thread->mtx);
886
887 if (t_ptr) {
888 *t_ptr = thread;
889 thread->ref = t_ptr;
890 }
891
892 AWAKEN(m);
893 }
894 pthread_mutex_unlock(&m->mtx);
895
896 return thread;
718e3744 897}
898
63ccb9cb
QY
899/* Thread cancellation ------------------------------------------------------ */
900
8797240e
QY
901/**
902 * NOT's out the .events field of pollfd corresponding to the given file
903 * descriptor. The event to be NOT'd is passed in the 'state' parameter.
904 *
905 * This needs to happen for both copies of pollfd's. See 'thread_fetch'
906 * implementation for details.
907 *
908 * @param master
909 * @param fd
910 * @param state the event to cancel. One or more (OR'd together) of the
911 * following:
912 * - POLLIN
913 * - POLLOUT
914 */
d62a17ae 915static void thread_cancel_rw(struct thread_master *master, int fd, short state)
0a95a0d0 916{
d62a17ae 917 /* Cancel POLLHUP too just in case some bozo set it */
918 state |= POLLHUP;
919
920 /* find the index of corresponding pollfd */
921 nfds_t i;
922
923 for (i = 0; i < master->handler.pfdcount; i++)
924 if (master->handler.pfds[i].fd == fd)
925 break;
926
927 /* NOT out event. */
928 master->handler.pfds[i].events &= ~(state);
929
930 /* If all events are canceled, delete / resize the pollfd array. */
931 if (master->handler.pfds[i].events == 0) {
932 memmove(master->handler.pfds + i, master->handler.pfds + i + 1,
933 (master->handler.pfdcount - i - 1)
934 * sizeof(struct pollfd));
935 master->handler.pfdcount--;
936 }
937
938 /* If we have the same pollfd in the copy, perform the same operations,
939 * otherwise return. */
940 if (i >= master->handler.copycount)
941 return;
942
943 master->handler.copy[i].events &= ~(state);
944
945 if (master->handler.copy[i].events == 0) {
946 memmove(master->handler.copy + i, master->handler.copy + i + 1,
947 (master->handler.copycount - i - 1)
948 * sizeof(struct pollfd));
949 master->handler.copycount--;
950 }
0a95a0d0
DS
951}
952
1189d95f 953/**
63ccb9cb 954 * Process cancellation requests.
1189d95f 955 *
63ccb9cb
QY
956 * This may only be run from the pthread which owns the thread_master.
957 *
958 * @param master the thread master to process
959 * @REQUIRE master->mtx
1189d95f 960 */
d62a17ae 961static void do_thread_cancel(struct thread_master *master)
718e3744 962{
d62a17ae 963 struct thread_list *list = NULL;
964 struct pqueue *queue = NULL;
965 struct thread **thread_array = NULL;
966 struct thread *thread;
967
968 struct cancel_req *cr;
969 struct listnode *ln;
970 for (ALL_LIST_ELEMENTS_RO(master->cancel_req, ln, cr)) {
971 /* If this is an event object cancellation, linear search
972 * through event
973 * list deleting any events which have the specified argument.
974 * We also
975 * need to check every thread in the ready queue. */
976 if (cr->eventobj) {
977 struct thread *t;
978 thread = master->event.head;
979
980 while (thread) {
981 t = thread;
982 thread = t->next;
983
984 if (t->arg == cr->eventobj) {
985 thread_list_delete(&master->event, t);
986 if (t->ref)
987 *t->ref = NULL;
988 thread_add_unuse(master, t);
989 }
990 }
991
992 thread = master->ready.head;
993 while (thread) {
994 t = thread;
995 thread = t->next;
996
997 if (t->arg == cr->eventobj) {
998 thread_list_delete(&master->ready, t);
999 if (t->ref)
1000 *t->ref = NULL;
1001 thread_add_unuse(master, t);
1002 }
1003 }
1004 continue;
1005 }
1006
1007 /* The pointer varies depending on whether the cancellation
1008 * request was
1009 * made asynchronously or not. If it was, we need to check
1010 * whether the
1011 * thread even exists anymore before cancelling it. */
1012 thread = (cr->thread) ? cr->thread : *cr->threadref;
1013
1014 if (!thread)
1015 continue;
1016
1017 /* Determine the appropriate queue to cancel the thread from */
1018 switch (thread->type) {
1019 case THREAD_READ:
1020 thread_cancel_rw(master, thread->u.fd, POLLIN);
1021 thread_array = master->read;
1022 break;
1023 case THREAD_WRITE:
1024 thread_cancel_rw(master, thread->u.fd, POLLOUT);
1025 thread_array = master->write;
1026 break;
1027 case THREAD_TIMER:
1028 queue = master->timer;
1029 break;
1030 case THREAD_EVENT:
1031 list = &master->event;
1032 break;
1033 case THREAD_READY:
1034 list = &master->ready;
1035 break;
1036 default:
1037 continue;
1038 break;
1039 }
1040
1041 if (queue) {
1042 assert(thread->index >= 0);
1043 pqueue_remove(thread, queue);
1044 } else if (list) {
1045 thread_list_delete(list, thread);
1046 } else if (thread_array) {
1047 thread_array[thread->u.fd] = NULL;
1048 } else {
1049 assert(!"Thread should be either in queue or list or array!");
1050 }
1051
1052 if (thread->ref)
1053 *thread->ref = NULL;
1054
1055 thread_add_unuse(thread->master, thread);
1056 }
1057
1058 /* Delete and free all cancellation requests */
1059 list_delete_all_node(master->cancel_req);
1060
1061 /* Wake up any threads which may be blocked in thread_cancel_async() */
1062 master->canceled = true;
1063 pthread_cond_broadcast(&master->cancel_cond);
718e3744 1064}
1065
63ccb9cb
QY
1066/**
1067 * Cancel any events which have the specified argument.
1068 *
1069 * MT-Unsafe
1070 *
1071 * @param m the thread_master to cancel from
1072 * @param arg the argument passed when creating the event
1073 */
d62a17ae 1074void thread_cancel_event(struct thread_master *master, void *arg)
718e3744 1075{
d62a17ae 1076 assert(master->owner == pthread_self());
1077
1078 pthread_mutex_lock(&master->mtx);
1079 {
1080 struct cancel_req *cr =
1081 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1082 cr->eventobj = arg;
1083 listnode_add(master->cancel_req, cr);
1084 do_thread_cancel(master);
1085 }
1086 pthread_mutex_unlock(&master->mtx);
63ccb9cb 1087}
1189d95f 1088
63ccb9cb
QY
1089/**
1090 * Cancel a specific task.
1091 *
1092 * MT-Unsafe
1093 *
1094 * @param thread task to cancel
1095 */
d62a17ae 1096void thread_cancel(struct thread *thread)
63ccb9cb 1097{
d62a17ae 1098 assert(thread->master->owner == pthread_self());
1099
1100 pthread_mutex_lock(&thread->master->mtx);
1101 {
1102 struct cancel_req *cr =
1103 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1104 cr->thread = thread;
1105 listnode_add(thread->master->cancel_req, cr);
1106 do_thread_cancel(thread->master);
1107 }
1108 pthread_mutex_unlock(&thread->master->mtx);
63ccb9cb 1109}
1189d95f 1110
63ccb9cb
QY
1111/**
1112 * Asynchronous cancellation.
1113 *
8797240e
QY
1114 * Called with either a struct thread ** or void * to an event argument,
1115 * this function posts the correct cancellation request and blocks until it is
1116 * serviced.
63ccb9cb
QY
1117 *
1118 * If the thread is currently running, execution blocks until it completes.
1119 *
8797240e
QY
1120 * The last two parameters are mutually exclusive, i.e. if you pass one the
1121 * other must be NULL.
1122 *
1123 * When the cancellation procedure executes on the target thread_master, the
1124 * thread * provided is checked for nullity. If it is null, the thread is
1125 * assumed to no longer exist and the cancellation request is a no-op. Thus
1126 * users of this API must pass a back-reference when scheduling the original
1127 * task.
1128 *
63ccb9cb
QY
1129 * MT-Safe
1130 *
8797240e
QY
1131 * @param master the thread master with the relevant event / task
1132 * @param thread pointer to thread to cancel
1133 * @param eventobj the event
63ccb9cb 1134 */
d62a17ae 1135void thread_cancel_async(struct thread_master *master, struct thread **thread,
1136 void *eventobj)
63ccb9cb 1137{
d62a17ae 1138 assert(!(thread && eventobj) && (thread || eventobj));
1139 assert(master->owner != pthread_self());
1140
1141 pthread_mutex_lock(&master->mtx);
1142 {
1143 master->canceled = false;
1144
1145 if (thread) {
1146 struct cancel_req *cr =
1147 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1148 cr->threadref = thread;
1149 listnode_add(master->cancel_req, cr);
1150 } else if (eventobj) {
1151 struct cancel_req *cr =
1152 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1153 cr->eventobj = eventobj;
1154 listnode_add(master->cancel_req, cr);
1155 }
1156 AWAKEN(master);
1157
1158 while (!master->canceled)
1159 pthread_cond_wait(&master->cancel_cond, &master->mtx);
1160 }
1161 pthread_mutex_unlock(&master->mtx);
718e3744 1162}
63ccb9cb 1163/* ------------------------------------------------------------------------- */
718e3744 1164
d62a17ae 1165static struct timeval *thread_timer_wait(struct pqueue *queue,
1166 struct timeval *timer_val)
718e3744 1167{
d62a17ae 1168 if (queue->size) {
1169 struct thread *next_timer = queue->array[0];
1170 monotime_until(&next_timer->u.sands, timer_val);
1171 return timer_val;
1172 }
1173 return NULL;
718e3744 1174}
718e3744 1175
d62a17ae 1176static struct thread *thread_run(struct thread_master *m, struct thread *thread,
1177 struct thread *fetch)
718e3744 1178{
d62a17ae 1179 *fetch = *thread;
1180 thread_add_unuse(m, thread);
1181 return fetch;
718e3744 1182}
1183
d62a17ae 1184static int thread_process_io_helper(struct thread_master *m,
1185 struct thread *thread, short state, int pos)
5d4ccd4e 1186{
d62a17ae 1187 struct thread **thread_array;
1188
1189 if (!thread)
1190 return 0;
1191
1192 if (thread->type == THREAD_READ)
1193 thread_array = m->read;
1194 else
1195 thread_array = m->write;
1196
1197 thread_array[thread->u.fd] = NULL;
1198 thread_list_add(&m->ready, thread);
1199 thread->type = THREAD_READY;
1200 /* if another pthread scheduled this file descriptor for the event we're
1201 * responding to, no problem; we're getting to it now */
1202 thread->master->handler.pfds[pos].events &= ~(state);
1203 return 1;
5d4ccd4e
DS
1204}
1205
8797240e
QY
1206/**
1207 * Process I/O events.
1208 *
1209 * Walks through file descriptor array looking for those pollfds whose .revents
1210 * field has something interesting. Deletes any invalid file descriptors.
1211 *
1212 * @param m the thread master
1213 * @param num the number of active file descriptors (return value of poll())
1214 */
d62a17ae 1215static void thread_process_io(struct thread_master *m, unsigned int num)
0a95a0d0 1216{
d62a17ae 1217 unsigned int ready = 0;
1218 struct pollfd *pfds = m->handler.copy;
1219
1220 for (nfds_t i = 0; i < m->handler.copycount && ready < num; ++i) {
1221 /* no event for current fd? immediately continue */
1222 if (pfds[i].revents == 0)
1223 continue;
1224
1225 ready++;
1226
1227 /* Unless someone has called thread_cancel from another pthread,
1228 * the only
1229 * thing that could have changed in m->handler.pfds while we
1230 * were
1231 * asleep is the .events field in a given pollfd. Barring
1232 * thread_cancel()
1233 * that value should be a superset of the values we have in our
1234 * copy, so
1235 * there's no need to update it. Similarily, barring deletion,
1236 * the fd
1237 * should still be a valid index into the master's pfds. */
1238 if (pfds[i].revents & (POLLIN | POLLHUP))
1239 thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN,
1240 i);
1241 if (pfds[i].revents & POLLOUT)
1242 thread_process_io_helper(m, m->write[pfds[i].fd],
1243 POLLOUT, i);
1244
1245 /* if one of our file descriptors is garbage, remove the same
1246 * from
1247 * both pfds + update sizes and index */
1248 if (pfds[i].revents & POLLNVAL) {
1249 memmove(m->handler.pfds + i, m->handler.pfds + i + 1,
1250 (m->handler.pfdcount - i - 1)
1251 * sizeof(struct pollfd));
1252 m->handler.pfdcount--;
1253
1254 memmove(pfds + i, pfds + i + 1,
1255 (m->handler.copycount - i - 1)
1256 * sizeof(struct pollfd));
1257 m->handler.copycount--;
1258
1259 i--;
1260 }
1261 }
718e3744 1262}
1263
8b70d0b0 1264/* Add all timers that have popped to the ready list. */
d62a17ae 1265static unsigned int thread_process_timers(struct pqueue *queue,
1266 struct timeval *timenow)
a48b4e6d 1267{
d62a17ae 1268 struct thread *thread;
1269 unsigned int ready = 0;
1270
1271 while (queue->size) {
1272 thread = queue->array[0];
1273 if (timercmp(timenow, &thread->u.sands, <))
1274 return ready;
1275 pqueue_dequeue(queue);
1276 thread->type = THREAD_READY;
1277 thread_list_add(&thread->master->ready, thread);
1278 ready++;
1279 }
1280 return ready;
a48b4e6d 1281}
1282
2613abe6 1283/* process a list en masse, e.g. for event thread lists */
d62a17ae 1284static unsigned int thread_process(struct thread_list *list)
2613abe6 1285{
d62a17ae 1286 struct thread *thread;
1287 struct thread *next;
1288 unsigned int ready = 0;
1289
1290 for (thread = list->head; thread; thread = next) {
1291 next = thread->next;
1292 thread_list_delete(list, thread);
1293 thread->type = THREAD_READY;
1294 thread_list_add(&thread->master->ready, thread);
1295 ready++;
1296 }
1297 return ready;
2613abe6
PJ
1298}
1299
1300
718e3744 1301/* Fetch next ready thread. */
d62a17ae 1302struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
718e3744 1303{
d62a17ae 1304 struct thread *thread = NULL;
1305 struct timeval now;
1306 struct timeval zerotime = {0, 0};
1307 struct timeval tv;
1308 struct timeval *tw = NULL;
1309
1310 int num = 0;
1311
1312 do {
1313 /* Handle signals if any */
1314 if (m->handle_signals)
1315 quagga_sigevent_process();
1316
1317 pthread_mutex_lock(&m->mtx);
1318
1319 /* Process any pending cancellation requests */
1320 do_thread_cancel(m);
1321
bca37d17
QY
1322 /*
1323 * Post events to ready queue. This must come before the
1324 * following block since events should occur immediately
1325 */
d62a17ae 1326 thread_process(&m->event);
1327
bca37d17
QY
1328 /*
1329 * If there are no tasks on the ready queue, we will poll()
1330 * until a timer expires or we receive I/O, whichever comes
1331 * first. The strategy for doing this is:
d62a17ae 1332 *
1333 * - If there are events pending, set the poll() timeout to zero
1334 * - If there are no events pending, but there are timers
1335 * pending, set the
1336 * timeout to the smallest remaining time on any timer
1337 * - If there are neither timers nor events pending, but there
1338 * are file
1339 * descriptors pending, block indefinitely in poll()
1340 * - If nothing is pending, it's time for the application to die
1341 *
1342 * In every case except the last, we need to hit poll() at least
bca37d17
QY
1343 * once per loop to avoid starvation by events
1344 */
d62a17ae 1345 if (m->ready.count == 0)
1346 tw = thread_timer_wait(m->timer, &tv);
1347
1348 if (m->ready.count != 0 || (tw && !timercmp(tw, &zerotime, >)))
1349 tw = &zerotime;
1350
1351 if (!tw && m->handler.pfdcount == 0) { /* die */
1352 pthread_mutex_unlock(&m->mtx);
1353 fetch = NULL;
1354 break;
1355 }
1356
bca37d17
QY
1357 /*
1358 * Copy pollfd array + # active pollfds in it. Not necessary to
1359 * copy the array size as this is fixed.
1360 */
d62a17ae 1361 m->handler.copycount = m->handler.pfdcount;
1362 memcpy(m->handler.copy, m->handler.pfds,
1363 m->handler.copycount * sizeof(struct pollfd));
1364
d764d2cc
QY
1365 /*
1366 * Attempt to flush ready queue before going into poll().
1367 * This is performance-critical. Think twice before modifying.
1368 */
1369 if (m->ready.count == 0 || m->tick_since_io >= MAX_TICK_IO) {
1370 pthread_mutex_unlock(&m->mtx);
1371 {
1372 m->tick_since_io = 0;
1373 num = fd_poll(m, m->handler.copy,
1374 m->handler.pfdsize,
1375 m->handler.copycount, tw);
1376 }
1377 pthread_mutex_lock(&m->mtx);
d62a17ae 1378
d764d2cc
QY
1379 /* Handle any errors received in poll() */
1380 if (num < 0) {
1381 if (errno == EINTR) {
1382 pthread_mutex_unlock(&m->mtx);
1383 /* loop around to signal handler */
1384 continue;
1385 }
1386
1387 /* else die */
1388 zlog_warn("poll() error: %s",
1389 safe_strerror(errno));
d62a17ae 1390 pthread_mutex_unlock(&m->mtx);
d764d2cc
QY
1391 fetch = NULL;
1392 break;
d62a17ae 1393 }
1394
bca37d17
QY
1395 /*
1396 * Since we could have received more cancellation
1397 * requests during poll(), process those
1398 */
d764d2cc 1399 do_thread_cancel(m);
d62a17ae 1400
bca37d17 1401 } else {
d764d2cc 1402 m->tick_since_io++;
bca37d17 1403 }
d62a17ae 1404
1405 /* Post timers to ready queue. */
1406 monotime(&now);
1407 thread_process_timers(m->timer, &now);
1408
1409 /* Post I/O to ready queue. */
1410 if (num > 0)
1411 thread_process_io(m, num);
1412
bca37d17 1413 /* have a ready task ==> return it to caller */
d62a17ae 1414 if ((thread = thread_trim_head(&m->ready))) {
1415 fetch = thread_run(m, thread, fetch);
1416 if (fetch->ref)
1417 *fetch->ref = NULL;
1418 }
1419
1420 pthread_mutex_unlock(&m->mtx);
1421
1422 } while (!thread && m->spin);
1423
1424 return fetch;
718e3744 1425}
1426
d62a17ae 1427static unsigned long timeval_elapsed(struct timeval a, struct timeval b)
62f44022 1428{
d62a17ae 1429 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
1430 + (a.tv_usec - b.tv_usec));
62f44022
QY
1431}
1432
d62a17ae 1433unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start,
1434 unsigned long *cputime)
718e3744 1435{
d62a17ae 1436 /* This is 'user + sys' time. */
1437 *cputime = timeval_elapsed(now->cpu.ru_utime, start->cpu.ru_utime)
1438 + timeval_elapsed(now->cpu.ru_stime, start->cpu.ru_stime);
1439 return timeval_elapsed(now->real, start->real);
8b70d0b0 1440}
1441
50596be0
DS
1442/* We should aim to yield after yield milliseconds, which defaults
1443 to THREAD_YIELD_TIME_SLOT .
8b70d0b0 1444 Note: we are using real (wall clock) time for this calculation.
1445 It could be argued that CPU time may make more sense in certain
1446 contexts. The things to consider are whether the thread may have
1447 blocked (in which case wall time increases, but CPU time does not),
1448 or whether the system is heavily loaded with other processes competing
d62a17ae 1449 for CPU time. On balance, wall clock time seems to make sense.
8b70d0b0 1450 Plus it has the added benefit that gettimeofday should be faster
1451 than calling getrusage. */
d62a17ae 1452int thread_should_yield(struct thread *thread)
718e3744 1453{
d62a17ae 1454 int result;
1455 pthread_mutex_lock(&thread->mtx);
1456 {
1457 result = monotime_since(&thread->real, NULL)
1458 > (int64_t)thread->yield;
1459 }
1460 pthread_mutex_unlock(&thread->mtx);
1461 return result;
50596be0
DS
1462}
1463
d62a17ae 1464void thread_set_yield_time(struct thread *thread, unsigned long yield_time)
50596be0 1465{
d62a17ae 1466 pthread_mutex_lock(&thread->mtx);
1467 {
1468 thread->yield = yield_time;
1469 }
1470 pthread_mutex_unlock(&thread->mtx);
718e3744 1471}
1472
d62a17ae 1473void thread_getrusage(RUSAGE_T *r)
db9c0df9 1474{
d62a17ae 1475 monotime(&r->real);
1476 getrusage(RUSAGE_SELF, &(r->cpu));
db9c0df9
PJ
1477}
1478
718e3744 1479/* We check thread consumed time. If the system has getrusage, we'll
8b70d0b0 1480 use that to get in-depth stats on the performance of the thread in addition
1481 to wall clock time stats from gettimeofday. */
d62a17ae 1482void thread_call(struct thread *thread)
718e3744 1483{
d62a17ae 1484 unsigned long realtime, cputime;
1485 RUSAGE_T before, after;
cc8b13a0 1486
d62a17ae 1487 GETRUSAGE(&before);
1488 thread->real = before.real;
718e3744 1489
d62a17ae 1490 pthread_setspecific(thread_current, thread);
1491 (*thread->func)(thread);
1492 pthread_setspecific(thread_current, NULL);
718e3744 1493
d62a17ae 1494 GETRUSAGE(&after);
718e3744 1495
d62a17ae 1496 realtime = thread_consumed_time(&after, &before, &cputime);
1497 thread->hist->real.total += realtime;
1498 if (thread->hist->real.max < realtime)
1499 thread->hist->real.max = realtime;
1500 thread->hist->cpu.total += cputime;
1501 if (thread->hist->cpu.max < cputime)
1502 thread->hist->cpu.max = cputime;
e04ab74d 1503
d62a17ae 1504 ++(thread->hist->total_calls);
1505 thread->hist->types |= (1 << thread->add_type);
718e3744 1506
924b9229 1507#ifdef CONSUMED_TIME_CHECK
d62a17ae 1508 if (realtime > CONSUMED_TIME_CHECK) {
1509 /*
1510 * We have a CPU Hog on our hands.
1511 * Whinge about it now, so we're aware this is yet another task
1512 * to fix.
1513 */
1514 zlog_warn(
1515 "SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
1516 thread->funcname, (unsigned long)thread->func,
1517 realtime / 1000, cputime / 1000);
1518 }
924b9229 1519#endif /* CONSUMED_TIME_CHECK */
718e3744 1520}
1521
1522/* Execute thread */
d62a17ae 1523void funcname_thread_execute(struct thread_master *m,
1524 int (*func)(struct thread *), void *arg, int val,
1525 debugargdef)
718e3744 1526{
d62a17ae 1527 struct cpu_thread_history tmp;
1528 struct thread dummy;
718e3744 1529
d62a17ae 1530 memset(&dummy, 0, sizeof(struct thread));
718e3744 1531
d62a17ae 1532 pthread_mutex_init(&dummy.mtx, NULL);
1533 dummy.type = THREAD_EVENT;
1534 dummy.add_type = THREAD_EXECUTE;
1535 dummy.master = NULL;
1536 dummy.arg = arg;
1537 dummy.u.val = val;
9c7753e4 1538
d62a17ae 1539 tmp.func = dummy.func = func;
1540 tmp.funcname = dummy.funcname = funcname;
1541 dummy.hist = hash_get(m->cpu_record, &tmp,
1542 (void *(*)(void *))cpu_record_hash_alloc);
f7c62e11 1543
d62a17ae 1544 dummy.schedfrom = schedfrom;
1545 dummy.schedfrom_line = fromln;
9c7753e4 1546
d62a17ae 1547 thread_call(&dummy);
718e3744 1548}