00001 /* 00002 Copyright (C) 2011 Computer Sciences Department, 00003 University of Wisconsin -- Madison 00004 00005 ---------------------------------------------------------------------- 00006 00007 This file is part of Mnemosyne: Lightweight Persistent Memory, 00008 originally developed at the University of Wisconsin -- Madison. 00009 00010 Mnemosyne was originally developed primarily by Haris Volos 00011 with contributions from Andres Jaan Tack. 00012 00013 ---------------------------------------------------------------------- 00014 00015 Mnemosyne is free software; you can redistribute it and/or 00016 modify it under the terms of the GNU General Public License 00017 as published by the Free Software Foundation, version 2 00018 of the License. 00019 00020 Mnemosyne is distributed in the hope that it will be useful, 00021 but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 GNU General Public License for more details. 00024 00025 You should have received a copy of the GNU General Public License 00026 along with this program; if not, write to the Free Software 00027 Foundation, Inc., 51 Franklin Street, Fifth Floor, 00028 Boston, MA 02110-1301, USA. 00029 00030 ### END HEADER ### 00031 */ 00032 00033 /* 00034 * Source code is partially derived from TinySTM (license is attached) 00035 * 00036 * 00037 * Author(s): 00038 * Pascal Felber <pascal.felber@unine.ch> 00039 * 00040 * Copyright (c) 2007-2009. 00041 * 00042 * This program is free software; you can redistribute it and/or 00043 * modify it under the terms of the GNU General Public License 00044 * as published by the Free Software Foundation, version 2 00045 * of the License. 00046 * 00047 * This program is distributed in the hope that it will be useful, 00048 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00049 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00050 * GNU General Public License for more details. 00051 */ 00052 00053 00054 #ifndef _LOCKS_H 00055 #define _LOCKS_H 00056 00057 /* ################################################################### * 00058 * LOCKS 00059 * ################################################################### */ 00060 00061 /* 00062 * A lock is a unsigned int of the size of a pointer. 00063 * The LSB is the lock bit. If it is set, this means: 00064 * - At least some covered memory addresses is being written. 00065 * - Write-back (ETL): all bits of the lock apart from the lock bit form 00066 * a pointer that points to the write log entry holding the new 00067 * value. Multiple values covered by the same log entry and orginized 00068 * in a linked list in the write log. 00069 * - Write-through and write-back (CTL): all bits of the lock apart from 00070 * the lock bit form a pointer that points to the transaction 00071 * descriptor containing the write-set. 00072 * If the lock bit is not set, then: 00073 * - All covered memory addresses contain consistent values. 00074 * - Write-back (ETL and CTL): all bits of the lock besides the lock bit 00075 * contain a version number (timestamp). 00076 * - Write-through: all bits of the lock besides the lock bit contain a 00077 * version number. 00078 * - The high order bits contain the commit time. 00079 * - The low order bits contain an incarnation number (incremented 00080 * upon abort while writing the covered memory addresses). 00081 * When using the PRIORITY contention manager, the format of locks is 00082 * slightly different. It is documented elsewhere. 00083 */ 00084 00085 #define OWNED_MASK 0x01 /* 1 bit */ 00086 #if CM == CM_PRIORITY 00087 # define WAIT_MASK 0x02 /* 1 bit */ 00088 # define PRIORITY_BITS 3 /* 3 bits */ 00089 # define PRIORITY_MAX ((1 << PRIORITY_BITS) - 1) 00090 # define PRIORITY_MASK (PRIORITY_MAX << 2) 00091 # define ALIGNMENT (1 << (PRIORITY_BITS + 2)) 00092 #else 00093 # define ALIGNMENT 1 /* no alignment requirement */ 00094 #endif /* CM == CM_PRIORITY */ 00095 #define ALIGNMENT_MASK (ALIGNMENT - 1) 00096 00097 /* 00098 * Everything hereafter relates to the actual locking protection mechanism. 00099 */ 00100 #define LOCK_GET_OWNED(l) ((l) & OWNED_MASK) 00101 #if CM == CM_PRIORITY 00102 # define LOCK_SET_ADDR(a, p) ((a) | ((p) << 2) | OWNED_MASK) 00103 # define LOCK_GET_WAIT(l) ((l) & WAIT_MASK) 00104 # define LOCK_GET_PRIORITY(l) (((l) & PRIORITY_MASK) >> 2) 00105 # define LOCK_SET_PRIORITY_WAIT(l, p) (((l) & ~(mtm_word_t)PRIORITY_MASK) | ((p) << 2) | WAIT_MASK) 00106 # define LOCK_GET_ADDR(l) ((l) & ~(mtm_word_t)(OWNED_MASK | WAIT_MASK | PRIORITY_MASK)) 00107 #else /* CM != CM_PRIORITY */ 00108 # define LOCK_SET_ADDR(a) ((a) | OWNED_MASK) /* OWNED bit set */ 00109 # define LOCK_GET_ADDR(l) ((l) & ~(mtm_word_t)OWNED_MASK) 00110 #endif /* CM != CM_PRIORITY */ 00111 #define LOCK_UNIT (~(mtm_word_t)0) 00112 00113 /* 00114 * We use an array of locks and hash the address to find the location of the lock. 00115 * We try to avoid collisions as much as possible (two addresses covered by the same lock). 00116 */ 00117 #define LOCK_ARRAY_SIZE (1 << LOCK_ARRAY_LOG_SIZE) 00118 #define LOCK_MASK (LOCK_ARRAY_SIZE - 1) 00119 //#define LOCK_SHIFT (((sizeof(mtm_word_t) == 4) ? 2 : 3) + LOCK_SHIFT_EXTRA) 00120 // Map the words of a cacheline on the same lock 00121 #define LOCK_SHIFT 6 00122 #define LOCK_IDX(a) (((mtm_word_t)((a)) >> LOCK_SHIFT) & LOCK_MASK) 00123 #ifdef LOCK_IDX_SWAP 00124 # if LOCK_ARRAY_LOG_SIZE < 16 00125 # error "LOCK_IDX_SWAP requires LOCK_ARRAY_LOG_SIZE to be at least 16" 00126 # endif /* LOCK_ARRAY_LOG_SIZE < 16 */ 00127 # define GET_LOCK(a) (locks + lock_idx_swap(LOCK_IDX((a)))) 00128 #else /* ! LOCK_IDX_SWAP */ 00129 # define GET_LOCK(a) (locks + LOCK_IDX((a))) 00130 #endif /* ! LOCK_IDX_SWAP */ 00131 00132 00133 00134 /* ################################################################### * 00135 * PRIVATE PSEUDO-LOCKS 00136 * ################################################################### */ 00137 00138 /* 00139 * For write-back, the original TinySTM keeps new values into linked lists 00140 * accessible through the global lock hash-table. 00141 * 00142 * For persistent write-back, when isolation is disabled, going through 00143 * the global lock hash-table would require fine-grain synchronization 00144 * so that locks are not held for the duration of a transaction. To avoid 00145 * paying the cost of such unnecessary synchronization we use a private lock 00146 * hash-table instead. The structure of the private table is the same as 00147 * the global one's to keep code changes minimal; its size may be different 00148 * though. 00149 * 00150 * Private pseudo-locks are not actually locks but a hack to keep the code 00151 * that deals with version-management common between the isolation and 00152 * no-isolation path. Since never two threads may compete for these pseudo-locks, 00153 * we don't need to use CAS to atomically acquire them but instead we can just 00154 * set them using a normal STORE. 00155 */ 00156 00157 #define PRIVATE_LOCK_ARRAY_SIZE (1 << PRIVATE_LOCK_ARRAY_LOG_SIZE) 00158 #define PRIVATE_LOCK_MASK (PRIVATE_LOCK_ARRAY_SIZE - 1) 00159 #define PRIVATE_LOCK_SHIFT 6 00160 #define PRIVATE_LOCK_IDX(a) (((mtm_word_t)((a)) >> PRIVATE_LOCK_SHIFT) & PRIVATE_LOCK_MASK) 00161 #define PRIVATE_GET_LOCK(tx, a) (tx->wb_table + PRIVATE_LOCK_IDX((a))) 00162 00163 00164 #endif /* _LOCKS_H */