Phoenix
Object-oriented orthogonally persistent operating system
md_lock.h
Go to the documentation of this file.
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_ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines