]> git.proxmox.com Git - mirror_frr.git/blob - lib/thread.c
[lib] Optimise thread_call by caching pointer to thread history in the thread
[mirror_frr.git] / lib / thread.c
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 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 /* #define DEBUG */
23
24 #include <zebra.h>
25
26 #include "thread.h"
27 #include "memory.h"
28 #include "log.h"
29 #include "hash.h"
30 #include "command.h"
31 #include "sigevent.h"
32 \f
33 struct timeval recent_time;
34 static struct hash *cpu_record = NULL;
35 \f
36 /* Struct timeval's tv_usec one second value. */
37 #define TIMER_SECOND_MICRO 1000000L
38
39 /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
40 And change negative values to 0. */
41 static struct timeval
42 timeval_adjust (struct timeval a)
43 {
44 while (a.tv_usec >= TIMER_SECOND_MICRO)
45 {
46 a.tv_usec -= TIMER_SECOND_MICRO;
47 a.tv_sec++;
48 }
49
50 while (a.tv_usec < 0)
51 {
52 a.tv_usec += TIMER_SECOND_MICRO;
53 a.tv_sec--;
54 }
55
56 if (a.tv_sec < 0)
57 /* Change negative timeouts to 0. */
58 a.tv_sec = a.tv_usec = 0;
59
60 return a;
61 }
62
63 static struct timeval
64 timeval_subtract (struct timeval a, struct timeval b)
65 {
66 struct timeval ret;
67
68 ret.tv_usec = a.tv_usec - b.tv_usec;
69 ret.tv_sec = a.tv_sec - b.tv_sec;
70
71 return timeval_adjust (ret);
72 }
73
74 static long
75 timeval_cmp (struct timeval a, struct timeval b)
76 {
77 return (a.tv_sec == b.tv_sec
78 ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
79 }
80
81 static unsigned long
82 timeval_elapsed (struct timeval a, struct timeval b)
83 {
84 return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
85 + (a.tv_usec - b.tv_usec));
86 }
87 \f
88 static unsigned int
89 cpu_record_hash_key (struct cpu_thread_history *a)
90 {
91 return (uintptr_t) a->func;
92 }
93
94 static int
95 cpu_record_hash_cmp (struct cpu_thread_history *a,
96 struct cpu_thread_history *b)
97 {
98 return a->func == b->func;
99 }
100
101 static void *
102 cpu_record_hash_alloc (struct cpu_thread_history *a)
103 {
104 struct cpu_thread_history *new;
105 new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history));
106 new->func = a->func;
107 new->funcname = XSTRDUP(MTYPE_THREAD_FUNCNAME, a->funcname);
108 return new;
109 }
110
111 static inline void
112 vty_out_cpu_thread_history(struct vty* vty,
113 struct cpu_thread_history *a)
114 {
115 #ifdef HAVE_RUSAGE
116 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
117 a->cpu.total/1000, a->cpu.total%1000, a->total_calls,
118 a->cpu.total/a->total_calls, a->cpu.max,
119 a->real.total/a->total_calls, a->real.max);
120 #else
121 vty_out(vty, "%7ld.%03ld %9d %8ld %9ld",
122 a->real.total/1000, a->real.total%1000, a->total_calls,
123 a->real.total/a->total_calls, a->real.max);
124 #endif
125 vty_out(vty, " %c%c%c%c%c%c %s%s",
126 a->types & (1 << THREAD_READ) ? 'R':' ',
127 a->types & (1 << THREAD_WRITE) ? 'W':' ',
128 a->types & (1 << THREAD_TIMER) ? 'T':' ',
129 a->types & (1 << THREAD_EVENT) ? 'E':' ',
130 a->types & (1 << THREAD_EXECUTE) ? 'X':' ',
131 a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ',
132 a->funcname, VTY_NEWLINE);
133 }
134
135 static void
136 cpu_record_hash_print(struct hash_backet *bucket,
137 void *args[])
138 {
139 struct cpu_thread_history *totals = args[0];
140 struct vty *vty = args[1];
141 unsigned char *filter = args[2];
142 struct cpu_thread_history *a = bucket->data;
143
144 a = bucket->data;
145 if ( !(a->types & *filter) )
146 return;
147 vty_out_cpu_thread_history(vty,a);
148 totals->total_calls += a->total_calls;
149 totals->real.total += a->real.total;
150 if (totals->real.max < a->real.max)
151 totals->real.max = a->real.max;
152 #ifdef HAVE_RUSAGE
153 totals->cpu.total += a->cpu.total;
154 if (totals->cpu.max < a->cpu.max)
155 totals->cpu.max = a->cpu.max;
156 #endif
157 }
158
159 static void
160 cpu_record_print(struct vty *vty, unsigned char filter)
161 {
162 struct cpu_thread_history tmp;
163 void *args[3] = {&tmp, vty, &filter};
164
165 memset(&tmp, 0, sizeof tmp);
166 tmp.funcname = "TOTAL";
167 tmp.types = filter;
168
169 #ifdef HAVE_RUSAGE
170 vty_out(vty, "%21s %18s %18s%s",
171 "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE);
172 #endif
173 vty_out(vty, "Runtime(ms) Invoked Avg uSec Max uSecs");
174 #ifdef HAVE_RUSAGE
175 vty_out(vty, " Avg uSec Max uSecs");
176 #endif
177 vty_out(vty, " Type Thread%s", VTY_NEWLINE);
178 hash_iterate(cpu_record,
179 (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
180 args);
181
182 if (tmp.total_calls > 0)
183 vty_out_cpu_thread_history(vty, &tmp);
184 }
185
186 DEFUN(show_thread_cpu,
187 show_thread_cpu_cmd,
188 "show thread cpu [FILTER]",
189 SHOW_STR
190 "Thread information\n"
191 "Thread CPU usage\n"
192 "Display filter (rwtexb)\n")
193 {
194 int i = 0;
195 unsigned char filter = 0xff;
196
197 if (argc > 0)
198 {
199 filter = 0;
200 while (argv[0][i] != '\0')
201 {
202 switch ( argv[0][i] )
203 {
204 case 'r':
205 case 'R':
206 filter |= (1 << THREAD_READ);
207 break;
208 case 'w':
209 case 'W':
210 filter |= (1 << THREAD_WRITE);
211 break;
212 case 't':
213 case 'T':
214 filter |= (1 << THREAD_TIMER);
215 break;
216 case 'e':
217 case 'E':
218 filter |= (1 << THREAD_EVENT);
219 break;
220 case 'x':
221 case 'X':
222 filter |= (1 << THREAD_EXECUTE);
223 break;
224 case 'b':
225 case 'B':
226 filter |= (1 << THREAD_BACKGROUND);
227 break;
228 default:
229 break;
230 }
231 ++i;
232 }
233 if (filter == 0)
234 {
235 vty_out(vty, "Invalid filter \"%s\" specified,"
236 " must contain at least one of 'RWTEXB'%s",
237 argv[0], VTY_NEWLINE);
238 return CMD_WARNING;
239 }
240 }
241
242 cpu_record_print(vty, filter);
243 return CMD_SUCCESS;
244 }
245 \f
246 /* List allocation and head/tail print out. */
247 static void
248 thread_list_debug (struct thread_list *list)
249 {
250 printf ("count [%d] head [%p] tail [%p]\n",
251 list->count, list->head, list->tail);
252 }
253
254 /* Debug print for thread_master. */
255 static void __attribute__ ((unused))
256 thread_master_debug (struct thread_master *m)
257 {
258 printf ("-----------\n");
259 printf ("readlist : ");
260 thread_list_debug (&m->read);
261 printf ("writelist : ");
262 thread_list_debug (&m->write);
263 printf ("timerlist : ");
264 thread_list_debug (&m->timer);
265 printf ("eventlist : ");
266 thread_list_debug (&m->event);
267 printf ("unuselist : ");
268 thread_list_debug (&m->unuse);
269 printf ("bgndlist : ");
270 thread_list_debug (&m->background);
271 printf ("total alloc: [%ld]\n", m->alloc);
272 printf ("-----------\n");
273 }
274 \f
275 /* Allocate new thread master. */
276 struct thread_master *
277 thread_master_create ()
278 {
279 if (cpu_record == NULL)
280 cpu_record
281 = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key,
282 (int (*) (void *, void *))cpu_record_hash_cmp);
283
284 return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
285 sizeof (struct thread_master));
286 }
287
288 /* Add a new thread to the list. */
289 static void
290 thread_list_add (struct thread_list *list, struct thread *thread)
291 {
292 thread->next = NULL;
293 thread->prev = list->tail;
294 if (list->tail)
295 list->tail->next = thread;
296 else
297 list->head = thread;
298 list->tail = thread;
299 list->count++;
300 }
301
302 /* Add a new thread just before the point. */
303 static void
304 thread_list_add_before (struct thread_list *list,
305 struct thread *point,
306 struct thread *thread)
307 {
308 thread->next = point;
309 thread->prev = point->prev;
310 if (point->prev)
311 point->prev->next = thread;
312 else
313 list->head = thread;
314 point->prev = thread;
315 list->count++;
316 }
317
318 /* Delete a thread from the list. */
319 static struct thread *
320 thread_list_delete (struct thread_list *list, struct thread *thread)
321 {
322 if (thread->next)
323 thread->next->prev = thread->prev;
324 else
325 list->tail = thread->prev;
326 if (thread->prev)
327 thread->prev->next = thread->next;
328 else
329 list->head = thread->next;
330 thread->next = thread->prev = NULL;
331 list->count--;
332 return thread;
333 }
334
335 /* Move thread to unuse list. */
336 static void
337 thread_add_unuse (struct thread_master *m, struct thread *thread)
338 {
339 assert (m != NULL && thread != NULL);
340 assert (thread->next == NULL);
341 assert (thread->prev == NULL);
342 assert (thread->type == THREAD_UNUSED);
343 thread_list_add (&m->unuse, thread);
344 /* XXX: Should we deallocate funcname here? */
345 }
346
347 /* Free all unused thread. */
348 static void
349 thread_list_free (struct thread_master *m, struct thread_list *list)
350 {
351 struct thread *t;
352 struct thread *next;
353
354 for (t = list->head; t; t = next)
355 {
356 next = t->next;
357 XFREE (MTYPE_THREAD_FUNCNAME, t->funcname);
358 XFREE (MTYPE_THREAD, t);
359 list->count--;
360 m->alloc--;
361 }
362 }
363
364 /* Stop thread scheduler. */
365 void
366 thread_master_free (struct thread_master *m)
367 {
368 thread_list_free (m, &m->read);
369 thread_list_free (m, &m->write);
370 thread_list_free (m, &m->timer);
371 thread_list_free (m, &m->event);
372 thread_list_free (m, &m->ready);
373 thread_list_free (m, &m->unuse);
374 thread_list_free (m, &m->background);
375
376 XFREE (MTYPE_THREAD_MASTER, m);
377 }
378
379 /* Thread list is empty or not. */
380 static inline int
381 thread_empty (struct thread_list *list)
382 {
383 return list->head ? 0 : 1;
384 }
385
386 /* Delete top of the list and return it. */
387 static struct thread *
388 thread_trim_head (struct thread_list *list)
389 {
390 if (!thread_empty (list))
391 return thread_list_delete (list, list->head);
392 return NULL;
393 }
394
395 /* Return remain time in second. */
396 unsigned long
397 thread_timer_remain_second (struct thread *thread)
398 {
399 gettimeofday (&recent_time, NULL);
400
401 if (thread->u.sands.tv_sec - recent_time.tv_sec > 0)
402 return thread->u.sands.tv_sec - recent_time.tv_sec;
403 else
404 return 0;
405 }
406
407 /* Trim blankspace and "()"s */
408 static char *
409 strip_funcname (const char *funcname)
410 {
411 char buff[100];
412 char tmp, *ret, *e, *b = buff;
413
414 strncpy(buff, funcname, sizeof(buff));
415 buff[ sizeof(buff) -1] = '\0';
416 e = buff +strlen(buff) -1;
417
418 /* Wont work for funcname == "Word (explanation)" */
419
420 while (*b == ' ' || *b == '(')
421 ++b;
422 while (*e == ' ' || *e == ')')
423 --e;
424 e++;
425
426 tmp = *e;
427 *e = '\0';
428 ret = XSTRDUP (MTYPE_THREAD_FUNCNAME, b);
429 *e = tmp;
430
431 return ret;
432 }
433
434 /* Get new thread. */
435 static struct thread *
436 thread_get (struct thread_master *m, u_char type,
437 int (*func) (struct thread *), void *arg, const char* funcname)
438 {
439 struct thread *thread;
440
441 if (!thread_empty (&m->unuse))
442 {
443 thread = thread_trim_head (&m->unuse);
444 if (thread->funcname)
445 XFREE(MTYPE_THREAD_FUNCNAME, thread->funcname);
446 }
447 else
448 {
449 thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
450 m->alloc++;
451 }
452 thread->type = type;
453 thread->add_type = type;
454 thread->master = m;
455 thread->func = func;
456 thread->arg = arg;
457
458 thread->funcname = strip_funcname(funcname);
459
460 return thread;
461 }
462
463 /* Add new read thread. */
464 struct thread *
465 funcname_thread_add_read (struct thread_master *m,
466 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
467 {
468 struct thread *thread;
469
470 assert (m != NULL);
471
472 if (FD_ISSET (fd, &m->readfd))
473 {
474 zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
475 return NULL;
476 }
477
478 thread = thread_get (m, THREAD_READ, func, arg, funcname);
479 FD_SET (fd, &m->readfd);
480 thread->u.fd = fd;
481 thread_list_add (&m->read, thread);
482
483 return thread;
484 }
485
486 /* Add new write thread. */
487 struct thread *
488 funcname_thread_add_write (struct thread_master *m,
489 int (*func) (struct thread *), void *arg, int fd, const char* funcname)
490 {
491 struct thread *thread;
492
493 assert (m != NULL);
494
495 if (FD_ISSET (fd, &m->writefd))
496 {
497 zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
498 return NULL;
499 }
500
501 thread = thread_get (m, THREAD_WRITE, func, arg, funcname);
502 FD_SET (fd, &m->writefd);
503 thread->u.fd = fd;
504 thread_list_add (&m->write, thread);
505
506 return thread;
507 }
508
509 static struct thread *
510 funcname_thread_add_timer_timeval (struct thread_master *m,
511 int (*func) (struct thread *),
512 int type,
513 void *arg,
514 struct timeval *time_relative,
515 const char* funcname)
516 {
517 struct thread *thread;
518 struct timeval alarm_time;
519 struct thread_list *list;
520 struct thread *tt;
521
522 assert (m != NULL);
523
524 assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
525 assert (time_relative);
526
527 list = ((type == THREAD_TIMER) ? &m->timer : &m->background);
528 thread = thread_get (m, type, func, arg, funcname);
529
530 /* Do we need jitter here? */
531 gettimeofday (&recent_time, NULL);
532 alarm_time.tv_sec = recent_time.tv_sec + time_relative->tv_sec;
533 alarm_time.tv_usec = recent_time.tv_usec + time_relative->tv_usec;
534 thread->u.sands = timeval_adjust(alarm_time);
535
536 /* Sort by timeval. */
537 for (tt = list->head; tt; tt = tt->next)
538 if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
539 break;
540
541 if (tt)
542 thread_list_add_before (list, tt, thread);
543 else
544 thread_list_add (list, thread);
545
546 return thread;
547 }
548
549
550 /* Add timer event thread. */
551 struct thread *
552 funcname_thread_add_timer (struct thread_master *m,
553 int (*func) (struct thread *),
554 void *arg, long timer, const char* funcname)
555 {
556 struct timeval trel;
557
558 assert (m != NULL);
559
560 trel.tv_sec = timer;
561 trel.tv_usec = 0;
562
563 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg,
564 &trel, funcname);
565 }
566
567 /* Add timer event thread with "millisecond" resolution */
568 struct thread *
569 funcname_thread_add_timer_msec (struct thread_master *m,
570 int (*func) (struct thread *),
571 void *arg, long timer, const char* funcname)
572 {
573 struct timeval trel;
574
575 assert (m != NULL);
576
577 trel.tv_sec = timer / 1000;
578 trel.tv_usec = 1000*(timer % 1000);
579
580 return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER,
581 arg, &trel, funcname);
582 }
583
584 /* Add a background thread, with an optional millisec delay */
585 struct thread *
586 funcname_thread_add_background (struct thread_master *m,
587 int (*func) (struct thread *),
588 void *arg, long delay,
589 const char *funcname)
590 {
591 struct timeval trel;
592
593 assert (m != NULL);
594
595 if (delay)
596 {
597 trel.tv_sec = delay / 1000;
598 trel.tv_usec = 1000*(delay % 1000);
599 }
600 else
601 {
602 trel.tv_sec = 0;
603 trel.tv_usec = 0;
604 }
605
606 return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND,
607 arg, &trel, funcname);
608 }
609
610 /* Add simple event thread. */
611 struct thread *
612 funcname_thread_add_event (struct thread_master *m,
613 int (*func) (struct thread *), void *arg, int val, const char* funcname)
614 {
615 struct thread *thread;
616
617 assert (m != NULL);
618
619 thread = thread_get (m, THREAD_EVENT, func, arg, funcname);
620 thread->u.val = val;
621 thread_list_add (&m->event, thread);
622
623 return thread;
624 }
625
626 /* Cancel thread from scheduler. */
627 void
628 thread_cancel (struct thread *thread)
629 {
630 struct thread_list *list;
631
632 switch (thread->type)
633 {
634 case THREAD_READ:
635 assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
636 FD_CLR (thread->u.fd, &thread->master->readfd);
637 list = &thread->master->read;
638 break;
639 case THREAD_WRITE:
640 assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
641 FD_CLR (thread->u.fd, &thread->master->writefd);
642 list = &thread->master->write;
643 break;
644 case THREAD_TIMER:
645 list = &thread->master->timer;
646 break;
647 case THREAD_EVENT:
648 list = &thread->master->event;
649 break;
650 case THREAD_READY:
651 list = &thread->master->ready;
652 break;
653 case THREAD_BACKGROUND:
654 list = &thread->master->background;
655 break;
656 default:
657 return;
658 break;
659 }
660 thread_list_delete (list, thread);
661 thread->type = THREAD_UNUSED;
662 thread_add_unuse (thread->master, thread);
663 }
664
665 /* Delete all events which has argument value arg. */
666 unsigned int
667 thread_cancel_event (struct thread_master *m, void *arg)
668 {
669 unsigned int ret = 0;
670 struct thread *thread;
671
672 thread = m->event.head;
673 while (thread)
674 {
675 struct thread *t;
676
677 t = thread;
678 thread = t->next;
679
680 if (t->arg == arg)
681 {
682 ret++;
683 thread_list_delete (&m->event, t);
684 t->type = THREAD_UNUSED;
685 thread_add_unuse (m, t);
686 }
687 }
688 return ret;
689 }
690
691 static struct timeval *
692 thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val)
693 {
694 if (!thread_empty (tlist))
695 {
696 *timer_val = timeval_subtract (tlist->head->u.sands, recent_time);
697 return timer_val;
698 }
699 return NULL;
700 }
701
702 static struct thread *
703 thread_run (struct thread_master *m, struct thread *thread,
704 struct thread *fetch)
705 {
706 *fetch = *thread;
707 thread->type = THREAD_UNUSED;
708 thread_add_unuse (m, thread);
709 return fetch;
710 }
711
712 static int
713 thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset)
714 {
715 struct thread *thread;
716 struct thread *next;
717 int ready = 0;
718
719 assert (list);
720
721 for (thread = list->head; thread; thread = next)
722 {
723 next = thread->next;
724
725 if (FD_ISSET (THREAD_FD (thread), fdset))
726 {
727 assert (FD_ISSET (THREAD_FD (thread), mfdset));
728 FD_CLR(THREAD_FD (thread), mfdset);
729 thread_list_delete (list, thread);
730 thread_list_add (&thread->master->ready, thread);
731 thread->type = THREAD_READY;
732 ready++;
733 }
734 }
735 return ready;
736 }
737
738 /* Add all timers that have popped to the ready list. */
739 static unsigned int
740 thread_timer_process (struct thread_list *list, struct timeval *timenow)
741 {
742 struct thread *thread;
743 unsigned int ready = 0;
744
745 for (thread = list->head; thread; thread = thread->next)
746 {
747 if (timeval_cmp (*timenow, thread->u.sands) < 0)
748 return ready;
749 thread_list_delete (list, thread);
750 thread->type = THREAD_READY;
751 thread_list_add (&thread->master->ready, thread);
752 ready++;
753 }
754 return ready;
755 }
756
757 /* Fetch next ready thread. */
758 struct thread *
759 thread_fetch (struct thread_master *m, struct thread *fetch)
760 {
761 struct thread *thread;
762 fd_set readfd;
763 fd_set writefd;
764 fd_set exceptfd;
765 struct timeval timer_val;
766 struct timeval timer_val_bg;
767 struct timeval *timer_wait;
768 struct timeval *timer_wait_bg;
769
770 while (1)
771 {
772 int num = 0;
773
774 /* Signals are highest priority */
775 quagga_sigevent_process ();
776
777 /* Normal event are the next highest priority. */
778 if ((thread = thread_trim_head (&m->event)) != NULL)
779 return thread_run (m, thread, fetch);
780
781 /* If there are any ready threads from previous scheduler runs,
782 * process top of them.
783 */
784 if ((thread = thread_trim_head (&m->ready)) != NULL)
785 return thread_run (m, thread, fetch);
786
787 /* Structure copy. */
788 readfd = m->readfd;
789 writefd = m->writefd;
790 exceptfd = m->exceptfd;
791
792 /* Calculate select wait timer if nothing else to do */
793 gettimeofday (&recent_time, NULL);
794 timer_wait = thread_timer_wait (&m->timer, &timer_val);
795 timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
796
797 if (timer_wait_bg &&
798 (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
799 timer_wait = timer_wait_bg;
800
801 num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
802
803 /* Signals should get quick treatment */
804 if (num < 0)
805 {
806 if (errno == EINTR)
807 continue; /* signal received - process it */
808 zlog_warn ("select() error: %s", safe_strerror (errno));
809 return NULL;
810 }
811
812 /* Check foreground timers. Historically, they have had higher
813 priority than I/O threads, so let's push them onto the ready
814 list in front of the I/O threads. */
815 gettimeofday (&recent_time, NULL);
816 thread_timer_process (&m->timer, &recent_time);
817
818 /* Got IO, process it */
819 if (num > 0)
820 {
821 /* Normal priority read thead. */
822 thread_process_fd (&m->read, &readfd, &m->readfd);
823 /* Write thead. */
824 thread_process_fd (&m->write, &writefd, &m->writefd);
825 }
826
827 #if 0
828 /* If any threads were made ready above (I/O or foreground timer),
829 perhaps we should avoid adding background timers to the ready
830 list at this time. If this is code is uncommented, then background
831 timer threads will not run unless there is nothing else to do. */
832 if ((thread = thread_trim_head (&m->ready)) != NULL)
833 return thread_run (m, thread, fetch);
834 #endif
835
836 /* Background timer/events, lowest priority */
837 thread_timer_process (&m->background, &recent_time);
838
839 if ((thread = thread_trim_head (&m->ready)) != NULL)
840 return thread_run (m, thread, fetch);
841 }
842 }
843
844 unsigned long
845 thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
846 {
847 #ifdef HAVE_RUSAGE
848 /* This is 'user + sys' time. */
849 *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) +
850 timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime);
851 #else
852 *cputime = 0;
853 #endif /* HAVE_RUSAGE */
854 return timeval_elapsed (now->real, start->real);
855 }
856
857 /* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
858 Note: we are using real (wall clock) time for this calculation.
859 It could be argued that CPU time may make more sense in certain
860 contexts. The things to consider are whether the thread may have
861 blocked (in which case wall time increases, but CPU time does not),
862 or whether the system is heavily loaded with other processes competing
863 for CPU time. On balance, wall clock time seems to make sense.
864 Plus it has the added benefit that gettimeofday should be faster
865 than calling getrusage. */
866 int
867 thread_should_yield (struct thread *thread)
868 {
869 gettimeofday(&recent_time, NULL);
870 return (timeval_elapsed(recent_time, thread->ru.real) >
871 THREAD_YIELD_TIME_SLOT);
872 }
873
874 /* We check thread consumed time. If the system has getrusage, we'll
875 use that to get in-depth stats on the performance of the thread in addition
876 to wall clock time stats from gettimeofday. */
877 void
878 thread_call (struct thread *thread)
879 {
880 unsigned long realtime, cputime;
881 RUSAGE_T ru;
882
883 /* Cache a pointer to the relevant cpu history thread, if the thread
884 * does not have it yet.
885 *
886 * Callers submitting 'dummy threads' hence must take care that
887 * thread->cpu is NULL
888 */
889 if (!thread->hist)
890 {
891 struct cpu_thread_history tmp;
892
893 tmp.func = thread->func;
894 tmp.funcname = thread->funcname;
895
896 thread->hist = hash_get (cpu_record, &tmp,
897 (void * (*) (void *))cpu_record_hash_alloc);
898 }
899
900 GETRUSAGE (&thread->ru);
901
902 (*thread->func) (thread);
903
904 GETRUSAGE (&ru);
905
906 realtime = thread_consumed_time (&ru, &thread->ru, &cputime);
907 thread->hist->real.total += realtime;
908 if (thread->hist->real.max < realtime)
909 thread->hist->real.max = realtime;
910 #ifdef HAVE_RUSAGE
911 thread->hist->cpu.total += cputime;
912 if (thread->hist->cpu.max < cputime)
913 thread->hist->cpu.max = cputime;
914 #endif
915
916 ++(thread->hist->total_calls);
917 thread->hist->types |= (1 << thread->add_type);
918
919 #ifdef CONSUMED_TIME_CHECK
920 if (realtime > CONSUMED_TIME_CHECK)
921 {
922 /*
923 * We have a CPU Hog on our hands.
924 * Whinge about it now, so we're aware this is yet another task
925 * to fix.
926 */
927 zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
928 thread->funcname,
929 (unsigned long) thread->func,
930 realtime/1000, cputime/1000);
931 }
932 #endif /* CONSUMED_TIME_CHECK */
933 }
934
935 /* Execute thread */
936 struct thread *
937 funcname_thread_execute (struct thread_master *m,
938 int (*func)(struct thread *),
939 void *arg,
940 int val,
941 const char* funcname)
942 {
943 struct thread dummy;
944
945 memset (&dummy, 0, sizeof (struct thread));
946
947 dummy.type = THREAD_EVENT;
948 dummy.add_type = THREAD_EXECUTE;
949 dummy.master = NULL;
950 dummy.func = func;
951 dummy.arg = arg;
952 dummy.u.val = val;
953 dummy.funcname = strip_funcname (funcname);
954 thread_call (&dummy);
955
956 XFREE (MTYPE_THREAD_FUNCNAME, dummy.funcname);
957
958 return NULL;
959 }