| 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 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. |
| 23 | * Use is subject to license terms. |
| 24 | */ |
| 25 | /* |
| 26 | * Copyright (c) 2012 by Delphix. All rights reserved. |
| 27 | */ |
| 28 | |
| 29 | #ifndef _SYS_RR_RW_LOCK_H |
| 30 | #define _SYS_RR_RW_LOCK_H |
| 31 | |
| 32 | #ifdef __cplusplus |
| 33 | extern "C" { |
| 34 | #endif |
| 35 | |
| 36 | #include <sys/zfs_context.h> |
| 37 | #include <sys/refcount.h> |
| 38 | |
| 39 | /* |
| 40 | * A reader-writer lock implementation that allows re-entrant reads, but |
| 41 | * still gives writers priority on "new" reads. |
| 42 | * |
| 43 | * See rrwlock.c for more details about the implementation. |
| 44 | * |
| 45 | * Fields of the rrwlock_t structure: |
| 46 | * - rr_lock: protects modification and reading of rrwlock_t fields |
| 47 | * - rr_cv: cv for waking up readers or waiting writers |
| 48 | * - rr_writer: thread id of the current writer |
| 49 | * - rr_anon_rount: number of active anonymous readers |
| 50 | * - rr_linked_rcount: total number of non-anonymous active readers |
| 51 | * - rr_writer_wanted: a writer wants the lock |
| 52 | */ |
| 53 | typedef struct rrwlock { |
| 54 | kmutex_t rr_lock; |
| 55 | kcondvar_t rr_cv; |
| 56 | kthread_t *rr_writer; |
| 57 | refcount_t rr_anon_rcount; |
| 58 | refcount_t rr_linked_rcount; |
| 59 | boolean_t rr_writer_wanted; |
| 60 | boolean_t rr_track_all; |
| 61 | } rrwlock_t; |
| 62 | |
| 63 | /* |
| 64 | * 'tag' is used in reference counting tracking. The |
| 65 | * 'tag' must be the same in a rrw_enter() as in its |
| 66 | * corresponding rrw_exit(). |
| 67 | */ |
| 68 | void rrw_init(rrwlock_t *rrl, boolean_t track_all); |
| 69 | void rrw_destroy(rrwlock_t *rrl); |
| 70 | void rrw_enter(rrwlock_t *rrl, krw_t rw, void *tag); |
| 71 | void rrw_enter_read(rrwlock_t *rrl, void *tag); |
| 72 | void rrw_enter_read_prio(rrwlock_t *rrl, void *tag); |
| 73 | void rrw_enter_write(rrwlock_t *rrl); |
| 74 | void rrw_exit(rrwlock_t *rrl, void *tag); |
| 75 | boolean_t rrw_held(rrwlock_t *rrl, krw_t rw); |
| 76 | void rrw_tsd_destroy(void *arg); |
| 77 | |
| 78 | #define RRW_READ_HELD(x) rrw_held(x, RW_READER) |
| 79 | #define RRW_WRITE_HELD(x) rrw_held(x, RW_WRITER) |
| 80 | #define RRW_LOCK_HELD(x) \ |
| 81 | (rrw_held(x, RW_WRITER) || rrw_held(x, RW_READER)) |
| 82 | |
| 83 | /* |
| 84 | * A reader-mostly lock implementation, tuning above reader-writer locks |
| 85 | * for hightly parallel read acquisitions, pessimizing write acquisitions. |
| 86 | * |
| 87 | * This should be a prime number. See comment in rrwlock.c near |
| 88 | * RRM_TD_LOCK() for details. |
| 89 | */ |
| 90 | #define RRM_NUM_LOCKS 17 |
| 91 | typedef struct rrmlock { |
| 92 | rrwlock_t locks[RRM_NUM_LOCKS]; |
| 93 | } rrmlock_t; |
| 94 | |
| 95 | void rrm_init(rrmlock_t *rrl, boolean_t track_all); |
| 96 | void rrm_destroy(rrmlock_t *rrl); |
| 97 | void rrm_enter(rrmlock_t *rrl, krw_t rw, void *tag); |
| 98 | void rrm_enter_read(rrmlock_t *rrl, void *tag); |
| 99 | void rrm_enter_write(rrmlock_t *rrl); |
| 100 | void rrm_exit(rrmlock_t *rrl, void *tag); |
| 101 | boolean_t rrm_held(rrmlock_t *rrl, krw_t rw); |
| 102 | |
| 103 | #define RRM_READ_HELD(x) rrm_held(x, RW_READER) |
| 104 | #define RRM_WRITE_HELD(x) rrm_held(x, RW_WRITER) |
| 105 | #define RRM_LOCK_HELD(x) \ |
| 106 | (rrm_held(x, RW_WRITER) || rrm_held(x, RW_READER)) |
| 107 | |
| 108 | #ifdef __cplusplus |
| 109 | } |
| 110 | #endif |
| 111 | |
| 112 | #endif /* _SYS_RR_RW_LOCK_H */ |
| 113 | |