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