*/
RCSID("$Id$")
-#include <freeradius-devel/io/schedule.h>
+#include <freeradius-devel/io/thread.h>
#include <freeradius-devel/server/base.h>
#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/server/radmin.h>
* won't go into la-la-land. They might find unfinished
* commands, but they don't crash.
*/
- if (fr_schedule_pthread_create(&cli_pthread_id, fr_radmin, NULL) < 0) {
+ if (fr_thread_create(&cli_pthread_id, fr_radmin, NULL) < 0) {
PERROR("Failed creating radmin thread");
return -1;
}
EXIT_WITH_FAILURE;
}
- if (unlang_thread_instantiate(thread_ctx) < 0) {
- fr_perror("%s", config->name);
- EXIT_WITH_FAILURE;
- }
-
/*
* Set the panic action (if required)
*/
sc->max_workers = num_workers;
sc->sem = sem;
- if (fr_schedule_pthread_create(&sc->pthread_id, fr_coordinate_thread, sc) < 0) {
+ if (fr_thread_create(&sc->pthread_id, fr_coordinate_thread, sc) < 0) {
talloc_free(sc);
PERROR("Failed creating coordinator %s", coord_reg->name);
return -1;
}
/*
- * See if all the coordinators have started.
+ * Wait for all the coordinators to start.
*/
- fr_dlist_foreach(coord_threads, fr_schedule_coord_t, sc) {
- DEBUG3("Waiting for semaphore from coordinator %s", sc->coord_reg->name);
- SEM_WAIT_INTR(sem);
- }
+ fr_thread_wait(sem, fr_dlist_num_elements(coord_threads));
/*
* Insert the coordinators in the tree
return NULL;
}
-/** Creates a new thread using our standard set of options
- *
- * New threads are:
- * - Joinable, i.e. you can call pthread_join on them to confirm they've exited
- * - Immune to catchable signals.
- *
- * @param[out] thread handled that was created by pthread_create.
- * @param[in] func entry point for the thread.
- * @param[in] arg Argument to pass to func.
- * @return
- * - 0 on success.
- * - -1 on failure.
- */
-int fr_schedule_pthread_create(pthread_t *thread, void *(*func)(void *), void *arg)
-{
- pthread_attr_t attr;
- int ret;
-
- /*
- * Set the thread to wait around after it's exited
- * so it can be joined. This is more of a useful
- * mechanism for the parent to determine if all
- * the threads have exited so it can continue with
- * a graceful shutdown.
- */
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
- ret = pthread_create(thread, &attr, func, arg);
- if (ret != 0) {
- pthread_attr_destroy(&attr);
- fr_strerror_printf("Failed creating thread: %s", fr_syserror(ret));
- return -1;
- }
- pthread_attr_destroy(&attr);
-
- return 0;
-}
-
/** Create a scheduler and spawn the child threads.
*
* @param[in] ctx talloc context.
sn->sc = sc;
sn->status = FR_CHILD_INITIALIZING;
- if (fr_schedule_pthread_create(&sn->pthread_id, fr_schedule_network_thread, sn) < 0) {
+ if (fr_thread_create(&sn->pthread_id, fr_schedule_network_thread, sn) < 0) {
talloc_free(sn);
PERROR("Failed creating network %u", i);
break;
* they've started, OR there's been a problem and they
* can't start.
*/
- for (i = 0; i < (unsigned int)fr_dlist_num_elements(&sc->networks); i++) {
- DEBUG3("Waiting for semaphore from network %u/%u",
- i + 1, (unsigned int)fr_dlist_num_elements(&sc->networks));
- SEM_WAIT_INTR(sc->network_sem);
- }
+ fr_thread_wait(sc->network_sem, fr_dlist_num_elements(&sc->networks));
/*
* See if all of the networks have started.
sw->sc = sc;
sw->status = FR_CHILD_INITIALIZING;
- if (fr_schedule_pthread_create(&sw->pthread_id, fr_schedule_worker_thread, sw) < 0) {
+ if (fr_thread_create(&sw->pthread_id, fr_schedule_worker_thread, sw) < 0) {
talloc_free(sw);
PERROR("Failed creating worker %u", i);
break;
* they've started, OR there's been a problem and they
* can't start.
*/
- for (i = 0; i < (unsigned int)fr_dlist_num_elements(&sc->workers); i++) {
- DEBUG3("Waiting for semaphore from worker %u/%u",
- i + 1, (unsigned int)fr_dlist_num_elements(&sc->workers));
- SEM_WAIT_INTR(sc->worker_sem);
- }
+ fr_thread_wait(sc->worker_sem, fr_dlist_num_elements(&sc->workers));
/*
* See if all of the workers have started.
int fr_schedule_worker_id(void);
-int fr_schedule_pthread_create(pthread_t *thread, void *(*func)(void *), void *arg);
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_thread_instantiate_t worker_thread_instantiate,
fr_schedule_thread_detach_t worker_thread_detach,
#include <signal.h>
+/** Create a joinable thread
+ *
+ * @param[out] thread handle that was created by pthread_create.
+ * @param[in] func entry point for the thread.
+ * @param[in] arg Argument to pass to func.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+int fr_thread_create(pthread_t *thread, fr_thread_entry_t func, void *arg)
+{
+ pthread_attr_t attr;
+ int rcode;
+
+ /*
+ * Set the thread to wait around after it's exited so it
+ * can be joined. This is more of a useful mechanism for
+ * the parent to determine if all the threads have exited
+ * so it can continue with a graceful shutdown.
+ */
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ rcode = pthread_create(thread, &attr, func, arg);
+ if (rcode != 0) {
+ fr_strerror_printf("Failed creating thread: %s", fr_syserror(rcode));
+ pthread_attr_destroy(&attr);
+ return -1;
+ }
+ pthread_attr_destroy(&attr);
+
+ return 0;
+}
+
+/** Wait for multiple threads to signal readiness via a semaphore
+ *
+ * @param[in] sem semaphore to wait on.
+ * @param[in] count number of times to wait (once per thread).
+ */
+void fr_thread_wait(fr_sem_t *sem, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ SEM_WAIT_INTR(sem);
+ }
+}
+
/** Common setup for child threads: block signals, allocate a talloc context, and create an event list
*
* @param[out] out_ctx The talloc ctx we allocate
int fr_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
{
#ifdef WITH_TLS
+ /*
+ * Modules may use thread-specific OpenSSL contexts, so initialize this first.
+ */
if (fr_openssl_thread_init(main_config->openssl_async_pool_init,
main_config->openssl_async_pool_max) < 0) return -1;
#endif
#include <freeradius-devel/util/talloc.h>
#include <freeradius-devel/util/dlist.h>
+#include <pthread.h>
+
+typedef void *(*fr_thread_entry_t)(void *);
+
+int fr_thread_create(pthread_t *thread, fr_thread_entry_t func, void *arg);
+
+void fr_thread_wait(fr_sem_t *sem, unsigned int count);
+
int fr_thread_setup(TALLOC_CTX **ctx, fr_event_list_t **el, char const *name);
int fr_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el);
*/
pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
- if (fr_schedule_pthread_create(&event_thread, sigtran_event_loop, NULL) < 0) {
+ if (fr_thread_create(&event_thread, sigtran_event_loop, NULL) < 0) {
ERROR("main thread - Failed spawning thread for multiplexer event loop: %s", fr_syserror(errno));
return -1;
}