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
pthread_barrier_init(pthread_barrier_t * barrier,pthread_barrierattr_t * attr,unsigned int count)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
pthread_barrier_destroy(pthread_barrier_t * barrier)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
pthread_barrier_wait(pthread_barrier_t * barrier)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