Esempio n. 1
0
static void do_destroy(RServerCtx * ctx) {

	if (ctx) {

		if (ctx->csLtr) {
			RServerCSLtr_Destroy(ctx->csLtr);
			ctx->csLtr = NULL;
		}

		if (ctx->cusEv) {
			evhr_cus_event_del(ctx->cusEv);
			ctx->cusEv = NULL;
		}

		if (ctx->evhr) {
			evhr_release(ctx->evhr);
			ctx->evhr = NULL;
		}

		if (ctx->taskPool) {
			tpool_destroy(ctx->taskPool);
			ctx->taskPool = NULL;
		}

		free(ctx);
	}
}
Esempio n. 2
0
struct thread_pool *tpool_create(int num_threads)
{
	int i;
	struct thread_pool *tpool;

	if(!(tpool = calloc(1, sizeof *tpool))) {
		return 0;
	}
	pthread_mutex_init(&tpool->workq_mutex, 0);
	pthread_cond_init(&tpool->workq_condvar, 0);
	pthread_cond_init(&tpool->done_condvar, 0);

	if(num_threads <= 0) {
		num_threads = tpool_num_processors();
	}
	tpool->num_threads = num_threads;

	if(!(tpool->threads = calloc(num_threads, sizeof *tpool->threads))) {
		free(tpool);
		return 0;
	}
	for(i=0; i<num_threads; i++) {
		if(pthread_create(tpool->threads + i, 0, thread_func, tpool) == -1) {
			/*tpool->threads[i] = 0;*/
			tpool_destroy(tpool);
			return 0;
		}
	}
	return tpool;
}
Esempio n. 3
0
int tpool_release(struct thread_pool *tpool)
{
	if(--tpool->nref <= 0) {
		tpool_destroy(tpool);
		return 0;
	}
	return tpool->nref;
}
Esempio n. 4
0
File: tpool.c Progetto: yenpai/libRC
TPOOL_RTN_E tpool_create(struct tpool_ctx ** obj, uint8_t num) {

	int i;
	struct tpool_ctx * tpool = NULL;

	if ((tpool = malloc(sizeof(struct tpool_ctx))) == NULL)
		return TPOOL_FAILED;
	memset(tpool, 0, sizeof(struct tpool_ctx));

	tpool->workers_num_total = 0;
	tpool->workers_num_running = 0;
	tpool->workers_num_working = 0;
	tpool->keep_alive = 0;

	pthread_mutex_init(&tpool->workers_num_lock, NULL);
	pthread_cond_init(&tpool->workers_idle_cond, NULL);
	pthread_mutex_init(&tpool->tasks_uid_lock, NULL);

	// Initial tasks
	if (qlist_create(&tpool->tasks) != QLIST_SUCCESS) {
		tpool_destroy(tpool);
		return TPOOL_FAILED;
	}

	// Initial workers array
	tpool->workers = (struct tpool_worker **) malloc(sizeof(struct tpool_worker *) * num);
	if (tpool->workers == NULL) {
		tpool_destroy(tpool);
		return TPOOL_FAILED;
	}

	// Initial all workers
	for (i = 0; i < num; i++) {
		if (worker_create(&tpool->workers[i]) != TPOOL_SUCCESS) {
			tpool_destroy(tpool);
			return TPOOL_FAILED;
		}

		tpool->workers[i]->uid = 0;
		tpool->workers[i]->tpool = tpool;
		tpool->workers_num_total++;
	}

	*obj = tpool;
	return TPOOL_SUCCESS;
}
Esempio n. 5
0
int main(int argc, const char * argv[]) {
  
    url_result_t url_r;      // 结构体,主要包括all_url_list和existed_page, 用于存储爬取到的所有url。
    urlq_t queue;            // url队列
    int num;                 // 用于向queue加入种子页面, queue中存储的是all_url_list中的位置
    tpool_t *tpool;          // 线程池
    char *url_sed;           // 种子网页
    time_t starttime;        // 起始时间
    time_t endtime;          // 结束时间
    
    
    if (url_result_init(&url_r) == INIT_FAILURE) {
        printf("初始化url结果失败,退出程序\n");
        exit(1);
    }
    if (queue_init(&queue) == INIT_FAILURE) {
        printf("初始化队列失败,退出程序\n");
        exit(1);
    }
    if ((tpool = tpool_create(MAX_THREADS, &url_r, &queue)) == NULL) {
        printf("初始化线程池失败\n");
        exit(1);
    }
    url_sed = "http://news.sohu.com/";
    time(&starttime);
    printf("start work!\n");
    // 休眠2秒,为了创造完所有的线程.
    sleep(2);
    pthread_mutex_lock(&tpool->mutex);
    // 首先把种子网页加入到线程中
    num = url_result_add(&url_r, url_sed);
    queue_push(&queue, num);
    addStr(url_r.bloomfilter, url_sed);
    pthread_mutex_unlock(&tpool->mutex);
    pthread_cond_signal(&tpool->cond);
    
    while (queue.size > 0 || tpool->at_work != 0) {
        printf("queue_size: %d\n", queue.size);
        printf("front: %d\n", queue.front);
        printf("tail: %d\n", queue.tail);
        printf("list_size: %d\n", url_r.all_url_list_size);
        printf("at_work: %d\n", tpool->at_work);
        printf("existed_page_size: %d\n", url_r.existed_page_size);
        sleep(1);  // 每隔1秒,输出一次日志。
    }
    write_url_result_to_file(&url_r);
    tpool_destroy();
    sleep(2);
    time(&endtime);
    printf("finish work");
    printf("total time: %ld\n", endtime - starttime);
    printf("all_url_list_size: %d\n", url_r.all_url_list_size);
    printf("exited_page_size: %d\n", url_r.existed_page_size);
    
    return 0;
}
Esempio n. 6
0
int main()
{
	struct web_graph webg;
	int i;
	urlq_t queue;
	int num;
	tpool_t *tpool;

	if (init_webg(&webg) == INIT_FAIL)
	{
		printf("初始化图失败,退出程序!\n");
		exit(1);
	}
	if (queue_init(&queue) == INIT_QUEUE_FAIL)
	{
		printf("初始化队列失败,退出程序!\n");
		exit(1);
	}

	if ((tpool = tpool_create(MAX_THREADS, &webg, &queue)) == NULL)
	{
		printf("初始化线程池失败!\n");
		exit(1);
	}
	printf("start work!\n");
	//首先要将index.html加入点集和队列中
	pthread_mutex_lock(&tpool->lock);
	num = insert_vertex(&webg, "/techqq/index.html");
	queue_push(&queue, num);
	pthread_mutex_unlock(&tpool->lock);
	pthread_cond_signal(&tpool->cond);

	while (queue.size > 0 || tpool->at_work != 0)
	{
		printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@queue_size: %d@@@@@@@@@@@@@@@@@@@@@@@\n", queue.size);
		printf("front: %d\n", queue.front);
		printf("tail: %d\n", queue.tail);
		printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@list_size: %d@@@@@@@@@@@@@@@@@@@@@@@\n", webg.all_url_list_size);
		printf("$$$$$$$$$$$$$$$$$edge_set_size:  %d\n", webg.edge_set_size);
		printf("at_work: %d\n", tpool->at_work);
		printf("---------------existed_page_size: %d\n", webg.existed_page_size);
		sleep(2);
	}
	printf("finish work!\n");
	tpool_destroy();
	printf("size: %d\n", webg.all_url_list_size);
	printf("queue_size: %d\n", queue.size);
	print_webg_to_file(&webg);
	destroy_webg(&webg);
	output_result_file();
}
int main(void)
{
    int i;
    tpool_t test_pool;

    tpool_init(&test_pool, 8, 20);

    for ( i = 0; i < 5; i++) {
        tpool_add_work(test_pool, job, str[i]);
    }

    tpool_destroy(test_pool, 1);

    return 0;
}
Esempio n. 8
0
int main(int argc,char **argv)
{
	printf("Http server welcome you!\n");
    tpool_create(10);
	if(1!=argc)
	getoption(argc,argv);//It's hard to learn how to use it  
	if(NULL==_log)
		logfd=open(DEFAULTLOG,O_WRONLY | O_APPEND | O_CREAT);
	else
		logfd=open(_log,O_WRONLY | O_CREAT | O_APPEND);
	
	daytime();
	int sockfd,sockfds;
	if(daemon_check)
		daemons();
    ssl_init(ctx);
    signal(SIGPIPE,SIG_IGN);
	signal(SIGCHLD, SIG_IGN);
	sockfd=make_socket(sockfd);
    sockfds=make_socket_ssl(sockfds);
	if(sockfd<0||sockfds<0)
		errorfunc("sockfd error!");
	int addrlen = 1;  
    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&addrlen,sizeof(addrlen));//set the port quickly reuse
    setsockopt(sockfds,SOL_SOCKET,SO_REUSEADDR,&addrlen,sizeof(addrlen));
    struct epoll_event events[MAXEVENTS];//question
	int epollfd=epoll_create(MAXEVENTS);
	addfd(epollfd,sockfd,0);
    addfd(epollfd,sockfds,0);
	chdir("/home/wangyao/web");
	while(1)
	{
		int ret=epoll_wait(epollfd,events,MAXEVENTS,-1);//epoll func should be use in here
		if(ret<0)
			errorfunc("epoll_wait error!");
		lt(events,ret,epollfd,sockfd,sockfds);
	}
    close(sockfds);
	close(sockfd);
    close(epollfd);
    sleep(10);
    tpool_destroy();
    SSL_CTX_free(ctx);         
	exit(0);
}
Esempio n. 9
0
int
main(int argc, char **argv)
{
    printf("main start...........\n");
    tpool_t *tpool = tpool_create(3);
    if(tpool == NULL) {
	printf("tpool_create failed...\n");
	exit(1);
    }
    size_t i = 10;
    size_t a[10];
    for(i = 0; i < 10; i++) {
	a[i] = i;
	tpool_task_add(tpool, func, (void*)&(a[i]));
    }
    tpool_destroy(tpool);
    printf("main end...........\n");
    return 0;
}
Esempio n. 10
0
int main()
{
	tpool_t *t;
	char buf[256], *ptr;
	int len, i = 0;

#    ifdef DEBUG
	log_open("stderr", "tp_test", -1);
#    endif

	t = tpool_init(NULL, 3, 2, 2);

	printf("Thread Pool[%d] initlized OK, try to write your message after >\n", getpid());
	printf("Main thread: %p\n", pthread_self());
	do
	{
		printf(">");
		fflush(stdout);

		if (!fgets(buf, sizeof(buf) - 1, stdin))
		{
			puts("Aborted!\n");
			break;
		}
		if (buf[0] == '\r' || buf[0] == '\n')
			continue;
		len = strlen(buf);
		buf[len - 1] = '\0';
		if (!strcasecmp(buf, "quit") || !strcasecmp(buf, "exit"))
		{
			puts("Quit!\n");
			break;
		}
		else if (!strcasecmp(buf, "cancel"))
		{
			for (i = 0; i < t->max_total; i++)
			{
				int cc;

				if (!(t->threads[i].status & TPOOL_THREAD_ACTIVED))
					continue;
				pthread_cancel(t->threads[i].tid);
			}
			continue;
		}
		else if (!strcasecmp(buf, "cancel2"))
		{
			tpool_cancel(t);
			tpool_destroy(t);
			exit(0);
		}
		else if (!strcasecmp(buf, "timeout"))
		{
			tpool_cancel_timeout(t, 5);
			continue;
		}
		else if (!strcasecmp(buf, "display"))
		{
			ptr = tpool_draw(t);
			puts(ptr);
			free(ptr);
			continue;
		}
		ptr = strdup(buf);
		printf("strdup(%p)\n", ptr);
		tpool_exec(t, test_task, test_cancel, ptr);
	}
	while (1);

	//tpool_cancel(t);
	tpool_destroy(t);
	exit(0);
}
Esempio n. 11
0
int main(int argc, char *argv[])
{
	 
	    tpool_t *pool;  
	  
	    
	    logmy=log_open("test.log", 0);
		
	   
	    pool=tpool_init(10,20,1);

		
		socket_branch();

		char  Construction[2];
   
    while(1)
     	{

		
         

			
		 	printf("Please Input Construction number On Server:\t"); 
		 	scanf("%s", Construction); 
			printf("%s\n", Construction);
			
            switch (Construction[1]) {
            

            case 9:
                	tpool_destroy(pool,1);
					log_close(logmy);
					pthread_exit(NULL);
					exit (EXIT_SUCCESS);

            case 8:
                    exit (EXIT_FAILURE);
					
		    case 6:
                    break;

            default:
                    break;
            }
    			 

		
         struct sockaddr_in client_addr;
		 int client_addr_length =sizeof(client_addr);

 		 int new_server_socket_fd =accept(server_socket_fd,(struct sockaddr*)&client_addr, &client_addr_length);
		 if(new_server_socket_fd < 0)
		 	{
				perror("Server Accept Failed:");
				break;
		    }
		 else
		 	{   

                printf("Accept Client Socket Address\n");
				char peeraddrstr[60];
			    char peerip[18];
			    
			    time_t timep;
				time(&timep);

				
				int len = sizeof(client_addr);
				if(!getpeername(new_server_socket_fd, (struct sockaddr *)&client_addr, &len))
				 {
					 sprintf(peeraddrstr, "time: %s\npeer address: %s:%d\n\n",ctime(&timep) , inet_ntop(AF_INET, &client_addr.sin_addr, peerip, sizeof(peerip)), ntohs(client_addr.sin_port));
	                 printf("%s\n", peeraddrstr);
				 }
		 	 	
				tpool_add_work(pool,thread,peeraddrstr);
		 	}
     	}
     
	

	sleep(5);
	
	tpool_destroy(pool,1);
	log_close(logmy);
	pthread_exit(NULL);
}
Esempio n. 12
0
/*
 * Given a list of directories to search, find all pools stored on disk.  This
 * includes partial pools which are not available to import.  If no args are
 * given (argc is 0), then the default directory (/dev/dsk) is searched.
 * poolname or guid (but not both) are provided by the caller when trying
 * to import a specific pool.
 */
static nvlist_t *
zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
{
	int i, dirs = iarg->paths;
	struct dirent64 *dp;
	char path[MAXPATHLEN];
	char *end, **dir = iarg->path;
	size_t pathleft;
	nvlist_t *ret = NULL;
	static char *default_dir = "/dev/dsk";
	pool_list_t pools = { 0 };
	pool_entry_t *pe, *penext;
	vdev_entry_t *ve, *venext;
	config_entry_t *ce, *cenext;
	name_entry_t *ne, *nenext;
	avl_tree_t slice_cache;
	rdsk_node_t *slice;
	void *cookie;

	if (dirs == 0) {
		dirs = 1;
		dir = &default_dir;
	}

	/*
	 * Go through and read the label configuration information from every
	 * possible device, organizing the information according to pool GUID
	 * and toplevel GUID.
	 */
	for (i = 0; i < dirs; i++) {
		tpool_t *t;
		char *rdsk;
		int dfd;
		boolean_t config_failed = B_FALSE;
		DIR *dirp;

		/* use realpath to normalize the path */
		if (realpath(dir[i], path) == 0) {
			(void) zfs_error_fmt(hdl, EZFS_BADPATH,
			    dgettext(TEXT_DOMAIN, "cannot open '%s'"), dir[i]);
			goto error;
		}
		end = &path[strlen(path)];
		*end++ = '/';
		*end = 0;
		pathleft = &path[sizeof (path)] - end;

		/*
		 * Using raw devices instead of block devices when we're
		 * reading the labels skips a bunch of slow operations during
		 * close(2) processing, so we replace /dev/dsk with /dev/rdsk.
		 */
		if (strcmp(path, "/dev/dsk/") == 0)
			rdsk = "/dev/rdsk/";
		else
			rdsk = path;

		if ((dfd = open64(rdsk, O_RDONLY)) < 0 ||
		    (dirp = fdopendir(dfd)) == NULL) {
			if (dfd >= 0)
				(void) close(dfd);
			zfs_error_aux(hdl, strerror(errno));
			(void) zfs_error_fmt(hdl, EZFS_BADPATH,
			    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
			    rdsk);
			goto error;
		}

		avl_create(&slice_cache, slice_cache_compare,
		    sizeof (rdsk_node_t), offsetof(rdsk_node_t, rn_node));
		/*
		 * This is not MT-safe, but we have no MT consumers of libzfs
		 */
		while ((dp = readdir64(dirp)) != NULL) {
			const char *name = dp->d_name;
			if (name[0] == '.' &&
			    (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
				continue;

			slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
			slice->rn_name = zfs_strdup(hdl, name);
			slice->rn_avl = &slice_cache;
			slice->rn_dfd = dfd;
			slice->rn_hdl = hdl;
			slice->rn_nozpool = B_FALSE;
			avl_add(&slice_cache, slice);
		}
		/*
		 * create a thread pool to do all of this in parallel;
		 * rn_nozpool is not protected, so this is racy in that
		 * multiple tasks could decide that the same slice can
		 * not hold a zpool, which is benign.  Also choose
		 * double the number of processors; we hold a lot of
		 * locks in the kernel, so going beyond this doesn't
		 * buy us much.
		 */
		t = tpool_create(1, 2 * sysconf(_SC_NPROCESSORS_ONLN),
		    0, NULL);
		for (slice = avl_first(&slice_cache); slice;
		    (slice = avl_walk(&slice_cache, slice,
		    AVL_AFTER)))
			(void) tpool_dispatch(t, zpool_open_func, slice);
		tpool_wait(t);
		tpool_destroy(t);

		cookie = NULL;
		while ((slice = avl_destroy_nodes(&slice_cache,
		    &cookie)) != NULL) {
			if (slice->rn_config != NULL && !config_failed) {
				nvlist_t *config = slice->rn_config;
				boolean_t matched = B_TRUE;

				if (iarg->poolname != NULL) {
					char *pname;

					matched = nvlist_lookup_string(config,
					    ZPOOL_CONFIG_POOL_NAME,
					    &pname) == 0 &&
					    strcmp(iarg->poolname, pname) == 0;
				} else if (iarg->guid != 0) {
					uint64_t this_guid;

					matched = nvlist_lookup_uint64(config,
					    ZPOOL_CONFIG_POOL_GUID,
					    &this_guid) == 0 &&
					    iarg->guid == this_guid;
				}
				if (!matched) {
					nvlist_free(config);
				} else {
					/*
					 * use the non-raw path for the config
					 */
					(void) strlcpy(end, slice->rn_name,
					    pathleft);
					if (add_config(hdl, &pools, path,
					    config) != 0)
						config_failed = B_TRUE;
				}
			}
			free(slice->rn_name);
			free(slice);
		}
		avl_destroy(&slice_cache);

		(void) closedir(dirp);

		if (config_failed)
			goto error;
	}

	ret = get_configs(hdl, &pools, iarg->can_be_active);

error:
	for (pe = pools.pools; pe != NULL; pe = penext) {
		penext = pe->pe_next;
		for (ve = pe->pe_vdevs; ve != NULL; ve = venext) {
			venext = ve->ve_next;
			for (ce = ve->ve_configs; ce != NULL; ce = cenext) {
				cenext = ce->ce_next;
				if (ce->ce_config)
					nvlist_free(ce->ce_config);
				free(ce);
			}
			free(ve);
		}
		free(pe);
	}

	for (ne = pools.names; ne != NULL; ne = nenext) {
		nenext = ne->ne_next;
		free(ne->ne_name);
		free(ne);
	}

	return (ret);
}
Esempio n. 13
0
int
main (int argc, char **argv)
{
    int             opt = 0;                            /* Option Identifier */
    int             optindex = 0;                            /* Option Index */
    bool            isProfiling = false;      /* Are we profiling the cache? */
    bool            isPriming = false;          /* Are we priming the cache? */
    long            numCPUs = 0;                /* The number of online CPUs */
    struct dirent  *dp = NULL;                    /* Directory Entry Pointer */
    DIR            *dfd = NULL;                          /* Directory Stream */
    double          loadAverages[3] = { 0.00 };      /* System Load Averages */
    PGconn         *pgh = NULL;                /* Postgres Connection Handle */
    bool            isPWDRequired = false;     /* Is Postgres Password Reqd? */

    struct option   long_options[] =                 /* Options for getopt() */
    {
        {"connect-string",  required_argument,  NULL, 'c'},
        {"profile",         no_argument,        NULL, 'p'},
        {"prime",           no_argument,        NULL, 'w'},
        {"data-dir",        required_argument,  NULL, 'D'},
        {"postgres-only",   no_argument,        NULL, 'o'},
        {"sqlite-db",       required_argument,  NULL, 's'},
        {"help",            no_argument,        NULL, 'h'},
        {"debug",           no_argument,        NULL, 'd'},
        {NULL, 0, NULL, 0}
    };

    /* Go for the glory! */
    fprintf(stderr, "\n%s: Release %s - %s\n", PACKAGE_NAME,
        PACKAGE_VERSION, APP_RELEASE);
    fprintf(stderr, "\n%s\n\n", APP_COPYRIGHT);
    fflush(stdout);

    /* Process command-line options */
    while ((opt = getopt_long(argc, argv, "c:s:D:awhdp",
        long_options, &optindex)) != -1)
    {
        switch (opt)
        {
            case 'h':
                usage();
                exit(EXIT_SUCCESS);
                break;
            case 'p':
                if (isPriming == false)
                    isProfiling = true;
                else
                {
                    fprintf(stderr,
                        "Profiling and warming are mutually exlusive!\n");
                    exit(EXIT_FAILURE);
                }
                break;
            case 'w':
                if (isProfiling == false)
                    isPriming = true;
                else
                {
                    fprintf(stderr,
                        "Profiling and warming are mutually exlusive!\n");
                    exit(EXIT_FAILURE);
                }
                break;
            case 'd':
                is_debug = true;
                break;
            case 's':
                dbFileName = xstrdup(optarg);
                break;
            case 'c':
                pgConnectString = xstrdup(optarg);
                break;
            case 'D':
                pgDataDir = optarg;
                break;
            default:
                usage();
                exit(EXIT_FAILURE);
        }
    }

    /* Make sure user requested profile OR prime */
    if (isProfiling == false && isPriming == false)
    {
        fprintf(stderr, "Expected either -p or -w\n");
        usage();
        exit(EXIT_FAILURE);
    }

    /* Make sure the database name is set */

    /* Get the PG log file name from the end of the command line */
    if (optind < (argc - 1))
    {
        fprintf(stderr, "too many command-line arguments (first is \"%s\")\n",
                argv[optind + 1]);
        usage();
        exit(EXIT_FAILURE);
    }

    /* Perform a Postgres connection test & get password (if required) */
    do
    {
        isPWDRequired = false;
        pgh = PQsetdbLogin(NULL, NULL, NULL, NULL,
            pgConnectString == NULL ? "postgres"
                                    : pgConnectString,
            NULL, pgPassword);
        if (PQstatus(pgh) == CONNECTION_BAD)
        {
            if (PQconnectionNeedsPassword(pgh) && pgPassword == NULL)
            {
                printf("\nTesting Postgres Connection\n");
                PQfinish(pgh);
                pgPassword = simple_prompt("Password: "******"%s", "Connection Test Failed\n");
                ERROR_PRINT("SQLERRMC: %s\n", PQerrorMessage(pgh));
                PQfinish(pgh);
                exit(EXIT_FAILURE);
            }
        }
    } while (isPWDRequired);
    PQfinish(pgh);
    /* Get the number of available CPUs */
    numCPUs = sysconf(_SC_NPROCESSORS_ONLN);
    if (numCPUs < 1)
        numCPUs = 1;

    /*
     * Choose the number of CPUs to use in the thread pool based on load
     * average.  It only makes sense to do this if we have more than one CPU
     * to play with.
     */
    if ((numCPUs > 1)
        && (getloadavg(loadAverages, 3) == 3))
    {
        long    idleCPUs = 0;                     /* The number of idle CPUs */

        /* Show what we got */
        printf("load averages.... %3.2f %3.2f %3.2f\n",
            loadAverages[0], loadAverages[1], loadAverages[2]);

        /*
         * We're going to base the number of usable CPUs by subtracting
         * the sum of 1 (to account for OS and I/O overhead) plus the 1 minute
         * load average from the number of available CPUs.
         */
        idleCPUs = numCPUs - (1 + (int)(loadAverages[0] + 0.5));

        /* Assign # of available CPUs with some sanity checking */
        if (idleCPUs < numCPUs)
            numCPUs = idleCPUs;
        if (numCPUs < 1)
            numCPUs = 1;
    }

    /* Inform user of # of CPUs that will be used */
    printf("usable CPUs...... %d\n", numCPUs);

    /* If we have more than one CPU, multi-thread our operations */
    if (numCPUs > 1)
    {
        /* Initialize the thread pool */
        thp = tpool_init(numCPUs, 1024, true);
    }

    if (isProfiling)
        BuildCacheProfile();
    else /* isPriming */
        PrimeCache();

    /* If we have more than one CPU, multi-thread our operations */
    if (POINTER_IS_VALID(thp))
    {
        /* Destroy the thread pool */
        tpool_destroy(thp, 1); 
    }

    /* Cleanup */
    free(dbFileName);

    return EXIT_SUCCESS;

} /* main() */