25RCSID(
"$Id: c5fd2abb57a44689e0e1e4bfd2a25affaf5a587c $")
 
   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);
 
  255                        PERROR(
"%s - Failed adding worker to network %u", worker_name, sn->
id);
 
  260        DEBUG3(
"%s - Started", worker_name);
 
  265        sem_post(&
sc->worker_sem);
 
  282        INFO(
"%s - Exiting", worker_name);
 
  284        if (
sc->worker_thread_detach) 
sc->worker_thread_detach(NULL);   
 
  296        sem_post(&
sc->worker_sem);
 
 
  325        char                            network_name[32];
 
  351        pthread_sigmask(SIG_BLOCK, &sigset, NULL);
 
  354        snprintf(network_name, 
sizeof(network_name), 
"Network %d", sn->
id);
 
  356        INFO(
"%s - Starting", network_name);
 
  358        sn->
ctx = ctx = talloc_init(
"%s", network_name);
 
  360                ERROR(
"%s - Failed allocating memory", network_name);
 
  366                PERROR(
"%s - Failed creating event list", network_name);
 
  372                PERROR(
"%s - Failed creating network", network_name);
 
  381        sem_post(&
sc->network_sem);
 
  383        DEBUG3(
"%s - Started", network_name);
 
  403        INFO(
"%s - Exiting", network_name);
 
  408        sem_post(&
sc->network_sem);
 
 
  440        pthread_attr_init(&attr);
 
  441        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 
  443        ret = pthread_create(thread, &attr, func, arg);
 
 
  488        sc->worker_thread_instantiate = worker_thread_instantiate;
 
  489        sc->worker_thread_detach = worker_thread_detach;
 
  497                if (!
sc->single_network) {
 
  498                        PERROR(
"Failed creating network");
 
  499                pre_instantiate_st_fail:
 
  505                if (!
sc->single_worker) {
 
  506                        PERROR(
"Failed creating worker");
 
  508                                PERROR(
"Failed destroying network");
 
  510                        goto pre_instantiate_st_fail;
 
  516                if (
sc->worker_thread_instantiate) {
 
  522                        if (
sc->worker_thread_instantiate(
sc->single_worker, 
el, subcs) < 0) {
 
  523                                PERROR(
"Worker thread instantiation failed");
 
  526                                        PERROR(
"Failed destroying network");
 
  529                                goto pre_instantiate_st_fail;
 
  534                        PERROR(
"Failed adding worker commands");
 
  536                        if (
sc->worker_thread_detach) 
sc->worker_thread_detach(NULL);
 
  541                        PERROR(
"Failed adding network commands");
 
  550                DEBUG(
"Scheduler created in single-threaded mode");
 
  573                sc->config->max_networks = 1;
 
  574                sc->config->max_workers = 4;
 
  578                if (
sc->config->max_networks < 1) 
sc->config->max_networks = 1;
 
  579                if (
sc->config->max_networks > 64) 
sc->config->max_networks = 64;
 
  580                if (
sc->config->max_workers < 1) 
sc->config->max_workers = 1;
 
  581                if (
sc->config->max_workers > 64) 
sc->config->max_workers = 64;
 
  590        memset(&
sc->network_sem, 0, 
sizeof(
sc->network_sem));
 
  597        memset(&
sc->worker_sem, 0, 
sizeof(
sc->worker_sem));
 
  607        for (i = 0; i < 
sc->config->max_networks; i++) {
 
  608                DEBUG3(
"Creating %u/%u networks", i + 1, 
sc->config->max_networks);
 
  615                        ERROR(
"Network %u - Failed allocating memory", i);
 
  625                        PERROR(
"Failed creating network %u", i);
 
  636                DEBUG3(
"Waiting for semaphore from network %u/%u",
 
  666        for (i = 0; i < 
sc->config->max_workers; i++) {
 
  667                DEBUG3(
"Creating %u/%u workers", i + 1, 
sc->config->max_workers);
 
  674                        ERROR(
"Worker %u - Failed allocating memory", i);
 
  684                        PERROR(
"Failed creating worker %u", i);
 
  695                DEBUG3(
"Waiting for semaphore from worker %u/%u",
 
  732                        PERROR(
"Failed adding worker commands");
 
  746                        PERROR(
"Failed adding network commands");
 
  751        if (
sc) 
INFO(
"Scheduler created successfully with %u networks and %u workers",
 
 
  789                        ERROR(
"Failed destroying network");
 
  802                        PERROR(
"Failed signaling network %i to exit", sn->
id);
 
  814                DEBUG2(
"Scheduler - Waiting for semaphore indicating network exit %u/%u", i + 1,
 
  818        DEBUG2(
"Scheduler - All networks indicated exit complete");
 
  831                if ((ret = pthread_join(sn->
pthread_id, NULL)) != 0) {
 
  834                        DEBUG2(
"Network %i joined (cleaned up)", sn->
id);
 
  844                DEBUG2(
"Scheduler - Waiting for semaphore indicating worker exit %u/%u", i + 1,
 
  848        DEBUG2(
"Scheduler - All workers indicated exit complete");
 
  864                if ((ret = pthread_join(sw->
pthread_id, NULL)) != 0) {
 
  867                        DEBUG2(
"Worker %i joined (cleaned up)", sw->
id);
 
  871        sem_destroy(&
sc->network_sem);
 
  872        sem_destroy(&
sc->worker_sem);
 
 
  899                nr = 
sc->single_network;
 
 
  931                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.
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.
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.
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.
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
fr_timer_t * ev
timer for stats_interval
sem_t worker_sem
for inter-thread signaling
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
fr_log_lvl_t lvl
log level
static void stats_timer(fr_timer_list_t *tl, fr_time_t now, void *uctx)
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_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.
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.