freeradius 多线程pool
1.thread_pool_manage
1.1 Loop over the thread pool, deleting exited threads. 状态 THREAD_EXITED
for (handle = thread_pool.head; handle; handle = next) {
next = handle->next;
/*
* Maybe we've asked the thread to exit, and it
* has agreed.
*/
if (handle->status == THREAD_EXITED) {
pthread_join(handle->pthread_id, NULL);
delete_thread(handle);
#ifdef HAVE_STDATOMIC_H
CAS_DECR(thread_pool.exited_threads);
#else
pthread_mutex_lock(&thread_pool.queue_mutex);
thread_pool.exited_threads--;
pthread_mutex_unlock(&thread_pool.queue_mutex);
#endif
}
}
1.2If there are too few spare threads. Go create some more.
/*
* Create a number of spare threads.
*/
for (i = 0; i < total; i++) {
handle = spawn_thread(now, 1);
if (handle == NULL) {
return;
}
}
1.3 If there are too many spare threads, delete one. 设置为 handle->status = THREAD_CANCELLED;
/*
* Walk through the thread pool, deleting the
* first idle thread we come across.
*/
for (handle = thread_pool.head; (handle != NULL) && (spare > 0) ; handle = next) {
next = handle->next;
/*
* If the thread is not handling a
* request, but still live, then tell it
* to exit.
*
* It will eventually wake up, and realize
* it's been told to commit suicide.
*/
if ((handle->request == NULL) &&
(handle->status == THREAD_RUNNING)) {
handle->status = THREAD_CANCELLED;
/*
* Post an extra semaphore, as a
* signal to wake up, and exit.
*/
sem_post(&thread_pool.semaphore);
spare--;
break;
}
}
1.4Spawn a new thread, and place it in the thread pool.
static THREAD_HANDLE *spawn_thread(time_t now, int do_trigger)
{
int rcode;
THREAD_HANDLE *handle;
/*
* Ensure that we don't spawn too many threads.
*/
if (thread_pool.total_threads >= thread_pool.max_threads) {
DEBUG2("Thread spawn failed. Maximum number of threads (%d) already running.", thread_pool.max_threads);
return NULL;
}
/*
* Allocate a new thread handle.
*/
handle = (THREAD_HANDLE *) rad_malloc(sizeof(THREAD_HANDLE));
memset(handle, 0, sizeof(THREAD_HANDLE));
handle->prev = NULL;
handle->next = NULL;
handle->thread_num = thread_pool.max_thread_num++;
handle->request_count = 0;
handle->status = THREAD_RUNNING;
handle->timestamp = time(NULL);
/*
* Create the thread joinable, so that it can be cleaned up
* using pthread_join().
*
* Note that the function returns non-zero on error, NOT
* -1. The return code is the error, and errno isn't set.
*/
rcode = pthread_create(&handle->pthread_id, 0, request_handler_thread, handle);
if (rcode != 0) {
free(handle);
ERROR("Thread create failed: %s",
fr_syserror(rcode));
return NULL;
}
/*
* One more thread to go into the list.
*/
thread_pool.total_threads++;
DEBUG2("Thread spawned new child %d. Total threads in pool: %d",
handle->thread_num, thread_pool.total_threads);
if (do_trigger) exec_trigger(NULL, NULL, "server.thread.start", true);
/*
* Add the thread handle to the tail of the thread pool list.
*/
if (thread_pool.tail) {
thread_pool.tail->next = handle;
handle->prev = thread_pool.tail;
thread_pool.tail = handle;
} else {
rad_assert(thread_pool.head == NULL);
thread_pool.head = thread_pool.tail = handle;
}
/*
* Update the time we last spawned a thread.
*/
thread_pool.time_last_spawned = now;
/*
* Fire trigger if maximum number of threads reached
*/
if (thread_pool.total_threads >= thread_pool.max_threads)
exec_trigger(NULL, NULL, "server.thread.max_threads", true);
/*
* And return the new handle to the caller.
*/
return handle;
}
2、 The main thread handler for requests. Wait on the semaphore until we have it, and process the request.
static void *request_handler_thread(void *arg)
{
THREAD_HANDLE *self = (THREAD_HANDLE *) arg;
radlog_set_pthread_id(self->pthread_id);
char tmpbuf[128];
sprintf(tmpbuf, "request work%d", self->thread_num);
INFO("start req hander thread:%s, tid:%d", tmpbuf, gettid());
pthread_setname_np(pthread_self(), tmpbuf);
/*
* Loop forever, until told to exit.
*/
do {
/*
* Wait to be signalled.
*/
DEBUG2("Thread %d waiting to be assigned a request",
self->thread_num);
re_wait:
if (sem_wait(&thread_pool.semaphore) != 0) { // Wait to be signalled.
/*
* Interrupted system call. Go back to
* waiting, but DON'T print out any more
* text.
*/
if ((errno == EINTR) || (errno == EAGAIN)) {
DEBUG2("Re-wait %d", self->thread_num);
goto re_wait;
}
ERROR("Thread %d failed waiting for semaphore: %s: Exiting\n",
self->thread_num, fr_syserror(errno));
break;
}
DEBUG2("Thread %d got semaphore", self->thread_num);
#ifdef HAVE_OPENSSL_ERR_H
/*
* Clear the error queue for the current thread.
*/
ERR_clear_error();
#endif
/*
* The server is exiting. Don't dequeue any
* requests.
*/
if (thread_pool.stop_flag) break;
/*
* Try to grab a request from the queue.
*
* It may be empty, in which case we fail
* gracefully.
*/
if (!request_dequeue(&self->request)) continue;
self->request->child_pid = self->pthread_id;
self->request_count++;
self->request->auth_sock_id = self->thread_num;
DEBUG2("Thread %d handling request %d, (%d handled so far)",
self->thread_num, self->request->number,
self->request_count);
self->request->process(self->request, FR_ACTION_RUN);
self->request = NULL;
#ifdef HAVE_STDATOMIC_H
CAS_DECR(thread_pool.active_threads);
#else
/*
* Update the active threads.
*/
pthread_mutex_lock(&thread_pool.queue_mutex);
rad_assert(thread_pool.active_threads > 0);
thread_pool.active_threads--;
pthread_mutex_unlock(&thread_pool.queue_mutex);
#endif
/*
* If the thread has handled too many requests, then make it
* exit.
*/
if ((thread_pool.max_requests_per_thread > 0) &&
(self->request_count >= thread_pool.max_requests_per_thread)) {
DEBUG2("Thread %d handled too many requests",
self->thread_num);
break;
}
} while (self->status != THREAD_CANCELLED);
OUT:
DEBUG2("Thread %d exiting...", self->thread_num);
#ifdef HAVE_OPENSSL_ERR_H
/*
* If we linked with OpenSSL, the application
* must remove the thread's error queue before
* exiting to prevent memory leaks.
*/
#if OPENSSL_VERSION_NUMBER < 0x10000000L
ERR_remove_state(0);
#elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
ERR_remove_thread_state(NULL);
#endif
#endif
#ifdef HAVE_STDATOMIC_H
CAS_INCR(thread_pool.exited_threads);
#else
pthread_mutex_lock(&thread_pool.queue_mutex);
thread_pool.exited_threads++;
pthread_mutex_unlock(&thread_pool.queue_mutex);
#endif
/*
* Do this as the LAST thing before exiting.
*/
self->request = NULL;
self->status = THREAD_EXITED;
exec_trigger(NULL, NULL, "server.thread.stop", true);
return NULL;
}
/*
* Take a THREAD_HANDLE, delete it from the thread pool and
* free its resources.
*
* This function is called ONLY from the main server thread,
* ONLY after the thread has exited.
*/
static void delete_thread(THREAD_HANDLE *handle)
{
THREAD_HANDLE *prev;
THREAD_HANDLE *next;
rad_assert(handle->request == NULL);
DEBUG2("Deleting thread %d", handle->thread_num);
prev = handle->prev;
next = handle->next;
rad_assert(thread_pool.total_threads > 0);
thread_pool.total_threads--;
/*
* Remove the handle from the list.
*/
if (prev == NULL) {
rad_assert(thread_pool.head == handle);
thread_pool.head = next;
} else {
prev->next = next;
}
if (next == NULL) {
rad_assert(thread_pool.tail == handle);
thread_pool.tail = prev;
} else {
next->prev = prev;
}
/*
* Free the handle, now that it's no longer referencable.
*/
free(handle);
}
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
2022-11-16 epollwait惊群回头看
2021-11-16 sack dsack 相关介绍
2020-11-16 内核 空指针 panic