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 #include "lint.h" 28 #include "thr_uberdata.h" 29 #include <pthread.h> 30 31 /* 32 * Implementation-private attribute structure (for extensibility). 33 */ 34 typedef struct { 35 int pshared; 36 } barrierattr_t; 37 38 int 39 pthread_barrierattr_init(pthread_barrierattr_t *attr) 40 { 41 barrierattr_t *ap; 42 43 if ((ap = lmalloc(sizeof (barrierattr_t))) == NULL) 44 return (ENOMEM); 45 ap->pshared = PTHREAD_PROCESS_PRIVATE; 46 attr->__pthread_barrierattrp = ap; 47 return (0); 48 } 49 50 int 51 pthread_barrierattr_destroy(pthread_barrierattr_t *attr) 52 { 53 if (attr == NULL || attr->__pthread_barrierattrp == NULL) 54 return (EINVAL); 55 lfree(attr->__pthread_barrierattrp, sizeof (barrierattr_t)); 56 attr->__pthread_barrierattrp = NULL; 57 return (0); 58 } 59 60 int 61 pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) 62 { 63 barrierattr_t *ap; 64 65 if (attr == NULL || (ap = attr->__pthread_barrierattrp) == NULL || 66 (pshared != PTHREAD_PROCESS_PRIVATE && 67 pshared != PTHREAD_PROCESS_SHARED)) 68 return (EINVAL); 69 ap->pshared = pshared; 70 return (0); 71 } 72 73 int 74 pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared) 75 { 76 barrierattr_t *ap; 77 78 if (attr == NULL || (ap = attr->__pthread_barrierattrp) == NULL || 79 pshared == NULL) 80 return (EINVAL); 81 *pshared = ap->pshared; 82 return (0); 83 } 84 85 int 86 pthread_barrier_init(pthread_barrier_t *barrier, 87 const pthread_barrierattr_t *attr, uint_t count) 88 { 89 mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock; 90 cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond; 91 barrierattr_t *ap; 92 int type; 93 94 if (attr == NULL) 95 type = PTHREAD_PROCESS_PRIVATE; 96 else if ((ap = attr->__pthread_barrierattrp) != NULL) 97 type = ap->pshared; 98 else 99 type = -1; 100 101 if (count == 0 || 102 (type != PTHREAD_PROCESS_PRIVATE && type != PTHREAD_PROCESS_SHARED)) 103 return (EINVAL); 104 105 barrier->__pthread_barrier_count = count; 106 barrier->__pthread_barrier_current = count; 107 barrier->__pthread_barrier_cycle = 0; 108 barrier->__pthread_barrier_reserved = 0; 109 (void) mutex_init(mp, type, NULL); 110 (void) cond_init(cvp, type, NULL); 111 112 /* 113 * This should be at the beginning of the function, 114 * but for the sake of old broken applications that 115 * do not have proper alignment for their barriers 116 * (and don't check the return code from pthread_barrier_init), 117 * we put it here, after initializing the barrier regardless. 118 */ 119 if (((uintptr_t)barrier & (_LONG_LONG_ALIGNMENT - 1)) && 120 curthread->ul_misaligned == 0) 121 return (EINVAL); 122 123 return (0); 124 } 125 126 int 127 pthread_barrier_destroy(pthread_barrier_t *barrier) 128 { 129 mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock; 130 cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond; 131 132 (void) mutex_destroy(mp); 133 (void) cond_destroy(cvp); 134 (void) memset(barrier, -1, sizeof (*barrier)); 135 return (0); 136 } 137 138 /* 139 * pthread_barrier_wait() is not a cancellation point; 140 */ 141 int 142 pthread_barrier_wait(pthread_barrier_t *barrier) 143 { 144 mutex_t *mp = (mutex_t *)&barrier->__pthread_barrier_lock; 145 cond_t *cvp = (cond_t *)&barrier->__pthread_barrier_cond; 146 uint64_t cycle; 147 int cancel_state; 148 149 (void) mutex_lock(mp); 150 151 if (--barrier->__pthread_barrier_current == 0) { 152 barrier->__pthread_barrier_cycle++; 153 barrier->__pthread_barrier_current = 154 barrier->__pthread_barrier_count; 155 (void) mutex_unlock(mp); 156 (void) cond_broadcast(cvp); 157 return (PTHREAD_BARRIER_SERIAL_THREAD); 158 } 159 160 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); 161 cycle = barrier->__pthread_barrier_cycle; 162 do { 163 (void) cond_wait(cvp, mp); 164 } while (cycle == barrier->__pthread_barrier_cycle); 165 (void) pthread_setcancelstate(cancel_state, NULL); 166 167 (void) mutex_unlock(mp); 168 return (0); 169 } 170