25RCSID(
"$Id: 5f85964fe7b49c741b07ec97a8a9aec32345a67f $")
27#define LOG_DST sc->log
29#include <freeradius-devel/autoconf.h>
31#include <freeradius-devel/io/schedule.h>
32#include <freeradius-devel/util/dlist.h>
33#include <freeradius-devel/util/rb.h>
34#include <freeradius-devel/util/syserror.h>
35#include <freeradius-devel/server/trigger.h>
42#ifdef HAVE_SEMAPHORE_H
46#define SEMAPHORE_LOCKED (0)
50#include <mach/mach_init.h>
51#include <mach/semaphore.h>
54#define sem_t semaphore_t
56#define sem_init(s,p,c) semaphore_create(mach_task_self(),s,SYNC_POLICY_FIFO,c)
58#define sem_wait(s) semaphore_wait(*s)
60#define sem_post(s) semaphore_signal(*s)
62#define sem_destroy(s) semaphore_destroy(mach_task_self(),*s)
65#define SEM_WAIT_INTR(_x) do {if (sem_wait(_x) == 0) break;} while (errno == EINTR)
174 char worker_name[32];
200 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
205 snprintf(worker_name,
sizeof(worker_name),
"Worker %d", sw->
id);
207 sw->
ctx = ctx = talloc_init(
"%s", worker_name);
209 ERROR(
"%s - Failed allocating memory", worker_name);
213 INFO(
"%s - Starting", worker_name);
217 PERROR(
"%s - Failed creating event list", worker_name);
224 PERROR(
"%s - Failed creating worker", worker_name);
231 if (
sc->worker_thread_instantiate) {
233 char section_name[32];
235 snprintf(section_name,
sizeof(section_name),
"%u", sw->
id);
240 if (
sc->worker_thread_instantiate(sw->
ctx, sw->
el, cs) < 0) {
241 PERROR(
"%s - Worker thread instantiation failed", worker_name);
257 DEBUG3(
"%s - Started", worker_name);
262 sem_post(&
sc->worker_sem);
279 INFO(
"%s - Exiting", worker_name);
281 if (
sc->worker_thread_detach)
sc->worker_thread_detach(NULL);
293 sem_post(&
sc->worker_sem);
322 char network_name[32];
348 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
351 snprintf(network_name,
sizeof(network_name),
"Network %d", sn->
id);
353 INFO(
"%s - Starting", network_name);
355 sn->
ctx = ctx = talloc_init(
"%s", network_name);
357 ERROR(
"%s - Failed allocating memory", network_name);
363 PERROR(
"%s - Failed creating event list", network_name);
369 PERROR(
"%s - Failed creating network", network_name);
378 sem_post(&
sc->network_sem);
380 DEBUG3(
"%s - Started", network_name);
400 INFO(
"%s - Exiting", network_name);
405 sem_post(&
sc->network_sem);
437 pthread_attr_init(&attr);
438 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
440 ret = pthread_create(thread, &attr, func, arg);
485 sc->worker_thread_instantiate = worker_thread_instantiate;
486 sc->worker_thread_detach = worker_thread_detach;
494 if (!
sc->single_network) {
495 PERROR(
"Failed creating network");
496 pre_instantiate_st_fail:
502 if (!
sc->single_worker) {
503 PERROR(
"Failed creating worker");
505 goto pre_instantiate_st_fail;
511 if (
sc->worker_thread_instantiate) {
517 if (
sc->worker_thread_instantiate(
sc->single_worker,
el, subcs) < 0) {
518 PERROR(
"Worker thread instantiation failed");
522 goto pre_instantiate_st_fail;
527 PERROR(
"Failed adding worker commands");
529 if (
sc->worker_thread_detach)
sc->worker_thread_detach(NULL);
534 PERROR(
"Failed adding network commands");
543 DEBUG(
"Scheduler created in single-threaded mode");
566 sc->config->max_networks = 1;
567 sc->config->max_workers = 4;
571 if (
sc->config->max_networks < 1)
sc->config->max_networks = 1;
572 if (
sc->config->max_networks > 64)
sc->config->max_networks = 64;
573 if (
sc->config->max_workers < 1)
sc->config->max_workers = 1;
574 if (
sc->config->max_workers > 64)
sc->config->max_workers = 64;
583 memset(&
sc->network_sem, 0,
sizeof(
sc->network_sem));
590 memset(&
sc->worker_sem, 0,
sizeof(
sc->worker_sem));
600 for (i = 0; i <
sc->config->max_networks; i++) {
601 DEBUG3(
"Creating %u/%u networks", i + 1,
sc->config->max_networks);
608 ERROR(
"Network %u - Failed allocating memory", i);
618 PERROR(
"Failed creating network %u", i);
629 DEBUG3(
"Waiting for semaphore from network %u/%u",
659 for (i = 0; i <
sc->config->max_workers; i++) {
660 DEBUG3(
"Creating %u/%u workers", i + 1,
sc->config->max_workers);
667 ERROR(
"Worker %u - Failed allocating memory", i);
677 PERROR(
"Failed creating worker %u", i);
688 DEBUG3(
"Waiting for semaphore from worker %u/%u",
725 PERROR(
"Failed adding worker commands");
739 PERROR(
"Failed adding network commands");
744 if (
sc)
INFO(
"Scheduler created successfully with %u networks and %u workers",
803 DEBUG2(
"Scheduler - Waiting for semaphore indicating network exit %u/%u", i + 1,
807 DEBUG2(
"Scheduler - All networks indicated exit complete");
820 if ((ret = pthread_join(sn->
pthread_id, NULL)) != 0) {
823 DEBUG2(
"Network %i joined (cleaned up)", sn->
id);
833 DEBUG2(
"Scheduler - Waiting for semaphore indicating worker exit %u/%u", i + 1,
837 DEBUG2(
"Scheduler - All workers indicated exit complete");
853 if ((ret = pthread_join(sw->
pthread_id, NULL)) != 0) {
856 DEBUG2(
"Worker %i joined (cleaned up)", sw->
id);
860 sem_destroy(&
sc->network_sem);
861 sem_destroy(&
sc->worker_sem);
888 nr =
sc->single_network;
920 nr =
sc->single_network;
static int const char char buffer[256]
A section grouping multiple CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
fr_command_register_hook_t fr_command_register_hook
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
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.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Head of a doubly linked list.
Entry in a doubly linked list.
#define fr_event_timer_at(...)
#define fr_event_timer_in(...)
fr_cmd_table_t cmd_network_table[]
int fr_network_listen_add(fr_network_t *nr, fr_listen_t *li)
Add a fr_listen_t to a network.
int fr_network_worker_add(fr_network_t *nr, fr_worker_t *worker)
Add a worker to a network in a different thread.
int fr_network_destroy(fr_network_t *nr)
Stop a network thread in an orderly way.
int fr_network_directory_add(fr_network_t *nr, fr_listen_t *li)
Add a "watch directory" call to a network.
void fr_network(fr_network_t *nr)
The main network worker function.
void fr_network_worker_add_self(fr_network_t *nr, fr_worker_t *worker)
Add a worker to a network in the same thread.
int fr_network_exit(fr_network_t *nr)
Signal a network thread to exit.
void fr_network_stats_log(fr_network_t const *nr, fr_log_t const *log)
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.
int fr_event_post_insert(fr_event_list_t *el, fr_event_timer_cb_t callback, void *uctx)
Add a post-event callback to the event list.
fr_event_list_t * fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t status, void *status_uctx)
Initialise a new event list.
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.
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Stores all information relating to an event list.
static const conf_parser_t config[]
CONF_SECTION * cs
thread pool configuration section
TALLOC_CTX * ctx
our allocation ctx
sem_t worker_sem
for inter-thread signaling
fr_event_timer_t const * ev
timer for stats_interval
fr_schedule_child_status_t status
status of the worker
static _Thread_local int worker_id
Internal ID of the current worker thread.
fr_event_list_t * el
event list for single-threaded mode.
fr_schedule_t * sc
the scheduler we are running under
fr_worker_t * single_worker
for single-threaded mode
static void stats_timer(fr_event_list_t *el, fr_time_t now, void *uctx)
fr_log_lvl_t lvl
log level
fr_network_t * fr_schedule_directory_add(fr_schedule_t *sc, fr_listen_t *li)
Add a directory NOTE_EXTEND to a scheduler.
#define SEM_WAIT_INTR(_x)
fr_schedule_config_t * config
configuration
fr_network_t * single_network
for single-threaded mode
fr_schedule_thread_instantiate_t worker_thread_instantiate
thread instantiation callback
fr_schedule_child_status_t
Track the child thread status.
@ FR_CHILD_FAIL
failed, and in the exited queue
@ FR_CHILD_FREE
child is free
@ FR_CHILD_RUNNING
running, and in the running queue
@ FR_CHILD_EXITED
exited, and in the exited queue
@ FR_CHILD_INITIALIZING
initialized, but not running
fr_network_t * fr_schedule_listen_add(fr_schedule_t *sc, fr_listen_t *li)
Add a fr_listen_t to a scheduler.
fr_network_t * nr
the receive data structure
fr_schedule_thread_detach_t worker_thread_detach
bool running
is the scheduler running?
int fr_schedule_worker_id(void)
Return the worker id for the current thread.
static void * fr_schedule_worker_thread(void *arg)
Entry point for worker threads.
int fr_schedule_pthread_create(pthread_t *thread, void *(*func)(void *), void *arg)
Creates a new thread using our standard set of options.
fr_schedule_t * fr_schedule_create(TALLOC_CTX *ctx, 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.
unsigned int num_workers_exited
number of exited workers
sem_t network_sem
for inter-thread signaling
int fr_schedule_destroy(fr_schedule_t **sc_to_free)
Destroy a scheduler, and tell its child threads to exit.
unsigned int id
a unique ID
fr_dlist_head_t networks
list of networks
pthread_t pthread_id
the thread of this network
fr_log_t * log
log destination
fr_dlist_head_t workers
list of workers
static void * fr_schedule_network_thread(void *arg)
Initialize and run the network thread.
fr_dlist_t entry
our entry into the linked list of networks
Scheduler specific information for network threads.
int(* fr_schedule_thread_instantiate_t)(TALLOC_CTX *ctx, fr_event_list_t *el, void *uctx)
Setup a new thread.
void(* fr_schedule_thread_detach_t)(void *uctx)
Explicitly free resources allocated by fr_schedule_thread_instantiate_t.
fr_time_delta_t stats_interval
print channel statistics
static const uchar sc[16]
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define fr_time_delta_ispos(_a)
#define fr_time_add(_a, _b)
Add a time/time delta together.
static fr_event_list_t * el
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
int fr_worker_pre_event(UNUSED fr_time_t now, UNUSED fr_time_delta_t wake, void *uctx)
Pre-event handler.
fr_worker_t * fr_worker_create(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.
fr_cmd_table_t cmd_worker_table[]
void fr_worker_destroy(fr_worker_t *worker)
Destroy a worker.
void fr_worker_post_event(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Post-event handler.
void fr_worker(fr_worker_t *worker)
The main loop and entry point of the stand-alone worker thread.
A worker which takes packets from a master, and processes them.
unsigned int id
a unique ID
int uses
how many network threads are using it
pthread_t pthread_id
the thread of this worker
fr_schedule_t * sc
the scheduler we are running under
TALLOC_CTX * ctx
our allocation ctx
fr_event_list_t * el
our event list
fr_time_t cpu_time
how much CPU time this worker has used
fr_dlist_t entry
our entry into the linked list of workers
fr_schedule_child_status_t status
status of the worker
fr_worker_t * worker
the worker data structure
Scheduler specific information for worker threads.