1114902Sscottl/* $OpenBSD: rthread_barrier.c,v 1.5 2020/04/06 00:01:08 pirofti Exp $ */ 2114902Sscottl/* 3114902Sscottl * Copyright (c) 2012 Paul Irofti <paul@irofti.net> 4114902Sscottl * 5114902Sscottl * Permission to use, copy, modify, and/or distribute this software for any 6114902Sscottl * purpose with or without fee is hereby granted, provided that the above 7114902Sscottl * copyright notice and this permission notice appear in all copies. 8114902Sscottl * 9114902Sscottl * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10114902Sscottl * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11114902Sscottl * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12114902Sscottl * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13114902Sscottl * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14114902Sscottl * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15114902Sscottl * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16114902Sscottl */ 17114902Sscottl 18114902Sscottl#include <errno.h> 19114902Sscottl#include <stdlib.h> 20114902Sscottl 21114902Sscottl#include <pthread.h> 22114902Sscottl 23114902Sscottl#include "rthread.h" 24114902Sscottl 25114902Sscottlint 26114902Sscottlpthread_barrier_init(pthread_barrier_t *barrier, pthread_barrierattr_t *attr, 27114902Sscottl unsigned int count) { 28114902Sscottl int rc = 0; 29114902Sscottl pthread_barrier_t b = NULL; 30114902Sscottl 31114902Sscottl if (barrier == NULL) 32114902Sscottl return (EINVAL); 33114902Sscottl 34114902Sscottl if (count == 0) 35114902Sscottl return (EINVAL); 36114902Sscottl 37114902Sscottl if (attr != NULL) { 38114902Sscottl if (*attr == NULL) 39114902Sscottl return (EINVAL); 40114902Sscottl 41114902Sscottl if ((*attr)->pshared != PTHREAD_PROCESS_PRIVATE) 42114902Sscottl return (ENOTSUP); 43114902Sscottl } 44114902Sscottl 45114902Sscottl b = calloc(1, sizeof *b); 46114902Sscottl if (b == NULL) 47114902Sscottl return (ENOMEM); 48119280Simp 49119280Simp if ((rc = pthread_mutex_init(&b->mutex, NULL))) 50114902Sscottl goto err; 51114902Sscottl if ((rc = pthread_cond_init(&b->cond, NULL))) 52114902Sscottl goto err; 53114902Sscottl 54114902Sscottl b->threshold = count; 55114902Sscottl 56114902Sscottl *barrier = b; 57114902Sscottl 58114902Sscottl return (0); 59114902Sscottl 60114902Sscottlerr: 61114902Sscottl if (b) { 62114902Sscottl if (b->mutex) 63125975Sphk pthread_mutex_destroy(&b->mutex); 64114902Sscottl if (b->cond) 65114902Sscottl pthread_cond_destroy(&b->cond); 66 free(b); 67 } 68 69 return (rc); 70} 71 72int 73pthread_barrier_destroy(pthread_barrier_t *barrier) 74{ 75 int rc; 76 pthread_barrier_t b; 77 78 if (barrier == NULL || *barrier == NULL) 79 return (EINVAL); 80 81 if ((rc = pthread_mutex_lock(&(*barrier)->mutex))) 82 return (rc); 83 84 b = *barrier; 85 86 if (b->out > 0 || b->in > 0) { 87 pthread_mutex_unlock(&b->mutex); 88 return (EBUSY); 89 } 90 91 *barrier = NULL; 92 pthread_mutex_unlock(&b->mutex); 93 pthread_mutex_destroy(&b->mutex); 94 pthread_cond_destroy(&b->cond); 95 free(b); 96 return (0); 97} 98 99int 100pthread_barrier_wait(pthread_barrier_t *barrier) 101{ 102 pthread_barrier_t b; 103 int rc, old_state, gen; 104 int done = 0; 105 106 if (barrier == NULL || *barrier == NULL) 107 return (EINVAL); 108 109 if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state))) 110 return (rc); 111 112 b = *barrier; 113 if ((rc = pthread_mutex_lock(&b->mutex))) 114 goto cancel; 115 116 _rthread_debug(6, "in: %d, threshold: %d\n", b->in, b->threshold); 117 if (++b->in == b->threshold) { 118 b->out = b->in - 1; 119 b->in = 0; 120 b->generation++; 121 if ((rc = pthread_cond_signal(&b->cond))) 122 goto err; 123 done = 1; 124 _rthread_debug(6, "threshold reached\n"); 125 } else { 126 gen = b->generation; 127 _rthread_debug(6, "waiting on condition\n"); 128 do { 129 if ((rc = pthread_cond_wait(&b->cond, &b->mutex))) 130 goto err; 131 } while (gen == b->generation); 132 b->out--; /* mark thread exit */ 133 if ((rc = pthread_cond_signal(&b->cond))) 134 goto err; 135 } 136 137err: 138 if ((rc = pthread_mutex_unlock(&b->mutex))) 139 return (rc); 140cancel: 141 rc = pthread_setcancelstate(old_state, NULL); 142 if (rc == 0 && done) 143 rc = PTHREAD_BARRIER_SERIAL_THREAD; 144 145 return (rc); 146} 147