Phoenix
Object-oriented orthogonally persistent operating system
|
00001 /* 00002 * /phoenix/kernel/sys/arch/x86_64/md_lock.h 00003 * 00004 * This file is a part of Phoenix operating system. 00005 * Copyright (c) 2011-2012, Artyom Lebedev <artyom.lebedev@gmail.com> 00006 * All rights reserved. 00007 * See COPYING file for copyright details. 00008 */ 00009 00014 #ifndef MD_LOCK_H_ 00015 #define MD_LOCK_H_ 00016 00022 #define Barrier() { \ 00023 ASM ("" ::: "memory"); \ 00024 mfence(); \ 00025 } 00026 00033 class SpinLock { 00034 private: 00035 volatile u32 _flag; 00036 public: 00037 inline SpinLock() { _flag = 0; } 00038 00039 inline ~SpinLock() { ASSERT(!_flag); } 00040 00042 inline void Lock() { 00043 ASM ( 00044 "1: lock btsl $0, %[flag]\n" 00045 "jnc 2f\n" 00046 "pause\n" 00047 "jmp 1b\n" 00048 "2:\n" 00049 : 00050 : [flag]"m"(_flag) 00051 : "cc" 00052 ); 00053 } 00054 00056 inline void Unlock() { 00057 ASM ( 00058 "lock btcl $0, %[flag]" 00059 : 00060 : [flag]"m"(_flag) 00061 : "cc" 00062 ); 00063 } 00064 00071 inline int TryLock() { 00072 register int rc; 00073 ASM ( 00074 "xorl %%eax, %%eax\n" 00075 "lock btsl $0, %[flag]\n" 00076 "jnc 1f\n" 00077 "movl $-1, %%eax\n" 00078 "1:\n" 00079 : "=&a"(rc) 00080 : [flag]"m"(_flag) 00081 : "cc" 00082 ); 00083 return rc; 00084 } 00085 00089 inline operator bool() { return _flag ? true : false; } 00090 }; 00091 00107 class RWSpinLock { 00108 private: 00109 /* Higher bits indicate write lock acquisition and pending. Lower bits store 00110 * number of read locks acquired or pending. 00111 */ 00112 enum { 00113 WRITE_LOCK = 0x80000000, 00114 WRITE_PENDING = 0x40000000, 00115 READ_LOCK = 0x3fffffff 00116 }; 00117 00118 volatile u32 _state; 00119 public: 00120 inline RWSpinLock() { _state = 0; } 00121 inline ~RWSpinLock() { ASSERT(!_state); } 00122 00124 inline void ReadLock() { 00125 ASM( 00126 /* Wait until PWR is not set. */ 00127 "movl %[state], %%eax\n" 00128 "1:\n" 00129 "andl %[notPwr], %%eax\n" 00130 "movl %%eax, %%edx\n" 00131 "incl %%edx\n" /* Increment pending or acquired reads counter */ 00132 "lock cmpxchgl %%edx, %[state]\n" 00133 "jz 2f\n" /* Reads counter incremented */ 00134 "pause\n" 00135 "jmp 1b\n" 00136 "2:\n" 00137 : 00138 : [state]"m"(_state), 00139 [notPwr]"i"(~WRITE_PENDING) 00140 : "cc", "eax", "edx"); 00141 00142 /* Wait until write lock released. No atomicity required because 00143 * pending read is non-zero so new write lock can not be acquired 00144 * until read locks are released. 00145 */ 00146 while (_state & WRITE_LOCK) { 00147 cpu::Pause(); 00148 } 00149 } 00150 00152 inline void ReadUnlock() { 00153 ASSERT(_state & READ_LOCK); 00154 ASSERT(!(_state & WRITE_LOCK)); 00155 ASM( 00156 "lock decl %[state]\n" /* Decrement acquired read. */ 00157 : 00158 : [state]"m"(_state) 00159 : "cc"); 00160 } 00161 00166 inline void WriteLock() { 00167 ASM( 00168 /* Set PWR flag. This can be done only if WR is cleared. */ 00169 "movl %[state], %%eax\n" 00170 "jmp 3f\n" 00171 "1:\n" 00172 "andl %[notWr], %%eax\n" /* WR should be cleared */ 00173 "movl %%eax, %%edx\n" 00174 "orl %[pwr], %%edx\n" 00175 "lock cmpxchgl %%edx, %[state]\n" 00176 "jz 2f\n" /* PWR was set */ 00177 "pause\n" 00178 "jmp 1b\n" 00179 "2:\n" 00180 /* Wait until there are no pending reads and check that PWR is set. */ 00181 "movl %%edx, %%eax\n" 00182 "3:\n" 00183 "testl %[pwr], %%eax\n" 00184 "jz 1b\n" /* PWR is not set (other CPU acquired write lock), roll back to the previous loop */ 00185 "andl %[notRd], %%eax\n" /* Read locks counter should be zero */ 00186 "movl %%eax, %%edx\n" 00187 "orl %[wr], %%edx\n" /* Set WR */ 00188 "andl %[notPwr], %%edx\n" /* Clear PWR */ 00189 "lock cmpxchgl %%edx, %[state]\n" 00190 "jz 4f\n" 00191 "pause\n" 00192 "jmp 3b\n" 00193 "4:\n" 00194 : 00195 : [state]"m"(_state), 00196 [wr]"i"(WRITE_LOCK), 00197 [notWr]"i"(~WRITE_LOCK), 00198 [pwr]"i"(WRITE_PENDING), 00199 [notPwr]"i"(~WRITE_PENDING), 00200 [notRd]"i"(~READ_LOCK) 00201 : "cc", "eax", "edx" 00202 ); 00203 } 00204 00206 inline void WriteUnlock() { 00207 ASSERT(_state & WRITE_LOCK); 00208 ASM( 00209 "lock andl %[notWr], %[state]\n" 00210 : 00211 : [state]"m"(_state), 00212 [notWr]"r"(~WRITE_LOCK) 00213 : "cc"); 00214 } 00215 }; 00216 00217 #endif /* MD_LOCK_H_ */