Home | History | Annotate | Download | only in diskomizer
      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