17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5a574db85Sraf  * Common Development and Distribution License (the "License").
6a574db85Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21a574db85Sraf 
227c478bd9Sstevel@tonic-gate /*
23a574db85Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include "lint.h"
287c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
297c478bd9Sstevel@tonic-gate #include <pthread.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * Implementation-private attribute structure (for extensibility).
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate typedef struct {
357c478bd9Sstevel@tonic-gate 	int	pshared;
367c478bd9Sstevel@tonic-gate } barrierattr_t;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate int
pthread_barrierattr_init(pthread_barrierattr_t * attr)397257d1b4Sraf pthread_barrierattr_init(pthread_barrierattr_t *attr)
407c478bd9Sstevel@tonic-gate {
417c478bd9Sstevel@tonic-gate 	barrierattr_t *ap;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate 	if ((ap = lmalloc(sizeof (barrierattr_t))) == NULL)
447c478bd9Sstevel@tonic-gate 		return (ENOMEM);
457c478bd9Sstevel@tonic-gate 	ap->pshared = PTHREAD_PROCESS_PRIVATE;
467c478bd9Sstevel@tonic-gate 	attr->__pthread_barrierattrp = ap;
477c478bd9Sstevel@tonic-gate 	return (0);
487c478bd9Sstevel@tonic-gate }
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate int
pthread_barrierattr_destroy(pthread_barrierattr_t * attr)517257d1b4Sraf pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
527c478bd9Sstevel@tonic-gate {
537c478bd9Sstevel@tonic-gate 	if (attr == NULL || attr->__pthread_barrierattrp == NULL)
547c478bd9Sstevel@tonic-gate 		return (EINVAL);
557c478bd9Sstevel@tonic-gate 	lfree(attr->__pthread_barrierattrp, sizeof (barrierattr_t));
567c478bd9Sstevel@tonic-gate 	attr->__pthread_barrierattrp = NULL;
577c478bd9Sstevel@tonic-gate 	return (0);
587c478bd9Sstevel@tonic-gate }
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate int
pthread_barrierattr_setpshared(pthread_barrierattr_t * attr,int pshared)617257d1b4Sraf pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate 	barrierattr_t *ap;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	if (attr == NULL || (ap = attr->__pthread_barrierattrp) == NULL ||
667c478bd9Sstevel@tonic-gate 	    (pshared != PTHREAD_PROCESS_PRIVATE &&
677c478bd9Sstevel@tonic-gate 	    pshared != PTHREAD_PROCESS_SHARED))
687c478bd9Sstevel@tonic-gate 		return (EINVAL);
697c478bd9Sstevel@tonic-gate 	ap->pshared = pshared;
707c478bd9Sstevel@tonic-gate 	return (0);
717c478bd9Sstevel@tonic-gate }
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate int
pthread_barrierattr_getpshared(const pthread_barrierattr_t * attr,int * pshared)747257d1b4Sraf pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	barrierattr_t *ap;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	if (attr == NULL || (ap = attr->__pthread_barrierattrp) == NULL ||
797c478bd9Sstevel@tonic-gate 	    pshared == NULL)
807c478bd9Sstevel@tonic-gate 		return (EINVAL);
817c478bd9Sstevel@tonic-gate 	*pshared = ap->pshared;
827c478bd9Sstevel@tonic-gate 	return (0);
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate int
pthread_barrier_init(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,uint_t count)867257d1b4Sraf pthread_barrier_init(pthread_barrier_t *barrier,
877c5714f6Sraf     const pthread_barrierattr_t *attr, uint_t count)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
907c478bd9Sstevel@tonic-gate 	cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
917c478bd9Sstevel@tonic-gate 	barrierattr_t *ap;
927c478bd9Sstevel@tonic-gate 	int type;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	if (attr == NULL)
95*a90d75b8SRichard PALO 		type = PTHREAD_PROCESS_PRIVATE;
967c478bd9Sstevel@tonic-gate 	else if ((ap = attr->__pthread_barrierattrp) != NULL)
977c478bd9Sstevel@tonic-gate 		type = ap->pshared;
987c478bd9Sstevel@tonic-gate 	else
997c478bd9Sstevel@tonic-gate 		type = -1;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	if (count == 0 ||
1027c478bd9Sstevel@tonic-gate 	    (type != PTHREAD_PROCESS_PRIVATE && type != PTHREAD_PROCESS_SHARED))
1037c478bd9Sstevel@tonic-gate 		return (EINVAL);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	barrier->__pthread_barrier_count = count;
1067c478bd9Sstevel@tonic-gate 	barrier->__pthread_barrier_current = count;
1077c478bd9Sstevel@tonic-gate 	barrier->__pthread_barrier_cycle = 0;
1087c478bd9Sstevel@tonic-gate 	barrier->__pthread_barrier_reserved = 0;
1097257d1b4Sraf 	(void) mutex_init(mp, type, NULL);
1107257d1b4Sraf 	(void) cond_init(cvp, type, NULL);
1117c5714f6Sraf 
1127c5714f6Sraf 	/*
1137c5714f6Sraf 	 * This should be at the beginning of the function,
1147c5714f6Sraf 	 * but for the sake of old broken applications that
1157c5714f6Sraf 	 * do not have proper alignment for their barriers
1167c5714f6Sraf 	 * (and don't check the return code from pthread_barrier_init),
1177c5714f6Sraf 	 * we put it here, after initializing the barrier regardless.
1187c5714f6Sraf 	 */
1197c5714f6Sraf 	if (((uintptr_t)barrier & (_LONG_LONG_ALIGNMENT - 1)) &&
1207c5714f6Sraf 	    curthread->ul_misaligned == 0)
1217c5714f6Sraf 		return (EINVAL);
1227c5714f6Sraf 
1237c478bd9Sstevel@tonic-gate 	return (0);
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate int
pthread_barrier_destroy(pthread_barrier_t * barrier)1277257d1b4Sraf pthread_barrier_destroy(pthread_barrier_t *barrier)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
1307c478bd9Sstevel@tonic-gate 	cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
1317c478bd9Sstevel@tonic-gate 
1327257d1b4Sraf 	(void) mutex_destroy(mp);
1337257d1b4Sraf 	(void) cond_destroy(cvp);
1348cd45542Sraf 	(void) memset(barrier, -1, sizeof (*barrier));
1357c478bd9Sstevel@tonic-gate 	return (0);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate  * pthread_barrier_wait() is not a cancellation point;
1407c478bd9Sstevel@tonic-gate  */
1417c478bd9Sstevel@tonic-gate int
pthread_barrier_wait(pthread_barrier_t * barrier)1427257d1b4Sraf pthread_barrier_wait(pthread_barrier_t *barrier)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock;
1457c478bd9Sstevel@tonic-gate 	cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond;
1467c478bd9Sstevel@tonic-gate 	uint64_t cycle;
147a574db85Sraf 	int cancel_state;
1487c478bd9Sstevel@tonic-gate 
1497257d1b4Sraf 	(void) mutex_lock(mp);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	if (--barrier->__pthread_barrier_current == 0) {
1527c478bd9Sstevel@tonic-gate 		barrier->__pthread_barrier_cycle++;
1537c478bd9Sstevel@tonic-gate 		barrier->__pthread_barrier_current =
154a574db85Sraf 		    barrier->__pthread_barrier_count;
1557257d1b4Sraf 		(void) mutex_unlock(mp);
1567257d1b4Sraf 		(void) cond_broadcast(cvp);
1577c478bd9Sstevel@tonic-gate 		return (PTHREAD_BARRIER_SERIAL_THREAD);
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate 
1607257d1b4Sraf 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
1617c478bd9Sstevel@tonic-gate 	cycle = barrier->__pthread_barrier_cycle;
1627c478bd9Sstevel@tonic-gate 	do {
1637257d1b4Sraf 		(void) cond_wait(cvp, mp);
1647c478bd9Sstevel@tonic-gate 	} while (cycle == barrier->__pthread_barrier_cycle);
1657257d1b4Sraf 	(void) pthread_setcancelstate(cancel_state, NULL);
1667c478bd9Sstevel@tonic-gate 
1677257d1b4Sraf 	(void) mutex_unlock(mp);
1687c478bd9Sstevel@tonic-gate 	return (0);
1697c478bd9Sstevel@tonic-gate }
170