xref: /openbsd-src/lib/librthread/rthread_barrier.c (revision 8855e28c066fcedf8b2ce6df476d3f9b3d0ee8f9)
1*8855e28cSpirofti /*	$OpenBSD: rthread_barrier.c,v 1.5 2020/04/06 00:01:08 pirofti Exp $	*/
2c9961bb2Spirofti /*
3*8855e28cSpirofti  * Copyright (c) 2012 Paul Irofti <paul@irofti.net>
4c9961bb2Spirofti  *
5c9961bb2Spirofti  * Permission to use, copy, modify, and/or distribute this software for any
6c9961bb2Spirofti  * purpose with or without fee is hereby granted, provided that the above
7c9961bb2Spirofti  * copyright notice and this permission notice appear in all copies.
8c9961bb2Spirofti  *
9c9961bb2Spirofti  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c9961bb2Spirofti  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c9961bb2Spirofti  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c9961bb2Spirofti  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c9961bb2Spirofti  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c9961bb2Spirofti  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c9961bb2Spirofti  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c9961bb2Spirofti  */
17c9961bb2Spirofti 
18c9961bb2Spirofti #include <errno.h>
19c9961bb2Spirofti #include <stdlib.h>
20c9961bb2Spirofti 
21c9961bb2Spirofti #include <pthread.h>
22c9961bb2Spirofti 
23c9961bb2Spirofti #include "rthread.h"
24c9961bb2Spirofti 
25c9961bb2Spirofti int
pthread_barrier_init(pthread_barrier_t * barrier,pthread_barrierattr_t * attr,unsigned int count)26c9961bb2Spirofti pthread_barrier_init(pthread_barrier_t *barrier, pthread_barrierattr_t *attr,
27c9961bb2Spirofti     unsigned int count) {
28c9961bb2Spirofti 	int rc = 0;
29c9961bb2Spirofti 	pthread_barrier_t b = NULL;
30c9961bb2Spirofti 
31d01bddc4Spirofti 	if (barrier == NULL)
32d01bddc4Spirofti 		return (EINVAL);
33d01bddc4Spirofti 
346c3d037bSpirofti 	if (count == 0)
356c3d037bSpirofti 		return (EINVAL);
366c3d037bSpirofti 
37c9961bb2Spirofti 	if (attr != NULL) {
38d01bddc4Spirofti 		if (*attr == NULL)
39d01bddc4Spirofti 			return (EINVAL);
40d01bddc4Spirofti 
41d01bddc4Spirofti 		if ((*attr)->pshared != PTHREAD_PROCESS_PRIVATE)
42d01bddc4Spirofti 			return (ENOTSUP);
43c9961bb2Spirofti 	}
44c9961bb2Spirofti 
45c9961bb2Spirofti 	b = calloc(1, sizeof *b);
46d01bddc4Spirofti 	if (b == NULL)
47d01bddc4Spirofti 		return (ENOMEM);
48c9961bb2Spirofti 
49d01bddc4Spirofti 	if ((rc = pthread_mutex_init(&b->mutex, NULL)))
50c9961bb2Spirofti 		goto err;
51d01bddc4Spirofti 	if ((rc = pthread_cond_init(&b->cond, NULL)))
52c9961bb2Spirofti 		goto err;
53c9961bb2Spirofti 
54c9961bb2Spirofti 	b->threshold = count;
55c9961bb2Spirofti 
56c9961bb2Spirofti 	*barrier = b;
57c9961bb2Spirofti 
58d01bddc4Spirofti 	return (0);
59c9961bb2Spirofti 
60c9961bb2Spirofti err:
61c9961bb2Spirofti 	if (b) {
62d01bddc4Spirofti 		if (b->mutex)
63c9961bb2Spirofti 			pthread_mutex_destroy(&b->mutex);
64d01bddc4Spirofti 		if (b->cond)
65c9961bb2Spirofti 			pthread_cond_destroy(&b->cond);
66c9961bb2Spirofti 		free(b);
67c9961bb2Spirofti 	}
68d01bddc4Spirofti 
69d01bddc4Spirofti 	return (rc);
70c9961bb2Spirofti }
71c9961bb2Spirofti 
72c9961bb2Spirofti int
pthread_barrier_destroy(pthread_barrier_t * barrier)73c9961bb2Spirofti pthread_barrier_destroy(pthread_barrier_t *barrier)
74c9961bb2Spirofti {
757446b51cStedu 	int rc;
76c9961bb2Spirofti 	pthread_barrier_t b;
77c9961bb2Spirofti 
78d01bddc4Spirofti 	if (barrier == NULL || *barrier == NULL)
79d01bddc4Spirofti 		return (EINVAL);
80c9961bb2Spirofti 
817446b51cStedu 	if ((rc = pthread_mutex_lock(&(*barrier)->mutex)))
827446b51cStedu 		return (rc);
837446b51cStedu 
84c9961bb2Spirofti 	b = *barrier;
85c9961bb2Spirofti 
867446b51cStedu 	if (b->out > 0 || b->in > 0) {
877446b51cStedu 		pthread_mutex_unlock(&b->mutex);
88d01bddc4Spirofti 		return (EBUSY);
897446b51cStedu 	}
90c9961bb2Spirofti 
91c9961bb2Spirofti 	*barrier = NULL;
927446b51cStedu 	pthread_mutex_unlock(&b->mutex);
93c9961bb2Spirofti 	pthread_mutex_destroy(&b->mutex);
94c9961bb2Spirofti 	pthread_cond_destroy(&b->cond);
95c9961bb2Spirofti 	free(b);
96d01bddc4Spirofti 	return (0);
97c9961bb2Spirofti }
98c9961bb2Spirofti 
99c9961bb2Spirofti int
pthread_barrier_wait(pthread_barrier_t * barrier)100c9961bb2Spirofti pthread_barrier_wait(pthread_barrier_t *barrier)
101c9961bb2Spirofti {
102c9961bb2Spirofti 	pthread_barrier_t b;
103c9961bb2Spirofti 	int rc, old_state, gen;
104c9961bb2Spirofti 	int done = 0;
105c9961bb2Spirofti 
106d01bddc4Spirofti 	if (barrier == NULL || *barrier == NULL)
107d01bddc4Spirofti 		return (EINVAL);
108c9961bb2Spirofti 
109d01bddc4Spirofti 	if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state)))
110d01bddc4Spirofti 		return (rc);
111c9961bb2Spirofti 
112c9961bb2Spirofti 	b = *barrier;
113d01bddc4Spirofti 	if ((rc = pthread_mutex_lock(&b->mutex)))
114c9961bb2Spirofti 		goto cancel;
115c9961bb2Spirofti 
1167446b51cStedu 	_rthread_debug(6, "in: %d, threshold: %d\n", b->in, b->threshold);
1177446b51cStedu 	if (++b->in == b->threshold) {
1187446b51cStedu 		b->out = b->in - 1;
1197446b51cStedu 		b->in = 0;
120c9961bb2Spirofti 		b->generation++;
1217446b51cStedu 		if ((rc = pthread_cond_signal(&b->cond)))
122c9961bb2Spirofti 			goto err;
123c9961bb2Spirofti 		done = 1;
124c9961bb2Spirofti 		_rthread_debug(6, "threshold reached\n");
125c9961bb2Spirofti 	} else {
126c9961bb2Spirofti 		gen = b->generation;
127c9961bb2Spirofti 		_rthread_debug(6, "waiting on condition\n");
128c9961bb2Spirofti 		do {
129d01bddc4Spirofti 			if ((rc = pthread_cond_wait(&b->cond, &b->mutex)))
130c9961bb2Spirofti 				goto err;
131c9961bb2Spirofti 		} while (gen == b->generation);
1327446b51cStedu 		b->out--; /* mark thread exit */
1337446b51cStedu 		if ((rc = pthread_cond_signal(&b->cond)))
1347446b51cStedu 			goto err;
135c9961bb2Spirofti 	}
136c9961bb2Spirofti 
137c9961bb2Spirofti err:
138d01bddc4Spirofti 	if ((rc = pthread_mutex_unlock(&b->mutex)))
139d01bddc4Spirofti 		return (rc);
140c9961bb2Spirofti cancel:
141c9961bb2Spirofti 	rc = pthread_setcancelstate(old_state, NULL);
142d01bddc4Spirofti 	if (rc == 0 && done)
143c9961bb2Spirofti 		rc = PTHREAD_BARRIER_SERIAL_THREAD;
144d01bddc4Spirofti 
145d01bddc4Spirofti 	return (rc);
146c9961bb2Spirofti }
147