25 RCSID(
"$Id: eb4ec47bf0228a87b36c1f8c69b6d8e8f919a280 $")
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
43 #include <semaphore.h>
46 #define SEMAPHORE_LOCKED (0)
49 #include <mach/task.h>
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];
178 snprintf(worker_name,
sizeof(worker_name),
"Worker %d", sw->
id);
180 sw->
ctx = ctx = talloc_init(
"%s", worker_name);
182 ERROR(
"%s - Failed allocating memory", worker_name);
186 INFO(
"%s - Starting", worker_name);
190 PERROR(
"%s - Failed creating event list", worker_name);
197 PERROR(
"%s - Failed creating worker", worker_name);
204 if (
sc->worker_thread_instantiate) {
206 char section_name[32];
208 snprintf(section_name,
sizeof(section_name),
"%u", sw->
id);
213 if (
sc->worker_thread_instantiate(sw->
ctx, sw->
el, cs) < 0) {
214 PERROR(
"%s - Worker thread instantiation failed", worker_name);
230 DEBUG3(
"%s - Started", worker_name);
235 sem_post(&
sc->worker_sem);
252 INFO(
"%s - Exiting", worker_name);
254 if (
sc->worker_thread_detach)
sc->worker_thread_detach(NULL);
266 sem_post(&
sc->worker_sem);
295 char network_name[32];
297 snprintf(network_name,
sizeof(network_name),
"Network %d", sn->
id);
299 INFO(
"%s - Starting", network_name);
301 sn->
ctx = ctx = talloc_init(
"%s", network_name);
303 ERROR(
"%s - Failed allocating memory", network_name);
309 PERROR(
"%s - Failed creating event list", network_name);
315 PERROR(
"%s - Failed creating network", network_name);
324 sem_post(&
sc->network_sem);
326 DEBUG3(
"%s - Started", network_name);
346 INFO(
"%s - Exiting", network_name);
351 sem_post(&
sc->network_sem);
383 pthread_attr_init(&attr);
384 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
386 ret = pthread_create(thread, &attr, func, arg);
431 sc->worker_thread_instantiate = worker_thread_instantiate;
432 sc->worker_thread_detach = worker_thread_detach;
440 if (!
sc->single_network) {
441 PERROR(
"Failed creating network");
442 pre_instantiate_st_fail:
448 if (!
sc->single_worker) {
449 PERROR(
"Failed creating worker");
451 goto pre_instantiate_st_fail;
457 if (
sc->worker_thread_instantiate) {
463 if (
sc->worker_thread_instantiate(
sc->single_worker,
el, subcs) < 0) {
464 PERROR(
"Worker thread instantiation failed");
468 goto pre_instantiate_st_fail;
473 PERROR(
"Failed adding worker commands");
475 if (
sc->worker_thread_detach)
sc->worker_thread_detach(NULL);
480 PERROR(
"Failed adding network commands");
485 DEBUG(
"Scheduler created in single-threaded mode");
508 sc->config->max_networks = 1;
509 sc->config->max_workers = 4;
513 if (
sc->config->max_networks < 1)
sc->config->max_networks = 1;
514 if (
sc->config->max_networks > 64)
sc->config->max_networks = 64;
515 if (
sc->config->max_workers < 1)
sc->config->max_workers = 1;
516 if (
sc->config->max_workers > 64)
sc->config->max_workers = 64;
525 memset(&
sc->network_sem, 0,
sizeof(
sc->network_sem));
532 memset(&
sc->worker_sem, 0,
sizeof(
sc->worker_sem));
542 for (i = 0; i <
sc->config->max_networks; i++) {
543 DEBUG3(
"Creating %u/%u networks", i + 1,
sc->config->max_networks);
550 ERROR(
"Network %u - Failed allocating memory", i);
560 PERROR(
"Failed creating network %u", i);
571 DEBUG3(
"Waiting for semaphore from network %u/%u",
601 for (i = 0; i <
sc->config->max_workers; i++) {
602 DEBUG3(
"Creating %u/%u workers", i + 1,
sc->config->max_workers);
609 ERROR(
"Worker %u - Failed allocating memory", i);
619 PERROR(
"Failed creating worker %u", i);
630 DEBUG3(
"Waiting for semaphore from worker %u/%u",
667 PERROR(
"Failed adding worker commands");
681 PERROR(
"Failed adding network commands");
686 if (
sc)
INFO(
"Scheduler created successfully with %u networks and %u workers",
745 DEBUG2(
"Scheduler - Waiting for semaphore indicating network exit %u/%u", i + 1,
749 DEBUG2(
"Scheduler - All networks indicated exit complete");
762 if ((ret = pthread_join(sn->
pthread_id, NULL)) != 0) {
765 DEBUG2(
"Network %i joined (cleaned up)", sn->
id);
775 DEBUG2(
"Scheduler - Waiting for semaphore indicating worker exit %u/%u", i + 1,
779 DEBUG2(
"Scheduler - All workers indicated exit complete");
795 if ((ret = pthread_join(sw->
pthread_id, NULL)) != 0) {
798 DEBUG2(
"Worker %i joined (cleaned up)", sw->
id);
802 sem_destroy(&
sc->network_sem);
803 sem_destroy(&
sc->worker_sem);
830 nr =
sc->single_network;
862 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_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
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 int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of 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.
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.
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.
void fr_network(fr_network_t *nr)
The main network worker function.
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_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_post_insert(fr_event_list_t *el, fr_event_timer_cb_t callback, void *uctx)
Add a post-event callback to the 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
#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 * 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.
int fr_schedule_pthread_create(pthread_t *thread, void *(*func)(void *), void *arg)
Creates a new thread using our standard set of options.
unsigned int num_workers_exited
number of exited workers
sem_t network_sem
for inter-thread signaling
static void * fr_schedule_network_thread(void *arg)
Initialize and run the network thread.
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.
int fr_schedule_destroy(fr_schedule_t **sc_to_free)
Destroy a scheduler, and tell its child threads to exit.
static void * fr_schedule_worker_thread(void *arg)
Entry point for worker threads.
unsigned int id
a unique ID
fr_network_t * fr_schedule_directory_add(fr_schedule_t *sc, fr_listen_t *li)
Add a directory NOTE_EXTEND to a scheduler.
fr_dlist_head_t networks
list of networks
pthread_t pthread_id
the thread of this network
fr_network_t * fr_schedule_listen_add(fr_schedule_t *sc, fr_listen_t *li)
Add a fr_listen_t to a scheduler.
fr_log_t * log
log destination
fr_dlist_head_t workers
list of workers
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)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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_cmd_table_t cmd_worker_table[]
void fr_worker_destroy(fr_worker_t *worker)
Destroy a worker.
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.
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.