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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 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 int
pthread_barrierattr_init(pthread_barrierattr_t * attr)41 pthread_barrierattr_init(pthread_barrierattr_t *attr)
42 {
43 barrierattr_t *ap;
44
45 if ((ap = lmalloc(sizeof (barrierattr_t))) == NULL)
46 return (ENOMEM);
47 ap->pshared = PTHREAD_PROCESS_PRIVATE;
48 attr->__pthread_barrierattrp = ap;
49 return (0);
50 }
51
52 int
pthread_barrierattr_destroy(pthread_barrierattr_t * attr)53 pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
54 {
55 if (attr == NULL || attr->__pthread_barrierattrp == NULL)
56 return (EINVAL);
57 lfree(attr->__pthread_barrierattrp, sizeof (barrierattr_t));
58 attr->__pthread_barrierattrp = NULL;
59 return (0);
60 }
61
62 int
pthread_barrierattr_setpshared(pthread_barrierattr_t * attr,int pshared)63 pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
64 {
65 barrierattr_t *ap;
66
67 if (attr == NULL || (ap = attr->__pthread_barrierattrp) == NULL ||
68 (pshared != PTHREAD_PROCESS_PRIVATE &&
69 pshared != PTHREAD_PROCESS_SHARED))
70 return (EINVAL);
71 ap->pshared = pshared;
72 return (0);
73 }
74
75 int
pthread_barrierattr_getpshared(const pthread_barrierattr_t * attr,int * pshared)76 pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared)
77 {
78 barrierattr_t *ap;
79
80 if (attr == NULL || (ap = attr->__pthread_barrierattrp) == NULL ||
81 pshared == NULL)
82 return (EINVAL);
83 *pshared = ap->pshared;
84 return (0);
85 }
86
87 int
pthread_barrier_init(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,uint_t count)88 pthread_barrier_init(pthread_barrier_t *barrier,
89 const pthread_barrierattr_t *attr, uint_t count)
90 {
91 mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
92 cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
93 barrierattr_t *ap;
94 int type;
95
96 if (attr == NULL)
97 type = DEFAULT_TYPE;
98 else if ((ap = attr->__pthread_barrierattrp) != NULL)
99 type = ap->pshared;
100 else
101 type = -1;
102
103 if (count == 0 ||
104 (type != PTHREAD_PROCESS_PRIVATE && type != PTHREAD_PROCESS_SHARED))
105 return (EINVAL);
106
107 barrier->__pthread_barrier_count = count;
108 barrier->__pthread_barrier_current = count;
109 barrier->__pthread_barrier_cycle = 0;
110 barrier->__pthread_barrier_reserved = 0;
111 (void) mutex_init(mp, type, NULL);
112 (void) cond_init(cvp, type, NULL);
113
114 /*
115 * This should be at the beginning of the function,
116 * but for the sake of old broken applications that
117 * do not have proper alignment for their barriers
118 * (and don't check the return code from pthread_barrier_init),
119 * we put it here, after initializing the barrier regardless.
120 */
121 if (((uintptr_t)barrier & (_LONG_LONG_ALIGNMENT - 1)) &&
122 curthread->ul_misaligned == 0)
123 return (EINVAL);
124
125 return (0);
126 }
127
128 int
pthread_barrier_destroy(pthread_barrier_t * barrier)129 pthread_barrier_destroy(pthread_barrier_t *barrier)
130 {
131 mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
132 cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
133
134 (void) mutex_destroy(mp);
135 (void) cond_destroy(cvp);
136 (void) memset(barrier, -1, sizeof (*barrier));
137 return (0);
138 }
139
140 /*
141 * pthread_barrier_wait() is not a cancellation point;
142 */
143 int
pthread_barrier_wait(pthread_barrier_t * barrier)144 pthread_barrier_wait(pthread_barrier_t *barrier)
145 {
146 mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
147 cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
148 uint64_t cycle;
149 int cancel_state;
150
151 (void) mutex_lock(mp);
152
153 if (--barrier->__pthread_barrier_current == 0) {
154 barrier->__pthread_barrier_cycle++;
155 barrier->__pthread_barrier_current =
156 barrier->__pthread_barrier_count;
157 (void) mutex_unlock(mp);
158 (void) cond_broadcast(cvp);
159 return (PTHREAD_BARRIER_SERIAL_THREAD);
160 }
161
162 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
163 cycle = barrier->__pthread_barrier_cycle;
164 do {
165 (void) cond_wait(cvp, mp);
166 } while (cycle == barrier->__pthread_barrier_cycle);
167 (void) pthread_setcancelstate(cancel_state, NULL);
168
169 (void) mutex_unlock(mp);
170 return (0);
171 }
172