Annotation of src/lib/libpthread/pthread_barrier.c, Revision 1.18
1.18 ! ad 1: /* $NetBSD: pthread_barrier.c,v 1.17 2008/04/28 20:23:01 martin Exp $ */
1.2 thorpej 2:
3: /*-
1.10 ad 4: * Copyright (c) 2001, 2003, 2006, 2007 The NetBSD Foundation, Inc.
1.2 thorpej 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
1.11 ad 8: * by Nathan J. Williams, by Jason R. Thorpe, and by Andrew Doran.
1.2 thorpej 9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
1.6 lukem 31:
32: #include <sys/cdefs.h>
1.18 ! ad 33: __RCSID("$NetBSD: pthread_barrier.c,v 1.17 2008/04/28 20:23:01 martin Exp $");
1.2 thorpej 34:
35: #include <errno.h>
36:
37: #include "pthread.h"
38: #include "pthread_int.h"
39:
40: int
41: pthread_barrier_init(pthread_barrier_t *barrier,
1.18 ! ad 42: const pthread_barrierattr_t *attr, unsigned int count)
1.2 thorpej 43: {
1.18 ! ad 44: pthread_mutex_t *interlock;
! 45:
1.2 thorpej 46: #ifdef ERRORCHECK
47: if ((barrier == NULL) ||
48: (attr && (attr->ptba_magic != _PT_BARRIERATTR_MAGIC)))
49: return EINVAL;
50: #endif
51:
52: if (count == 0)
53: return EINVAL;
54:
55: if (barrier->ptb_magic == _PT_BARRIER_MAGIC) {
1.18 ! ad 56: interlock = pthread__hashlock(barrier);
1.15 ad 57:
1.2 thorpej 58: /*
59: * We're simply reinitializing the barrier to a
60: * new count.
61: */
1.18 ! ad 62: pthread_mutex_lock(interlock);
1.2 thorpej 63:
64: if (barrier->ptb_magic != _PT_BARRIER_MAGIC) {
1.18 ! ad 65: pthread_mutex_unlock(interlock);
1.2 thorpej 66: return EINVAL;
67: }
68:
69: if (!PTQ_EMPTY(&barrier->ptb_waiters)) {
1.18 ! ad 70: pthread_mutex_unlock(interlock);
1.2 thorpej 71: return EBUSY;
72: }
73:
74: barrier->ptb_initcount = count;
75: barrier->ptb_curcount = 0;
1.3 nathanw 76: barrier->ptb_generation = 0;
1.2 thorpej 77:
1.18 ! ad 78: pthread_mutex_unlock(interlock);
1.2 thorpej 79:
80: return 0;
81: }
82:
83: barrier->ptb_magic = _PT_BARRIER_MAGIC;
84: PTQ_INIT(&barrier->ptb_waiters);
85: barrier->ptb_initcount = count;
86: barrier->ptb_curcount = 0;
1.3 nathanw 87: barrier->ptb_generation = 0;
1.2 thorpej 88:
89: return 0;
90: }
91:
92:
93: int
94: pthread_barrier_destroy(pthread_barrier_t *barrier)
95: {
1.18 ! ad 96: pthread_mutex_t *interlock;
1.2 thorpej 97:
98: #ifdef ERRORCHECK
99: if ((barrier == NULL) || (barrier->ptb_magic != _PT_BARRIER_MAGIC))
100: return EINVAL;
101: #endif
102:
1.18 ! ad 103: interlock = pthread__hashlock(barrier);
! 104: pthread_mutex_lock(interlock);
1.2 thorpej 105:
106: if (barrier->ptb_magic != _PT_BARRIER_MAGIC) {
1.18 ! ad 107: pthread_mutex_unlock(interlock);
1.2 thorpej 108: return EINVAL;
109: }
110:
111: if (!PTQ_EMPTY(&barrier->ptb_waiters)) {
1.18 ! ad 112: pthread_mutex_unlock(interlock);
1.2 thorpej 113: return EBUSY;
114: }
115:
116: barrier->ptb_magic = _PT_BARRIER_DEAD;
117:
1.18 ! ad 118: pthread_mutex_unlock(interlock);
1.2 thorpej 119:
120: return 0;
121: }
122:
123:
124: int
125: pthread_barrier_wait(pthread_barrier_t *barrier)
126: {
1.18 ! ad 127: pthread_mutex_t *interlock;
1.2 thorpej 128: pthread_t self;
1.3 nathanw 129: unsigned int gen;
1.2 thorpej 130:
131: #ifdef ERRORCHECK
132: if ((barrier == NULL) || (barrier->ptb_magic != _PT_BARRIER_MAGIC))
133: return EINVAL;
134: #endif
135: self = pthread__self();
1.18 ! ad 136: interlock = pthread__hashlock(barrier);
1.2 thorpej 137:
1.18 ! ad 138: pthread_mutex_lock(interlock);
1.2 thorpej 139:
140: /*
141: * A single arbitrary thread is supposed to return
142: * PTHREAD_BARRIER_SERIAL_THREAD, and everone else
143: * is supposed to return 0. Since pthread_barrier_wait()
144: * is not a cancellation point, this is trivial; we
145: * simply elect that the thread that causes the barrier
146: * to be satisfied gets the special return value. Note
147: * that this final thread does not actually need to block,
148: * but instead is responsible for waking everyone else up.
149: */
150: if (barrier->ptb_curcount + 1 == barrier->ptb_initcount) {
1.8 ad 151: barrier->ptb_generation++;
1.18 ! ad 152: pthread__unpark_all(&barrier->ptb_waiters, self,
! 153: interlock);
! 154: pthread_mutex_unlock(interlock);
1.2 thorpej 155: return PTHREAD_BARRIER_SERIAL_THREAD;
156: }
157:
1.3 nathanw 158: barrier->ptb_curcount++;
159: gen = barrier->ptb_generation;
160: while (gen == barrier->ptb_generation) {
1.11 ad 161: PTQ_INSERT_TAIL(&barrier->ptb_waiters, self, pt_sleep);
162: self->pt_sleepobj = &barrier->ptb_waiters;
1.18 ! ad 163: (void)pthread__park(self, interlock, &barrier->ptb_waiters,
! 164: NULL, 0, __UNVOLATILE(&interlock->ptm_waiters));
! 165: pthread_mutex_lock(interlock);
1.3 nathanw 166: }
1.18 ! ad 167: pthread_mutex_unlock(interlock);
1.2 thorpej 168:
169: return 0;
170: }
171:
172:
173: int
174: pthread_barrierattr_init(pthread_barrierattr_t *attr)
175: {
176:
177: #ifdef ERRORCHECK
178: if (attr == NULL)
179: return EINVAL;
180: #endif
181:
182: attr->ptba_magic = _PT_BARRIERATTR_MAGIC;
183:
184: return 0;
185: }
186:
187:
188: int
189: pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
190: {
191:
192: #ifdef ERRORCHECK
193: if ((attr == NULL) ||
194: (attr->ptba_magic != _PT_BARRIERATTR_MAGIC))
195: return EINVAL;
196: #endif
197:
198: attr->ptba_magic = _PT_BARRIERATTR_DEAD;
199:
200: return 0;
201: }
CVSweb <webmaster@jp.NetBSD.org>