wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
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