xref: /illumos-gate/usr/src/lib/libc/port/threads/pthr_barrier.c (revision 69ed0c8ece2346b34605e2c9567c9f7b0dad5dc8)
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 
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
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
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