/* See LICENSE file for copyright and license details. */ #include "common.h" void barrierwait(pthread_barrier_t *barrier) { #ifndef SINGLE_THREADED int r = pthread_barrier_wait(barrier); if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) { errno = r; eprintf("pthread_barrier_wait:"); } #else (void) barrier; #endif } void barriersend(struct barrier_group *group, struct global_data *global, void (*action)(struct algorithm *, struct global_data *)) { size_t index; global->action = action; if (group->nthreads) barrierwait(&group->barrier); for (index = 0; index < global->nalgorithms; index += group->nthreads + 1U) (*action)(&global->algorithms[index], global); if (group->nthreads) barrierwait(&group->barrier); } #ifndef SINGLE_THREADED static void * slaveloop(void *thread_param) { struct thread_data *data = thread_param; void (*action)(struct algorithm *, struct global_data *); size_t index; for (;;) { barrierwait(&data->group->barrier); action = data->global->action; if (!action) break; for (index = data->index; index < data->global->nalgorithms; index += data->group->nthreads + 1U) (*action)(&data->global->algorithms[index], data->global); barrierwait(&data->group->barrier); } return NULL; } #endif void createbarriergroup(struct barrier_group *group_out, size_t count, struct global_data *global) { #ifndef SINGLE_THREADED size_t i; group_out->nthreads = count - 1U; group_out->threads = NULL; if (!group_out->nthreads) return; group_out->threads = ecalloc(group_out->nthreads, sizeof(*group_out->threads)); if ((errno = pthread_barrier_init(&group_out->barrier, NULL, (unsigned)count))) eprintf("pthread_barrier_init NULL %u:", (unsigned)count); for (i = 0; i < group_out->nthreads; i++) { group_out->threads[i].group = group_out; group_out->threads[i].global = global; group_out->threads[i].index = i + 1U; errno = pthread_create(&group_out->threads[i].thread, NULL, &slaveloop, &group_out->threads[i]); if (errno) eprintf("pthread_create NULL:"); } #else group_out->nthreads = 0U; group_out->threads = NULL; (void) global; (void) count; #endif } void killbarriergroup(struct barrier_group *group, struct global_data *global) { #ifndef SINGLE_THREADED size_t i; if (!group->nthreads) return; global->action = NULL; for (i = 0; i < group->nthreads; i++) group->threads[i].global = global; barrierwait(&group->barrier); for (i = 0; i < group->nthreads; i++) if ((errno = pthread_join(group->threads[i].thread, NULL))) weprintf("pthread_join:"); pthread_barrier_destroy(&group->barrier); free(group->threads); #else (void) group; (void) global; #endif }