1 /* $OpenBSD: rthread_barrier.c,v 1.2 2012/04/23 08:30:33 pirofti 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 pthread_barrier_t b; 73 74 if (barrier == NULL || *barrier == NULL) 75 return (EINVAL); 76 77 b = *barrier; 78 79 if (b->sofar > 0) 80 return (EBUSY); 81 82 *barrier = NULL; 83 pthread_mutex_destroy(&b->mutex); 84 pthread_cond_destroy(&b->cond); 85 free(b); 86 return (0); 87 } 88 89 int 90 pthread_barrier_wait(pthread_barrier_t *barrier) 91 { 92 pthread_barrier_t b; 93 int rc, old_state, gen; 94 int done = 0; 95 96 if (barrier == NULL || *barrier == NULL) 97 return (EINVAL); 98 99 if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state))) 100 return (rc); 101 102 b = *barrier; 103 if ((rc = pthread_mutex_lock(&b->mutex))) 104 goto cancel; 105 106 _rthread_debug(6, "sofar: %d, threshold: %d\n", b->sofar, b->threshold); 107 if (++b->sofar == b->threshold) { 108 b->sofar = 0; 109 b->generation++; 110 if ((rc = pthread_cond_broadcast(&b->cond))) 111 goto err; 112 done = 1; 113 _rthread_debug(6, "threshold reached\n"); 114 } else { 115 gen = b->generation; 116 _rthread_debug(6, "waiting on condition\n"); 117 do { 118 if ((rc = pthread_cond_wait(&b->cond, &b->mutex))) 119 goto err; 120 } while (gen == b->generation); 121 } 122 123 err: 124 if ((rc = pthread_mutex_unlock(&b->mutex))) 125 return (rc); 126 cancel: 127 rc = pthread_setcancelstate(old_state, NULL); 128 if (rc == 0 && done) 129 rc = PTHREAD_BARRIER_SERIAL_THREAD; 130 131 return (rc); 132 } 133