1 /* $OpenBSD: rthread_barrier.c,v 1.5 2020/04/06 00:01:08 pirofti Exp $ */ 2 /* 3 * Copyright (c) 2012 Paul Irofti <paul@irofti.net> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <errno.h> 19 #include <stdlib.h> 20 21 #include <pthread.h> 22 23 #include "rthread.h" 24 25 int 26 pthread_barrier_init(pthread_barrier_t *barrier, pthread_barrierattr_t *attr, 27 unsigned int count) { 28 int rc = 0; 29 pthread_barrier_t b = NULL; 30 31 if (barrier == NULL) 32 return (EINVAL); 33 34 if (count == 0) 35 return (EINVAL); 36 37 if (attr != NULL) { 38 if (*attr == NULL) 39 return (EINVAL); 40 41 if ((*attr)->pshared != PTHREAD_PROCESS_PRIVATE) 42 return (ENOTSUP); 43 } 44 45 b = calloc(1, sizeof *b); 46 if (b == NULL) 47 return (ENOMEM); 48 49 if ((rc = pthread_mutex_init(&b->mutex, NULL))) 50 goto err; 51 if ((rc = pthread_cond_init(&b->cond, NULL))) 52 goto err; 53 54 b->threshold = count; 55 56 *barrier = b; 57 58 return (0); 59 60 err: 61 if (b) { 62 if (b->mutex) 63 pthread_mutex_destroy(&b->mutex); 64 if (b->cond) 65 pthread_cond_destroy(&b->cond); 66 free(b); 67 } 68 69 return (rc); 70 } 71 72 int 73 pthread_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 99 int 100 pthread_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 137 err: 138 if ((rc = pthread_mutex_unlock(&b->mutex))) 139 return (rc); 140 cancel: 141 rc = pthread_setcancelstate(old_state, NULL); 142 if (rc == 0 && done) 143 rc = PTHREAD_BARRIER_SERIAL_THREAD; 144 145 return (rc); 146 } 147