]> git.proxmox.com Git - mirror_frr.git/blame - lib/thread.c
Merge pull request #2080 from qlyoung/docuser
[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"
bd74dc61 34#include "jhash.h"
d6be5fb9 35
d62a17ae 36DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread")
4a1ab8e4 37DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master")
d62a17ae 38DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
4a1ab8e4 39
3b96b781
HT
40#if defined(__APPLE__)
41#include <mach/mach.h>
42#include <mach/mach_time.h>
43#endif
44
d62a17ae 45#define AWAKEN(m) \
46 do { \
47 static unsigned char wakebyte = 0x01; \
48 write(m->io_pipe[1], &wakebyte, 1); \
49 } while (0);
3bf2673b 50
62f44022 51/* control variable for initializer */
e0bebc7c 52pthread_once_t init_once = PTHREAD_ONCE_INIT;
e0bebc7c 53pthread_key_t thread_current;
6b0655a2 54
62f44022
QY
55pthread_mutex_t masters_mtx = PTHREAD_MUTEX_INITIALIZER;
56static struct list *masters;
57
6b0655a2 58
62f44022 59/* CLI start ---------------------------------------------------------------- */
d62a17ae 60static unsigned int cpu_record_hash_key(struct cpu_thread_history *a)
e04ab74d 61{
996c9314 62 int size = sizeof(&a->func);
bd74dc61
DS
63
64 return jhash(&a->func, size, 0);
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{
d1667f53 92 vty_out(vty, "%5d %10lu.%03lu %9u %8lu %9lu %8lu %9lu", a->total_active,
d62a17ae 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
d62a17ae 346struct thread_master *thread_master_create(const char *name)
718e3744 347{
d62a17ae 348 struct thread_master *rv;
349 struct rlimit limit;
350
351 pthread_once(&init_once, &initializer);
352
353 rv = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct thread_master));
354 if (rv == NULL)
355 return NULL;
356
357 /* Initialize master mutex */
358 pthread_mutex_init(&rv->mtx, NULL);
359 pthread_cond_init(&rv->cancel_cond, NULL);
360
361 /* Set name */
362 rv->name = name ? XSTRDUP(MTYPE_THREAD_MASTER, name) : NULL;
363
364 /* Initialize I/O task data structures */
365 getrlimit(RLIMIT_NOFILE, &limit);
366 rv->fd_limit = (int)limit.rlim_cur;
367 rv->read =
368 XCALLOC(MTYPE_THREAD, sizeof(struct thread *) * rv->fd_limit);
369 if (rv->read == NULL) {
370 XFREE(MTYPE_THREAD_MASTER, rv);
371 return NULL;
372 }
373 rv->write =
374 XCALLOC(MTYPE_THREAD, sizeof(struct thread *) * rv->fd_limit);
375 if (rv->write == NULL) {
376 XFREE(MTYPE_THREAD, rv->read);
377 XFREE(MTYPE_THREAD_MASTER, rv);
378 return NULL;
379 }
380
bd74dc61 381 rv->cpu_record = hash_create_size(
996c9314 382 8, (unsigned int (*)(void *))cpu_record_hash_key,
bd74dc61
DS
383 (int (*)(const void *, const void *))cpu_record_hash_cmp,
384 "Thread Hash");
d62a17ae 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
d8a8a8de
QY
428void thread_master_set_name(struct thread_master *master, const char *name)
429{
430 pthread_mutex_lock(&master->mtx);
431 {
432 if (master->name)
433 XFREE(MTYPE_THREAD_MASTER, master->name);
434 master->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
435 }
436 pthread_mutex_unlock(&master->mtx);
437}
438
718e3744 439/* Add a new thread to the list. */
d62a17ae 440static void thread_list_add(struct thread_list *list, struct thread *thread)
718e3744 441{
d62a17ae 442 thread->next = NULL;
443 thread->prev = list->tail;
444 if (list->tail)
445 list->tail->next = thread;
446 else
447 list->head = thread;
448 list->tail = thread;
449 list->count++;
718e3744 450}
451
718e3744 452/* Delete a thread from the list. */
d62a17ae 453static struct thread *thread_list_delete(struct thread_list *list,
454 struct thread *thread)
718e3744 455{
d62a17ae 456 if (thread->next)
457 thread->next->prev = thread->prev;
458 else
459 list->tail = thread->prev;
460 if (thread->prev)
461 thread->prev->next = thread->next;
462 else
463 list->head = thread->next;
464 thread->next = thread->prev = NULL;
465 list->count--;
466 return thread;
718e3744 467}
468
495f0b13 469/* Thread list is empty or not. */
d62a17ae 470static int thread_empty(struct thread_list *list)
495f0b13 471{
d62a17ae 472 return list->head ? 0 : 1;
495f0b13
DS
473}
474
475/* Delete top of the list and return it. */
d62a17ae 476static struct thread *thread_trim_head(struct thread_list *list)
495f0b13 477{
d62a17ae 478 if (!thread_empty(list))
479 return thread_list_delete(list, list->head);
480 return NULL;
495f0b13
DS
481}
482
718e3744 483/* Move thread to unuse list. */
d62a17ae 484static void thread_add_unuse(struct thread_master *m, struct thread *thread)
718e3744 485{
d62a17ae 486 assert(m != NULL && thread != NULL);
487 assert(thread->next == NULL);
488 assert(thread->prev == NULL);
489 thread->ref = NULL;
490
491 thread->type = THREAD_UNUSED;
492 thread->hist->total_active--;
493 thread_list_add(&m->unuse, thread);
718e3744 494}
495
496/* Free all unused thread. */
d62a17ae 497static void thread_list_free(struct thread_master *m, struct thread_list *list)
718e3744 498{
d62a17ae 499 struct thread *t;
500 struct thread *next;
501
502 for (t = list->head; t; t = next) {
503 next = t->next;
504 XFREE(MTYPE_THREAD, t);
505 list->count--;
506 m->alloc--;
507 }
718e3744 508}
509
d62a17ae 510static void thread_array_free(struct thread_master *m,
511 struct thread **thread_array)
308d14ae 512{
d62a17ae 513 struct thread *t;
514 int index;
515
516 for (index = 0; index < m->fd_limit; ++index) {
517 t = thread_array[index];
518 if (t) {
519 thread_array[index] = NULL;
520 XFREE(MTYPE_THREAD, t);
521 m->alloc--;
522 }
523 }
524 XFREE(MTYPE_THREAD, thread_array);
308d14ae
DV
525}
526
d62a17ae 527static void thread_queue_free(struct thread_master *m, struct pqueue *queue)
4becea72 528{
d62a17ae 529 int i;
4becea72 530
d62a17ae 531 for (i = 0; i < queue->size; i++)
532 XFREE(MTYPE_THREAD, queue->array[i]);
4becea72 533
d62a17ae 534 m->alloc -= queue->size;
535 pqueue_delete(queue);
4becea72
CF
536}
537
495f0b13
DS
538/*
539 * thread_master_free_unused
540 *
541 * As threads are finished with they are put on the
542 * unuse list for later reuse.
543 * If we are shutting down, Free up unused threads
544 * So we can see if we forget to shut anything off
545 */
d62a17ae 546void thread_master_free_unused(struct thread_master *m)
495f0b13 547{
d62a17ae 548 pthread_mutex_lock(&m->mtx);
549 {
550 struct thread *t;
551 while ((t = thread_trim_head(&m->unuse)) != NULL) {
552 pthread_mutex_destroy(&t->mtx);
553 XFREE(MTYPE_THREAD, t);
554 }
555 }
556 pthread_mutex_unlock(&m->mtx);
495f0b13
DS
557}
558
718e3744 559/* Stop thread scheduler. */
d62a17ae 560void thread_master_free(struct thread_master *m)
718e3744 561{
d62a17ae 562 pthread_mutex_lock(&masters_mtx);
563 {
564 listnode_delete(masters, m);
eff09c66 565 if (masters->count == 0) {
acdf5e25 566 list_delete_and_null(&masters);
eff09c66 567 }
d62a17ae 568 }
569 pthread_mutex_unlock(&masters_mtx);
570
571 thread_array_free(m, m->read);
572 thread_array_free(m, m->write);
573 thread_queue_free(m, m->timer);
574 thread_list_free(m, &m->event);
575 thread_list_free(m, &m->ready);
576 thread_list_free(m, &m->unuse);
577 pthread_mutex_destroy(&m->mtx);
33844bbe 578 pthread_cond_destroy(&m->cancel_cond);
d62a17ae 579 close(m->io_pipe[0]);
580 close(m->io_pipe[1]);
affe9e99 581 list_delete_and_null(&m->cancel_req);
1a0a92ea 582 m->cancel_req = NULL;
d62a17ae 583
584 hash_clean(m->cpu_record, cpu_record_hash_free);
585 hash_free(m->cpu_record);
586 m->cpu_record = NULL;
587
4e1000a1
QY
588 if (m->name)
589 XFREE(MTYPE_THREAD_MASTER, m->name);
d62a17ae 590 XFREE(MTYPE_THREAD_MASTER, m->handler.pfds);
591 XFREE(MTYPE_THREAD_MASTER, m->handler.copy);
592 XFREE(MTYPE_THREAD_MASTER, m);
718e3744 593}
594
718e3744 595/* Return remain time in second. */
d62a17ae 596unsigned long thread_timer_remain_second(struct thread *thread)
718e3744 597{
d62a17ae 598 int64_t remain;
1189d95f 599
d62a17ae 600 pthread_mutex_lock(&thread->mtx);
601 {
602 remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
603 }
604 pthread_mutex_unlock(&thread->mtx);
1189d95f 605
d62a17ae 606 return remain < 0 ? 0 : remain;
718e3744 607}
608
9c7753e4
DL
609#define debugargdef const char *funcname, const char *schedfrom, int fromln
610#define debugargpass funcname, schedfrom, fromln
e04ab74d 611
d62a17ae 612struct timeval thread_timer_remain(struct thread *thread)
6ac44687 613{
d62a17ae 614 struct timeval remain;
615 pthread_mutex_lock(&thread->mtx);
616 {
617 monotime_until(&thread->u.sands, &remain);
618 }
619 pthread_mutex_unlock(&thread->mtx);
620 return remain;
6ac44687
CF
621}
622
718e3744 623/* Get new thread. */
d7c0a89a 624static struct thread *thread_get(struct thread_master *m, uint8_t type,
d62a17ae 625 int (*func)(struct thread *), void *arg,
626 debugargdef)
718e3744 627{
d62a17ae 628 struct thread *thread = thread_trim_head(&m->unuse);
629 struct cpu_thread_history tmp;
630
631 if (!thread) {
632 thread = XCALLOC(MTYPE_THREAD, sizeof(struct thread));
633 /* mutex only needs to be initialized at struct creation. */
634 pthread_mutex_init(&thread->mtx, NULL);
635 m->alloc++;
636 }
637
638 thread->type = type;
639 thread->add_type = type;
640 thread->master = m;
641 thread->arg = arg;
642 thread->index = -1;
643 thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
644 thread->ref = NULL;
645
646 /*
647 * So if the passed in funcname is not what we have
648 * stored that means the thread->hist needs to be
649 * updated. We keep the last one around in unused
650 * under the assumption that we are probably
651 * going to immediately allocate the same
652 * type of thread.
653 * This hopefully saves us some serious
654 * hash_get lookups.
655 */
656 if (thread->funcname != funcname || thread->func != func) {
657 tmp.func = func;
658 tmp.funcname = funcname;
659 thread->hist =
660 hash_get(m->cpu_record, &tmp,
661 (void *(*)(void *))cpu_record_hash_alloc);
662 }
663 thread->hist->total_active++;
664 thread->func = func;
665 thread->funcname = funcname;
666 thread->schedfrom = schedfrom;
667 thread->schedfrom_line = fromln;
668
669 return thread;
718e3744 670}
671
d62a17ae 672static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
673 nfds_t count, const struct timeval *timer_wait)
209a72a6 674{
d62a17ae 675 /* If timer_wait is null here, that means poll() should block
676 * indefinitely,
677 * unless the thread_master has overriden it by setting
678 * ->selectpoll_timeout.
679 * If the value is positive, it specifies the maximum number of
680 * milliseconds
681 * to wait. If the timeout is -1, it specifies that we should never wait
682 * and
683 * always return immediately even if no event is detected. If the value
684 * is
685 * zero, the behavior is default. */
686 int timeout = -1;
687
688 /* number of file descriptors with events */
689 int num;
690
691 if (timer_wait != NULL
692 && m->selectpoll_timeout == 0) // use the default value
693 timeout = (timer_wait->tv_sec * 1000)
694 + (timer_wait->tv_usec / 1000);
695 else if (m->selectpoll_timeout > 0) // use the user's timeout
696 timeout = m->selectpoll_timeout;
697 else if (m->selectpoll_timeout
698 < 0) // effect a poll (return immediately)
699 timeout = 0;
700
701 /* add poll pipe poker */
702 assert(count + 1 < pfdsize);
703 pfds[count].fd = m->io_pipe[0];
704 pfds[count].events = POLLIN;
705 pfds[count].revents = 0x00;
706
707 num = poll(pfds, count + 1, timeout);
708
709 unsigned char trash[64];
710 if (num > 0 && pfds[count].revents != 0 && num--)
711 while (read(m->io_pipe[0], &trash, sizeof(trash)) > 0)
712 ;
713
714 return num;
209a72a6
DS
715}
716
718e3744 717/* Add new read thread. */
d62a17ae 718struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
719 int (*func)(struct thread *),
720 void *arg, int fd,
721 struct thread **t_ptr,
722 debugargdef)
718e3744 723{
d62a17ae 724 struct thread *thread = NULL;
725
726 pthread_mutex_lock(&m->mtx);
727 {
728 if (t_ptr
729 && *t_ptr) // thread is already scheduled; don't reschedule
730 {
731 pthread_mutex_unlock(&m->mtx);
732 return NULL;
733 }
734
735 /* default to a new pollfd */
736 nfds_t queuepos = m->handler.pfdcount;
737
738 /* if we already have a pollfd for our file descriptor, find and
739 * use it */
740 for (nfds_t i = 0; i < m->handler.pfdcount; i++)
741 if (m->handler.pfds[i].fd == fd) {
742 queuepos = i;
743 break;
744 }
745
746 /* make sure we have room for this fd + pipe poker fd */
747 assert(queuepos + 1 < m->handler.pfdsize);
748
749 thread = thread_get(m, dir, func, arg, debugargpass);
750
751 m->handler.pfds[queuepos].fd = fd;
752 m->handler.pfds[queuepos].events |=
753 (dir == THREAD_READ ? POLLIN : POLLOUT);
754
755 if (queuepos == m->handler.pfdcount)
756 m->handler.pfdcount++;
757
758 if (thread) {
759 pthread_mutex_lock(&thread->mtx);
760 {
761 thread->u.fd = fd;
762 if (dir == THREAD_READ)
763 m->read[thread->u.fd] = thread;
764 else
765 m->write[thread->u.fd] = thread;
766 }
767 pthread_mutex_unlock(&thread->mtx);
768
769 if (t_ptr) {
770 *t_ptr = thread;
771 thread->ref = t_ptr;
772 }
773 }
774
775 AWAKEN(m);
776 }
777 pthread_mutex_unlock(&m->mtx);
778
779 return thread;
718e3744 780}
781
56a94b36 782static struct thread *
d62a17ae 783funcname_thread_add_timer_timeval(struct thread_master *m,
784 int (*func)(struct thread *), int type,
785 void *arg, struct timeval *time_relative,
786 struct thread **t_ptr, debugargdef)
718e3744 787{
d62a17ae 788 struct thread *thread;
789 struct pqueue *queue;
790
791 assert(m != NULL);
792
793 assert(type == THREAD_TIMER);
794 assert(time_relative);
795
796 pthread_mutex_lock(&m->mtx);
797 {
798 if (t_ptr
799 && *t_ptr) // thread is already scheduled; don't reschedule
800 {
801 pthread_mutex_unlock(&m->mtx);
802 return NULL;
803 }
804
805 queue = m->timer;
806 thread = thread_get(m, type, func, arg, debugargpass);
807
808 pthread_mutex_lock(&thread->mtx);
809 {
810 monotime(&thread->u.sands);
811 timeradd(&thread->u.sands, time_relative,
812 &thread->u.sands);
813 pqueue_enqueue(thread, queue);
814 if (t_ptr) {
815 *t_ptr = thread;
816 thread->ref = t_ptr;
817 }
818 }
819 pthread_mutex_unlock(&thread->mtx);
820
821 AWAKEN(m);
822 }
823 pthread_mutex_unlock(&m->mtx);
824
825 return thread;
9e867fe6 826}
827
98c91ac6 828
829/* Add timer event thread. */
d62a17ae 830struct thread *funcname_thread_add_timer(struct thread_master *m,
831 int (*func)(struct thread *),
832 void *arg, long timer,
833 struct thread **t_ptr, debugargdef)
9e867fe6 834{
d62a17ae 835 struct timeval trel;
9e867fe6 836
d62a17ae 837 assert(m != NULL);
9e867fe6 838
d62a17ae 839 trel.tv_sec = timer;
840 trel.tv_usec = 0;
9e867fe6 841
d62a17ae 842 return funcname_thread_add_timer_timeval(m, func, THREAD_TIMER, arg,
843 &trel, t_ptr, debugargpass);
98c91ac6 844}
9e867fe6 845
98c91ac6 846/* Add timer event thread with "millisecond" resolution */
d62a17ae 847struct thread *funcname_thread_add_timer_msec(struct thread_master *m,
848 int (*func)(struct thread *),
849 void *arg, long timer,
850 struct thread **t_ptr,
851 debugargdef)
98c91ac6 852{
d62a17ae 853 struct timeval trel;
9e867fe6 854
d62a17ae 855 assert(m != NULL);
718e3744 856
d62a17ae 857 trel.tv_sec = timer / 1000;
858 trel.tv_usec = 1000 * (timer % 1000);
98c91ac6 859
d62a17ae 860 return funcname_thread_add_timer_timeval(m, func, THREAD_TIMER, arg,
861 &trel, t_ptr, debugargpass);
a48b4e6d 862}
863
d03c4cbd 864/* Add timer event thread with "millisecond" resolution */
d62a17ae 865struct thread *funcname_thread_add_timer_tv(struct thread_master *m,
866 int (*func)(struct thread *),
867 void *arg, struct timeval *tv,
868 struct thread **t_ptr, debugargdef)
d03c4cbd 869{
d62a17ae 870 return funcname_thread_add_timer_timeval(m, func, THREAD_TIMER, arg, tv,
871 t_ptr, debugargpass);
d03c4cbd
DL
872}
873
718e3744 874/* Add simple event thread. */
d62a17ae 875struct thread *funcname_thread_add_event(struct thread_master *m,
876 int (*func)(struct thread *),
877 void *arg, int val,
878 struct thread **t_ptr, debugargdef)
718e3744 879{
d62a17ae 880 struct thread *thread;
881
882 assert(m != NULL);
883
884 pthread_mutex_lock(&m->mtx);
885 {
886 if (t_ptr
887 && *t_ptr) // thread is already scheduled; don't reschedule
888 {
889 pthread_mutex_unlock(&m->mtx);
890 return NULL;
891 }
892
893 thread = thread_get(m, THREAD_EVENT, func, arg, debugargpass);
894 pthread_mutex_lock(&thread->mtx);
895 {
896 thread->u.val = val;
897 thread_list_add(&m->event, thread);
898 }
899 pthread_mutex_unlock(&thread->mtx);
900
901 if (t_ptr) {
902 *t_ptr = thread;
903 thread->ref = t_ptr;
904 }
905
906 AWAKEN(m);
907 }
908 pthread_mutex_unlock(&m->mtx);
909
910 return thread;
718e3744 911}
912
63ccb9cb
QY
913/* Thread cancellation ------------------------------------------------------ */
914
8797240e
QY
915/**
916 * NOT's out the .events field of pollfd corresponding to the given file
917 * descriptor. The event to be NOT'd is passed in the 'state' parameter.
918 *
919 * This needs to happen for both copies of pollfd's. See 'thread_fetch'
920 * implementation for details.
921 *
922 * @param master
923 * @param fd
924 * @param state the event to cancel. One or more (OR'd together) of the
925 * following:
926 * - POLLIN
927 * - POLLOUT
928 */
d62a17ae 929static void thread_cancel_rw(struct thread_master *master, int fd, short state)
0a95a0d0 930{
42d74538
QY
931 bool found = false;
932
d62a17ae 933 /* Cancel POLLHUP too just in case some bozo set it */
934 state |= POLLHUP;
935
936 /* find the index of corresponding pollfd */
937 nfds_t i;
938
939 for (i = 0; i < master->handler.pfdcount; i++)
42d74538
QY
940 if (master->handler.pfds[i].fd == fd) {
941 found = true;
d62a17ae 942 break;
42d74538
QY
943 }
944
945 if (!found) {
946 zlog_debug(
947 "[!] Received cancellation request for nonexistent rw job");
948 zlog_debug("[!] threadmaster: %s | fd: %d",
996c9314 949 master->name ? master->name : "", fd);
42d74538
QY
950 return;
951 }
d62a17ae 952
953 /* NOT out event. */
954 master->handler.pfds[i].events &= ~(state);
955
956 /* If all events are canceled, delete / resize the pollfd array. */
957 if (master->handler.pfds[i].events == 0) {
958 memmove(master->handler.pfds + i, master->handler.pfds + i + 1,
959 (master->handler.pfdcount - i - 1)
960 * sizeof(struct pollfd));
961 master->handler.pfdcount--;
962 }
963
964 /* If we have the same pollfd in the copy, perform the same operations,
965 * otherwise return. */
966 if (i >= master->handler.copycount)
967 return;
968
969 master->handler.copy[i].events &= ~(state);
970
971 if (master->handler.copy[i].events == 0) {
972 memmove(master->handler.copy + i, master->handler.copy + i + 1,
973 (master->handler.copycount - i - 1)
974 * sizeof(struct pollfd));
975 master->handler.copycount--;
976 }
0a95a0d0
DS
977}
978
1189d95f 979/**
63ccb9cb 980 * Process cancellation requests.
1189d95f 981 *
63ccb9cb
QY
982 * This may only be run from the pthread which owns the thread_master.
983 *
984 * @param master the thread master to process
985 * @REQUIRE master->mtx
1189d95f 986 */
d62a17ae 987static void do_thread_cancel(struct thread_master *master)
718e3744 988{
d62a17ae 989 struct thread_list *list = NULL;
990 struct pqueue *queue = NULL;
991 struct thread **thread_array = NULL;
992 struct thread *thread;
993
994 struct cancel_req *cr;
995 struct listnode *ln;
996 for (ALL_LIST_ELEMENTS_RO(master->cancel_req, ln, cr)) {
997 /* If this is an event object cancellation, linear search
998 * through event
999 * list deleting any events which have the specified argument.
1000 * We also
1001 * need to check every thread in the ready queue. */
1002 if (cr->eventobj) {
1003 struct thread *t;
1004 thread = master->event.head;
1005
1006 while (thread) {
1007 t = thread;
1008 thread = t->next;
1009
1010 if (t->arg == cr->eventobj) {
1011 thread_list_delete(&master->event, t);
1012 if (t->ref)
1013 *t->ref = NULL;
1014 thread_add_unuse(master, t);
1015 }
1016 }
1017
1018 thread = master->ready.head;
1019 while (thread) {
1020 t = thread;
1021 thread = t->next;
1022
1023 if (t->arg == cr->eventobj) {
1024 thread_list_delete(&master->ready, t);
1025 if (t->ref)
1026 *t->ref = NULL;
1027 thread_add_unuse(master, t);
1028 }
1029 }
1030 continue;
1031 }
1032
1033 /* The pointer varies depending on whether the cancellation
1034 * request was
1035 * made asynchronously or not. If it was, we need to check
1036 * whether the
1037 * thread even exists anymore before cancelling it. */
1038 thread = (cr->thread) ? cr->thread : *cr->threadref;
1039
1040 if (!thread)
1041 continue;
1042
1043 /* Determine the appropriate queue to cancel the thread from */
1044 switch (thread->type) {
1045 case THREAD_READ:
1046 thread_cancel_rw(master, thread->u.fd, POLLIN);
1047 thread_array = master->read;
1048 break;
1049 case THREAD_WRITE:
1050 thread_cancel_rw(master, thread->u.fd, POLLOUT);
1051 thread_array = master->write;
1052 break;
1053 case THREAD_TIMER:
1054 queue = master->timer;
1055 break;
1056 case THREAD_EVENT:
1057 list = &master->event;
1058 break;
1059 case THREAD_READY:
1060 list = &master->ready;
1061 break;
1062 default:
1063 continue;
1064 break;
1065 }
1066
1067 if (queue) {
1068 assert(thread->index >= 0);
522f7f99
DS
1069 assert(thread == queue->array[thread->index]);
1070 pqueue_remove_at(thread->index, queue);
d62a17ae 1071 } else if (list) {
1072 thread_list_delete(list, thread);
1073 } else if (thread_array) {
1074 thread_array[thread->u.fd] = NULL;
1075 } else {
1076 assert(!"Thread should be either in queue or list or array!");
1077 }
1078
1079 if (thread->ref)
1080 *thread->ref = NULL;
1081
1082 thread_add_unuse(thread->master, thread);
1083 }
1084
1085 /* Delete and free all cancellation requests */
1086 list_delete_all_node(master->cancel_req);
1087
1088 /* Wake up any threads which may be blocked in thread_cancel_async() */
1089 master->canceled = true;
1090 pthread_cond_broadcast(&master->cancel_cond);
718e3744 1091}
1092
63ccb9cb
QY
1093/**
1094 * Cancel any events which have the specified argument.
1095 *
1096 * MT-Unsafe
1097 *
1098 * @param m the thread_master to cancel from
1099 * @param arg the argument passed when creating the event
1100 */
d62a17ae 1101void thread_cancel_event(struct thread_master *master, void *arg)
718e3744 1102{
d62a17ae 1103 assert(master->owner == pthread_self());
1104
1105 pthread_mutex_lock(&master->mtx);
1106 {
1107 struct cancel_req *cr =
1108 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1109 cr->eventobj = arg;
1110 listnode_add(master->cancel_req, cr);
1111 do_thread_cancel(master);
1112 }
1113 pthread_mutex_unlock(&master->mtx);
63ccb9cb 1114}
1189d95f 1115
63ccb9cb
QY
1116/**
1117 * Cancel a specific task.
1118 *
1119 * MT-Unsafe
1120 *
1121 * @param thread task to cancel
1122 */
d62a17ae 1123void thread_cancel(struct thread *thread)
63ccb9cb 1124{
d62a17ae 1125 assert(thread->master->owner == pthread_self());
1126
1127 pthread_mutex_lock(&thread->master->mtx);
1128 {
1129 struct cancel_req *cr =
1130 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1131 cr->thread = thread;
1132 listnode_add(thread->master->cancel_req, cr);
1133 do_thread_cancel(thread->master);
1134 }
1135 pthread_mutex_unlock(&thread->master->mtx);
63ccb9cb 1136}
1189d95f 1137
63ccb9cb
QY
1138/**
1139 * Asynchronous cancellation.
1140 *
8797240e
QY
1141 * Called with either a struct thread ** or void * to an event argument,
1142 * this function posts the correct cancellation request and blocks until it is
1143 * serviced.
63ccb9cb
QY
1144 *
1145 * If the thread is currently running, execution blocks until it completes.
1146 *
8797240e
QY
1147 * The last two parameters are mutually exclusive, i.e. if you pass one the
1148 * other must be NULL.
1149 *
1150 * When the cancellation procedure executes on the target thread_master, the
1151 * thread * provided is checked for nullity. If it is null, the thread is
1152 * assumed to no longer exist and the cancellation request is a no-op. Thus
1153 * users of this API must pass a back-reference when scheduling the original
1154 * task.
1155 *
63ccb9cb
QY
1156 * MT-Safe
1157 *
8797240e
QY
1158 * @param master the thread master with the relevant event / task
1159 * @param thread pointer to thread to cancel
1160 * @param eventobj the event
63ccb9cb 1161 */
d62a17ae 1162void thread_cancel_async(struct thread_master *master, struct thread **thread,
1163 void *eventobj)
63ccb9cb 1164{
d62a17ae 1165 assert(!(thread && eventobj) && (thread || eventobj));
1166 assert(master->owner != pthread_self());
1167
1168 pthread_mutex_lock(&master->mtx);
1169 {
1170 master->canceled = false;
1171
1172 if (thread) {
1173 struct cancel_req *cr =
1174 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1175 cr->threadref = thread;
1176 listnode_add(master->cancel_req, cr);
1177 } else if (eventobj) {
1178 struct cancel_req *cr =
1179 XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
1180 cr->eventobj = eventobj;
1181 listnode_add(master->cancel_req, cr);
1182 }
1183 AWAKEN(master);
1184
1185 while (!master->canceled)
1186 pthread_cond_wait(&master->cancel_cond, &master->mtx);
1187 }
1188 pthread_mutex_unlock(&master->mtx);
718e3744 1189}
63ccb9cb 1190/* ------------------------------------------------------------------------- */
718e3744 1191
d62a17ae 1192static struct timeval *thread_timer_wait(struct pqueue *queue,
1193 struct timeval *timer_val)
718e3744 1194{
d62a17ae 1195 if (queue->size) {
1196 struct thread *next_timer = queue->array[0];
1197 monotime_until(&next_timer->u.sands, timer_val);
1198 return timer_val;
1199 }
1200 return NULL;
718e3744 1201}
718e3744 1202
d62a17ae 1203static struct thread *thread_run(struct thread_master *m, struct thread *thread,
1204 struct thread *fetch)
718e3744 1205{
d62a17ae 1206 *fetch = *thread;
1207 thread_add_unuse(m, thread);
1208 return fetch;
718e3744 1209}
1210
d62a17ae 1211static int thread_process_io_helper(struct thread_master *m,
1212 struct thread *thread, short state, int pos)
5d4ccd4e 1213{
d62a17ae 1214 struct thread **thread_array;
1215
1216 if (!thread)
1217 return 0;
1218
1219 if (thread->type == THREAD_READ)
1220 thread_array = m->read;
1221 else
1222 thread_array = m->write;
1223
1224 thread_array[thread->u.fd] = NULL;
1225 thread_list_add(&m->ready, thread);
1226 thread->type = THREAD_READY;
1227 /* if another pthread scheduled this file descriptor for the event we're
1228 * responding to, no problem; we're getting to it now */
1229 thread->master->handler.pfds[pos].events &= ~(state);
1230 return 1;
5d4ccd4e
DS
1231}
1232
8797240e
QY
1233/**
1234 * Process I/O events.
1235 *
1236 * Walks through file descriptor array looking for those pollfds whose .revents
1237 * field has something interesting. Deletes any invalid file descriptors.
1238 *
1239 * @param m the thread master
1240 * @param num the number of active file descriptors (return value of poll())
1241 */
d62a17ae 1242static void thread_process_io(struct thread_master *m, unsigned int num)
0a95a0d0 1243{
d62a17ae 1244 unsigned int ready = 0;
1245 struct pollfd *pfds = m->handler.copy;
1246
1247 for (nfds_t i = 0; i < m->handler.copycount && ready < num; ++i) {
1248 /* no event for current fd? immediately continue */
1249 if (pfds[i].revents == 0)
1250 continue;
1251
1252 ready++;
1253
1254 /* Unless someone has called thread_cancel from another pthread,
1255 * the only
1256 * thing that could have changed in m->handler.pfds while we
1257 * were
1258 * asleep is the .events field in a given pollfd. Barring
1259 * thread_cancel()
1260 * that value should be a superset of the values we have in our
1261 * copy, so
1262 * there's no need to update it. Similarily, barring deletion,
1263 * the fd
1264 * should still be a valid index into the master's pfds. */
1265 if (pfds[i].revents & (POLLIN | POLLHUP))
1266 thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN,
1267 i);
1268 if (pfds[i].revents & POLLOUT)
1269 thread_process_io_helper(m, m->write[pfds[i].fd],
1270 POLLOUT, i);
1271
1272 /* if one of our file descriptors is garbage, remove the same
1273 * from
1274 * both pfds + update sizes and index */
1275 if (pfds[i].revents & POLLNVAL) {
1276 memmove(m->handler.pfds + i, m->handler.pfds + i + 1,
1277 (m->handler.pfdcount - i - 1)
1278 * sizeof(struct pollfd));
1279 m->handler.pfdcount--;
1280
1281 memmove(pfds + i, pfds + i + 1,
1282 (m->handler.copycount - i - 1)
1283 * sizeof(struct pollfd));
1284 m->handler.copycount--;
1285
1286 i--;
1287 }
1288 }
718e3744 1289}
1290
8b70d0b0 1291/* Add all timers that have popped to the ready list. */
d62a17ae 1292static unsigned int thread_process_timers(struct pqueue *queue,
1293 struct timeval *timenow)
a48b4e6d 1294{
d62a17ae 1295 struct thread *thread;
1296 unsigned int ready = 0;
1297
1298 while (queue->size) {
1299 thread = queue->array[0];
1300 if (timercmp(timenow, &thread->u.sands, <))
1301 return ready;
1302 pqueue_dequeue(queue);
1303 thread->type = THREAD_READY;
1304 thread_list_add(&thread->master->ready, thread);
1305 ready++;
1306 }
1307 return ready;
a48b4e6d 1308}
1309
2613abe6 1310/* process a list en masse, e.g. for event thread lists */
d62a17ae 1311static unsigned int thread_process(struct thread_list *list)
2613abe6 1312{
d62a17ae 1313 struct thread *thread;
1314 struct thread *next;
1315 unsigned int ready = 0;
1316
1317 for (thread = list->head; thread; thread = next) {
1318 next = thread->next;
1319 thread_list_delete(list, thread);
1320 thread->type = THREAD_READY;
1321 thread_list_add(&thread->master->ready, thread);
1322 ready++;
1323 }
1324 return ready;
2613abe6
PJ
1325}
1326
1327
718e3744 1328/* Fetch next ready thread. */
d62a17ae 1329struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
718e3744 1330{
d62a17ae 1331 struct thread *thread = NULL;
1332 struct timeval now;
1333 struct timeval zerotime = {0, 0};
1334 struct timeval tv;
1335 struct timeval *tw = NULL;
1336
1337 int num = 0;
1338
1339 do {
1340 /* Handle signals if any */
1341 if (m->handle_signals)
1342 quagga_sigevent_process();
1343
1344 pthread_mutex_lock(&m->mtx);
1345
1346 /* Process any pending cancellation requests */
1347 do_thread_cancel(m);
1348
e3c9529e
QY
1349 /*
1350 * Attempt to flush ready queue before going into poll().
1351 * This is performance-critical. Think twice before modifying.
1352 */
1353 if ((thread = thread_trim_head(&m->ready))) {
1354 fetch = thread_run(m, thread, fetch);
1355 if (fetch->ref)
1356 *fetch->ref = NULL;
1357 pthread_mutex_unlock(&m->mtx);
1358 break;
1359 }
1360
1361 /* otherwise, tick through scheduling sequence */
1362
bca37d17
QY
1363 /*
1364 * Post events to ready queue. This must come before the
1365 * following block since events should occur immediately
1366 */
d62a17ae 1367 thread_process(&m->event);
1368
bca37d17
QY
1369 /*
1370 * If there are no tasks on the ready queue, we will poll()
1371 * until a timer expires or we receive I/O, whichever comes
1372 * first. The strategy for doing this is:
d62a17ae 1373 *
1374 * - If there are events pending, set the poll() timeout to zero
1375 * - If there are no events pending, but there are timers
1376 * pending, set the
1377 * timeout to the smallest remaining time on any timer
1378 * - If there are neither timers nor events pending, but there
1379 * are file
1380 * descriptors pending, block indefinitely in poll()
1381 * - If nothing is pending, it's time for the application to die
1382 *
1383 * In every case except the last, we need to hit poll() at least
bca37d17
QY
1384 * once per loop to avoid starvation by events
1385 */
d62a17ae 1386 if (m->ready.count == 0)
1387 tw = thread_timer_wait(m->timer, &tv);
1388
1389 if (m->ready.count != 0 || (tw && !timercmp(tw, &zerotime, >)))
1390 tw = &zerotime;
1391
1392 if (!tw && m->handler.pfdcount == 0) { /* die */
1393 pthread_mutex_unlock(&m->mtx);
1394 fetch = NULL;
1395 break;
1396 }
1397
bca37d17
QY
1398 /*
1399 * Copy pollfd array + # active pollfds in it. Not necessary to
1400 * copy the array size as this is fixed.
1401 */
d62a17ae 1402 m->handler.copycount = m->handler.pfdcount;
1403 memcpy(m->handler.copy, m->handler.pfds,
1404 m->handler.copycount * sizeof(struct pollfd));
1405
e3c9529e
QY
1406 pthread_mutex_unlock(&m->mtx);
1407 {
1408 num = fd_poll(m, m->handler.copy, m->handler.pfdsize,
1409 m->handler.copycount, tw);
1410 }
1411 pthread_mutex_lock(&m->mtx);
d764d2cc 1412
e3c9529e
QY
1413 /* Handle any errors received in poll() */
1414 if (num < 0) {
1415 if (errno == EINTR) {
d62a17ae 1416 pthread_mutex_unlock(&m->mtx);
e3c9529e
QY
1417 /* loop around to signal handler */
1418 continue;
d62a17ae 1419 }
1420
e3c9529e
QY
1421 /* else die */
1422 zlog_warn("poll() error: %s", safe_strerror(errno));
1423 pthread_mutex_unlock(&m->mtx);
1424 fetch = NULL;
1425 break;
bca37d17 1426 }
d62a17ae 1427
1428 /* Post timers to ready queue. */
1429 monotime(&now);
1430 thread_process_timers(m->timer, &now);
1431
1432 /* Post I/O to ready queue. */
1433 if (num > 0)
1434 thread_process_io(m, num);
1435
d62a17ae 1436 pthread_mutex_unlock(&m->mtx);
1437
1438 } while (!thread && m->spin);
1439
1440 return fetch;
718e3744 1441}
1442
d62a17ae 1443static unsigned long timeval_elapsed(struct timeval a, struct timeval b)
62f44022 1444{
d62a17ae 1445 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
1446 + (a.tv_usec - b.tv_usec));
62f44022
QY
1447}
1448
d62a17ae 1449unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start,
1450 unsigned long *cputime)
718e3744 1451{
d62a17ae 1452 /* This is 'user + sys' time. */
1453 *cputime = timeval_elapsed(now->cpu.ru_utime, start->cpu.ru_utime)
1454 + timeval_elapsed(now->cpu.ru_stime, start->cpu.ru_stime);
1455 return timeval_elapsed(now->real, start->real);
8b70d0b0 1456}
1457
50596be0
DS
1458/* We should aim to yield after yield milliseconds, which defaults
1459 to THREAD_YIELD_TIME_SLOT .
8b70d0b0 1460 Note: we are using real (wall clock) time for this calculation.
1461 It could be argued that CPU time may make more sense in certain
1462 contexts. The things to consider are whether the thread may have
1463 blocked (in which case wall time increases, but CPU time does not),
1464 or whether the system is heavily loaded with other processes competing
d62a17ae 1465 for CPU time. On balance, wall clock time seems to make sense.
8b70d0b0 1466 Plus it has the added benefit that gettimeofday should be faster
1467 than calling getrusage. */
d62a17ae 1468int thread_should_yield(struct thread *thread)
718e3744 1469{
d62a17ae 1470 int result;
1471 pthread_mutex_lock(&thread->mtx);
1472 {
1473 result = monotime_since(&thread->real, NULL)
1474 > (int64_t)thread->yield;
1475 }
1476 pthread_mutex_unlock(&thread->mtx);
1477 return result;
50596be0
DS
1478}
1479
d62a17ae 1480void thread_set_yield_time(struct thread *thread, unsigned long yield_time)
50596be0 1481{
d62a17ae 1482 pthread_mutex_lock(&thread->mtx);
1483 {
1484 thread->yield = yield_time;
1485 }
1486 pthread_mutex_unlock(&thread->mtx);
718e3744 1487}
1488
d62a17ae 1489void thread_getrusage(RUSAGE_T *r)
db9c0df9 1490{
d62a17ae 1491 monotime(&r->real);
1492 getrusage(RUSAGE_SELF, &(r->cpu));
db9c0df9
PJ
1493}
1494
718e3744 1495/* We check thread consumed time. If the system has getrusage, we'll
8b70d0b0 1496 use that to get in-depth stats on the performance of the thread in addition
1497 to wall clock time stats from gettimeofday. */
d62a17ae 1498void thread_call(struct thread *thread)
718e3744 1499{
d62a17ae 1500 unsigned long realtime, cputime;
1501 RUSAGE_T before, after;
cc8b13a0 1502
d62a17ae 1503 GETRUSAGE(&before);
1504 thread->real = before.real;
718e3744 1505
d62a17ae 1506 pthread_setspecific(thread_current, thread);
1507 (*thread->func)(thread);
1508 pthread_setspecific(thread_current, NULL);
718e3744 1509
d62a17ae 1510 GETRUSAGE(&after);
718e3744 1511
d62a17ae 1512 realtime = thread_consumed_time(&after, &before, &cputime);
1513 thread->hist->real.total += realtime;
1514 if (thread->hist->real.max < realtime)
1515 thread->hist->real.max = realtime;
1516 thread->hist->cpu.total += cputime;
1517 if (thread->hist->cpu.max < cputime)
1518 thread->hist->cpu.max = cputime;
e04ab74d 1519
d62a17ae 1520 ++(thread->hist->total_calls);
1521 thread->hist->types |= (1 << thread->add_type);
718e3744 1522
924b9229 1523#ifdef CONSUMED_TIME_CHECK
d62a17ae 1524 if (realtime > CONSUMED_TIME_CHECK) {
1525 /*
1526 * We have a CPU Hog on our hands.
1527 * Whinge about it now, so we're aware this is yet another task
1528 * to fix.
1529 */
1530 zlog_warn(
1531 "SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
1532 thread->funcname, (unsigned long)thread->func,
1533 realtime / 1000, cputime / 1000);
1534 }
924b9229 1535#endif /* CONSUMED_TIME_CHECK */
718e3744 1536}
1537
1538/* Execute thread */
d62a17ae 1539void funcname_thread_execute(struct thread_master *m,
1540 int (*func)(struct thread *), void *arg, int val,
1541 debugargdef)
718e3744 1542{
d62a17ae 1543 struct cpu_thread_history tmp;
1544 struct thread dummy;
718e3744 1545
d62a17ae 1546 memset(&dummy, 0, sizeof(struct thread));
718e3744 1547
d62a17ae 1548 pthread_mutex_init(&dummy.mtx, NULL);
1549 dummy.type = THREAD_EVENT;
1550 dummy.add_type = THREAD_EXECUTE;
1551 dummy.master = NULL;
1552 dummy.arg = arg;
1553 dummy.u.val = val;
9c7753e4 1554
d62a17ae 1555 tmp.func = dummy.func = func;
1556 tmp.funcname = dummy.funcname = funcname;
1557 dummy.hist = hash_get(m->cpu_record, &tmp,
1558 (void *(*)(void *))cpu_record_hash_alloc);
f7c62e11 1559
d62a17ae 1560 dummy.schedfrom = schedfrom;
1561 dummy.schedfrom_line = fromln;
9c7753e4 1562
d62a17ae 1563 thread_call(&dummy);
718e3744 1564}