1 /** 2 * The mutex module provides a primitive for maintaining mutually exclusive 3 * access. 4 * 5 * Copyright: Copyright Sean Kelly 2005 - 2009. 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Authors: Sean Kelly 8 * Source: $(DRUNTIMESRC core/sync/_mutex.d) 9 */ 10 11 /* Copyright Sean Kelly 2005 - 2009. 12 * Distributed under the Boost Software License, Version 1.0. 13 * (See accompanying file LICENSE or copy at 14 * http://www.boost.org/LICENSE_1_0.txt) 15 */ 16 module java.nonstandard.sync.mutex; 17 18 19 version(Tango){ 20 21 public import tango.core.sync.Mutex; 22 23 } else { // Phobos 24 25 public import java.nonstandard.sync.exception; 26 27 version( Windows ) 28 { 29 private import core.sys.windows.windows; 30 } 31 else version( Posix ) 32 { 33 private import core.sys.posix.pthread; 34 } 35 else 36 { 37 static assert(false, "Platform not supported"); 38 } 39 40 41 //////////////////////////////////////////////////////////////////////////////// 42 // Mutex 43 // 44 // void lock(); 45 // void unlock(); 46 // bool tryLock(); 47 //////////////////////////////////////////////////////////////////////////////// 48 49 50 /** 51 * This class represents a general purpose, recursive mutex. 52 */ 53 class Mutex : 54 Object.Monitor 55 { 56 //////////////////////////////////////////////////////////////////////////// 57 // Initialization 58 //////////////////////////////////////////////////////////////////////////// 59 60 61 /** 62 * Initializes a mutex object. 63 * 64 * Throws: 65 * SyncError on error. 66 */ 67 this() @trusted 68 { 69 version( Windows ) 70 { 71 InitializeCriticalSection( &m_hndl ); 72 } 73 else version( Posix ) 74 { 75 pthread_mutexattr_t attr = void; 76 77 if( pthread_mutexattr_init( &attr ) ) 78 throw new SyncException( "Unable to initialize mutex" ); 79 scope(exit) pthread_mutexattr_destroy( &attr ); 80 81 if( pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ) ) 82 throw new SyncException( "Unable to initialize mutex" ); 83 84 if( pthread_mutex_init( &m_hndl, &attr ) ) 85 throw new SyncException( "Unable to initialize mutex" ); 86 } 87 m_proxy.link = this; 88 this.__monitor = &m_proxy; 89 } 90 91 92 /** 93 * Initializes a mutex object and sets it as the monitor for o. 94 * 95 * In: 96 * o must not already have a monitor. 97 */ 98 this( Object o ) @trusted 99 in 100 { 101 assert( o.__monitor is null ); 102 } 103 body 104 { 105 this(); 106 o.__monitor = &m_proxy; 107 } 108 109 110 ~this() 111 { 112 version( Windows ) 113 { 114 DeleteCriticalSection( &m_hndl ); 115 } 116 else version( Posix ) 117 { 118 int rc = pthread_mutex_destroy( &m_hndl ); 119 assert( !rc, "Unable to destroy mutex" ); 120 } 121 this.__monitor = null; 122 } 123 124 125 //////////////////////////////////////////////////////////////////////////// 126 // General Actions 127 //////////////////////////////////////////////////////////////////////////// 128 129 130 /** 131 * If this lock is not already held by the caller, the lock is acquired, 132 * then the internal counter is incremented by one. 133 * 134 * Throws: 135 * SyncError on error. 136 */ 137 @trusted void lock() 138 { 139 version( Windows ) 140 { 141 EnterCriticalSection( &m_hndl ); 142 } 143 else version( Posix ) 144 { 145 int rc = pthread_mutex_lock( &m_hndl ); 146 if( rc ) 147 throw new SyncException( "Unable to lock mutex" ); 148 } 149 } 150 151 /** 152 * Decrements the internal lock count by one. If this brings the count to 153 * zero, the lock is released. 154 * 155 * Throws: 156 * SyncError on error. 157 */ 158 @trusted void unlock() 159 { 160 version( Windows ) 161 { 162 LeaveCriticalSection( &m_hndl ); 163 } 164 else version( Posix ) 165 { 166 int rc = pthread_mutex_unlock( &m_hndl ); 167 if( rc ) 168 throw new SyncException( "Unable to unlock mutex" ); 169 } 170 } 171 172 /** 173 * If the lock is held by another caller, the method returns. Otherwise, 174 * the lock is acquired if it is not already held, and then the internal 175 * counter is incremented by one. 176 * 177 * Throws: 178 * SyncError on error. 179 * 180 * Returns: 181 * true if the lock was acquired and false if not. 182 */ 183 bool tryLock() 184 { 185 version( Windows ) 186 { 187 return TryEnterCriticalSection( &m_hndl ) != 0; 188 } 189 else version( Posix ) 190 { 191 return pthread_mutex_trylock( &m_hndl ) == 0; 192 } 193 } 194 195 196 private: 197 version( Windows ) 198 { 199 CRITICAL_SECTION m_hndl; 200 } 201 else version( Posix ) 202 { 203 pthread_mutex_t m_hndl; 204 } 205 206 struct MonitorProxy 207 { 208 Object.Monitor link; 209 } 210 211 MonitorProxy m_proxy; 212 213 214 package: 215 version( Posix ) 216 { 217 pthread_mutex_t* handleAddr() 218 { 219 return &m_hndl; 220 } 221 } 222 } 223 224 225 //////////////////////////////////////////////////////////////////////////////// 226 // Unit Tests 227 //////////////////////////////////////////////////////////////////////////////// 228 229 230 version( unittest ) 231 { 232 private import core.thread; 233 234 235 unittest 236 { 237 auto mutex = new Mutex; 238 int numThreads = 10; 239 int numTries = 1000; 240 int lockCount = 0; 241 242 void testFn() 243 { 244 for( int i = 0; i < numTries; ++i ) 245 { 246 synchronized( mutex ) 247 { 248 ++lockCount; 249 } 250 } 251 } 252 253 auto group = new ThreadGroup; 254 255 for( int i = 0; i < numThreads; ++i ) 256 group.create( &testFn ); 257 258 group.joinAll(); 259 assert( lockCount == numThreads * numTries ); 260 } 261 } 262 263 } 264