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 <fcntl.h> 49 50#include "libmicro.h" 51 52#ifndef LOCK_EX 53#include "/usr/ucbinclude/sys/file.h" 54extern int flock(int fd, int operation); 55#endif 56 57typedef struct { 58 int ts_once; 59 int ts_id; 60 int ts_us0; /* our lock indices */ 61 int ts_us1; 62 int ts_them0; /* their lock indices */ 63 int ts_them1; 64} tsd_t; 65 66static int nthreads; 67 68/* 69 * API-specific code BEGINS here 70 */ 71 72#define DEFD "/private/tmp" 73 74static char *optd = DEFD; 75static int nfiles; 76static int *files; 77 78int 79benchmark_init() 80{ 81 lm_tsdsize = sizeof (tsd_t); 82 83 (void) sprintf(lm_optstr, "d:"); 84 85 lm_defN = "cscd_flock"; 86 87 (void) sprintf(lm_usage, 88 " [-d directory for temp files (default %s)]\n" 89 "notes: thread cascade using flock file locking\n", 90 DEFD); 91 92 return (0); 93} 94 95int 96benchmark_optswitch(int opt, char *optarg) 97{ 98 switch (opt) { 99 case 'd': 100 optd = optarg; 101 break; 102 default: 103 return (-1); 104 } 105 return (0); 106} 107 108int 109benchmark_initrun() 110{ 111 int i; 112 int errors = 0; 113 char fname[1024]; 114 115 nthreads = lm_optP * lm_optT; 116 nfiles = nthreads * 2; 117 (void) setfdlimit(nfiles + 10); 118 files = (int *)malloc(nfiles * sizeof (int)); 119 if (files == NULL) { 120 return (1); 121 } 122 123 (void) sprintf(fname, "%s/cascade.%ld", optd, getpid()); 124 125 for (i = 0; i < nfiles; i++) { 126 files[i] = open(fname, O_CREAT | O_TRUNC | O_RDWR, 0600); 127 if (files[i] == -1) { 128 errors++; 129 } 130 if (unlink(fname)) { 131 errors++; 132 } 133 } 134 135 return (errors); 136} 137 138int 139block(int index) 140{ 141 return (flock(files[index], LOCK_EX) == -1); 142} 143 144int 145unblock(int index) 146{ 147 return (flock(files[index], LOCK_UN) == -1); 148} 149 150/* 151 * API-specific code ENDS here 152 */ 153 154int 155benchmark_initbatch(void *tsd) 156{ 157 tsd_t *ts = (tsd_t *)tsd; 158 int e = 0; 159 160 if (ts->ts_once == 0) { 161 int us, them; 162 163#if !defined(__APPLE__) 164 us = (getpindex() * lm_optT) + gettindex(); 165#else 166 us = gettsdindex(tsd); 167#endif /* __APPLE__ */ 168 169 them = (us + 1) % (lm_optP * lm_optT); 170 171 ts->ts_id = us; 172 173 /* lock index asignment for us and them */ 174 ts->ts_us0 = (us * 2); 175 ts->ts_us1 = (us * 2) + 1; 176 if (us < nthreads - 1) { 177 /* straight-thru connection to them */ 178 ts->ts_them0 = (them * 2); 179 ts->ts_them1 = (them * 2) + 1; 180 } else { 181 /* cross-over connection to them */ 182 ts->ts_them0 = (them * 2) + 1; 183 ts->ts_them1 = (them * 2); 184 } 185 186 ts->ts_once = 1; 187 } 188 189 /* block their first move */ 190 e += block(ts->ts_them0); 191 192 return (e); 193} 194 195int 196benchmark(void *tsd, result_t *res) 197{ 198 tsd_t *ts = (tsd_t *)tsd; 199 int i; 200 int e = 0; 201 202 /* wait to be unblocked (id == 0 will not block) */ 203 e += block(ts->ts_us0); 204 205 for (i = 0; i < lm_optB; i += 2) { 206 /* allow them to block us again */ 207 e += unblock(ts->ts_us0); 208 209 /* block their next + 1 move */ 210 e += block(ts->ts_them1); 211 212 /* unblock their next move */ 213 e += unblock(ts->ts_them0); 214 215 /* wait for them to unblock us */ 216 e += block(ts->ts_us1); 217 218 /* repeat with locks reversed */ 219 e += unblock(ts->ts_us1); 220 e += block(ts->ts_them0); 221 e += unblock(ts->ts_them1); 222 e += block(ts->ts_us0); 223 } 224 225 /* finish batch with nothing blocked */ 226 e += unblock(ts->ts_them0); 227 e += unblock(ts->ts_us0); 228 229 res->re_count = i; 230 res->re_errors = e; 231 232 return (0); 233} 234