1 /* $OpenBSD: rthread_barrier.c,v 1.3 2016/04/15 17:54:17 tedu Exp $ */ 2 /* 3 * Copyright (c) 2012 Paul Irofti <pirofti@openbsd.org> 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 (attr != NULL) { 35 if (*attr == NULL) 36 return (EINVAL); 37 38 if ((*attr)->pshared != PTHREAD_PROCESS_PRIVATE) 39 return (ENOTSUP); 40 } 41 42 b = calloc(1, sizeof *b); 43 if (b == NULL) 44 return (ENOMEM); 45 46 if ((rc = pthread_mutex_init(&b->mutex, NULL))) 47 goto err; 48 if ((rc = pthread_cond_init(&b->cond, NULL))) 49 goto err; 50 51 b->threshold = count; 52 53 *barrier = b; 54 55 return (0); 56 57 err: 58 if (b) { 59 if (b->mutex) 60 pthread_mutex_destroy(&b->mutex); 61 if (b->cond) 62 pthread_cond_destroy(&b->cond); 63 free(b); 64 } 65 66 return (rc); 67 } 68 69 int 70 pthread_barrier_destroy(pthread_barrier_t *barrier) 71 { 72 int rc; 73 pthread_barrier_t b; 74 75 if (barrier == NULL || *barrier == NULL) 76 return (EINVAL); 77 78 if ((rc = pthread_mutex_lock(&(*barrier)->mutex))) 79 return (rc); 80 81 b = *barrier; 82 83 if (b->out > 0 || b->in > 0) { 84 pthread_mutex_unlock(&b->mutex); 85 return (EBUSY); 86 } 87 88 *barrier = NULL; 89 pthread_mutex_unlock(&b->mutex); 90 pthread_mutex_destroy(&b->mutex); 91 pthread_cond_destroy(&b->cond); 92 free(b); 93 return (0); 94 } 95 96 int 97 pthread_barrier_wait(pthread_barrier_t *barrier) 98 { 99 pthread_barrier_t b; 100 int rc, old_state, gen; 101 int done = 0; 102 103 if (barrier == NULL || *barrier == NULL) 104 return (EINVAL); 105 106 if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state))) 107 return (rc); 108 109 b = *barrier; 110 if ((rc = pthread_mutex_lock(&b->mutex))) 111 goto cancel; 112 113 _rthread_debug(6, "in: %d, threshold: %d\n", b->in, b->threshold); 114 if (++b->in == b->threshold) { 115 b->out = b->in - 1; 116 b->in = 0; 117 b->generation++; 118 if ((rc = pthread_cond_signal(&b->cond))) 119 goto err; 120 done = 1; 121 _rthread_debug(6, "threshold reached\n"); 122 } else { 123 gen = b->generation; 124 _rthread_debug(6, "waiting on condition\n"); 125 do { 126 if ((rc = pthread_cond_wait(&b->cond, &b->mutex))) 127 goto err; 128 } while (gen == b->generation); 129 b->out--; /* mark thread exit */ 130 if ((rc = pthread_cond_signal(&b->cond))) 131 goto err; 132 } 133 134 err: 135 if ((rc = pthread_mutex_unlock(&b->mutex))) 136 return (rc); 137 cancel: 138 rc = pthread_setcancelstate(old_state, NULL); 139 if (rc == 0 && done) 140 rc = PTHREAD_BARRIER_SERIAL_THREAD; 141 142 return (rc); 143 } 144