/* What each thread is doing * * In principle this is an endless loop. The only time this loop gets interuppted is once * thpool_destroy() is invoked or the program exits. * * @param thread thread that will run this function * @return nothing */ static void* thread_do(struct thread* thread_p){ /* Set thread name for profiling and debuging */ char thread_name[128] = {0}; sprintf(thread_name, "thread-pool-%d", thread_p->id); prctl(PR_SET_NAME, thread_name); /* Assure all threads have been created before starting serving */ thpool_* thpool_p = thread_p->thpool_p; /* Register signal handler */ struct sigaction act; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = thread_hold; if (sigaction(SIGUSR1, &act, NULL) == -1) { fprintf(stderr, "thread_do(): cannot handle SIGUSR1"); } /* Mark thread as alive (initialized) */ pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_alive += 1; pthread_mutex_unlock(&thpool_p->thcount_lock); while(threads_keepalive){ bsem_wait(thpool_p->jobqueue.has_jobs); if (threads_keepalive){ pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_working++; pthread_mutex_unlock(&thpool_p->thcount_lock); /* Read job from queue and execute it */ void*(*func_buff)(void* arg); void* arg_buff; job* job_p = jobqueue_pull(&thpool_p->jobqueue); if (job_p) { func_buff = job_p->function; arg_buff = job_p->arg; func_buff(arg_buff); free(job_p); } pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_working--; if (!thpool_p->num_threads_working) { pthread_cond_signal(&thpool_p->threads_all_idle); } pthread_mutex_unlock(&thpool_p->thcount_lock); } } pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_alive --; pthread_mutex_unlock(&thpool_p->thcount_lock); return NULL; }
/* Clear the queue */ static void jobqueue_clear(thpool_* thpool_p){ while(thpool_p->jobqueue_p->len){ free(jobqueue_pull(thpool_p)); } thpool_p->jobqueue_p->front = NULL; thpool_p->jobqueue_p->rear = NULL; bsem_reset(thpool_p->jobqueue_p->has_jobs); thpool_p->jobqueue_p->len = 0; }
/* What each thread is doing * * In principle this is an endless loop. The only time this loop gets interuppted is once * thpool_destroy() is invoked or the program exits. * * @param thread thread that will run this function * @return nothing */ static void* thread_do(struct thread* thread_p){ /* Assure all threads have been created before starting serving */ thpool_* thpool_p = thread_p->thpool_p; /* Register signal handler */ struct sigaction act; act.sa_handler = thread_hold; if (sigaction(SIGUSR1, &act, NULL) == -1) { fprintf(stderr, "thread_do(): cannot handle SIGUSR1"); } /* Mark thread as alive (initialized) */ pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_alive += 1; pthread_mutex_unlock(&thpool_p->thcount_lock); while(threads_keepalive){ bsem_wait(thpool_p->jobqueue_p->has_jobs); if (threads_keepalive){ pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_working++; pthread_mutex_unlock(&thpool_p->thcount_lock); /* Read job from queue and execute it */ void*(*func_buff)(void* arg); void* arg_buff; job* job_p; pthread_mutex_lock(&thpool_p->jobqueue_p->rwmutex); job_p = jobqueue_pull(thpool_p); pthread_mutex_unlock(&thpool_p->jobqueue_p->rwmutex); if (job_p) { func_buff = job_p->function; arg_buff = job_p->arg; func_buff(arg_buff); free(job_p); } pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_working--; pthread_mutex_unlock(&thpool_p->thcount_lock); } } pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_alive --; pthread_mutex_unlock(&thpool_p->thcount_lock); return NULL; }
/* Clear the queue */ static void jobqueue_clear(jobqueue* jobqueue_p){ while(jobqueue_p->len){ free(jobqueue_pull(jobqueue_p)); } jobqueue_p->front = NULL; jobqueue_p->rear = NULL; bsem_reset(jobqueue_p->has_jobs); jobqueue_p->len = 0; }
/* Clear the queue */ static void jobqueue_clear(ThPool* thpool) { WorkGroup* group; int size; do { group = jobqueue_pull(thpool, -1); if (group == NULL) { size = 0; } else { size = group->size; free(group->jobs); free(group); } } while (size > 0); thpool->jobqueue->front = NULL; thpool->jobqueue->rear = NULL; bsem_reset(thpool->jobqueue->has_jobs); thpool->jobqueue->len = 0; thpool->jobqueue->group_front = NULL; thpool->jobqueue->total_time = 0; thpool->jobqueue->highest_expected_return = 0; }
/* What each thread is doing * * In principle this is an endless loop. The only time this loop gets interuppted is once * thpool_destroy() is invoked or the program exits. * * @param thread thread that will run this function * @return nothing */ static void* thread_do(struct thread* thread_p) { /* Set thread name for profiling and debuging */ char thread_name[128] = {0}; sprintf(thread_name, "thread-pool-%d", thread_p->id); #if defined(__linux__) /* Use prctl instead to prevent using _GNU_SOURCE flag and implicit declaration */ prctl(PR_SET_NAME, thread_name); #elif defined(__APPLE__) && defined(__MACH__) pthread_setname_np(thread_name); #else err("thread_do(): pthread_setname_np is not supported on this system"); #endif /* Assure all threads have been created before starting serving */ thpool_* thpool_p = thread_p->thpool_p; /* Register signal handler */ struct sigaction act; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = thread_hold; if (sigaction(SIGUSR1, &act, NULL) == -1) { err("thread_do(): cannot handle SIGUSR1"); } /* Mark thread as alive (initialized) */ pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_alive += 1; pthread_mutex_unlock(&thpool_p->thcount_lock); while (threads_keepalive) { bsem_wait(thpool_p->jobqueue.has_jobs); if (threads_keepalive) { pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_working++; pthread_mutex_unlock(&thpool_p->thcount_lock); /* Read job from queue and execute it */ void (*func_buff)(void*); void* arg_buff; job* job_p = jobqueue_pull(&thpool_p->jobqueue); if (job_p) { func_buff = job_p->function; arg_buff = job_p->arg; func_buff(arg_buff); free(job_p); } pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_working--; if (!thpool_p->num_threads_working) { pthread_cond_signal(&thpool_p->threads_all_idle); } pthread_mutex_unlock(&thpool_p->thcount_lock); } } pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_alive --; pthread_mutex_unlock(&thpool_p->thcount_lock); return NULL; }
/* What each thread is doing * * In principle this is an endless loop. The only time this loop gets interrupted is once * thpool_destroy() is invoked or the program exits. * * @param thread thread that will run this function * @return nothing */ static void* thread_do(Thread* thread) { float elapsed; int info; struct timespec cputime; JobQueue* queue; WorkGroup* workGroup; Job* job; thpool_function_type func_buff; void* arg_buff; int i; /* Set thread name for profiling and debugging */ char thread_name[128] = {0}; sprintf(thread_name, "thread-pool-%d", thread->id); #if defined(__linux__) /* Use prctl instead to prevent using _GNU_SOURCE flag and implicit declaration */ prctl(PR_SET_NAME, thread_name); #elif defined(__APPLE__) && defined(__MACH__) pthread_setname_np(thread_name); #else fprintf(stderr, "thread_do(): pthread_setname_np is not supported on this system"); #endif /* Assure all threads have been created before starting serving */ ThPool* thpool = thread->thpool; /* Mark thread as alive (initialized) */ pthread_mutex_lock(&thpool->thcount_lock); thpool->num_threads_alive += 1; pthread_mutex_unlock(&thpool->thcount_lock); queue = thpool->jobqueue; while (thpool->threads_keepalive) { bsem_wait(queue->has_jobs); if (!thpool->threads_keepalive) { break; } pthread_mutex_lock(&thpool->thcount_lock); thpool->num_threads_working++; pthread_mutex_unlock(&thpool->thcount_lock); while (thpool->threads_keepalive) { /* Read job from queue and execute it */ pthread_mutex_lock(&queue->rwmutex); workGroup = jobqueue_pull(thpool, thread->id); pthread_mutex_unlock(&queue->rwmutex); if (workGroup == NULL) break; if (cppadcg_pool_verbose) { get_monotonic_time2(&workGroup->startTime); } for (i = 0; i < workGroup->size; ++i) { job = &workGroup->jobs[i]; if (cppadcg_pool_verbose) { get_monotonic_time2(&job->startTime); } int do_benchmark = job->elapsed != NULL; if (do_benchmark) { elapsed = -get_thread_time(&cputime, &info); } /* Execute the job */ func_buff = job->function; arg_buff = job->arg; func_buff(arg_buff); if (do_benchmark && info == 0) { elapsed += get_thread_time(&cputime, &info); if (info == 0) { (*job->elapsed) = elapsed; } } if (cppadcg_pool_verbose) { get_monotonic_time2(&job->endTime); } } if (cppadcg_pool_verbose) { get_monotonic_time2(&workGroup->endTime); if (thread->processed_groups == NULL) { thread->processed_groups = workGroup; } else { workGroup->prev = thread->processed_groups; thread->processed_groups = workGroup; } } else { free(workGroup->jobs); free(workGroup); } } pthread_mutex_lock(&thpool->thcount_lock); thpool->num_threads_working--; if (!thpool->num_threads_working) { pthread_cond_signal(&thpool->threads_all_idle); } pthread_mutex_unlock(&thpool->thcount_lock); } pthread_mutex_lock(&thpool->thcount_lock); thpool->num_threads_alive--; pthread_mutex_unlock(&thpool->thcount_lock); return NULL; }