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
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
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
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
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
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 	return (0);
114 }
115 
116 int
117 pthread_barrier_destroy(pthread_barrier_t *barrier)
118 {
119 	mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
120 	cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
121 
122 	(void) mutex_destroy(mp);
123 	(void) cond_destroy(cvp);
124 	(void) memset(barrier, -1, sizeof (*barrier));
125 	return (0);
126 }
127 
128 /*
129  * pthread_barrier_wait() is not a cancellation point;
130  */
131 int
132 pthread_barrier_wait(pthread_barrier_t *barrier)
133 {
134 	mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
135 	cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
136 	uint64_t cycle;
137 	int cancel_state;
138 
139 	(void) mutex_lock(mp);
140 
141 	if (--barrier->__pthread_barrier_current == 0) {
142 		barrier->__pthread_barrier_cycle++;
143 		barrier->__pthread_barrier_current =
144 		    barrier->__pthread_barrier_count;
145 		(void) mutex_unlock(mp);
146 		(void) cond_broadcast(cvp);
147 		return (PTHREAD_BARRIER_SERIAL_THREAD);
148 	}
149 
150 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
151 	cycle = barrier->__pthread_barrier_cycle;
152 	do {
153 		(void) cond_wait(cvp, mp);
154 	} while (cycle == barrier->__pthread_barrier_cycle);
155 	(void) pthread_setcancelstate(cancel_state, NULL);
156 
157 	(void) mutex_unlock(mp);
158 	return (0);
159 }
160