int main(int argc, const char *argv[]) { pool_t pool; thread_pool_init(&pool, 4); thread_pool_start(&pool); srand(100); while(1) { sleep(1); task_t tsk; tsk.thread_callback = task_func; tsk.arg = (void *)(rand() % 100); thread_pool_add_task_to_queue(&pool, tsk); } thread_pool_stop(&pool); thread_pool_destroy(&pool); return 0; }
int start() { jparse_init(); rest_init(); http_start(); device_init(); #ifdef _DEBUG billing_init(); #endif #ifndef _MSC_VER const char *initrc = initSearch(search_file.c_str()); if (initrc && initrc[0]) { api_log_printf("%s\r\n", initrc); searcher = NULL; } else { searcher = makeSearcher(); } #endif api_listen_tcp(api_tag, host.c_str(), port.c_str(), &handlers); size_t num_cores; #ifdef WIN32 SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); num_cores = sysinfo.dwNumberOfProcessors; #elif MACOS int nm[2]; size_t len = 4; uint32_t count; nm[0] = CTL_HW; nm[1] = HW_AVAILCPU; sysctl(nm, 2, &count, &len, NULL, 0); if(count < 1) { nm[1] = HW_NCPU; sysctl(nm, 2, &count, &len, NULL, 0); if(count < 1) { count = 1; } } num_cores = count; #else num_cores = sysconf(_SC_NPROCESSORS_ONLN); #endif CPUINFO *cpu_info = cpu_get_info(); api_log_printf("[HTTP] CPU INFO: Brand name: %s, cores count: %u, Hyper threads: %s\r\n", cpu_info->vendor.c_str(), num_cores, (cpu_info->hyper_threads) ? "yes" : "no"); thread_pool_init(num_cores - 1); api_log_printf("[HTTP] Started\r\n"); return 0; }
void thread_pool_example(){ int i; struct thread_pool pool; thread_pool_init(&pool, 8); thread_sleep(100); for(i=0;i<20;i++){ thread_pool_add_task(&pool, task, NULL, i); } thread_sleep(1000); thread_pool_destory(&pool); }
int main(void) { thread_pool_t *tpool; thread_t *tp; task_t *task; tpool = thread_pool_init(5); if (tpool == NULL) { printf("init thread pool fail"); return -1; } tp = thread_pool_get(tpool); if (tp == NULL) { printf("fail to get thread."); free(tpool); return -1; } pthread_mutex_lock(&tp->thd.lock); task = (task_t *)malloc(sizeof(task_t)); if (task == NULL) { printf("init task fail."); } task->next = NULL; task->ctx = NULL; task->handler = func; tp->thd.taskqueue = task; tp->thd.busy = 1; pthread_mutex_unlock(&tp->thd.lock); pthread_cond_signal(&tp->thd.cond); printf("in main :pid[%lu],tid[%lu],process ....\n",(unsigned long)getpid(),(unsigned long)pthread_self()); sleep(5); thread_pool_destroy(tpool); return 0; }
int main(int argc, char *argv[]) { cp_cntx_t *ctx; int idx, thd_num; if (4 != argc) { fprintf(stderr, "Paramter isn't right!\n"); return -1; } //nice(-20); thd_num = atoi(argv[3]); if (thd_num <= 0) { thd_num = CP_THD_NUM; } /* > 初始化处理 */ ctx = (cp_cntx_t *)calloc(1, sizeof(cp_cntx_t)); if (NULL == ctx) { fprintf(stderr, "%s:[%d] errmsg:[%d] %s!\n", __FILE__, __LINE__, errno, strerror(errno)); return -1; } snprintf(ctx->src, sizeof(ctx->src), "%s", argv[1]); snprintf(ctx->dst, sizeof(ctx->dst), "%s", argv[2]); if (stat(ctx->src, &ctx->fst)) { fprintf(stderr, "%s:[%d] errmsg:[%d] %s!\n", __FILE__, __LINE__, errno, strerror(errno)); return -1; } /* > 创建线程池 */ ctx->tpool = thread_pool_init(thd_num, NULL, NULL); if (NULL == ctx->tpool) { fprintf(stderr, "%s:[%d] errmsg:[%d] %s!\n", __FILE__, __LINE__, errno, strerror(errno)); return -1; } /* > 执行拷贝处理 */ for (idx=0; idx<thd_num; ++idx) { thread_pool_add_worker(ctx->tpool, cp_copy_routine, ctx); } while (1) { pause(); } return 0; }
static int init_server(arguments *args) { printf("Starting server...\n"); if (evthread_use_pthreads() == -1) { printf("Error occured while turning on pthreads using\n"); return -1; } signal(SIGINT, int_handler); struct evconnlistener* listener; struct sockaddr_in sin; base = event_base_new(); if (!base) { printf("Error while creating event base\n"); free(args); return -1; } thread_pool* thpool = thread_pool_init(args->ncpu, args->doc_root); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons((unsigned short)args->port); listener = evconnlistener_new_bind(base, accept_connection_cb, (void*)thpool, (LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE), -1, (struct sockaddr*) &sin, sizeof(sin)); free(args); if (!listener) { printf("Error while creating listener\n"); thread_pool_destroy(thpool); event_base_free(base); return -1; } evconnlistener_set_error_cb(listener, accept_error_cb); printf("Server is running\nUse Ctrl+C to stop server\n"); event_base_dispatch(base); evconnlistener_free(listener); thread_pool_destroy(thpool); event_base_free(base); return 0; }
int main() { int i; int tmp[TASK_NUM]; thread_pool * tp = (thread_pool*)malloc(sizeof(thread_pool)); thread_pool_init(tp,THREAD_NUM); for(i = 0; i < TASK_NUM; i++) { tmp[i] = i; #ifdef DBG_MSG printf("task #%d added to thread pool!\n",i); #endif thread_pool_add_tsk(tp,threadrun,(void*)&tmp[i]); } sleep(2); thread_pool_destroy(&tp); return 0; }
int main(void) { int i; thread_pool_t *p = NULL; p = thread_pool_create(2); printf("%p\n", p); thread_pool_init(p, 0, 0); for(i = 0; i < 20; i++) { task_t *t = task_create(); task_init(t, task_callback, NULL); task_add(p, t); } sleep(60); return 0; }
void ipc_port_init( ipc_port_t port, ipc_space_t space, mach_port_name_t name) { /* port->ip_kobject doesn't have to be initialized */ port->ip_receiver = space; port->ip_receiver_name = name; port->ip_mscount = 0; port->ip_srights = 0; port->ip_sorights = 0; port->ip_nsrequest = IP_NULL; port->ip_pdrequest = IP_NULL; port->ip_dnrequests = IPR_NULL; port->ip_pset = IPS_NULL; port->ip_seqno = 0; port->ip_msgcount = 0; port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT; port->ip_subsystem = RPC_SUBSYSTEM_NULL; port->ip_flags = 0; port->ip_context = 0; /* * Turn no more senders detection on * for all ports. Eventually, this * default will go away, and nms * detection will be enabled depending * on how the port is allocated. XXX */ IP_SET_NMS(port); #if MACH_ASSERT ipc_port_init_debug(port); #endif /* MACH_ASSERT */ ipc_mqueue_init(&port->ip_messages); thread_pool_init(&port->ip_thread_pool); ipc_thread_queue_init(&port->ip_blocked); }
int main() { pool_t pool; thread_pool_init(&pool, 5); thread_pool_start(&pool); srand(10086); while(1) { task_t task; task.thread_callback = task_func; task.arg = (void *)(rand() % 100); thread_pool_add_task(&pool, task); printf("ThreadPool size: %d, TaskQueue size: %d\n", (int)pool.size_, (int)pool.queue_.size_); } thread_pool_stop(&pool); thread_pool_destroy(&pool); return 0; }
int main(int argc, char *argv[]) { thread_pool_handle *handle; int i; handle = thread_pool_init(10); if(!handle){ printf("thread_pool_init error!\n"); return -1; } sleep(3); for(i=0;i<10;i++){ thread_pool_add_worker(handle, try_printf, &i); sleep(1); } sleep(10); thread_pool_exit(handle); }
int main(int argc, int argv) { char *args[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30"}; thread_pool_t *thread_pool = thread_pool_init(1, 2); int i = 0, tag, value; for (i = 0; i < 30; i++) { do { tag = thread_pool_add_job(thread_pool, work, args[i]); if (tag == 1) { value = thread_pool_resize(thread_pool, thread_pool->thread_num * 2, thread_pool->queue_max_num * 2); if (value == -1) { printf("参数错误!\n"); exit(-1); } else if (value == -2) { printf("申请内存错误!\n"); exit(-1); } else if (value == -3) { printf("线程创建错误!\n"); exit(-1); } } }while (tag != 0); } sleep(2); thread_pool_destroy(thread_pool); return 0; }
int main(int argc, char **argv) { int result, nr_of_plugins, x; t_tissue_stack *t; char serv_command[20], load_command[150]; prctl(PR_SET_NAME, "TS_CORE"); // initialisation of some variable t = malloc(sizeof(*t)); init_prog(t); srand((unsigned) time(NULL)); // intitialisation the volume if (argc > 2) { if (argv[2] != NULL && strcmp(argv[2], "--prompt") != 0) { t->volume_first = malloc(sizeof(*t->volume_first)); if ((result = init_volume(t->memory_mappings, t->volume_first, argv[2])) != 0) return (result); } else if (argv[3] != NULL && strcmp(argv[3], "--prompt") != 0) { t->volume_first = malloc(sizeof(*t->volume_first)); if ((result = init_volume(t->memory_mappings, t->volume_first, argv[3])) != 0) return (result); } } else t->volume_first = NULL; // lunch thread_pool t->tp = malloc(sizeof(*t->tp)); thread_pool_init(t->tp, 16); nr_of_plugins = sizeof(PLUGINS) / sizeof(PLUGINS[0]); for (x = 0; x < nr_of_plugins; x++) { sprintf(load_command, "load %s %s/%s", PLUGINS[x][0], PLUGINS_PATH, PLUGINS[x][1]); plugin_load_from_string(load_command, t); DEBUG("Loading: %s\n", load_command); } sprintf(serv_command, "start serv %s", argv[1]); // start plugins (t->plug_actions)(t, serv_command, NULL); (t->plug_actions)(t, "start comm", NULL); task_clean_up(t); task_lunch(t); signal_manager(t); if ((argv[2] != NULL && strcmp(argv[2], "--prompt") == 0) || (argv[3] != NULL && strcmp(argv[3], "--prompt") == 0)) prompt_start(t); else { INFO("TissueStackImageServer Running!"); pthread_mutex_lock(&t->main_mutex); pthread_cond_wait(&t->main_cond, &t->main_mutex); pthread_mutex_unlock(&t->main_mutex); } // free all the stuff mallocked INFO("Shutting down TissueStackImageServer!"); t->tp->loop = 0; thread_pool_destroy(t->tp); free_core_struct(t); return (0); }
void zdb_init() { if(zdb_init_done) { return; } /* DO or DIE */ if(dnscore_getfingerprint() != (dnsdb_getfingerprint() & dnscore_fingerprint_mask())) { osformatln(termerr, "Mismatched fingerprints: %08x != (%08x = %08x & %08x)", dnscore_getfingerprint(), dnsdb_getfingerprint() & dnscore_fingerprint_mask(), dnsdb_getfingerprint() , dnscore_fingerprint_mask()); flusherr(); exit(-1); } zdb_init_done = TRUE; /* Init the dns core */ dnscore_init(); /* Init the error table */ zdb_register_errors(); /* Init the hash tables */ hash_init(); #if ZDB_OPENSSL_SUPPORT!=0 /* Init openssl */ ENGINE_load_openssl(); ENGINE_load_builtin_engines(); ssl_mutex_count = CRYPTO_num_locks(); MALLOC_OR_DIE(pthread_mutex_t*, ssl_mutex, ssl_mutex_count * sizeof (pthread_mutex_t), ZDB_SSLMUTEX_TAG); int i; for(i = 0; i < ssl_mutex_count; i++) { pthread_mutex_init(&ssl_mutex[i], NULL); } CRYPTO_set_id_callback(ssl_thread_id); CRYPTO_set_locking_callback(ssl_lock); #endif #if ZDB_USE_THREADPOOL != 0 /* * The default value for the database. * This initialization will do nothing if it has already been done. * * The server will have to do it before calling zdb_init(); * */ u32 count = sys_get_cpu_count() + 2; ya_result return_value = thread_pool_init(count); if(FAIL(return_value)) { log_crit("unable to initialise the thread pool to %d threads: %r", count, return_value); /* will ultimately lead to the end of the program */ exit(-1); } thread_pool_initialized_by_zdb = (return_value == count); #endif #if ZDB_USES_ZALLOC != 0 zdb_set_zowner(pthread_self()); #endif logger_start(); zdb_rdtsc_registations(); }
/* * 侦听端口及处理请求 */ int SelectAndHandle( int listensockfd, int listenunixfd ) { unsigned long addrsize; fd_set rset,allset; int connectfd,maxfd=listensockfd>listenunixfd?listensockfd:listenunixfd; int i,n; uid_t uid; int nready; struct sockaddr cliaddr; char recvbuf[SIZERCV+1]; char *p; CLIENT client[FDSIZE]; addrsize = sizeof( struct sockaddr ); FD_ZERO( &allset ); FD_SET( listensockfd, &allset ); FD_SET( listenunixfd, &allset ); for( i=0; i<FDSIZE; i++ ) { client[i].fd = -1; client[i].i = i; } printf("%sSelectAndHandle\n", AT); /* 初始化线程池 */ thread_pool_t *pool = NULL; if( thread_pool_init(&pool, POOLSIZE) < 0 ) { err_sys( "thread pool init error" ); } n=1; while (1) { rset = allset; /* 接受新连接 */ if (( nready = select( maxfd + 1, &rset, NULL, NULL, NULL ) ) < 0 ) { fprintf(stderr,"%sselect err %d %s",AT, nready, strerror(errno) ); continue; } if (FD_ISSET( listensockfd, &rset )) { if (( connectfd = accept( listensockfd, &cliaddr, ( socklen_t *)&addrsize ) ) == -1 ) { fprintf(stderr, "%saccept err", AT ); sleep(1); continue; } SOCKAGAIN: for( i = 0; i<FDSIZE; i++ ) { if( client[i].fd < 0 ) { client[i].fd = connectfd; client[i].type = SOCK; client[i].addr = cliaddr; client[i].n = n; thread_pool_add_worker(pool, ( FUNC )HandleInSide, &(client[i]) ); n++; break; } } if (i==FDSIZE) { /* 线程池已满 */ fprintf(stderr,"%s,pool is full\n", AT); sleep(1); goto SOCKAGAIN; } if ( --nready <= 0 ) continue; } if( FD_ISSET( listenunixfd, &rset ) ) { #if defined(Darwin) if (( connectfd = serv_accept( listenunixfd, NULL ) ) < 0 ) #else if (( connectfd = serv_accept( listenunixfd, &uid ) ) < 0 ) #endif { fprintf(stderr, "%sserv_accept err %d %s\n", AT, connectfd, strerror(errno) ); sleep(1); continue; } UNIXAGAIN: for( i = 0; i<FDSIZE; i++ ) { if( client[i].fd < 0 ) { client[i].fd = connectfd; #if !defined(Darwin) client[i].uid = uid; #endif client[i].type = SOCK; thread_pool_add_worker(pool, ( FUNC )HandleOutSide, &(client[i]) ); n++; break; } } if (i==FDSIZE) { fprintf(stderr,"%s,pool is full\n", AT); sleep(1); goto UNIXAGAIN; } if ( --nready <= 0 ) continue; } } thread_pool_destroy(pool); pool = NULL; return EXIT_SUCCESS; }
int main() { struct threadpool tp; hthread_mutex_t task_queue_mutex; hthread_cond_t active_task; // Init. global print mutex hthread_mutex_init(&print_mutex, NULL); // Setup mutex printf("Setting up mutex..."); hthread_mutexattr_t mta; hthread_mutexattr_settype(&mta, HTHREAD_MUTEX_RECURSIVE_NP); hthread_mutexattr_setnum(&mta, 1); hthread_mutex_init(&task_queue_mutex, &mta); printf("DONE\n"); // Setup cond. var printf("Setting up cond.var..."); hthread_condattr_t cta; hthread_condattr_init(&cta); hthread_cond_init(&active_task, &cta); printf("DONE\n"); // Setup threadpool struct tp.task_queue_mutex = &task_queue_mutex; tp.active_task = &active_task; tp.total_tasks = 0; tp.request_errors = 0; tp.head_ptr = NULL; tp.tail_ptr = NULL; // Init threadpool printf("Creating thread pool..."); thread_pool_init(&tp, 8); printf("DONE\n"); int i; void (*x) (void *); void (*y) (void *); x = func; y = func2; for (i = 0; i < 15; i++) { aprintf("Adding task %d...\n", i); if (i %4 == 0) { add_task(&tp, i, *x, (void*)i); } else { add_task(&tp, i, *y, (void*)i); } } aprintf("Waiting for completion...\n"); while (tp.total_tasks > 0) { aprintf("Main running (%d)...\n", tp.total_tasks); hthread_yield(); } aprintf("DONE!!!\n"); /* while(1) { hthread_yield(); } */ return 0; }
/* * The main guy. */ int main(int argc, char *argv[]) { int rcode = EXIT_SUCCESS; int status; int argval; bool display_version = false; int from_child[2] = {-1, -1}; char *p; /* * We probably don't want to free the talloc autofree context * directly, so we'll allocate a new context beneath it, and * free that before any leak reports. */ TALLOC_CTX *autofree = talloc_init("main"); #ifdef OSFC2 set_auth_parameters(argc, argv); #endif #ifdef WIN32 { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { fprintf(stderr, "%s: Unable to initialize socket library.\n", main_config.name); exit(EXIT_FAILURE); } } #endif rad_debug_lvl = 0; set_radius_dir(autofree, RADIUS_DIR); /* * Ensure that the configuration is initialized. */ memset(&main_config, 0, sizeof(main_config)); main_config.daemonize = true; main_config.spawn_workers = true; p = strrchr(argv[0], FR_DIR_SEP); if (!p) { main_config.name = argv[0]; } else { main_config.name = p + 1; } /* * Don't put output anywhere until we get told a little * more. */ default_log.dst = L_DST_NULL; default_log.fd = -1; main_config.log_file = NULL; /* Process the options. */ while ((argval = getopt(argc, argv, "Cd:D:fhi:l:mMn:p:PstvxX")) != EOF) { switch (argval) { case 'C': check_config = true; main_config.spawn_workers = false; main_config.daemonize = false; break; case 'd': set_radius_dir(autofree, optarg); break; case 'D': main_config.dictionary_dir = talloc_typed_strdup(autofree, optarg); break; case 'f': main_config.daemonize = false; break; case 'h': usage(0); break; case 'l': if (strcmp(optarg, "stdout") == 0) { goto do_stdout; } main_config.log_file = strdup(optarg); default_log.dst = L_DST_FILES; default_log.fd = open(main_config.log_file, O_WRONLY | O_APPEND | O_CREAT, 0640); if (default_log.fd < 0) { fprintf(stderr, "%s: Failed to open log file %s: %s\n", main_config.name, main_config.log_file, fr_syserror(errno)); exit(EXIT_FAILURE); } fr_log_fp = fdopen(default_log.fd, "a"); break; case 'n': main_config.name = optarg; break; case 'm': main_config.debug_memory = true; break; case 'M': main_config.memory_report = true; main_config.debug_memory = true; break; case 'P': /* Force the PID to be written, even in -f mode */ main_config.write_pid = true; break; case 's': /* Single process mode */ main_config.spawn_workers = false; main_config.daemonize = false; break; case 't': /* no child threads */ main_config.spawn_workers = false; break; case 'v': display_version = true; break; case 'X': main_config.spawn_workers = false; main_config.daemonize = false; rad_debug_lvl += 2; main_config.log_auth = true; main_config.log_auth_badpass = true; main_config.log_auth_goodpass = true; do_stdout: fr_log_fp = stdout; default_log.dst = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; break; case 'x': rad_debug_lvl++; break; default: usage(1); break; } } /* * Mismatch between the binary and the libraries it depends on. */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("%s", main_config.name); exit(EXIT_FAILURE); } if (rad_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) exit(EXIT_FAILURE); /* * Mismatch between build time OpenSSL and linked SSL, better to die * here than segfault later. */ #ifdef HAVE_OPENSSL_CRYPTO_H if (ssl_check_consistency() < 0) exit(EXIT_FAILURE); #endif /* * According to the talloc peeps, no two threads may modify any part of * a ctx tree with a common root without synchronisation. * * So we can't run with a null context and threads. */ if (main_config.memory_report) { if (main_config.spawn_workers) { fprintf(stderr, "%s: The server cannot produce memory reports (-M) in threaded mode\n", main_config.name); exit(EXIT_FAILURE); } talloc_enable_null_tracking(); } else { talloc_disable_null_tracking(); } /* * Initialising OpenSSL once, here, is safer than having individual modules do it. * Must be called before display_version to ensure relevant engines are loaded. */ #ifdef HAVE_OPENSSL_CRYPTO_H if (tls_global_init() < 0) exit(EXIT_FAILURE); #endif /* * Better here, so it doesn't matter whether we get passed -xv or -vx. */ if (display_version) { if (rad_debug_lvl == 0) rad_debug_lvl = 1; fr_log_fp = stdout; default_log.dst = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; INFO("%s: %s", main_config.name, radiusd_version); version_print(); exit(EXIT_SUCCESS); } if (rad_debug_lvl) version_print(); /* * Under linux CAP_SYS_PTRACE is usually only available before setuid/setguid, * so we need to check whether we can attach before calling those functions * (in main_config_init()). */ fr_store_debug_state(); /* * Write the PID always if we're running as a daemon. */ if (main_config.daemonize) main_config.write_pid = true; /* * Read the configuration files, BEFORE doing anything else. */ if (main_config_init() < 0) exit(EXIT_FAILURE); /* * This is very useful in figuring out why the panic_action didn't fire. */ INFO("%s", fr_debug_state_to_msg(fr_debug_state)); /* * Check for vulnerabilities in the version of libssl were linked against. */ #if defined(HAVE_OPENSSL_CRYPTO_H) && defined(ENABLE_OPENSSL_VERSION_CHECK) if (tls_global_version_check(main_config.allow_vulnerable_openssl) < 0) exit(EXIT_FAILURE); #endif fr_talloc_fault_setup(); /* * Set the panic action (if required) */ { char const *panic_action = NULL; panic_action = getenv("PANIC_ACTION"); if (!panic_action) panic_action = main_config.panic_action; if (panic_action && (fr_fault_setup(panic_action, argv[0]) < 0)) { fr_perror("%s", main_config.name); exit(EXIT_FAILURE); } } #ifndef __MINGW32__ /* * Disconnect from session */ if (main_config.daemonize) { pid_t pid; int devnull; /* * Really weird things happen if we leave stdin open and call things like * system() later. */ devnull = open("/dev/null", O_RDWR); if (devnull < 0) { ERROR("Failed opening /dev/null: %s", fr_syserror(errno)); exit(EXIT_FAILURE); } dup2(devnull, STDIN_FILENO); close(devnull); if (pipe(from_child) != 0) { ERROR("Couldn't open pipe for child status: %s", fr_syserror(errno)); exit(EXIT_FAILURE); } pid = fork(); if (pid < 0) { ERROR("Couldn't fork: %s", fr_syserror(errno)); exit(EXIT_FAILURE); } /* * The parent exits, so the child can run in the background. * * As the child can still encounter an error during initialisation * we do a blocking read on a pipe between it and the parent. * * Just before entering the event loop the child will send a success * or failure message to the parent, via the pipe. */ if (pid > 0) { uint8_t ret = 0; int stat_loc; /* So the pipe is correctly widowed if the child exits */ close(from_child[1]); /* * The child writes a 0x01 byte on success, and closes * the pipe on error. */ if ((read(from_child[0], &ret, 1) < 0)) { ret = 0; } /* For cleanliness... */ close(from_child[0]); /* Don't turn children into zombies */ if (!ret) { waitpid(pid, &stat_loc, WNOHANG); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* so the pipe is correctly widowed if the parent exits?! */ close(from_child[0]); # ifdef HAVE_SETSID setsid(); # endif } #endif /* * Ensure that we're using the CORRECT pid after forking, NOT the one * we started with. */ radius_pid = getpid(); #ifdef HAVE_PTHREAD_H /* * Parse the thread pool configuration. */ if (thread_pool_bootstrap(main_config.config, &main_config.spawn_workers) < 0) exit(EXIT_FAILURE); #endif /* * Initialize Auth-Type, etc. in the virtual servers * before loading the modules. Some modules need those * to be defined. */ if (virtual_servers_bootstrap(main_config.config) < 0) exit(EXIT_FAILURE); /* * Load the modules before starting up any threads. */ if (modules_init(main_config.config) < 0) exit(EXIT_FAILURE); /* * And then load the virtual servers. */ if (virtual_servers_init(main_config.config) < 0) exit(EXIT_FAILURE); /* * Initialize any event loops just enough so module instantiations can * add fd/event to them, but do not start them yet. * * This has to be done post-fork in case we're using kqueue, where the * queue isn't inherited by the child process. */ if (!radius_event_init(autofree)) exit(EXIT_FAILURE); /* * Redirect stderr/stdout as appropriate. */ if (radlog_init(&default_log, main_config.daemonize) < 0) { ERROR("%s", fr_strerror()); exit(EXIT_FAILURE); } #ifdef HAVE_PTHREAD_H /* * Initialize the threads ONLY if we're spawning, AND * we're running normally. */ if (main_config.spawn_workers && (thread_pool_init() < 0)) exit(EXIT_FAILURE); #endif event_loop_started = true; /* * Start the event loop. */ radius_event_start(main_config.spawn_workers); /* * If we're debugging, then a CTRL-C will cause the server to die * immediately. Use SIGTERM to shut down the server cleanly in * that case. */ if (main_config.debug_memory || (rad_debug_lvl == 0)) { if ((fr_set_signal(SIGINT, sig_fatal) < 0) #ifdef SIGQUIT || (fr_set_signal(SIGQUIT, sig_fatal) < 0) #endif ) { ERROR("%s", fr_strerror()); exit(EXIT_FAILURE); } } /* * Everything seems to have loaded OK, exit gracefully. */ if (check_config) { DEBUG("Configuration appears to be OK"); /* for -C -m|-M */ if (main_config.debug_memory) goto cleanup; exit(EXIT_SUCCESS); } /* * Now that we've set everything up, we can install the signal * handlers. Before this, if we get any signal, we don't know * what to do, so we might as well do the default, and die. */ #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif if ((fr_set_signal(SIGHUP, sig_hup) < 0) || (fr_set_signal(SIGTERM, sig_fatal) < 0)) { ERROR("%s", fr_strerror()); exit(EXIT_FAILURE); } #ifdef WITH_STATS radius_stats_init(0); #endif /* * Write the PID after we've forked, so that we write the correct one. */ if (main_config.write_pid) { FILE *fp; fp = fopen(main_config.pid_file, "w"); if (fp != NULL) { /* * @fixme What about following symlinks, * and having it over-write a normal file? */ fprintf(fp, "%d\n", (int) radius_pid); fclose(fp); } else { ERROR("Failed creating PID file %s: %s", main_config.pid_file, fr_syserror(errno)); exit(EXIT_FAILURE); } } exec_trigger(NULL, NULL, "server.start", false); /* * Inform the parent (who should still be waiting) that the rest of * initialisation went OK, and that it should exit with a 0 status. * If we don't get this far, then we just close the pipe on exit, and the * parent gets a read failure. */ if (main_config.daemonize) { if (write(from_child[1], "\001", 1) < 0) { WARN("Failed informing parent of successful start: %s", fr_syserror(errno)); } close(from_child[1]); } /* * Clear the libfreeradius error buffer. */ fr_strerror(); /* * Initialise the state rbtree (used to link multiple rounds of challenges). */ global_state = fr_state_tree_init(autofree, main_config.max_requests * 2, main_config.continuation_timeout); /* * Process requests until HUP or exit. */ while ((status = radius_event_process()) == 0x80) { #ifdef WITH_STATS radius_stats_init(1); #endif main_config_hup(); } if (status < 0) { ERROR("Exiting due to internal error: %s", fr_strerror()); rcode = EXIT_FAILURE; } else { INFO("Exiting normally"); rcode = EXIT_SUCCESS; } /* * Ignore the TERM signal: we're about to die. */ signal(SIGTERM, SIG_IGN); /* * Fire signal and stop triggers after ignoring SIGTERM, so handlers are * not killed with the rest of the process group, below. */ if (status == 2) exec_trigger(NULL, NULL, "server.signal.term", true); exec_trigger(NULL, NULL, "server.stop", false); /* * Send a TERM signal to all associated processes * (including us, which gets ignored.) */ #ifndef __MINGW32__ if (main_config.spawn_workers) kill(-radius_pid, SIGTERM); #endif /* * We're exiting, so we can delete the PID file. * (If it doesn't exist, we can ignore the error returned by unlink) */ if (main_config.daemonize) unlink(main_config.pid_file); /* * Free memory in an explicit and consistent order * * We could let everything be freed by the autofree * context, but in some cases there are odd interactions * with destructors that may cause double frees and * SEGVs. */ radius_event_free(); /* Free the requests */ #ifdef HAVE_PTHREAD_H thread_pool_stop(); /* stop all the threads */ #endif talloc_free(global_state); /* Free state entries */ cleanup: map_proc_free(); /* Free map processors */ main_config_free(); /* Free the main config */ modules_free(); /* Detach any modules (and their connection pools) */ xlat_free(); /* modules may have xlat's */ #ifdef WIN32 WSACleanup(); #endif #ifdef HAVE_OPENSSL_CRYPTO_H tls_global_cleanup(); /* Cleanup any memory malloced by OpenSSL and placed into globals */ #endif talloc_free(autofree); /* Cleanup everything else */ /* * Anything not cleaned up by the above is allocated in the NULL * top level context, and is likely leaked memory. */ if (main_config.memory_report) fr_log_talloc_report(NULL); return rcode; }