1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms 5 * of the Common Development and Distribution License 6 * (the "License"). You may not use this file except 7 * in compliance with the License. 8 * 9 * You can obtain a copy of the license at 10 * src/OPENSOLARIS.LICENSE 11 * or http://www.opensolaris.org/os/licensing. 12 * See the License for the specific language governing 13 * permissions and limitations under the License. 14 * 15 * When distributing Covered Code, include this CDDL 16 * HEADER in each file and include the License file at 17 * usr/src/OPENSOLARIS.LICENSE. If applicable, 18 * add the following below this CDDL HEADER, with the 19 * fields enclosed by brackets "[]" replaced with your 20 * own identifying information: Portions Copyright [yyyy] 21 * [name of copyright owner] 22 * 23 * CDDL HEADER END 24 */ 25 26/* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31/* 32 * The "cascade" test case is a multiprocess/multithread batten-passing model 33 * using lock primitives alone for synchronisation. Threads are arranged in a 34 * ring. Each thread has two locks of its own on which it blocks, and is able 35 * to manipulate the two locks belonging to the thread which follows it in the 36 * ring. 37 * 38 * The number of threads (nthreads) is specified by the generic libMicro -P/-T 39 * options. With nthreads == 1 (the default) the uncontended case can be timed. 40 * 41 * The main logic is generic and allows any simple blocking API to be tested. 42 * The API-specific component is clearly indicated. 43 */ 44 45#include <unistd.h> 46#include <stdlib.h> 47#include <stdio.h> 48#include <pthread.h> 49#include <sys/mman.h> 50 51#include "libmicro.h" 52 53typedef struct { 54 int ts_once; 55 int ts_id; 56 int ts_us0; /* our lock indices */ 57 int ts_us1; 58 int ts_them0; /* their lock indices */ 59 int ts_them1; 60} tsd_t; 61 62static int nthreads; 63 64/* 65 * API-specific code BEGINS here 66 */ 67 68static int opto = 0; 69static int opts = 0; 70static int nlocks; 71static pthread_mutex_t *mxs; 72static pthread_cond_t *cvs; 73static int *conds; 74 75int 76benchmark_init() 77{ 78 lm_tsdsize = sizeof (tsd_t); 79 80 (void) sprintf(lm_optstr, "os"); 81 82 lm_defN = "cscd_cond"; 83 84 (void) sprintf(lm_usage, 85 " [-o] (do signal outside mutex)\n" 86 " [-s] (force PTHREAD_PROCESS_SHARED)\n" 87 "notes: thread cascade using pthread_conds\n"); 88 89 return (0); 90} 91 92/*ARGSUSED*/ 93int 94benchmark_optswitch(int opt, char *optarg) 95{ 96 switch (opt) { 97 case 'o': 98 opto = 1; 99 break; 100 case 's': 101 opts = 1; 102 break; 103 default: 104 return (-1); 105 } 106 return (0); 107} 108 109int 110benchmark_initrun() 111{ 112 int i; 113 int e = 0; 114 pthread_mutexattr_t ma; 115 pthread_condattr_t ca; 116 117 nthreads = lm_optP * lm_optT; 118 nlocks = nthreads * 2; 119 /*LINTED*/ 120 mxs = (pthread_mutex_t *)mmap(NULL, 121 nlocks * sizeof (pthread_mutex_t), 122 PROT_READ | PROT_WRITE, 123 MAP_ANON | MAP_SHARED, 124 -1, 0L); 125 if (mxs == MAP_FAILED) { 126 return (1); 127 } 128 129 /*LINTED*/ 130 cvs = (pthread_cond_t *)mmap(NULL, 131 nlocks * sizeof (pthread_cond_t), 132 PROT_READ | PROT_WRITE, 133 MAP_ANON | MAP_SHARED, 134 -1, 0L); 135 if (cvs == MAP_FAILED) { 136 return (1); 137 } 138 139 /*LINTED*/ 140 conds = (int *)mmap(NULL, 141 nlocks * sizeof (pthread_cond_t), 142 PROT_READ | PROT_WRITE, 143 MAP_ANON | MAP_SHARED, 144 -1, 0L); 145 if (conds == MAP_FAILED) { 146 return (1); 147 } 148 149 (void) pthread_mutexattr_init(&ma); 150 (void) pthread_condattr_init(&ca); 151 if (lm_optP > 1 || opts) { 152 (void) pthread_mutexattr_setpshared(&ma, 153 PTHREAD_PROCESS_SHARED); 154 (void) pthread_condattr_setpshared(&ca, 155 PTHREAD_PROCESS_SHARED); 156 } else { 157 (void) pthread_mutexattr_setpshared(&ma, 158 PTHREAD_PROCESS_PRIVATE); 159 (void) pthread_condattr_setpshared(&ca, 160 PTHREAD_PROCESS_PRIVATE); 161 } 162 163 for (i = 0; i < nlocks; i++) { 164 (void) pthread_mutex_init(&mxs[i], &ma); 165 (void) pthread_cond_init(&cvs[i], &ca); 166 conds[i] = 0; 167 } 168 169 return (e); 170} 171 172int 173block(int index) 174{ 175 (void) pthread_mutex_lock(&mxs[index]); 176 while (conds[index] != 0) { 177 (void) pthread_cond_wait(&cvs[index], &mxs[index]); 178 } 179 conds[index] = 1; 180 (void) pthread_mutex_unlock(&mxs[index]); 181 182 return (0); 183} 184 185int 186unblock(int index) 187{ 188 (void) pthread_mutex_lock(&mxs[index]); 189 conds[index] = 0; 190 if (opto) { 191 (void) pthread_mutex_unlock(&mxs[index]); 192 (void) pthread_cond_signal(&cvs[index]); 193 } else { 194 (void) pthread_cond_signal(&cvs[index]); 195 (void) pthread_mutex_unlock(&mxs[index]); 196 } 197 return (0); 198} 199 200/* 201 * API-specific code ENDS here 202 */ 203 204int 205benchmark_initbatch(void *tsd) 206{ 207 tsd_t *ts = (tsd_t *)tsd; 208 int e = 0; 209 210 if (ts->ts_once == 0) { 211 int us, them; 212 213#if !defined(__APPLE__) 214 us = (getpindex() * lm_optT) + gettindex(); 215#else 216 us = gettsdindex(tsd); 217#endif /* __APPLE__ */ 218 219 them = (us + 1) % (lm_optP * lm_optT); 220 221 ts->ts_id = us; 222 223 /* lock index asignment for us and them */ 224 ts->ts_us0 = (us * 2); 225 ts->ts_us1 = (us * 2) + 1; 226 if (us < nthreads - 1) { 227 /* straight-thru connection to them */ 228 ts->ts_them0 = (them * 2); 229 ts->ts_them1 = (them * 2) + 1; 230 } else { 231 /* cross-over connection to them */ 232 ts->ts_them0 = (them * 2) + 1; 233 ts->ts_them1 = (them * 2); 234 } 235 236 ts->ts_once = 1; 237 } 238 239 /* block their first move */ 240 e += block(ts->ts_them0); 241 242 return (e); 243} 244 245int 246benchmark(void *tsd, result_t *res) 247{ 248 tsd_t *ts = (tsd_t *)tsd; 249 int i; 250 int e = 0; 251 252 /* wait to be unblocked (id == 0 will not block) */ 253 e += block(ts->ts_us0); 254 255 for (i = 0; i < lm_optB; i += 2) { 256 /* allow them to block us again */ 257 e += unblock(ts->ts_us0); 258 259 /* block their next + 1 move */ 260 e += block(ts->ts_them1); 261 262 /* unblock their next move */ 263 e += unblock(ts->ts_them0); 264 265 /* wait for them to unblock us */ 266 e += block(ts->ts_us1); 267 268 /* repeat with locks reversed */ 269 e += unblock(ts->ts_us1); 270 e += block(ts->ts_them0); 271 e += unblock(ts->ts_them1); 272 e += block(ts->ts_us0); 273 } 274 275 /* finish batch with nothing blocked */ 276 e += unblock(ts->ts_them0); 277 e += unblock(ts->ts_us0); 278 279 res->re_count = i; 280 res->re_errors = e; 281 282 return (0); 283} 284