* Start the network / worker threads.
*/
{
- fr_event_list_t *el = NULL;
fr_schedule_config_t *schedule;
MEM(schedule = talloc_zero(global_ctx, fr_schedule_config_t));
schedule->worker = config->worker;
schedule->cs = cf_section_find(config->root_cs, "thread", CF_IDENT_ANY);
- /*
- * Single server mode: use the global event list.
- * Otherwise, each network thread will create
- * its own event list.
- */
- if (!config->spawn_workers) {
- el = main_loop_event_list();
- }
-
/*
* Fix spurious messages
*/
fr_strerror_clear();
- sc = fr_schedule_create(NULL, el, &default_log, fr_debug_lvl,
+ sc = fr_schedule_create(NULL, !config->spawn_workers, main_loop_event_list(),
+ &default_log, fr_debug_lvl,
thread_instantiate, thread_detach, schedule);
if (!sc) {
PERROR("Failed starting the scheduler");
* to exit gracefully. fr_schedule_destroy only returns once all
* threads have been joined.
*/
- (void) fr_schedule_destroy(&sc);
+ if (unlikely(fr_schedule_destroy(&sc) < 0)) {
+ EXIT_WITH_PERROR;
+ }
/*
* We're exiting, so we can delete the PID file.
CONF_SECTION *cs; //!< thread pool configuration section
fr_event_list_t *el; //!< event list for single-threaded mode.
+ bool single_threaded; //!< true if running in single-threaded mode.
fr_log_t *log; //!< log destination
fr_log_lvl_t lvl; //!< log level
/** Create a scheduler and spawn the child threads.
*
* @param[in] ctx talloc context.
+ * @param[in] single_threaded no workers are spawned, everything runs in a common event loop.
* @param[in] el event list, only for single-threaded mode.
* @param[in] logger destination for all logging messages.
* @param[in] lvl log level.
* - NULL on error
* - fr_schedule_t new scheduler
*/
-fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el,
+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,
}
sc->el = el;
+ sc->single_threaded = single_threaded;
sc->log = logger;
sc->lvl = lvl;
sc->cs = sc->config->cs;
/*
* If we're single-threaded, create network / worker, and insert them into the event loop.
*/
- if (el) {
+ if (single_threaded) {
sc->single_network = fr_network_create(sc, el, "Network", sc->log, sc->lvl, &sc->config->network);
if (!sc->single_network) {
PERROR("Failed creating network");
if (sc) INFO("Scheduler created successfully with %u networks and %u workers",
sc->config->max_networks, (unsigned int)fr_dlist_num_elements(&sc->workers));
+ /*
+ * Instantiate thread-local data for the main thread too.
+ * In single-threaded mode this is done above. In
+ * multi-worker mode the main thread also needs module
+ * thread data so that triggers can use module xlats.
+ */
+ if (sc->worker_thread_instantiate &&
+ unlikely((sc->worker_thread_instantiate(NULL, el, NULL) < 0))) {
+ PERROR("Main thread instantiation failed");
+ goto mt_fail;
+ }
+
return sc;
}
sc->running = false;
+
+
/*
* Single threaded mode: kill the only network / worker we have.
*/
- if (sc->el) {
+ if (sc->single_threaded) {
/*
* Destroy the network side first. It tells the
* workers to close.
}
fr_worker_destroy(sc->single_worker);
fr_coords_destroy();
+
goto done;
+ } else {
+ /*
+ * Detach thread-local data for the main thread.
+ * Worker threads handle their own detach, but
+ * the main thread was instantiated explicitly
+ * by fr_schedule_create.
+ */
+ if (sc->worker_thread_detach) sc->worker_thread_detach(NULL);
}
/*
fr_sem_free(sc->coord_sem);
fr_sem_free(sc->network_sem);
fr_sem_free(sc->worker_sem);
+
done:
/*
* Now that all of the workers are done, we can return to
(void) talloc_get_type_abort(sc, fr_schedule_t);
- if (sc->el) {
+ if (sc->single_threaded) {
nr = sc->single_network;
} else {
fr_schedule_network_t *sn;
(void) talloc_get_type_abort(sc, fr_schedule_t);
- if (sc->el) {
+ if (sc->single_threaded) {
nr = sc->single_network;
} else {
fr_schedule_network_t *sn;
int fr_schedule_worker_id(void);
-fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, fr_event_list_t *el, fr_log_t *log, fr_log_lvl_t lvl,
+fr_schedule_t *fr_schedule_create(TALLOC_CTX *ctx, bool single_threaded, fr_event_list_t *el,
+ fr_log_t *log, 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) CC_HINT(nonnull(3));
connection_t *conn;
uint64_t id;
- fr_assert(el);
+ fr_assert_msg(el, "No event list provided");
MEM(conn = talloc(ctx, connection_t));
talloc_set_destructor(conn, _connection_free);
app_io_inst->ipaddr = my_ipaddr;
app_io_inst->port = my_port;
- sched = fr_schedule_create(autofree, NULL, &default_log, debug_lvl, num_networks, num_workers, NULL, NULL);
+ sched = fr_schedule_create(autofree, false, NULL, &default_log, debug_lvl, num_networks, num_workers, NULL, NULL);
if (!sched) {
fprintf(stderr, "schedule_test: Failed to create scheduler\n");
fr_exit_now(EXIT_FAILURE);
argv += (optind - 1);
#endif
- sched = fr_schedule_create(autofree, NULL, &default_log, L_DBG_LVL_MAX, num_networks, num_workers, NULL, NULL);
+ sched = fr_schedule_create(autofree, false, NULL, &default_log, L_DBG_LVL_MAX, num_networks, num_workers, NULL, NULL);
if (!sched) {
fprintf(stderr, "schedule_test: Failed to create scheduler\n");
fr_exit_now(EXIT_FAILURE);