thr_barrier.c revision 278668
1/*-
2 * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: stable/10/lib/libthr/thread/thr_barrier.c 278668 2015-02-13 08:42:01Z kib $
27 */
28
29#include "namespace.h"
30#include <errno.h>
31#include <stdlib.h>
32#include <pthread.h>
33#include "un-namespace.h"
34
35#include "thr_private.h"
36
37__weak_reference(_pthread_barrier_init,		pthread_barrier_init);
38__weak_reference(_pthread_barrier_wait,		pthread_barrier_wait);
39__weak_reference(_pthread_barrier_destroy,	pthread_barrier_destroy);
40
41int
42_pthread_barrier_destroy(pthread_barrier_t *barrier)
43{
44	pthread_barrier_t	bar;
45	struct pthread		*curthread;
46
47	if (barrier == NULL || *barrier == NULL)
48		return (EINVAL);
49
50	curthread = _get_curthread();
51	bar = *barrier;
52	THR_UMUTEX_LOCK(curthread, &bar->b_lock);
53	if (bar->b_destroying) {
54		THR_UMUTEX_UNLOCK(curthread, &bar->b_lock);
55		return (EBUSY);
56	}
57	bar->b_destroying = 1;
58	do {
59		if (bar->b_waiters > 0) {
60			bar->b_destroying = 0;
61			THR_UMUTEX_UNLOCK(curthread, &bar->b_lock);
62			return (EBUSY);
63		}
64		if (bar->b_refcount != 0) {
65			_thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0);
66			THR_UMUTEX_LOCK(curthread, &bar->b_lock);
67		} else
68			break;
69	} while (1);
70	bar->b_destroying = 0;
71	THR_UMUTEX_UNLOCK(curthread, &bar->b_lock);
72
73	*barrier = NULL;
74	free(bar);
75	return (0);
76}
77
78int
79_pthread_barrier_init(pthread_barrier_t *barrier,
80		      const pthread_barrierattr_t *attr, unsigned count)
81{
82	pthread_barrier_t	bar;
83
84	(void)attr;
85
86	if (barrier == NULL || count <= 0)
87		return (EINVAL);
88
89	bar = calloc(1, sizeof(struct pthread_barrier));
90	if (bar == NULL)
91		return (ENOMEM);
92
93	_thr_umutex_init(&bar->b_lock);
94	_thr_ucond_init(&bar->b_cv);
95	bar->b_count	= count;
96	*barrier	= bar;
97
98	return (0);
99}
100
101int
102_pthread_barrier_wait(pthread_barrier_t *barrier)
103{
104	struct pthread *curthread = _get_curthread();
105	pthread_barrier_t bar;
106	int64_t cycle;
107	int ret;
108
109	if (barrier == NULL || *barrier == NULL)
110		return (EINVAL);
111
112	bar = *barrier;
113	THR_UMUTEX_LOCK(curthread, &bar->b_lock);
114	if (++bar->b_waiters == bar->b_count) {
115		/* Current thread is lastest thread */
116		bar->b_waiters = 0;
117		bar->b_cycle++;
118		_thr_ucond_broadcast(&bar->b_cv);
119		THR_UMUTEX_UNLOCK(curthread, &bar->b_lock);
120		ret = PTHREAD_BARRIER_SERIAL_THREAD;
121	} else {
122		cycle = bar->b_cycle;
123		bar->b_refcount++;
124		do {
125			_thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0);
126			THR_UMUTEX_LOCK(curthread, &bar->b_lock);
127			/* test cycle to avoid bogus wakeup */
128		} while (cycle == bar->b_cycle);
129		if (--bar->b_refcount == 0 && bar->b_destroying)
130			_thr_ucond_broadcast(&bar->b_cv);
131		THR_UMUTEX_UNLOCK(curthread, &bar->b_lock);
132		ret = 0;
133	}
134	return (ret);
135}
136