comparison druntime/src/common/core/sync/mutex.d @ 1458:e0b2d67cfe7c

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