The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
schedule.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 35ea2bcfd8ff947c13a2b99033621ce0acccbc4c $
19 *
20 * @brief Network / worker thread scheduling
21 * @file io/schedule.c
22 *
23 * @copyright 2016 Alan DeKok (aland@freeradius.org)
24 */
25RCSID("$Id: 35ea2bcfd8ff947c13a2b99033621ce0acccbc4c $")
26
27#define LOG_DST sc->log
28
29#include <freeradius-devel/autoconf.h>
30
31#include <freeradius-devel/io/schedule.h>
32#include <freeradius-devel/io/thread.h>
33#include <freeradius-devel/util/dlist.h>
34#include <freeradius-devel/util/rb.h>
35#include <freeradius-devel/util/syserror.h>
36#include <freeradius-devel/server/trigger.h>
37#include <freeradius-devel/util/semaphore.h>
38
39#include <pthread.h>
40
41/** Scheduler specific information for worker threads
42 *
43 * Wraps a fr_worker_t, tracking additional information that
44 * the scheduler uses.
45 */
46typedef struct {
47 fr_thread_t thread; //!< common thread structure - must be first!
48
49 int uses; //!< how many network threads are using it
50 fr_time_t cpu_time; //!< how much CPU time this worker has used
51
52 fr_schedule_t *sc; //!< the scheduler we are running under
53
54 fr_worker_t *worker; //!< the worker data structure
56
57/** Scheduler specific information for network threads
58 *
59 * Wraps a fr_network_t, tracking additional information that
60 * the scheduler uses.
61 */
62typedef struct {
63 fr_thread_t thread; //!< common thread structure - must be first!
64
65 fr_schedule_t *sc; //!< the scheduler we are running under
66
67 fr_network_t *nr; //!< the receive data structure
68
69 fr_timer_t *ev; //!< timer for stats_interval
71
72
73/**
74 * The scheduler
75 */
77 bool running; //!< is the scheduler running?
78
79 CONF_SECTION *cs; //!< thread pool configuration section
80 fr_event_list_t *el; //!< event list for single-threaded mode.
81 bool single_threaded; //!< true if running in single-threaded mode.
82
83 fr_log_t *log; //!< log destination
84 fr_log_lvl_t lvl; //!< log level
85
86 fr_schedule_config_t *config; //!< configuration
87
88 unsigned int num_workers_exited; //!< number of exited workers
89
90 fr_sem_t *worker_sem; //!< for inter-thread signaling
91 fr_sem_t *network_sem; //!< for inter-thread signaling
92 fr_sem_t *coord_sem; //!< for inter-thread signaling
93
96
97 fr_dlist_head_t workers; //!< list of workers
98 fr_dlist_head_t networks; //!< list of networks
99
100 fr_network_t *single_network; //!< for single-threaded mode
101 fr_worker_t *single_worker; //!< for single-threaded mode
102};
103
104static _Thread_local int worker_id = -1; //!< Internal ID of the current worker thread.
105
106/** Return the worker id for the current thread
107 *
108 * @return worker ID
109 */
111{
112 return worker_id;
113}
114
115/** Explicitly set the worker id for the current thread
116 *
117 * **Only to be used in test programs like unit_test_module**
118 */
120{
121 worker_id = id;
122}
123
124/** Entry point for worker threads
125 *
126 * @param[in] arg the fr_schedule_worker_t
127 * @return NULL
128 */
129static void *fr_schedule_worker_thread(void *arg)
130{
131 fr_schedule_worker_t *sw = talloc_get_type_abort(arg, fr_schedule_worker_t);
132 fr_schedule_t *sc = sw->sc;
134 char worker_name[32];
135
136 worker_id = sw->thread.id; /* Store the current worker ID */
137
138 snprintf(worker_name, sizeof(worker_name), "Worker %d", sw->thread.id);
139
140#ifdef HAVE_PTHREAD_SETNAME_NP
141# ifdef __APPLE__
142 pthread_setname_np(worker_name);
143# else
144 pthread_setname_np(pthread_self(), worker_name);
145# endif
146#endif
147
148 if (fr_thread_setup(&sw->thread, worker_name) < 0) goto fail;
149
150 sw->worker = fr_worker_alloc(sw->thread.ctx, sw->thread.el, worker_name, sc->log, sc->lvl, &sc->config->worker);
151 if (!sw->worker) {
152 PERROR("%s - Failed creating worker", worker_name);
153 goto fail;
154 }
155
156 /*
157 * @todo make this a registry
158 */
159 if (sc->worker_thread_instantiate) {
160 CONF_SECTION *cs;
161 char section_name[32];
162
163 snprintf(section_name, sizeof(section_name), "%u", sw->thread.id);
164
165 cs = cf_section_find(sc->cs, "worker", section_name);
166 if (!cs) cs = cf_section_find(sc->cs, "worker", NULL);
167
168 if (sc->worker_thread_instantiate(sw->thread.ctx, sw->thread.el, cs) < 0) {
169 PERROR("%s - Worker thread instantiation failed", worker_name);
170 goto fail;
171 }
172 }
173
174 /*
175 * Add this worker to all network threads.
176 */
177 fr_dlist_foreach(&sc->networks, fr_schedule_network_t, sn) {
178 if (unlikely(fr_network_worker_add(sn->nr, sw->worker) < 0)) {
179 PERROR("%s - Failed adding worker to network %u", worker_name, sn->thread.id);
180 goto fail; /* FIXME - Should maybe try to undo partial adds? */
181 }
182 }
183
184 /*
185 * Tell the originator that the thread has started.
186 */
187 fr_thread_start(&sw->thread, sc->worker_sem);
188
189 /*
190 * Do all of the work.
191 */
192 fr_worker(sw->worker);
193
194 status = FR_THREAD_EXITED;
195
196fail:
197 if (sw->worker) {
199 sw->worker = NULL;
200 }
201
202 if (sc->worker_thread_detach) sc->worker_thread_detach(NULL); /* Fixme once we figure out what uctx should be */
203
204 fr_thread_exit(&sw->thread, status, sc->worker_sem);
205
206 return NULL;
207}
208
209
210static void stats_timer(fr_timer_list_t *tl, fr_time_t now, void *uctx)
211{
212 fr_schedule_network_t *sn = talloc_get_type_abort(uctx, fr_schedule_network_t);
213
214 fr_network_stats_log(sn->nr, sn->sc->log);
215
216 (void) fr_timer_at(sn, tl, &sn->ev, fr_time_add(now, sn->sc->config->stats_interval), false, stats_timer, sn);
217}
218
219/** Initialize and run the network thread.
220 *
221 * @param[in] arg the fr_schedule_network_t
222 * @return NULL
223 */
224static void *fr_schedule_network_thread(void *arg)
225{
226 fr_schedule_network_t *sn = talloc_get_type_abort(arg, fr_schedule_network_t);
227 fr_schedule_t *sc = sn->sc;
229 char network_name[32];
230
231 snprintf(network_name, sizeof(network_name), "Network %d", sn->thread.id);
232
233#ifdef HAVE_PTHREAD_SETNAME_NP
234# ifdef __APPLE__
235 pthread_setname_np(network_name);
236# else
237 pthread_setname_np(pthread_self(), network_name);
238# endif
239#endif
240
241 if (fr_thread_setup(&sn->thread, network_name) < 0) goto fail;
242
243 sn->nr = fr_network_create(sn->thread.ctx, sn->thread.el, network_name, sc->log, sc->lvl, &sc->config->network);
244 if (!sn->nr) {
245 PERROR("%s - Failed creating network", network_name);
246 goto fail;
247 }
248
249 /*
250 * Tell the originator that the thread has started.
251 */
252 fr_thread_start(&sn->thread, sc->network_sem);
253
254 /*
255 * Print out statistics for this network IO handler.
256 */
257 if (fr_time_delta_ispos(sc->config->stats_interval)) {
258 (void) fr_timer_in(sn, sn->thread.el->tl, &sn->ev, sn->sc->config->stats_interval, false, stats_timer, sn);
259 }
260
261 /*
262 * Call the main event processing loop of the network
263 * thread Will not return until the worker is about
264 * to exit.
265 */
266 fr_network(sn->nr);
267
268 status = FR_THREAD_EXITED;
269
270fail:
271 fr_thread_exit(&sn->thread, status, sc->network_sem);
272
273 return NULL;
274}
275
276/** Create a scheduler and spawn the child threads.
277 *
278 * @param[in] ctx talloc context.
279 * @param[in] single_threaded no workers are spawned, everything runs in a common event loop.
280 * @param[in] el event list, only for single-threaded mode.
281 * @param[in] logger destination for all logging messages.
282 * @param[in] lvl log level.
283 * @param[in] worker_thread_instantiate callback for new worker threads.
284 * @param[in] worker_thread_detach callback to destroy resources
285 * allocated by worker_thread_instantiate.
286 * @param[in] config configuration for the scheduler
287 * @return
288 * - NULL on error
289 * - fr_schedule_t new scheduler
290 */
292 bool single_threaded,
294 fr_log_t *logger, fr_log_lvl_t lvl,
295 fr_schedule_thread_instantiate_t worker_thread_instantiate,
296 fr_schedule_thread_detach_t worker_thread_detach,
298{
299 unsigned int i;
300 fr_schedule_worker_t *sw, *next_sw;
301 fr_schedule_network_t *sn, *next_sn;
303
304 sc = talloc_zero(ctx, fr_schedule_t);
305 if (!sc) {
306 fr_strerror_const("Failed allocating memory");
307 return NULL;
308 }
309
310 /*
311 * Parse any scheduler-specific configuration.
312 */
313 if (!config) {
314 MEM(sc->config = talloc_zero(sc, fr_schedule_config_t));
315 sc->config->max_networks = 1;
316 sc->config->max_workers = 4;
317 } else {
318 sc->config = config;
319
320 if (sc->config->max_networks < 1) sc->config->max_networks = 1;
321 if (sc->config->max_networks > 64) sc->config->max_networks = 64;
322 if (sc->config->max_workers < 1) sc->config->max_workers = 1;
323 if (sc->config->max_workers > 64) sc->config->max_workers = 64;
324 }
325
326 sc->el = el;
327 sc->single_threaded = single_threaded;
328 sc->log = logger;
329 sc->lvl = lvl;
330 sc->cs = sc->config->cs;
331
332 sc->worker_thread_instantiate = worker_thread_instantiate;
333 sc->worker_thread_detach = worker_thread_detach;
334 sc->running = true;
335
336 /*
337 * If we're single-threaded, create network / worker, and insert them into the event loop.
338 */
339 if (single_threaded) {
340 sc->single_network = fr_network_create(sc, el, "Network", sc->log, sc->lvl, &sc->config->network);
341 if (!sc->single_network) {
342 PERROR("Failed creating network");
343 pre_instantiate_st_fail:
345 return NULL;
346 }
347
348 if (fr_coords_create(sc, el) < 0) {
349 PERROR("Failed creating coordinators");
350 if (unlikely(fr_network_destroy(sc->single_network) < 0)) {
351 PERROR("Failed destroying network");
352 }
353 goto pre_instantiate_st_fail;
354 }
355
356 worker_id = 0;
357 sc->single_worker = fr_worker_alloc(sc, el, "Worker", sc->log, sc->lvl, &sc->config->worker);
358 if (!sc->single_worker) {
359 PERROR("Failed creating worker");
360 if (unlikely(fr_network_destroy(sc->single_network) < 0)) {
361 PERROR("Failed destroying network");
362 }
363 goto pre_instantiate_st_fail;
364 }
365
366 /*
367 * Parent thread-specific data from the single_worker
368 */
369 if (sc->worker_thread_instantiate) {
370 CONF_SECTION *subcs;
371
372 subcs = cf_section_find(sc->cs, "worker", "0");
373 if (!subcs) subcs = cf_section_find(sc->cs, "worker", NULL);
374
375 if (sc->worker_thread_instantiate(sc->single_worker, el, subcs) < 0) {
376 PERROR("Worker thread instantiation failed");
377 destroy_both:
378 if (unlikely(fr_network_destroy(sc->single_network) < 0)) {
379 PERROR("Failed destroying network");
380 }
381 fr_worker_destroy(sc->single_worker);
382 goto pre_instantiate_st_fail;
383 }
384 }
385
386 if (fr_command_register_hook(NULL, "0", sc->single_worker, cmd_worker_table) < 0) {
387 PERROR("Failed adding worker commands");
388 st_fail:
389 if (sc->worker_thread_detach) sc->worker_thread_detach(NULL);
390 goto destroy_both;
391 }
392
393 if (fr_command_register_hook(NULL, "0", sc->single_network, cmd_network_table) < 0) {
394 PERROR("Failed adding network commands");
395 goto st_fail;
396 }
397
398 /*
399 * Register the worker with the network, so
400 * things like fr_network_send_request() work.
401 */
402 fr_network_worker_add_self(sc->single_network, sc->single_worker);
403 DEBUG("Scheduler created in single-threaded mode");
404
405 if (fr_event_pre_insert(el, fr_worker_pre_event, sc->single_worker) < 0) {
406 fr_strerror_const("Failed adding pre-check to event list");
407 goto st_fail;
408 }
409
410 if (fr_coord_pre_event_insert(el) < 0) {
411 fr_strerror_const("Failed adding coordinator pre-check to event list");
412 goto st_fail;
413 }
414
415 /*
416 * Add the event which processes request_t packets.
417 */
418 if (fr_event_post_insert(el, fr_worker_post_event, sc->single_worker) < 0) {
419 fr_strerror_const("Failed inserting post-processing event");
420 goto st_fail;
421 }
422
424 fr_strerror_const("Failed adding coordinator post-processing to event list");
425 goto st_fail;
426 }
427
428 return sc;
429 }
430
431 /*
432 * Create the lists which hold the workers and networks.
433 */
434 fr_dlist_init(&sc->workers, fr_schedule_worker_t, thread.entry);
435 fr_dlist_init(&sc->networks, fr_schedule_network_t, thread.entry);
436
437 sc->network_sem = fr_sem_alloc();
438 if (!sc->network_sem) {
439 sem_fail:
440 ERROR("Failed creating semaphore: %s", fr_syserror(errno));
441 fr_sem_free(sc->network_sem);
442 fr_sem_free(sc->worker_sem);
444 return NULL;
445 }
446
447 sc->worker_sem = fr_sem_alloc();
448 if (!sc->worker_sem) goto sem_fail;
449
450 sc->coord_sem = fr_sem_alloc();
451 if (!sc->coord_sem) goto sem_fail;
452
453 /*
454 * Create the network threads first.
455 */
456 for (i = 0; i < sc->config->max_networks; i++) {
457 DEBUG3("Creating %u/%u networks", i + 1, sc->config->max_networks);
458
459 /*
460 * Create a worker "glue" structure
461 */
462 sn = talloc_zero(sc, fr_schedule_network_t);
463 if (!sn) {
464 ERROR("Network %u - Failed allocating memory", i);
465 break;
466 }
467
468 sn->thread.id = i;
469 sn->sc = sc;
471
473 talloc_free(sn);
474 PERROR("Failed creating network %u", i);
475 break;
476 }
477
478 fr_dlist_insert_head(&sc->networks, sn);
479 }
480
481 /*
482 * Wait for all of the networks to signal us that either
483 * they've started, OR there's been a problem and they
484 * can't start.
485 */
486 if (fr_thread_wait_list(sc->network_sem, &sc->networks) < 0) {
488 return NULL;
489 }
490
491 /*
492 * Create the coordination threads
493 */
494 if (fr_coord_start(sc->config->max_workers, sc->coord_sem) < 0) {
496 return NULL;
497 };
498
499 /*
500 * Create all of the workers.
501 */
502 for (i = 0; i < sc->config->max_workers; i++) {
503 DEBUG3("Creating %u/%u workers", i + 1, sc->config->max_workers);
504
505 /*
506 * Create a worker "glue" structure
507 */
508 sw = talloc_zero(sc, fr_schedule_worker_t);
509 if (!sw) {
510 ERROR("Worker %u - Failed allocating memory", i);
511 break;
512 }
513
514 sw->thread.id = i;
515 sw->sc = sc;
517
519 talloc_free(sw);
520 PERROR("Failed creating worker %u", i);
521 break;
522 }
523
524 fr_dlist_insert_head(&sc->workers, sw);
525 }
526
527 /*
528 * Wait for all of the workers to signal us that either
529 * they've started, OR there's been a problem and they
530 * can't start.
531 */
532 if (fr_thread_wait_list(sc->worker_sem, &sc->workers) < 0) {
534 return NULL;
535 }
536
537 for (sw = fr_dlist_head(&sc->workers), i = 0;
538 sw != NULL;
539 sw = next_sw, i++) {
540 char buffer[32];
541
542 next_sw = fr_dlist_next(&sc->workers, sw);
543
544 snprintf(buffer, sizeof(buffer), "%d", i);
546 PERROR("Failed adding worker commands");
547 mt_fail:
549 return NULL;
550 }
551 }
552
553 for (sn = fr_dlist_head(&sc->networks), i = 0;
554 sn != NULL;
555 sn = next_sn, i++) {
556 char buffer[32];
557
558 next_sn = fr_dlist_next(&sc->networks, sn);
559
560 snprintf(buffer, sizeof(buffer), "%d", i);
562 PERROR("Failed adding network commands");
563 goto mt_fail;
564 }
565 }
566
567 if (sc) INFO("Scheduler created successfully with %u networks and %u workers",
568 sc->config->max_networks, (unsigned int)fr_dlist_num_elements(&sc->workers));
569
570 /*
571 * Instantiate thread-local data for the main thread too.
572 * In single-threaded mode this is done above. In
573 * multi-worker mode the main thread also needs module
574 * thread data so that triggers can use module xlats.
575 */
576 if (sc->worker_thread_instantiate &&
577 unlikely((sc->worker_thread_instantiate(sc, el, NULL) < 0))) {
578 PERROR("Main thread instantiation failed");
579 goto mt_fail;
580 }
581
582 return sc;
583}
584
585/** Destroy a scheduler, and tell its child threads to exit.
586 *
587 * @note This may be called with no worker or network threads in the case of a
588 * instantiation error. This function _should_ deal with that condition
589 * gracefully.
590 *
591 * @param[in] sc_to_free the scheduler
592 * @return
593 * - <0 on error
594 * - 0 on success
595 */
597{
598 fr_schedule_t *sc = *sc_to_free;
599 unsigned int i;
602 int ret;
603
604 if (!sc) return 0;
605
606 sc->running = false;
607
608
609
610 /*
611 * Single threaded mode: kill the only network / worker we have.
612 */
613 if (sc->single_threaded) {
614 /*
615 * Destroy the network side first. It tells the
616 * workers to close.
617 */
618 if (unlikely(fr_network_destroy(sc->single_network) < 0)) {
619 ERROR("Failed destroying network");
620 }
621 fr_worker_destroy(sc->single_worker);
623
624 goto done;
625 } else {
626 /*
627 * Detach thread-local data for the main thread.
628 * Worker threads handle their own detach, but
629 * the main thread was instantiated explicitly
630 * by fr_schedule_create.
631 */
632 if (sc->worker_thread_detach) sc->worker_thread_detach(NULL);
633 }
634
635 /*
636 * Signal each network thread to exit.
637 */
638 fr_dlist_foreach(&sc->networks, fr_schedule_network_t, sne) {
639 if (fr_network_exit(sne->nr) < 0) {
640 PERROR("Failed signaling network %i to exit", sne->thread.id);
641 }
642 }
643
644 /*
645 * If the network threads are running, tell them to exit,
646 * and wait for them to do so. Each network thread tells
647 * all of its worker threads that it's exiting. It then
648 * closes the channels. When the workers see that there
649 * are no input channels, they exit, too.
650 */
651 for (i = 0; i < (unsigned int)fr_dlist_num_elements(&sc->networks); i++) {
652 DEBUG2("Scheduler - Waiting for semaphore indicating network exit %u/%u", i + 1,
653 (unsigned int)fr_dlist_num_elements(&sc->networks));
654 SEM_WAIT_INTR(sc->network_sem);
655 }
656 DEBUG2("Scheduler - All networks indicated exit complete");
657
658 while ((sn = fr_dlist_pop_head(&sc->networks)) != NULL) {
659 /*
660 * Ensure that the thread has exited before
661 * cleaning up the context.
662 *
663 * This also ensures that the child threads have
664 * exited before the main thread cleans up the
665 * module instances.
666 */
667 if ((ret = pthread_join(sn->thread.pthread_id, NULL)) != 0) {
668 ERROR("Failed joining network %i: %s", sn->thread.id, fr_syserror(ret));
669 } else {
670 DEBUG2("Network %i joined (cleaned up)", sn->thread.id);
671 }
672 }
673
674 /*
675 * Wait for all worker threads to finish. THEN clean up
676 * modules. Otherwise, the modules will be removed from
677 * underneath the workers!
678 */
679 for (i = 0; i < (unsigned int)fr_dlist_num_elements(&sc->workers); i++) {
680 DEBUG2("Scheduler - Waiting for semaphore indicating worker exit %u/%u", i + 1,
681 (unsigned int)fr_dlist_num_elements(&sc->workers));
682 SEM_WAIT_INTR(sc->worker_sem);
683 }
684 DEBUG2("Scheduler - All workers indicated exit complete");
685
686 /*
687 * Clean up the exited workers.
688 */
689 while ((sw = fr_dlist_pop_head(&sc->workers)) != NULL) {
690 /*
691 * Ensure that the thread has exited before
692 * cleaning up the context.
693 *
694 * This also ensures that the child threads have
695 * exited before the main thread cleans up the
696 * module instances.
697 */
698 if ((ret = pthread_join(sw->thread.pthread_id, NULL)) != 0) {
699 ERROR("Failed joining worker %i: %s", sw->thread.id, fr_syserror(ret));
700 } else {
701 DEBUG2("Worker %i joined (cleaned up)", sw->thread.id);
702 }
703 }
704
705 fr_sem_free(sc->coord_sem);
706 fr_sem_free(sc->network_sem);
707 fr_sem_free(sc->worker_sem);
708
709done:
710 /*
711 * Now that all of the workers are done, we can return to
712 * the caller, and have it dlclose() the modules.
713 */
715 *sc_to_free = NULL;
716
717 return 0;
718}
719
720/** Add a fr_listen_t to a scheduler.
721 *
722 * @param[in] sc the scheduler
723 * @param[in] li the ctx and callbacks for the transport.
724 * @return
725 * - NULL on error
726 * - the fr_network_t that the socket was added to.
727 */
729{
730 fr_network_t *nr;
731
732 (void) talloc_get_type_abort(sc, fr_schedule_t);
733
734 if (sc->single_threaded) {
735 nr = sc->single_network;
736 } else {
738
739 /*
740 * @todo - round robin it among the listeners?
741 * or maybe add it to the same parent thread?
742 */
743 sn = fr_dlist_head(&sc->networks);
744 nr = sn->nr;
745 }
746
747 if (fr_network_listen_add(nr, li) < 0) return NULL;
748
749 return nr;
750}
751
752/** Add a directory NOTE_EXTEND to a scheduler.
753 *
754 * @param[in] sc the scheduler
755 * @param[in] li the ctx and callbacks for the transport.
756 * @return
757 * - NULL on error
758 * - the fr_network_t that the socket was added to.
759 */
761{
762 fr_network_t *nr;
763
764 (void) talloc_get_type_abort(sc, fr_schedule_t);
765
766 if (sc->single_threaded) {
767 nr = sc->single_network;
768 } else {
770
771 /*
772 * @todo - round robin it among the listeners?
773 * or maybe add it to the same parent thread?
774 */
775 sn = fr_dlist_head(&sc->networks);
776 nr = sn->nr;
777 }
778
779 if (fr_network_directory_add(nr, li) < 0) return NULL;
780
781 return nr;
782}
static int const char char buffer[256]
Definition acutest.h:576
#define RCSID(id)
Definition build.h:512
#define unlikely(_x)
Definition build.h:407
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1029
fr_command_register_hook_t fr_command_register_hook
Definition command.c:41
int fr_coords_create(TALLOC_CTX *ctx, fr_event_list_t *el)
Start coordinators in single threaded mode.
Definition coord.c:592
void fr_coords_destroy(void)
Clean up coordinators in single threaded mode.
Definition coord.c:574
int fr_coord_post_event_insert(fr_event_list_t *el)
Insert instance specific post-event callbacks.
Definition coord.c:833
int fr_coord_pre_event_insert(fr_event_list_t *el)
Insert instance specific pre-event callbacks.
Definition coord.c:808
int fr_coord_start(uint32_t num_workers, fr_sem_t *sem)
Start all registered coordinator threads in multi-threaded mode.
Definition coord.c:524
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:242
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:468
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
Definition dlist.h:98
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:921
static void * fr_dlist_pop_head(fr_dlist_head_t *list_head)
Remove the head item in a list.
Definition dlist.h:654
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
Definition dlist.h:320
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:537
Head of a doubly linked list.
Definition dlist.h:51
talloc_free(hp)
fr_cmd_table_t cmd_network_table[]
Definition network.c:2154
int fr_network_listen_add(fr_network_t *nr, fr_listen_t *li)
Add a fr_listen_t to a network.
Definition network.c:231
int fr_network_worker_add(fr_network_t *nr, fr_worker_t *worker)
Add a worker to a network in a different thread.
Definition network.c:300
int fr_network_destroy(fr_network_t *nr)
Stop a network thread in an orderly way.
Definition network.c:1737
int fr_network_directory_add(fr_network_t *nr, fr_listen_t *li)
Add a "watch directory" call to a network.
Definition network.c:285
void fr_network(fr_network_t *nr)
The main network worker function.
Definition network.c:1853
void fr_network_worker_add_self(fr_network_t *nr, fr_worker_t *worker)
Add a worker to a network in the same thread.
Definition network.c:320
int fr_network_exit(fr_network_t *nr)
Signal a network thread to exit.
Definition network.c:1908
void fr_network_stats_log(fr_network_t const *nr, fr_log_t const *log)
Definition network.c:2087
fr_network_t * fr_network_create(TALLOC_CTX *ctx, fr_event_list_t *el, char const *name, fr_log_t const *logger, fr_log_lvl_t lvl, fr_network_config_t const *config)
Create a network.
Definition network.c:1941
#define PERROR(_fmt,...)
Definition log.h:228
#define DEBUG3(_fmt,...)
Definition log.h:266
int fr_event_pre_insert(fr_event_list_t *el, fr_event_status_cb_t callback, void *uctx)
Add a pre-event callback to the event list.
Definition event.c:1963
int fr_event_post_insert(fr_event_list_t *el, fr_event_post_cb_t callback, void *uctx)
Add a post-event callback to the event list.
Definition event.c:2010
Stores all information relating to an event list.
Definition event.c:377
fr_log_lvl_t
Definition log.h:64
static const conf_parser_t config[]
Definition base.c:163
#define DEBUG2(fmt,...)
static bool done
Definition radclient.c:80
#define INFO(fmt,...)
Definition radict.c:63
CONF_SECTION * cs
thread pool configuration section
Definition schedule.c:79
fr_thread_t thread
common thread structure - must be first!
Definition schedule.c:63
fr_timer_t * ev
timer for stats_interval
Definition schedule.c:69
static _Thread_local int worker_id
Internal ID of the current worker thread.
Definition schedule.c:104
fr_sem_t * coord_sem
for inter-thread signaling
Definition schedule.c:92
fr_schedule_t * fr_schedule_create(TALLOC_CTX *ctx, bool single_threaded, fr_event_list_t *el, fr_log_t *logger, fr_log_lvl_t lvl, fr_schedule_thread_instantiate_t worker_thread_instantiate, fr_schedule_thread_detach_t worker_thread_detach, fr_schedule_config_t *config)
Create a scheduler and spawn the child threads.
Definition schedule.c:291
fr_event_list_t * el
event list for single-threaded mode.
Definition schedule.c:80
fr_schedule_t * sc
the scheduler we are running under
Definition schedule.c:65
fr_sem_t * worker_sem
for inter-thread signaling
Definition schedule.c:90
fr_worker_t * single_worker
for single-threaded mode
Definition schedule.c:101
fr_log_lvl_t lvl
log level
Definition schedule.c:84
static void stats_timer(fr_timer_list_t *tl, fr_time_t now, void *uctx)
Definition schedule.c:210
fr_network_t * fr_schedule_directory_add(fr_schedule_t *sc, fr_listen_t *li)
Add a directory NOTE_EXTEND to a scheduler.
Definition schedule.c:760
fr_schedule_config_t * config
configuration
Definition schedule.c:86
fr_network_t * single_network
for single-threaded mode
Definition schedule.c:100
fr_schedule_thread_instantiate_t worker_thread_instantiate
thread instantiation callback
Definition schedule.c:94
fr_network_t * fr_schedule_listen_add(fr_schedule_t *sc, fr_listen_t *li)
Add a fr_listen_t to a scheduler.
Definition schedule.c:728
fr_network_t * nr
the receive data structure
Definition schedule.c:67
fr_schedule_thread_detach_t worker_thread_detach
Definition schedule.c:95
bool running
is the scheduler running?
Definition schedule.c:77
void fr_schedule_worker_id_set(int id)
Explicitly set the worker id for the current thread.
Definition schedule.c:119
int fr_schedule_worker_id(void)
Return the worker id for the current thread.
Definition schedule.c:110
static void * fr_schedule_worker_thread(void *arg)
Entry point for worker threads.
Definition schedule.c:129
fr_sem_t * network_sem
for inter-thread signaling
Definition schedule.c:91
unsigned int num_workers_exited
number of exited workers
Definition schedule.c:88
int fr_schedule_destroy(fr_schedule_t **sc_to_free)
Destroy a scheduler, and tell its child threads to exit.
Definition schedule.c:596
bool single_threaded
true if running in single-threaded mode.
Definition schedule.c:81
fr_dlist_head_t networks
list of networks
Definition schedule.c:98
fr_log_t * log
log destination
Definition schedule.c:83
fr_dlist_head_t workers
list of workers
Definition schedule.c:97
static void * fr_schedule_network_thread(void *arg)
Initialize and run the network thread.
Definition schedule.c:224
Scheduler specific information for network threads.
Definition schedule.c:62
The scheduler.
Definition schedule.c:76
int(* fr_schedule_thread_instantiate_t)(TALLOC_CTX *ctx, fr_event_list_t *el, void *uctx)
Setup a new thread.
Definition schedule.h:56
void(* fr_schedule_thread_detach_t)(void *uctx)
Explicitly free resources allocated by fr_schedule_thread_instantiate_t.
Definition schedule.h:62
fr_time_delta_t stats_interval
print channel statistics
Definition schedule.h:71
void fr_sem_free(fr_sem_t *sem)
Definition semaphore.c:50
fr_sem_t * fr_sem_alloc(void)
Definition semaphore.c:30
#define SEM_WAIT_INTR(_x)
Definition semaphore.h:56
sem_t fr_sem_t
Definition semaphore.h:53
static const uchar sc[16]
Definition smbdes.c:115
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
Definition log.h:93
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
void fr_thread_start(fr_thread_t *thread, fr_sem_t *sem)
Signal the parent that we're done.
Definition thread.c:203
int fr_thread_wait_list(fr_sem_t *sem, fr_dlist_head_t *head)
Wait for multiple threads to signal readiness via a semaphore.
Definition thread.c:79
int fr_thread_create(pthread_t *thread, fr_thread_entry_t func, void *arg)
Create a joinable thread.
Definition thread.c:46
int fr_thread_setup(fr_thread_t *out, char const *name)
Common setup for child threads: block signals, allocate a talloc context, and create an event list.
Definition thread.c:112
void fr_thread_exit(fr_thread_t *thread, fr_thread_status_t status, fr_sem_t *sem)
Signal the parent that we're done.
Definition thread.c:218
fr_thread_status_t status
running, etc.
Definition thread.h:49
fr_event_list_t * el
our event list
Definition thread.h:53
int id
unique ID for this thread
Definition thread.h:48
fr_thread_status_t
Track the child thread status.
Definition thread.h:38
@ FR_THREAD_INITIALIZING
initialized, but not running
Definition thread.h:40
@ FR_THREAD_EXITED
exited, and in the exited queue
Definition thread.h:42
@ FR_THREAD_FAIL
failed, and in the exited queue
Definition thread.h:43
TALLOC_CTX * ctx
our allocation ctx
Definition thread.h:52
pthread_t pthread_id
of this thread
Definition thread.h:50
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:49
A timer event.
Definition timer.c:83
#define fr_timer_in(...)
Definition timer.h:87
#define fr_timer_at(...)
Definition timer.h:81
static fr_event_list_t * el
#define fr_strerror_const(_msg)
Definition strerror.h:223
int fr_worker_pre_event(UNUSED fr_time_t now, UNUSED fr_time_delta_t wake, void *uctx)
Pre-event handler.
Definition worker.c:1560
fr_worker_t * fr_worker_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, char const *name, fr_log_t const *logger, fr_log_lvl_t lvl, fr_worker_config_t *config)
Create a worker.
Definition worker.c:1350
fr_cmd_table_t cmd_worker_table[]
Definition worker.c:1751
void fr_worker_destroy(fr_worker_t *worker)
Destroy a worker.
Definition worker.c:1010
void fr_worker_post_event(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Post-event handler.
Definition worker.c:1581
void fr_worker(fr_worker_t *worker)
The main loop and entry point of the stand-alone worker thread.
Definition worker.c:1502
A worker which takes packets from a master, and processes them.
Definition worker.c:90
int uses
how many network threads are using it
Definition schedule.c:49
fr_schedule_t * sc
the scheduler we are running under
Definition schedule.c:52
fr_thread_t thread
common thread structure - must be first!
Definition schedule.c:47
fr_time_t cpu_time
how much CPU time this worker has used
Definition schedule.c:50
fr_worker_t * worker
the worker data structure
Definition schedule.c:54
Scheduler specific information for worker threads.
Definition schedule.c:46