/* * Callback for freeing a client. */ void client_free(RADCLIENT *client) { if (!client) return; #ifdef WITH_DYNAMIC_CLIENTS if (client->dynamic == 2) { time_t now; if (!deleted_clients) { deleted_clients = fr_fifo_create(NULL, 1024, (void (*)(void *))client_free); if (!deleted_clients) return; /* MEMLEAK */ } /* * Mark it as in the fifo, and remember when we * pushed it. */ client->dynamic = 3; client->created = now = time(NULL); /* re-set it */ fr_fifo_push(deleted_clients, client); /* * Peek at the head of the fifo. If it might * still be in use, return. Otherwise, pop it * from the queue and delete it. */ client = fr_fifo_peek(deleted_clients); rad_assert(client != NULL); if ((client->created + 120) >= now) return; client = fr_fifo_pop(deleted_clients); rad_assert(client != NULL); } #endif talloc_free(client); }
/* * Allocate the thread pool, and seed it with an initial number * of threads. * * FIXME: What to do on a SIGHUP??? */ int thread_pool_init(CONF_SECTION *cs, int *spawn_flag) { #ifndef WITH_GCD int i, rcode; CONF_SECTION *pool_cf; #endif time_t now; cs = cs; /* -Wunused */ now = time(NULL); rad_assert(spawn_flag != NULL); rad_assert(*spawn_flag == TRUE); rad_assert(pool_initialized == FALSE); /* not called on HUP */ #ifndef WITH_GCD pool_cf = cf_subsection_find_next(cs, NULL, "thread"); if (!pool_cf) *spawn_flag = FALSE; #endif /* * Initialize the thread pool to some reasonable values. */ memset(&thread_pool, 0, sizeof(THREAD_POOL)); #ifndef WITH_GCD thread_pool.head = NULL; thread_pool.tail = NULL; thread_pool.total_threads = 0; thread_pool.max_thread_num = 1; thread_pool.cleanup_delay = 5; thread_pool.stop_flag = 0; #endif thread_pool.spawn_flag = *spawn_flag; /* * Don't bother initializing the mutexes or * creating the hash tables. They won't be used. */ if (!*spawn_flag) return 0; #ifdef WNOHANG if ((pthread_mutex_init(&thread_pool.wait_mutex,NULL) != 0)) { radlog(L_ERR, "FATAL: Failed to initialize wait mutex: %s", strerror(errno)); return -1; } /* * Create the hash table of child PID's */ thread_pool.waiters = fr_hash_table_create(pid_hash, pid_cmp, free); if (!thread_pool.waiters) { radlog(L_ERR, "FATAL: Failed to set up wait hash"); return -1; } #endif #ifndef WITH_GCD if (cf_section_parse(pool_cf, NULL, thread_config) < 0) { return -1; } /* * Catch corner cases. */ if (thread_pool.min_spare_threads < 1) thread_pool.min_spare_threads = 1; if (thread_pool.max_spare_threads < 1) thread_pool.max_spare_threads = 1; if (thread_pool.max_spare_threads < thread_pool.min_spare_threads) thread_pool.max_spare_threads = thread_pool.min_spare_threads; if (thread_pool.max_threads == 0) thread_pool.max_threads = 256; if ((thread_pool.max_queue_size < 2) || (thread_pool.max_queue_size > 1048576)) { radlog(L_ERR, "FATAL: max_queue_size value must be in range 2-1048576"); return -1; } #endif /* WITH_GCD */ /* * The pool has already been initialized. Don't spawn * new threads, and don't forget about forked children, */ if (pool_initialized) { return 0; } #ifndef WITH_GCD /* * Initialize the queue of requests. */ memset(&thread_pool.semaphore, 0, sizeof(thread_pool.semaphore)); rcode = sem_init(&thread_pool.semaphore, 0, SEMAPHORE_LOCKED); if (rcode != 0) { radlog(L_ERR, "FATAL: Failed to initialize semaphore: %s", strerror(errno)); return -1; } rcode = pthread_mutex_init(&thread_pool.queue_mutex,NULL); if (rcode != 0) { radlog(L_ERR, "FATAL: Failed to initialize queue mutex: %s", strerror(errno)); return -1; } /* * Allocate multiple fifos. */ for (i = 0; i < RAD_LISTEN_MAX; i++) { thread_pool.fifo[i] = fr_fifo_create(thread_pool.max_queue_size, NULL); if (!thread_pool.fifo[i]) { radlog(L_ERR, "FATAL: Failed to set up request fifo"); return -1; } } #endif #ifdef HAVE_OPENSSL_CRYPTO_H /* * If we're linking with OpenSSL too, then we need * to set up the mutexes and enable the thread callbacks. */ if (!setup_ssl_mutexes()) { radlog(L_ERR, "FATAL: Failed to set up SSL mutexes"); return -1; } #endif #ifndef WITH_GCD /* * Create a number of waiting threads. * * If we fail while creating them, do something intelligent. */ for (i = 0; i < thread_pool.start_threads; i++) { if (spawn_thread(now, 0) == NULL) { return -1; } } #else thread_pool.queue = dispatch_queue_create("org.freeradius.threads", NULL); if (!thread_pool.queue) { radlog(L_ERR, "Failed creating dispatch queue: %s\n", strerror(errno)); exit(1); } #endif DEBUG2("Thread pool initialized"); pool_initialized = TRUE; return 0; }
int main(int argc, char **argv) { int i, j, array[MAX]; fr_fifo_t *fi; fi = fr_fifo_create(NULL, MAX, NULL); if (!fi) fr_exit(1); for (j = 0; j < 5; j++) { #define SPLIT (MAX/3) #define COUNT ((j * SPLIT) + i) for (i = 0; i < SPLIT; i++) { array[COUNT % MAX] = COUNT; if (fr_fifo_push(fi, &array[COUNT % MAX]) < 0) { fprintf(stderr, "%d %d\tfailed pushing %d\n", j, i, COUNT); fr_exit(2); } if (fr_fifo_num_elements(fi) != (i + 1)) { fprintf(stderr, "%d %d\tgot size %d expected %d\n", j, i, i + 1, fr_fifo_num_elements(fi)); fr_exit(1); } } if (fr_fifo_num_elements(fi) != SPLIT) { fprintf(stderr, "HALF %d %d\n", fr_fifo_num_elements(fi), SPLIT); fr_exit(1); } for (i = 0; i < SPLIT; i++) { int *p; p = fr_fifo_pop(fi); if (!p) { fprintf(stderr, "No pop at %d\n", i); fr_exit(3); } if (*p != COUNT) { fprintf(stderr, "%d %d\tgot %d expected %d\n", j, i, *p, COUNT); fr_exit(4); } if (fr_fifo_num_elements(fi) != SPLIT - (i + 1)) { fprintf(stderr, "%d %d\tgot size %d expected %d\n", j, i, SPLIT - (i + 1), fr_fifo_num_elements(fi)); fr_exit(1); } } if (fr_fifo_num_elements(fi) != 0) { fprintf(stderr, "ZERO %d %d\n", fr_fifo_num_elements(fi), 0); fr_exit(1); } } talloc_free(fi); fr_exit(0); }
/* * Allocate the thread pool, and seed it with an initial number * of threads. * * FIXME: What to do on a SIGHUP??? */ int thread_pool_init(CONF_SECTION *cs, int spawn_flag) { int i, rcode; CONF_SECTION *pool_cf; time_t now; now = time(NULL); /* * We're not spawning new threads, don't do * anything. */ if (!spawn_flag) return 0; /* * After a SIGHUP, we don't over-write the previous values. */ if (!pool_initialized) { /* * Initialize the thread pool to some reasonable values. */ memset(&thread_pool, 0, sizeof(THREAD_POOL)); thread_pool.head = NULL; thread_pool.tail = NULL; thread_pool.total_threads = 0; thread_pool.max_thread_num = 1; thread_pool.cleanup_delay = 5; thread_pool.spawn_flag = spawn_flag; #ifdef WNOHANG if ((pthread_mutex_init(&thread_pool.wait_mutex,NULL) != 0)) { radlog(L_ERR, "FATAL: Failed to initialize wait mutex: %s", strerror(errno)); return -1; } /* * Create the hash table of child PID's */ thread_pool.waiters = fr_hash_table_create(pid_hash, pid_cmp, free); if (!thread_pool.waiters) { radlog(L_ERR, "FATAL: Failed to set up wait hash"); return -1; } #endif } pool_cf = cf_subsection_find_next(cs, NULL, "thread"); if (!pool_cf) { radlog(L_ERR, "FATAL: Attempting to start in multi-threaded mode with no thread configuration in radiusd.conf"); return -1; } if (cf_section_parse(pool_cf, NULL, thread_config) < 0) { return -1; } /* * Catch corner cases. */ if (thread_pool.min_spare_threads < 1) thread_pool.min_spare_threads = 1; if (thread_pool.max_spare_threads < 1) thread_pool.max_spare_threads = 1; if (thread_pool.max_spare_threads < thread_pool.min_spare_threads) thread_pool.max_spare_threads = thread_pool.min_spare_threads; /* * The pool has already been initialized. Don't spawn * new threads, and don't forget about forked children, */ if (pool_initialized) { return 0; } /* * Initialize the queue of requests. */ memset(&thread_pool.semaphore, 0, sizeof(thread_pool.semaphore)); rcode = sem_init(&thread_pool.semaphore, 0, SEMAPHORE_LOCKED); if (rcode != 0) { radlog(L_ERR, "FATAL: Failed to initialize semaphore: %s", strerror(errno)); return -1; } rcode = pthread_mutex_init(&thread_pool.queue_mutex,NULL); if (rcode != 0) { radlog(L_ERR, "FATAL: Failed to initialize queue mutex: %s", strerror(errno)); return -1; } /* * Allocate multiple fifos. */ for (i = 0; i < RAD_LISTEN_MAX; i++) { thread_pool.fifo[i] = fr_fifo_create(65536, NULL); if (!thread_pool.fifo[i]) { radlog(L_ERR, "FATAL: Failed to set up request fifo"); return -1; } } #ifdef HAVE_OPENSSL_CRYPTO_H /* * If we're linking with OpenSSL too, then we need * to set up the mutexes and enable the thread callbacks. */ if (!setup_ssl_mutexes()) { radlog(L_ERR, "FATAL: Failed to set up SSL mutexes"); return -1; } #endif /* * Create a number of waiting threads. * * If we fail while creating them, do something intelligent. */ for (i = 0; i < thread_pool.start_threads; i++) { if (spawn_thread(now) == NULL) { return -1; } } DEBUG2("Thread pool initialized"); pool_initialized = TRUE; return 0; }