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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "@(#)locks.c 1.14 09/05/26 SMI" 28 29 /* 30 * diskomizer64mpism 31 * 32 * Locking routines. 33 * stderr and stdout locks can be held recursively. 34 * other locks can not. 35 * Chris.Gerhard (at) uk.sun.com - Computer Systems CTE 36 */ 37 #include "diskomizer64mpism.h" 38 #include "locks.h" 39 #include <diskomizer/log.h> 40 #include "args.h" 41 /* 42 * statics 43 */ 44 static pthread_mutex_t *stdout_lock; 45 static pthread_mutex_t *stderr_lock; /* really any FILE != stdout */ 46 static int stdout_count; 47 static int stderr_count; 48 struct disko_lock_t { 49 pthread_mutex_t lock; 50 char pad[64]; /* Padded to get the lock onto the next cache line */ 51 }; 52 typedef struct disko_lock_t disko_lock_t; 53 static disko_lock_t *locks; 54 55 static sigset_t stderr_sigset; 56 static sigset_t stdout_sigset; 57 static int stdout_sigprocmask_status; 58 static int stderr_sigprocmask_status; 59 60 static void mutex_enter(off64_t off); 61 static void mutex_exit(off64_t off); 62 static void mutex_getnext(off64_t old, off64_t new); 63 static void grab_all_locks(void); 64 static void drop_all_locks(void); 65 static void stdout_enter(void); 66 static void stdout_exit(void); 67 static void stderr_enter(void); 68 static void stderr_exit(void); 69 70 static struct lock_funcs lockers = { 71 mutex_enter, 72 mutex_exit, 73 mutex_getnext, 74 grab_all_locks, 75 drop_all_locks, 76 stdout_enter, 77 stdout_exit, 78 stderr_enter, 79 stderr_exit 80 }; 81 static struct lock_funcs nops = { 82 (void (*)(off64_t off)) nop, 83 (void (*)(off64_t off)) nop, 84 (void (*)(off64_t old, off64_t new)) nop, 85 nop, 86 nop, 87 nop, 88 nop, 89 nop, 90 nop 91 }; 92 struct lock_funcs *mutex = &nops; 93 94 95 int 96 init_shared_lock(pthread_mutex_t *lock) 97 { 98 int ret; 99 pthread_mutexattr_t attr; 100 101 ret = pthread_mutexattr_init(&attr); 102 if (ret != 0x0) 103 pperror("pthread_mutexattr_init"); 104 ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); 105 if (ret != 0) 106 pperror("pthread_mutexattr_setpshared"); 107 plog(LOG_DEBUG, "initializing lock at %#lx\n", (ulong_t)lock); 108 ret = pthread_mutex_init(lock, &attr); 109 if (ret != 0) 110 pperror("pthread_mutex_init"); 111 if (pthread_mutexattr_destroy(&attr)) 112 pperror("pthread_mutexattr_destroy"); 113 return (ret); 114 } 115 void 116 init_locks(void) 117 { 118 if (opts.nprocs > 1) { 119 int i, ret; 120 plog(LOG_DEBUG, "allocating %d locks\n", opts.nlocks); 121 locks = (disko_lock_t *)alloc_mem(opts.nlocks + 2, 122 sizeof (disko_lock_t)); 123 plog(LOG_DEBUG, "initializing %d locks\n", opts.nlocks); 124 for (i = 0; i < opts.nlocks + 2; i++) { 125 plog(LOG_DEBUG, "initializing lock %d at %#lx\n", i, 126 (ulong_t)&locks[i].lock); 127 ret = init_shared_lock(&locks[i].lock); 128 if (ret == 0) 129 plog(LOG_DEBUG, "Lock %d initialised\n", i); 130 } 131 stdout_lock = &((locks++)->lock); 132 stderr_lock = &((locks++)->lock); 133 plog(LOG_DEBUG, "locks done\n"); 134 mutex = &lockers; 135 } else 136 mutex = &nops; 137 } 138 139 static void 140 stdout_enter(void) 141 { 142 NOTE(MUTEX_ACQUIRED_AS_SIDE_EFFECT(stdout_lock)) 143 sigset_t nset; /* new set */ 144 sigset_t oset; /* old set */ 145 int sigprocmask_status; 146 147 if (stdout_count == 0) { 148 (void) sigemptyset(&nset); 149 (void) sigaddset(&nset, SIGINT); 150 (void) sigaddset(&nset, SIGTERM); 151 sigprocmask_status = sigprocmask(SIG_BLOCK, &nset, &oset); 152 pthread_mutex_lock(stdout_lock); 153 stdout_sigprocmask_status = sigprocmask_status; 154 stdout_sigset = oset; 155 } 156 stdout_count++; 157 } 158 static void 159 stderr_enter(void) 160 { 161 NOTE(MUTEX_ACQUIRED_AS_SIDE_EFFECT(stderr_lock)) 162 sigset_t nset; /* new set */ 163 sigset_t oset; /* old set */ 164 int sigprocmask_status; 165 166 if (stderr_count == 0) { 167 (void) sigemptyset(&nset); 168 (void) sigaddset(&nset, SIGINT); 169 (void) sigaddset(&nset, SIGTERM); 170 sigprocmask_status = sigprocmask(SIG_BLOCK, &nset, &oset); 171 pthread_mutex_lock(stderr_lock); 172 stderr_sigprocmask_status = sigprocmask_status; 173 stderr_sigset = oset; 174 } 175 stderr_count++; 176 177 } 178 static void 179 stderr_exit(void) 180 { 181 NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(stderr_lock)) 182 if (--stderr_count == 0) { 183 pthread_mutex_unlock(stderr_lock); 184 if (stderr_sigprocmask_status == 0) 185 (void) sigprocmask(SIG_SETMASK, &stderr_sigset, NULL); 186 } 187 } 188 static void 189 stdout_exit(void) 190 { 191 NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(stdout_lock)) 192 if (--stdout_count == 0) { 193 pthread_mutex_unlock(stdout_lock); 194 if (stdout_sigprocmask_status == 0) 195 (void) sigprocmask(SIG_SETMASK, &stdout_sigset, NULL); 196 } 197 } 198 static void 199 mutex_enter(off64_t off) 200 { 201 NOTE(MUTEX_ACQUIRED_AS_SIDE_EFFECT(&locks[ 202 GET_OFF(off) % opts.nlocks].lock)) 203 int ret; 204 205 ret = pthread_mutex_lock(&locks[GET_OFF(off) % opts.nlocks].lock); 206 if (ret != 0) 207 pperror("pthread_mutex_lock"); 208 209 } 210 /* 211 * While holding a lock for offset old get a lock for offset new 212 * and loose the lock for old. 213 */ 214 static void 215 mutex_getnext(off64_t old, off64_t new) 216 { 217 ulong_t oldlock; 218 ulong_t newlock; 219 int ret; 220 221 oldlock = (GET_OFF(old) % opts.nlocks); 222 newlock = (GET_OFF(new) % opts.nlocks); 223 224 if (oldlock == newlock) 225 return; 226 227 ret = pthread_mutex_unlock(&locks[oldlock].lock); 228 if (ret != 0) 229 pperror("pthread_mutex_unlock"); 230 ret = pthread_mutex_lock(&locks[newlock].lock); 231 if (ret != 0) 232 pperror("pthread_mutex_lock"); 233 } 234 static void 235 mutex_exit(off64_t off) 236 { 237 int ret; 238 239 ret = pthread_mutex_unlock(&locks[GET_OFF(off) % opts.nlocks].lock); 240 if (ret != 0) 241 pperror("pthread_mutex_unlock"); 242 } 243 /* 244 * grab_all_locks grabs all the locks used for choosing blocks. This 245 * has the effect of stopping any new io requests from being queued. 246 * Used in error paths to stop the state of the buffers from being 247 * changed more than can't be avioded. 248 */ 249 static void 250 grab_all_locks(void) 251 { 252 int i; 253 254 for (i = 0; i < opts.nlocks; i++) { 255 if (pthread_mutex_lock(&locks[i].lock) != 0) 256 perror("pthread_mutex_lock"); 257 } 258 } 259 static void 260 drop_all_locks(void) 261 { 262 int i; 263 264 for (i = 0; i < opts.nlocks; i++) { 265 if (pthread_mutex_unlock(&locks[i].lock) != 0) 266 perror("pthread_mutex_unlock"); 267 } 268 } 269