wasCSharpSQLite – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System.Diagnostics; |
2 | using DWORD = System.Int32; |
||
3 | using System.Threading; |
||
4 | using System; |
||
5 | |||
6 | namespace Community.CsharpSqlite |
||
7 | { |
||
8 | public partial class Sqlite3 |
||
9 | { |
||
10 | /* |
||
11 | ** 2007 August 14 |
||
12 | ** |
||
13 | ** The author disclaims copyright to this source code. In place of |
||
14 | ** a legal notice, here is a blessing: |
||
15 | ** |
||
16 | ** May you do good and not evil. |
||
17 | ** May you find forgiveness for yourself and forgive others. |
||
18 | ** May you share freely, never taking more than you give. |
||
19 | ** |
||
20 | ************************************************************************* |
||
21 | ** This file contains the C functions that implement mutexes for win32 |
||
22 | ************************************************************************* |
||
23 | ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart |
||
24 | ** C#-SQLite is an independent reimplementation of the SQLite software library |
||
25 | ** |
||
26 | ** SQLITE_SOURCE_ID: 2010-03-09 19:31:43 4ae453ea7be69018d8c16eb8dabe05617397dc4d |
||
27 | ** |
||
28 | ************************************************************************* |
||
29 | */ |
||
30 | //#include "sqliteInt.h" |
||
31 | |||
32 | /* |
||
33 | ** The code in this file is only used if we are compiling multithreaded |
||
34 | ** on a win32 system. |
||
35 | */ |
||
36 | #if SQLITE_MUTEX_W32 |
||
37 | |||
38 | |||
39 | /* |
||
40 | ** Each recursive mutex is an instance of the following structure. |
||
41 | */ |
||
42 | public partial class sqlite3_mutex |
||
43 | { |
||
44 | public Object mutex; /* Mutex controlling the lock */ |
||
45 | public int id; /* Mutex type */ |
||
46 | public int nRef; /* Number of enterances */ |
||
47 | public DWORD owner; /* Thread holding this mutex */ |
||
48 | #if SQLITE_DEBUG |
||
49 | public int trace; /* True to trace changes */ |
||
50 | #endif |
||
51 | |||
52 | public sqlite3_mutex() |
||
53 | { |
||
54 | mutex = new Object(); |
||
55 | } |
||
56 | |||
57 | public sqlite3_mutex( Mutex mutex, int id, int nRef, DWORD owner |
||
58 | #if SQLITE_DEBUG |
||
59 | , int trace |
||
60 | #endif |
||
61 | ) |
||
62 | { |
||
63 | this.mutex = mutex; |
||
64 | this.id = id; |
||
65 | this.nRef = nRef; |
||
66 | this.owner = owner; |
||
67 | #if SQLITE_DEBUG |
||
68 | this.trace = 0; |
||
69 | #endif |
||
70 | } |
||
71 | }; |
||
72 | |||
73 | //#define SQLITE_W32_MUTEX_INITIALIZER { 0 } |
||
74 | static Mutex SQLITE_W32_MUTEX_INITIALIZER = null; |
||
75 | #if SQLITE_DEBUG |
||
76 | //#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 } |
||
77 | #else |
||
78 | //#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0 } |
||
79 | #endif |
||
80 | |||
81 | /* |
||
82 | ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, |
||
83 | ** or WinCE. Return false (zero) for Win95, Win98, or WinME. |
||
84 | ** |
||
85 | ** Here is an interesting observation: Win95, Win98, and WinME lack |
||
86 | ** the LockFileEx() API. But we can still statically link against that |
||
87 | ** API as long as we don't call it win running Win95/98/ME. A call to |
||
88 | ** this routine is used to determine if the host is Win95/98/ME or |
||
89 | ** WinNT/2K/XP so that we will know whether or not we can safely call |
||
90 | ** the LockFileEx() API. |
||
91 | ** |
||
92 | ** mutexIsNT() is only used for the TryEnterCriticalSection() API call, |
||
93 | ** which is only available if your application was compiled with |
||
94 | ** _WIN32_WINNT defined to a value >= 0x0400. Currently, the only |
||
95 | ** call to TryEnterCriticalSection() is #ifdef'ed out, so #if |
||
96 | ** this out as well. |
||
97 | */ |
||
98 | #if FALSE |
||
99 | #if SQLITE_OS_WINCE |
||
100 | //# define mutexIsNT() (1) |
||
101 | #else |
||
102 | static int mutexIsNT(void){ |
||
103 | static int osType = 0; |
||
104 | if( osType==0 ){ |
||
105 | OSVERSIONINFO sInfo; |
||
106 | sInfo.dwOSVersionInfoSize = sizeof(sInfo); |
||
107 | GetVersionEx(&sInfo); |
||
108 | osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; |
||
109 | } |
||
110 | return osType==2; |
||
111 | } |
||
112 | #endif //* SQLITE_OS_WINCE */ |
||
113 | #endif |
||
114 | |||
115 | #if SQLITE_DEBUG |
||
116 | /* |
||
117 | ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are |
||
118 | ** intended for use only inside Debug.Assert() statements. |
||
119 | */ |
||
120 | static bool winMutexHeld( sqlite3_mutex p ) |
||
121 | { |
||
122 | return p.nRef != 0 && p.owner == GetCurrentThreadId(); |
||
123 | } |
||
124 | static bool winMutexNotheld2( sqlite3_mutex p, DWORD tid ) |
||
125 | { |
||
126 | return p.nRef == 0 || p.owner != tid; |
||
127 | } |
||
128 | static bool winMutexNotheld( sqlite3_mutex p ) |
||
129 | { |
||
130 | DWORD tid = GetCurrentThreadId(); |
||
131 | return winMutexNotheld2( p, tid ); |
||
132 | } |
||
133 | #endif |
||
134 | |||
135 | |||
136 | /* |
||
137 | ** Initialize and deinitialize the mutex subsystem. |
||
138 | */ |
||
139 | //No MACROS under C#; Cannot use SQLITE3_MUTEX_INITIALIZER, |
||
140 | static sqlite3_mutex[] winMutex_staticMutexes = new sqlite3_mutex[]{ |
||
141 | new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0 |
||
142 | #if SQLITE_DEBUG |
||
143 | , 0 |
||
144 | #endif |
||
145 | ),// SQLITE3_MUTEX_INITIALIZER, |
||
146 | new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0 |
||
147 | #if SQLITE_DEBUG |
||
148 | , 0 |
||
149 | #endif |
||
150 | ),// SQLITE3_MUTEX_INITIALIZER, |
||
151 | new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0 |
||
152 | #if SQLITE_DEBUG |
||
153 | , 0 |
||
154 | #endif |
||
155 | ),// SQLITE3_MUTEX_INITIALIZER, |
||
156 | new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0 |
||
157 | #if SQLITE_DEBUG |
||
158 | , 0 |
||
159 | #endif |
||
160 | ),// SQLITE3_MUTEX_INITIALIZER, |
||
161 | new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0 |
||
162 | #if SQLITE_DEBUG |
||
163 | , 0 |
||
164 | #endif |
||
165 | ),// SQLITE3_MUTEX_INITIALIZER, |
||
166 | new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0 |
||
167 | #if SQLITE_DEBUG |
||
168 | , 0 |
||
169 | #endif |
||
170 | ),// SQLITE3_MUTEX_INITIALIZER, |
||
171 | }; |
||
172 | static int winMutex_isInit = 0; |
||
173 | /* As winMutexInit() and winMutexEnd() are called as part |
||
174 | ** of the sqlite3_initialize and sqlite3_shutdown() |
||
175 | ** processing, the "interlocked" magic is probably not |
||
176 | ** strictly necessary. |
||
177 | */ |
||
178 | static long winMutex_lock = 0; |
||
179 | |||
180 | private static System.Object lockThis = new System.Object(); |
||
181 | static int winMutexInit() |
||
182 | { |
||
183 | /* The first to increment to 1 does actual initialization */ |
||
184 | |||
185 | lock ( lockThis ) |
||
186 | //if ( Interlocked.CompareExchange(ref winMutex_lock, 1, 0 ) == 0 ) |
||
187 | { |
||
188 | int i; |
||
189 | for ( i = 0; i < ArraySize( winMutex_staticMutexes ); i++ ) |
||
190 | { |
||
191 | if (winMutex_staticMutexes[i].mutex== null) winMutex_staticMutexes[i].mutex = new Mutex(); |
||
192 | //InitializeCriticalSection( winMutex_staticMutexes[i].mutex ); |
||
193 | } |
||
194 | winMutex_isInit = 1; |
||
195 | } |
||
196 | //else |
||
197 | //{ |
||
198 | // /* Someone else is in the process of initing the static mutexes */ |
||
199 | // while ( 0 == winMutex_isInit ) |
||
200 | // { |
||
201 | // Thread.Sleep( 1 ); |
||
202 | // } |
||
203 | //} |
||
204 | return SQLITE_OK; |
||
205 | } |
||
206 | |||
207 | static int winMutexEnd() |
||
208 | { |
||
209 | /* The first to decrement to 0 does actual shutdown |
||
210 | ** (which should be the last to shutdown.) */ |
||
211 | if ( Interlocked.CompareExchange( ref winMutex_lock, 0, 1 ) == 1 ) |
||
212 | { |
||
213 | if ( winMutex_isInit == 1 ) |
||
214 | { |
||
215 | int i; |
||
216 | for ( i = 0; i < ArraySize( winMutex_staticMutexes ); i++ ) |
||
217 | { |
||
218 | DeleteCriticalSection( winMutex_staticMutexes[i].mutex ); |
||
219 | } |
||
220 | winMutex_isInit = 0; |
||
221 | } |
||
222 | } |
||
223 | return SQLITE_OK; |
||
224 | } |
||
225 | |||
226 | /* |
||
227 | ** The sqlite3_mutex_alloc() routine allocates a new |
||
228 | ** mutex and returns a pointer to it. If it returns NULL |
||
229 | ** that means that a mutex could not be allocated. SQLite |
||
230 | ** will unwind its stack and return an error. The argument |
||
231 | ** to sqlite3_mutex_alloc() is one of these integer constants: |
||
232 | ** |
||
233 | ** <ul> |
||
234 | ** <li> SQLITE_MUTEX_FAST |
||
235 | ** <li> SQLITE_MUTEX_RECURSIVE |
||
236 | ** <li> SQLITE_MUTEX_STATIC_MASTER |
||
237 | ** <li> SQLITE_MUTEX_STATIC_MEM |
||
238 | ** <li> SQLITE_MUTEX_STATIC_MEM2 |
||
239 | ** <li> SQLITE_MUTEX_STATIC_PRNG |
||
240 | ** <li> SQLITE_MUTEX_STATIC_LRU |
||
241 | ** <li> SQLITE_MUTEX_STATIC_LRU2 |
||
242 | ** </ul> |
||
243 | ** |
||
244 | ** The first two constants cause sqlite3_mutex_alloc() to create |
||
245 | ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE |
||
246 | ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. |
||
247 | ** The mutex implementation does not need to make a distinction |
||
248 | ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does |
||
249 | ** not want to. But SQLite will only request a recursive mutex in |
||
250 | ** cases where it really needs one. If a faster non-recursive mutex |
||
251 | ** implementation is available on the host platform, the mutex subsystem |
||
252 | ** might return such a mutex in response to SQLITE_MUTEX_FAST. |
||
253 | ** |
||
254 | ** The other allowed parameters to sqlite3_mutex_alloc() each return |
||
255 | ** a pointer to a static preexisting mutex. Six static mutexes are |
||
256 | ** used by the current version of SQLite. Future versions of SQLite |
||
257 | ** may add additional static mutexes. Static mutexes are for internal |
||
258 | ** use by SQLite only. Applications that use SQLite mutexes should |
||
259 | ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or |
||
260 | ** SQLITE_MUTEX_RECURSIVE. |
||
261 | ** |
||
262 | ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST |
||
263 | ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() |
||
264 | ** returns a different mutex on every call. But for the static |
||
265 | ** mutex types, the same mutex is returned on every call that has |
||
266 | ** the same type number. |
||
267 | */ |
||
268 | static sqlite3_mutex winMutexAlloc( int iType ) |
||
269 | { |
||
270 | sqlite3_mutex p; |
||
271 | |||
272 | switch ( iType ) |
||
273 | { |
||
274 | case SQLITE_MUTEX_FAST: |
||
275 | case SQLITE_MUTEX_RECURSIVE: |
||
276 | { |
||
277 | p = new sqlite3_mutex();//sqlite3MallocZero( sizeof(*p) ); |
||
278 | if ( p != null ) |
||
279 | { |
||
280 | p.id = iType; |
||
281 | InitializeCriticalSection( p.mutex ); |
||
282 | } |
||
283 | break; |
||
284 | } |
||
285 | default: |
||
286 | { |
||
287 | Debug.Assert( winMutex_isInit == 1 ); |
||
288 | Debug.Assert( iType - 2 >= 0 ); |
||
289 | Debug.Assert( iType - 2 < ArraySize( winMutex_staticMutexes ) ); |
||
290 | p = winMutex_staticMutexes[iType - 2]; |
||
291 | p.id = iType; |
||
292 | break; |
||
293 | } |
||
294 | } |
||
295 | return p; |
||
296 | } |
||
297 | |||
298 | |||
299 | /* |
||
300 | ** This routine deallocates a previously |
||
301 | ** allocated mutex. SQLite is careful to deallocate every |
||
302 | ** mutex that it allocates. |
||
303 | */ |
||
304 | static void winMutexFree( sqlite3_mutex p ) |
||
305 | { |
||
306 | Debug.Assert( p != null ); |
||
307 | Debug.Assert( p.nRef == 0 ); |
||
308 | Debug.Assert( p.id == SQLITE_MUTEX_FAST || p.id == SQLITE_MUTEX_RECURSIVE ); |
||
309 | DeleteCriticalSection( p.mutex ); |
||
310 | p.owner = 0; |
||
311 | //sqlite3_free( p ); |
||
312 | } |
||
313 | |||
314 | /* |
||
315 | ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt |
||
316 | ** to enter a mutex. If another thread is already within the mutex, |
||
317 | ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return |
||
318 | ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK |
||
319 | ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can |
||
320 | ** be entered multiple times by the same thread. In such cases the, |
||
321 | ** mutex must be exited an equal number of times before another thread |
||
322 | ** can enter. If the same thread tries to enter any other kind of mutex |
||
323 | ** more than once, the behavior is undefined. |
||
324 | */ |
||
325 | static void winMutexEnter( sqlite3_mutex p ) |
||
326 | { |
||
327 | DWORD tid = GetCurrentThreadId(); |
||
328 | Debug.Assert( p.id == SQLITE_MUTEX_RECURSIVE || winMutexNotheld2( p, tid ) ); |
||
329 | EnterCriticalSection( p.mutex ); |
||
330 | p.owner = tid; |
||
331 | p.nRef++; |
||
332 | #if SQLITE_DEBUG |
||
333 | if ( p.trace != 0 ) |
||
334 | { |
||
335 | printf( "enter mutex {0} ({1}) with nRef={2}\n", p.GetHashCode(), p.owner, p.nRef ); |
||
336 | } |
||
337 | #endif |
||
338 | } |
||
339 | |||
340 | static int winMutexTry( sqlite3_mutex p ) |
||
341 | { |
||
342 | #if !NDEBUG |
||
343 | DWORD tid = GetCurrentThreadId(); |
||
344 | #endif |
||
345 | int rc = SQLITE_BUSY; |
||
346 | Debug.Assert( p.id == SQLITE_MUTEX_RECURSIVE || winMutexNotheld2( p, tid ) ); |
||
347 | /* |
||
348 | ** The sqlite3_mutex_try() routine is very rarely used, and when it |
||
349 | ** is used it is merely an optimization. So it is OK for it to always |
||
350 | ** fail. |
||
351 | ** |
||
352 | ** The TryEnterCriticalSection() interface is only available on WinNT. |
||
353 | ** And some windows compilers complain if you try to use it without |
||
354 | ** first doing some #defines that prevent SQLite from building on Win98. |
||
355 | ** For that reason, we will omit this optimization for now. See |
||
356 | ** ticket #2685. |
||
357 | */ |
||
358 | #if FALSE |
||
359 | if( mutexIsNT() && TryEnterCriticalSection(p.mutex) ){ |
||
360 | p.owner = tid; |
||
361 | p.nRef++; |
||
362 | rc = SQLITE_OK; |
||
363 | } |
||
364 | #else |
||
365 | UNUSED_PARAMETER( p ); |
||
366 | #endif |
||
367 | #if SQLITE_DEBUG |
||
368 | if ( rc == SQLITE_OK && p.trace != 0 ) |
||
369 | { |
||
370 | printf( "try mutex {0} ({1}) with nRef={2}\n", p.GetHashCode(), p.owner, p.nRef ); |
||
371 | } |
||
372 | #endif |
||
373 | return rc; |
||
374 | } |
||
375 | |||
376 | /* |
||
377 | ** The sqlite3_mutex_leave() routine exits a mutex that was |
||
378 | ** previously entered by the same thread. The behavior |
||
379 | ** is undefined if the mutex is not currently entered or |
||
380 | ** is not currently allocated. SQLite will never do either. |
||
381 | */ |
||
382 | static void winMutexLeave( sqlite3_mutex p ) |
||
383 | { |
||
384 | #if !NDEBUG |
||
385 | DWORD tid = GetCurrentThreadId(); |
||
386 | #endif |
||
387 | Debug.Assert( p.nRef > 0 ); |
||
388 | Debug.Assert( p.owner == tid ); |
||
389 | p.nRef--; |
||
390 | Debug.Assert( p.nRef == 0 || p.id == SQLITE_MUTEX_RECURSIVE ); |
||
391 | if (p.nRef == 0) p.owner = 0; |
||
392 | LeaveCriticalSection( p.mutex ); |
||
393 | #if SQLITE_DEBUG |
||
394 | if ( p.trace != 0 ) |
||
395 | { |
||
396 | printf( "leave mutex {0} ({1}) with nRef={2}\n", p.GetHashCode(), p.owner, p.nRef ); |
||
397 | } |
||
398 | #endif |
||
399 | } |
||
400 | |||
401 | static sqlite3_mutex_methods sqlite3DefaultMutex() |
||
402 | { |
||
403 | sqlite3_mutex_methods sMutex = new sqlite3_mutex_methods ( |
||
404 | (dxMutexInit)winMutexInit, |
||
405 | (dxMutexEnd)winMutexEnd, |
||
406 | (dxMutexAlloc)winMutexAlloc, |
||
407 | (dxMutexFree)winMutexFree, |
||
408 | (dxMutexEnter)winMutexEnter, |
||
409 | (dxMutexTry)winMutexTry, |
||
410 | (dxMutexLeave)winMutexLeave, |
||
411 | #if SQLITE_DEBUG |
||
412 | (dxMutexHeld)winMutexHeld, |
||
413 | (dxMutexNotheld)winMutexNotheld |
||
414 | #else |
||
415 | null, |
||
416 | null |
||
417 | #endif |
||
418 | ); |
||
419 | |||
420 | return sMutex; |
||
421 | } |
||
422 | #endif // * SQLITE_MUTEX_W32 */ |
||
423 | } |
||
424 | } |
||
425 |