xref: /illumos-gate/usr/src/lib/libc/port/threads/pthr_barrier.c (revision 24da5b34f49324ed742a340010ed5bd3d4e06625)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "lint.h"
30 #include "thr_uberdata.h"
31 #include <pthread.h>
32 
33 /*
34  * Implementation-private attribute structure (for extensibility).
35  */
36 typedef struct {
37 	int	pshared;
38 } barrierattr_t;
39 
40 #pragma weak pthread_barrierattr_init = _pthread_barrierattr_init
41 int
42 _pthread_barrierattr_init(pthread_barrierattr_t *attr)
43 {
44 	barrierattr_t *ap;
45 
46 	if ((ap = lmalloc(sizeof (barrierattr_t))) == NULL)
47 		return (ENOMEM);
48 	ap->pshared = PTHREAD_PROCESS_PRIVATE;
49 	attr->__pthread_barrierattrp = ap;
50 	return (0);
51 }
52 
53 #pragma weak pthread_barrierattr_destroy = _pthread_barrierattr_destroy
54 int
55 _pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
56 {
57 	if (attr == NULL || attr->__pthread_barrierattrp == NULL)
58 		return (EINVAL);
59 	lfree(attr->__pthread_barrierattrp, sizeof (barrierattr_t));
60 	attr->__pthread_barrierattrp = NULL;
61 	return (0);
62 }
63 
64 #pragma weak pthread_barrierattr_setpshared =  _pthread_barrierattr_setpshared
65 int
66 _pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
67 {
68 	barrierattr_t *ap;
69 
70 	if (attr == NULL || (ap = attr->__pthread_barrierattrp) == NULL ||
71 	    (pshared != PTHREAD_PROCESS_PRIVATE &&
72 	    pshared != PTHREAD_PROCESS_SHARED))
73 		return (EINVAL);
74 	ap->pshared = pshared;
75 	return (0);
76 }
77 
78 #pragma weak pthread_barrierattr_getpshared =  _pthread_barrierattr_getpshared
79 int
80 _pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared)
81 {
82 	barrierattr_t *ap;
83 
84 	if (attr == NULL || (ap = attr->__pthread_barrierattrp) == NULL ||
85 	    pshared == NULL)
86 		return (EINVAL);
87 	*pshared = ap->pshared;
88 	return (0);
89 }
90 
91 #pragma weak pthread_barrier_init = _pthread_barrier_init
92 int
93 _pthread_barrier_init(pthread_barrier_t *barrier,
94 	const pthread_barrierattr_t *attr, uint_t count)
95 {
96 	mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
97 	cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
98 	barrierattr_t *ap;
99 	int type;
100 
101 	if (attr == NULL)
102 		type = DEFAULT_TYPE;
103 	else if ((ap = attr->__pthread_barrierattrp) != NULL)
104 		type = ap->pshared;
105 	else
106 		type = -1;
107 
108 	if (count == 0 ||
109 	    (type != PTHREAD_PROCESS_PRIVATE && type != PTHREAD_PROCESS_SHARED))
110 		return (EINVAL);
111 
112 	barrier->__pthread_barrier_count = count;
113 	barrier->__pthread_barrier_current = count;
114 	barrier->__pthread_barrier_cycle = 0;
115 	barrier->__pthread_barrier_reserved = 0;
116 	(void) __mutex_init(mp, type, NULL);
117 	(void) _cond_init(cvp, type, NULL);
118 	return (0);
119 }
120 
121 #pragma weak pthread_barrier_destroy = _pthread_barrier_destroy
122 int
123 _pthread_barrier_destroy(pthread_barrier_t *barrier)
124 {
125 	mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
126 	cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
127 
128 	(void) __mutex_destroy(mp);
129 	(void) _cond_destroy(cvp);
130 	(void) _private_memset(barrier, -1, sizeof (*barrier));
131 	return (0);
132 }
133 
134 /*
135  * pthread_barrier_wait() is not a cancellation point;
136  * call _cond_wait(), not cond_wait().
137  */
138 #pragma weak pthread_barrier_wait = _pthread_barrier_wait
139 int
140 _pthread_barrier_wait(pthread_barrier_t *barrier)
141 {
142 	mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
143 	cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
144 	uint64_t cycle;
145 
146 	(void) __mutex_lock(mp);
147 
148 	if (--barrier->__pthread_barrier_current == 0) {
149 		barrier->__pthread_barrier_cycle++;
150 		barrier->__pthread_barrier_current =
151 			barrier->__pthread_barrier_count;
152 		(void) __mutex_unlock(mp);
153 		(void) _cond_broadcast(cvp);
154 		return (PTHREAD_BARRIER_SERIAL_THREAD);
155 	}
156 
157 	cycle = barrier->__pthread_barrier_cycle;
158 	do {
159 		(void) _cond_wait(cvp, mp);
160 	} while (cycle == barrier->__pthread_barrier_cycle);
161 
162 	(void) __mutex_unlock(mp);
163 	return (0);
164 }
165