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;
}
Beispiel #2
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);
}
Beispiel #4
0
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;
}
Beispiel #5
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;
}
Beispiel #6
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;
}
Beispiel #7
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;
}
Beispiel #9
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);
}
Beispiel #10
0
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;
}
Beispiel #11
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);
}
Beispiel #12
0
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;
}
Beispiel #13
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);
}
Beispiel #14
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();
}
Beispiel #15
0
/*
 * 侦听端口及处理请求
 */
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;
}
Beispiel #16
0
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;
}
Beispiel #17
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;
}