diff options
Diffstat (limited to 'libraries/sqlite/win32/os_os2.c')
-rwxr-xr-x | libraries/sqlite/win32/os_os2.c | 1032 |
1 files changed, 1032 insertions, 0 deletions
diff --git a/libraries/sqlite/win32/os_os2.c b/libraries/sqlite/win32/os_os2.c new file mode 100755 index 0000000..c4fbe66 --- /dev/null +++ b/libraries/sqlite/win32/os_os2.c | |||
@@ -0,0 +1,1032 @@ | |||
1 | /* | ||
2 | ** 2006 Feb 14 | ||
3 | ** | ||
4 | ** The author disclaims copyright to this source code. In place of | ||
5 | ** a legal notice, here is a blessing: | ||
6 | ** | ||
7 | ** May you do good and not evil. | ||
8 | ** May you find forgiveness for yourself and forgive others. | ||
9 | ** May you share freely, never taking more than you give. | ||
10 | ** | ||
11 | ****************************************************************************** | ||
12 | ** | ||
13 | ** This file contains code that is specific to OS/2. | ||
14 | */ | ||
15 | |||
16 | #include "sqliteInt.h" | ||
17 | |||
18 | #if OS_OS2 | ||
19 | |||
20 | /* | ||
21 | ** Macros used to determine whether or not to use threads. | ||
22 | */ | ||
23 | #if defined(THREADSAFE) && THREADSAFE | ||
24 | # define SQLITE_OS2_THREADS 1 | ||
25 | #endif | ||
26 | |||
27 | /* | ||
28 | ** Include code that is common to all os_*.c files | ||
29 | */ | ||
30 | #include "os_common.h" | ||
31 | |||
32 | /* | ||
33 | ** The os2File structure is subclass of OsFile specific for the OS/2 | ||
34 | ** protability layer. | ||
35 | */ | ||
36 | typedef struct os2File os2File; | ||
37 | struct os2File { | ||
38 | IoMethod const *pMethod; /* Always the first entry */ | ||
39 | HFILE h; /* Handle for accessing the file */ | ||
40 | int delOnClose; /* True if file is to be deleted on close */ | ||
41 | char* pathToDel; /* Name of file to delete on close */ | ||
42 | unsigned char locktype; /* Type of lock currently held on this file */ | ||
43 | }; | ||
44 | |||
45 | /* | ||
46 | ** Do not include any of the File I/O interface procedures if the | ||
47 | ** SQLITE_OMIT_DISKIO macro is defined (indicating that there database | ||
48 | ** will be in-memory only) | ||
49 | */ | ||
50 | #ifndef SQLITE_OMIT_DISKIO | ||
51 | |||
52 | /* | ||
53 | ** Delete the named file | ||
54 | */ | ||
55 | int sqlite3Os2Delete( const char *zFilename ){ | ||
56 | APIRET rc = NO_ERROR; | ||
57 | |||
58 | rc = DosDelete( (PSZ)zFilename ); | ||
59 | OSTRACE2( "DELETE \"%s\"\n", zFilename ); | ||
60 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | ** Return TRUE if the named file exists. | ||
65 | */ | ||
66 | int sqlite3Os2FileExists( const char *zFilename ){ | ||
67 | FILESTATUS3 fsts3ConfigInfo; | ||
68 | memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); | ||
69 | return DosQueryPathInfo( (PSZ)zFilename, FIL_STANDARD, | ||
70 | &fsts3ConfigInfo, sizeof(FILESTATUS3) ) == NO_ERROR; | ||
71 | } | ||
72 | |||
73 | /* Forward declaration */ | ||
74 | int allocateOs2File( os2File *pInit, OsFile **pld ); | ||
75 | |||
76 | /* | ||
77 | ** Attempt to open a file for both reading and writing. If that | ||
78 | ** fails, try opening it read-only. If the file does not exist, | ||
79 | ** try to create it. | ||
80 | ** | ||
81 | ** On success, a handle for the open file is written to *id | ||
82 | ** and *pReadonly is set to 0 if the file was opened for reading and | ||
83 | ** writing or 1 if the file was opened read-only. The function returns | ||
84 | ** SQLITE_OK. | ||
85 | ** | ||
86 | ** On failure, the function returns SQLITE_CANTOPEN and leaves | ||
87 | ** *id and *pReadonly unchanged. | ||
88 | */ | ||
89 | int sqlite3Os2OpenReadWrite( | ||
90 | const char *zFilename, | ||
91 | OsFile **pld, | ||
92 | int *pReadonly | ||
93 | ){ | ||
94 | os2File f; | ||
95 | HFILE hf; | ||
96 | ULONG ulAction; | ||
97 | APIRET rc = NO_ERROR; | ||
98 | |||
99 | assert( *pld == 0 ); | ||
100 | rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, | ||
101 | FILE_ARCHIVED | FILE_NORMAL, | ||
102 | OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, | ||
103 | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | | ||
104 | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); | ||
105 | if( rc != NO_ERROR ){ | ||
106 | rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, | ||
107 | FILE_ARCHIVED | FILE_NORMAL, | ||
108 | OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, | ||
109 | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | | ||
110 | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); | ||
111 | if( rc != NO_ERROR ){ | ||
112 | return SQLITE_CANTOPEN; | ||
113 | } | ||
114 | *pReadonly = 1; | ||
115 | } | ||
116 | else{ | ||
117 | *pReadonly = 0; | ||
118 | } | ||
119 | f.h = hf; | ||
120 | f.locktype = NO_LOCK; | ||
121 | f.delOnClose = 0; | ||
122 | f.pathToDel = NULL; | ||
123 | OpenCounter(+1); | ||
124 | OSTRACE3( "OPEN R/W %d \"%s\"\n", hf, zFilename ); | ||
125 | return allocateOs2File( &f, pld ); | ||
126 | } | ||
127 | |||
128 | |||
129 | /* | ||
130 | ** Attempt to open a new file for exclusive access by this process. | ||
131 | ** The file will be opened for both reading and writing. To avoid | ||
132 | ** a potential security problem, we do not allow the file to have | ||
133 | ** previously existed. Nor do we allow the file to be a symbolic | ||
134 | ** link. | ||
135 | ** | ||
136 | ** If delFlag is true, then make arrangements to automatically delete | ||
137 | ** the file when it is closed. | ||
138 | ** | ||
139 | ** On success, write the file handle into *id and return SQLITE_OK. | ||
140 | ** | ||
141 | ** On failure, return SQLITE_CANTOPEN. | ||
142 | */ | ||
143 | int sqlite3Os2OpenExclusive( const char *zFilename, OsFile **pld, int delFlag ){ | ||
144 | os2File f; | ||
145 | HFILE hf; | ||
146 | ULONG ulAction; | ||
147 | APIRET rc = NO_ERROR; | ||
148 | |||
149 | assert( *pld == 0 ); | ||
150 | rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, FILE_NORMAL, | ||
151 | OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS, | ||
152 | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | | ||
153 | OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); | ||
154 | if( rc != NO_ERROR ){ | ||
155 | return SQLITE_CANTOPEN; | ||
156 | } | ||
157 | |||
158 | f.h = hf; | ||
159 | f.locktype = NO_LOCK; | ||
160 | f.delOnClose = delFlag ? 1 : 0; | ||
161 | f.pathToDel = delFlag ? sqlite3OsFullPathname( zFilename ) : NULL; | ||
162 | OpenCounter( +1 ); | ||
163 | if( delFlag ) DosForceDelete( (PSZ)sqlite3OsFullPathname( zFilename ) ); | ||
164 | OSTRACE3( "OPEN EX %d \"%s\"\n", hf, sqlite3OsFullPathname ( zFilename ) ); | ||
165 | return allocateOs2File( &f, pld ); | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | ** Attempt to open a new file for read-only access. | ||
170 | ** | ||
171 | ** On success, write the file handle into *id and return SQLITE_OK. | ||
172 | ** | ||
173 | ** On failure, return SQLITE_CANTOPEN. | ||
174 | */ | ||
175 | int sqlite3Os2OpenReadOnly( const char *zFilename, OsFile **pld ){ | ||
176 | os2File f; | ||
177 | HFILE hf; | ||
178 | ULONG ulAction; | ||
179 | APIRET rc = NO_ERROR; | ||
180 | |||
181 | assert( *pld == 0 ); | ||
182 | rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, | ||
183 | FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, | ||
184 | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | | ||
185 | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); | ||
186 | if( rc != NO_ERROR ){ | ||
187 | return SQLITE_CANTOPEN; | ||
188 | } | ||
189 | f.h = hf; | ||
190 | f.locktype = NO_LOCK; | ||
191 | f.delOnClose = 0; | ||
192 | f.pathToDel = NULL; | ||
193 | OpenCounter( +1 ); | ||
194 | OSTRACE3( "OPEN RO %d \"%s\"\n", hf, zFilename ); | ||
195 | return allocateOs2File( &f, pld ); | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | ** Attempt to open a file descriptor for the directory that contains a | ||
200 | ** file. This file descriptor can be used to fsync() the directory | ||
201 | ** in order to make sure the creation of a new file is actually written | ||
202 | ** to disk. | ||
203 | ** | ||
204 | ** This routine is only meaningful for Unix. It is a no-op under | ||
205 | ** OS/2 since OS/2 does not support hard links. | ||
206 | ** | ||
207 | ** On success, a handle for a previously open file is at *id is | ||
208 | ** updated with the new directory file descriptor and SQLITE_OK is | ||
209 | ** returned. | ||
210 | ** | ||
211 | ** On failure, the function returns SQLITE_CANTOPEN and leaves | ||
212 | ** *id unchanged. | ||
213 | */ | ||
214 | int os2OpenDirectory( | ||
215 | OsFile *id, | ||
216 | const char *zDirname | ||
217 | ){ | ||
218 | return SQLITE_OK; | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | ** Create a temporary file name in zBuf. zBuf must be big enough to | ||
223 | ** hold at least SQLITE_TEMPNAME_SIZE characters. | ||
224 | */ | ||
225 | int sqlite3Os2TempFileName( char *zBuf ){ | ||
226 | static const unsigned char zChars[] = | ||
227 | "abcdefghijklmnopqrstuvwxyz" | ||
228 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | ||
229 | "0123456789"; | ||
230 | int i, j; | ||
231 | PSZ zTempPath = 0; | ||
232 | if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){ | ||
233 | if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){ | ||
234 | if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){ | ||
235 | ULONG ulDriveNum = 0, ulDriveMap = 0; | ||
236 | DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); | ||
237 | sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | /* strip off a trailing slashes or backslashes, otherwise we would get * | ||
242 | * multiple (back)slashes which causes DosOpen() to fail */ | ||
243 | j = strlen(zTempPath); | ||
244 | while( j > 0 && zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' ){ | ||
245 | j--; | ||
246 | } | ||
247 | zTempPath[j] = '\0'; | ||
248 | for(;;){ | ||
249 | sprintf( zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath ); | ||
250 | j = strlen( zBuf ); | ||
251 | sqlite3Randomness( 15, &zBuf[j] ); | ||
252 | for( i = 0; i < 15; i++, j++ ){ | ||
253 | zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; | ||
254 | } | ||
255 | zBuf[j] = 0; | ||
256 | if( !sqlite3OsFileExists( zBuf ) ) break; | ||
257 | } | ||
258 | OSTRACE2( "TEMP FILENAME: %s\n", zBuf ); | ||
259 | return SQLITE_OK; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | ** Close a file. | ||
264 | */ | ||
265 | int os2Close( OsFile **pld ){ | ||
266 | os2File *pFile; | ||
267 | APIRET rc = NO_ERROR; | ||
268 | if( pld && (pFile = (os2File*)*pld) != 0 ){ | ||
269 | OSTRACE2( "CLOSE %d\n", pFile->h ); | ||
270 | rc = DosClose( pFile->h ); | ||
271 | pFile->locktype = NO_LOCK; | ||
272 | if( pFile->delOnClose != 0 ){ | ||
273 | rc = DosForceDelete( (PSZ)pFile->pathToDel ); | ||
274 | } | ||
275 | *pld = 0; | ||
276 | OpenCounter( -1 ); | ||
277 | } | ||
278 | |||
279 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | ** Read data from a file into a buffer. Return SQLITE_OK if all | ||
284 | ** bytes were read successfully and SQLITE_IOERR if anything goes | ||
285 | ** wrong. | ||
286 | */ | ||
287 | int os2Read( OsFile *id, void *pBuf, int amt ){ | ||
288 | ULONG got; | ||
289 | assert( id!=0 ); | ||
290 | SimulateIOError( return SQLITE_IOERR ); | ||
291 | OSTRACE3( "READ %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); | ||
292 | DosRead( ((os2File*)id)->h, pBuf, amt, &got ); | ||
293 | if (got == (ULONG)amt) | ||
294 | return SQLITE_OK; | ||
295 | else if (got == 0) | ||
296 | return SQLITE_IOERR_READ; | ||
297 | else { | ||
298 | memset(&((char*)pBuf)[got], 0, amt-got); | ||
299 | return SQLITE_IOERR_SHORT_READ; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | ** Write data from a buffer into a file. Return SQLITE_OK on success | ||
305 | ** or some other error code on failure. | ||
306 | */ | ||
307 | int os2Write( OsFile *id, const void *pBuf, int amt ){ | ||
308 | APIRET rc = NO_ERROR; | ||
309 | ULONG wrote; | ||
310 | assert( id!=0 ); | ||
311 | SimulateIOError( return SQLITE_IOERR ); | ||
312 | SimulateDiskfullError( return SQLITE_FULL ); | ||
313 | OSTRACE3( "WRITE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); | ||
314 | while( amt > 0 && | ||
315 | (rc = DosWrite( ((os2File*)id)->h, (PVOID)pBuf, amt, &wrote )) && wrote > 0 ){ | ||
316 | amt -= wrote; | ||
317 | pBuf = &((char*)pBuf)[wrote]; | ||
318 | } | ||
319 | |||
320 | return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK; | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | ** Move the read/write pointer in a file. | ||
325 | */ | ||
326 | int os2Seek( OsFile *id, i64 offset ){ | ||
327 | APIRET rc = NO_ERROR; | ||
328 | ULONG filePointer = 0L; | ||
329 | assert( id!=0 ); | ||
330 | rc = DosSetFilePtr( ((os2File*)id)->h, offset, FILE_BEGIN, &filePointer ); | ||
331 | OSTRACE3( "SEEK %d %lld\n", ((os2File*)id)->h, offset ); | ||
332 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | ** Make sure all writes to a particular file are committed to disk. | ||
337 | */ | ||
338 | int os2Sync( OsFile *id, int dataOnly ){ | ||
339 | assert( id!=0 ); | ||
340 | OSTRACE3( "SYNC %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); | ||
341 | return DosResetBuffer( ((os2File*)id)->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | ** Sync the directory zDirname. This is a no-op on operating systems other | ||
346 | ** than UNIX. | ||
347 | */ | ||
348 | int sqlite3Os2SyncDirectory( const char *zDirname ){ | ||
349 | SimulateIOError( return SQLITE_IOERR ); | ||
350 | return SQLITE_OK; | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | ** Truncate an open file to a specified size | ||
355 | */ | ||
356 | int os2Truncate( OsFile *id, i64 nByte ){ | ||
357 | APIRET rc = NO_ERROR; | ||
358 | ULONG upperBits = nByte>>32; | ||
359 | assert( id!=0 ); | ||
360 | OSTRACE3( "TRUNCATE %d %lld\n", ((os2File*)id)->h, nByte ); | ||
361 | SimulateIOError( return SQLITE_IOERR ); | ||
362 | rc = DosSetFilePtr( ((os2File*)id)->h, nByte, FILE_BEGIN, &upperBits ); | ||
363 | if( rc != NO_ERROR ){ | ||
364 | return SQLITE_IOERR; | ||
365 | } | ||
366 | rc = DosSetFilePtr( ((os2File*)id)->h, 0L, FILE_END, &upperBits ); | ||
367 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | ** Determine the current size of a file in bytes | ||
372 | */ | ||
373 | int os2FileSize( OsFile *id, i64 *pSize ){ | ||
374 | APIRET rc = NO_ERROR; | ||
375 | FILESTATUS3 fsts3FileInfo; | ||
376 | memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo)); | ||
377 | assert( id!=0 ); | ||
378 | SimulateIOError( return SQLITE_IOERR ); | ||
379 | rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) ); | ||
380 | if( rc == NO_ERROR ){ | ||
381 | *pSize = fsts3FileInfo.cbFile; | ||
382 | return SQLITE_OK; | ||
383 | } | ||
384 | else{ | ||
385 | return SQLITE_IOERR; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | ** Acquire a reader lock. | ||
391 | */ | ||
392 | static int getReadLock( os2File *id ){ | ||
393 | FILELOCK LockArea, | ||
394 | UnlockArea; | ||
395 | memset(&LockArea, 0, sizeof(LockArea)); | ||
396 | memset(&UnlockArea, 0, sizeof(UnlockArea)); | ||
397 | LockArea.lOffset = SHARED_FIRST; | ||
398 | LockArea.lRange = SHARED_SIZE; | ||
399 | UnlockArea.lOffset = 0L; | ||
400 | UnlockArea.lRange = 0L; | ||
401 | return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | ** Undo a readlock | ||
406 | */ | ||
407 | static int unlockReadLock( os2File *id ){ | ||
408 | FILELOCK LockArea, | ||
409 | UnlockArea; | ||
410 | memset(&LockArea, 0, sizeof(LockArea)); | ||
411 | memset(&UnlockArea, 0, sizeof(UnlockArea)); | ||
412 | LockArea.lOffset = 0L; | ||
413 | LockArea.lRange = 0L; | ||
414 | UnlockArea.lOffset = SHARED_FIRST; | ||
415 | UnlockArea.lRange = SHARED_SIZE; | ||
416 | return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
417 | } | ||
418 | |||
419 | #ifndef SQLITE_OMIT_PAGER_PRAGMAS | ||
420 | /* | ||
421 | ** Check that a given pathname is a directory and is writable | ||
422 | ** | ||
423 | */ | ||
424 | int sqlite3Os2IsDirWritable( char *zDirname ){ | ||
425 | FILESTATUS3 fsts3ConfigInfo; | ||
426 | APIRET rc = NO_ERROR; | ||
427 | memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); | ||
428 | if( zDirname==0 ) return 0; | ||
429 | if( strlen(zDirname)>CCHMAXPATH ) return 0; | ||
430 | rc = DosQueryPathInfo( (PSZ)zDirname, FIL_STANDARD, &fsts3ConfigInfo, sizeof(FILESTATUS3) ); | ||
431 | if( rc != NO_ERROR ) return 0; | ||
432 | if( (fsts3ConfigInfo.attrFile & FILE_DIRECTORY) != FILE_DIRECTORY ) return 0; | ||
433 | |||
434 | return 1; | ||
435 | } | ||
436 | #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ | ||
437 | |||
438 | /* | ||
439 | ** Lock the file with the lock specified by parameter locktype - one | ||
440 | ** of the following: | ||
441 | ** | ||
442 | ** (1) SHARED_LOCK | ||
443 | ** (2) RESERVED_LOCK | ||
444 | ** (3) PENDING_LOCK | ||
445 | ** (4) EXCLUSIVE_LOCK | ||
446 | ** | ||
447 | ** Sometimes when requesting one lock state, additional lock states | ||
448 | ** are inserted in between. The locking might fail on one of the later | ||
449 | ** transitions leaving the lock state different from what it started but | ||
450 | ** still short of its goal. The following chart shows the allowed | ||
451 | ** transitions and the inserted intermediate states: | ||
452 | ** | ||
453 | ** UNLOCKED -> SHARED | ||
454 | ** SHARED -> RESERVED | ||
455 | ** SHARED -> (PENDING) -> EXCLUSIVE | ||
456 | ** RESERVED -> (PENDING) -> EXCLUSIVE | ||
457 | ** PENDING -> EXCLUSIVE | ||
458 | ** | ||
459 | ** This routine will only increase a lock. The os2Unlock() routine | ||
460 | ** erases all locks at once and returns us immediately to locking level 0. | ||
461 | ** It is not possible to lower the locking level one step at a time. You | ||
462 | ** must go straight to locking level 0. | ||
463 | */ | ||
464 | int os2Lock( OsFile *id, int locktype ){ | ||
465 | APIRET rc = SQLITE_OK; /* Return code from subroutines */ | ||
466 | APIRET res = NO_ERROR; /* Result of an OS/2 lock call */ | ||
467 | int newLocktype; /* Set id->locktype to this value before exiting */ | ||
468 | int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ | ||
469 | FILELOCK LockArea, | ||
470 | UnlockArea; | ||
471 | os2File *pFile = (os2File*)id; | ||
472 | memset(&LockArea, 0, sizeof(LockArea)); | ||
473 | memset(&UnlockArea, 0, sizeof(UnlockArea)); | ||
474 | assert( pFile!=0 ); | ||
475 | OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ); | ||
476 | |||
477 | /* If there is already a lock of this type or more restrictive on the | ||
478 | ** OsFile, do nothing. Don't use the end_lock: exit path, as | ||
479 | ** sqlite3OsEnterMutex() hasn't been called yet. | ||
480 | */ | ||
481 | if( pFile->locktype>=locktype ){ | ||
482 | return SQLITE_OK; | ||
483 | } | ||
484 | |||
485 | /* Make sure the locking sequence is correct | ||
486 | */ | ||
487 | assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); | ||
488 | assert( locktype!=PENDING_LOCK ); | ||
489 | assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); | ||
490 | |||
491 | /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or | ||
492 | ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of | ||
493 | ** the PENDING_LOCK byte is temporary. | ||
494 | */ | ||
495 | newLocktype = pFile->locktype; | ||
496 | if( pFile->locktype==NO_LOCK | ||
497 | || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) | ||
498 | ){ | ||
499 | int cnt = 3; | ||
500 | |||
501 | LockArea.lOffset = PENDING_BYTE; | ||
502 | LockArea.lRange = 1L; | ||
503 | UnlockArea.lOffset = 0L; | ||
504 | UnlockArea.lRange = 0L; | ||
505 | |||
506 | while( cnt-->0 && (res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L) )!=NO_ERROR ){ | ||
507 | /* Try 3 times to get the pending lock. The pending lock might be | ||
508 | ** held by another reader process who will release it momentarily. | ||
509 | */ | ||
510 | OSTRACE2( "could not get a PENDING lock. cnt=%d\n", cnt ); | ||
511 | DosSleep(1); | ||
512 | } | ||
513 | gotPendingLock = res; | ||
514 | } | ||
515 | |||
516 | /* Acquire a shared lock | ||
517 | */ | ||
518 | if( locktype==SHARED_LOCK && res ){ | ||
519 | assert( pFile->locktype==NO_LOCK ); | ||
520 | res = getReadLock(pFile); | ||
521 | if( res == NO_ERROR ){ | ||
522 | newLocktype = SHARED_LOCK; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | /* Acquire a RESERVED lock | ||
527 | */ | ||
528 | if( locktype==RESERVED_LOCK && res ){ | ||
529 | assert( pFile->locktype==SHARED_LOCK ); | ||
530 | LockArea.lOffset = RESERVED_BYTE; | ||
531 | LockArea.lRange = 1L; | ||
532 | UnlockArea.lOffset = 0L; | ||
533 | UnlockArea.lRange = 0L; | ||
534 | res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
535 | if( res == NO_ERROR ){ | ||
536 | newLocktype = RESERVED_LOCK; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | /* Acquire a PENDING lock | ||
541 | */ | ||
542 | if( locktype==EXCLUSIVE_LOCK && res ){ | ||
543 | newLocktype = PENDING_LOCK; | ||
544 | gotPendingLock = 0; | ||
545 | } | ||
546 | |||
547 | /* Acquire an EXCLUSIVE lock | ||
548 | */ | ||
549 | if( locktype==EXCLUSIVE_LOCK && res ){ | ||
550 | assert( pFile->locktype>=SHARED_LOCK ); | ||
551 | res = unlockReadLock(pFile); | ||
552 | OSTRACE2( "unreadlock = %d\n", res ); | ||
553 | LockArea.lOffset = SHARED_FIRST; | ||
554 | LockArea.lRange = SHARED_SIZE; | ||
555 | UnlockArea.lOffset = 0L; | ||
556 | UnlockArea.lRange = 0L; | ||
557 | res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
558 | if( res == NO_ERROR ){ | ||
559 | newLocktype = EXCLUSIVE_LOCK; | ||
560 | }else{ | ||
561 | OSTRACE2( "error-code = %d\n", res ); | ||
562 | } | ||
563 | } | ||
564 | |||
565 | /* If we are holding a PENDING lock that ought to be released, then | ||
566 | ** release it now. | ||
567 | */ | ||
568 | if( gotPendingLock && locktype==SHARED_LOCK ){ | ||
569 | LockArea.lOffset = 0L; | ||
570 | LockArea.lRange = 0L; | ||
571 | UnlockArea.lOffset = PENDING_BYTE; | ||
572 | UnlockArea.lRange = 1L; | ||
573 | DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
574 | } | ||
575 | |||
576 | /* Update the state of the lock has held in the file descriptor then | ||
577 | ** return the appropriate result code. | ||
578 | */ | ||
579 | if( res == NO_ERROR ){ | ||
580 | rc = SQLITE_OK; | ||
581 | }else{ | ||
582 | OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h, | ||
583 | locktype, newLocktype ); | ||
584 | rc = SQLITE_BUSY; | ||
585 | } | ||
586 | pFile->locktype = newLocktype; | ||
587 | return rc; | ||
588 | } | ||
589 | |||
590 | /* | ||
591 | ** This routine checks if there is a RESERVED lock held on the specified | ||
592 | ** file by this or any other process. If such a lock is held, return | ||
593 | ** non-zero, otherwise zero. | ||
594 | */ | ||
595 | int os2CheckReservedLock( OsFile *id ){ | ||
596 | APIRET rc = NO_ERROR; | ||
597 | os2File *pFile = (os2File*)id; | ||
598 | assert( pFile!=0 ); | ||
599 | if( pFile->locktype>=RESERVED_LOCK ){ | ||
600 | rc = 1; | ||
601 | OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, rc ); | ||
602 | }else{ | ||
603 | FILELOCK LockArea, | ||
604 | UnlockArea; | ||
605 | memset(&LockArea, 0, sizeof(LockArea)); | ||
606 | memset(&UnlockArea, 0, sizeof(UnlockArea)); | ||
607 | LockArea.lOffset = RESERVED_BYTE; | ||
608 | LockArea.lRange = 1L; | ||
609 | UnlockArea.lOffset = 0L; | ||
610 | UnlockArea.lRange = 0L; | ||
611 | rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
612 | if( rc == NO_ERROR ){ | ||
613 | LockArea.lOffset = 0L; | ||
614 | LockArea.lRange = 0L; | ||
615 | UnlockArea.lOffset = RESERVED_BYTE; | ||
616 | UnlockArea.lRange = 1L; | ||
617 | rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
618 | } | ||
619 | OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, rc ); | ||
620 | } | ||
621 | return rc; | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | ** Lower the locking level on file descriptor id to locktype. locktype | ||
626 | ** must be either NO_LOCK or SHARED_LOCK. | ||
627 | ** | ||
628 | ** If the locking level of the file descriptor is already at or below | ||
629 | ** the requested locking level, this routine is a no-op. | ||
630 | ** | ||
631 | ** It is not possible for this routine to fail if the second argument | ||
632 | ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine | ||
633 | ** might return SQLITE_IOERR; | ||
634 | */ | ||
635 | int os2Unlock( OsFile *id, int locktype ){ | ||
636 | int type; | ||
637 | APIRET rc = SQLITE_OK; | ||
638 | os2File *pFile = (os2File*)id; | ||
639 | FILELOCK LockArea, | ||
640 | UnlockArea; | ||
641 | memset(&LockArea, 0, sizeof(LockArea)); | ||
642 | memset(&UnlockArea, 0, sizeof(UnlockArea)); | ||
643 | assert( pFile!=0 ); | ||
644 | assert( locktype<=SHARED_LOCK ); | ||
645 | OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ); | ||
646 | type = pFile->locktype; | ||
647 | if( type>=EXCLUSIVE_LOCK ){ | ||
648 | LockArea.lOffset = 0L; | ||
649 | LockArea.lRange = 0L; | ||
650 | UnlockArea.lOffset = SHARED_FIRST; | ||
651 | UnlockArea.lRange = SHARED_SIZE; | ||
652 | DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
653 | if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){ | ||
654 | /* This should never happen. We should always be able to | ||
655 | ** reacquire the read lock */ | ||
656 | rc = SQLITE_IOERR; | ||
657 | } | ||
658 | } | ||
659 | if( type>=RESERVED_LOCK ){ | ||
660 | LockArea.lOffset = 0L; | ||
661 | LockArea.lRange = 0L; | ||
662 | UnlockArea.lOffset = RESERVED_BYTE; | ||
663 | UnlockArea.lRange = 1L; | ||
664 | DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
665 | } | ||
666 | if( locktype==NO_LOCK && type>=SHARED_LOCK ){ | ||
667 | unlockReadLock(pFile); | ||
668 | } | ||
669 | if( type>=PENDING_LOCK ){ | ||
670 | LockArea.lOffset = 0L; | ||
671 | LockArea.lRange = 0L; | ||
672 | UnlockArea.lOffset = PENDING_BYTE; | ||
673 | UnlockArea.lRange = 1L; | ||
674 | DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); | ||
675 | } | ||
676 | pFile->locktype = locktype; | ||
677 | return rc; | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | ** Turn a relative pathname into a full pathname. Return a pointer | ||
682 | ** to the full pathname stored in space obtained from sqliteMalloc(). | ||
683 | ** The calling function is responsible for freeing this space once it | ||
684 | ** is no longer needed. | ||
685 | */ | ||
686 | char *sqlite3Os2FullPathname( const char *zRelative ){ | ||
687 | char *zFull = 0; | ||
688 | if( strchr(zRelative, ':') ){ | ||
689 | sqlite3SetString( &zFull, zRelative, (char*)0 ); | ||
690 | }else{ | ||
691 | ULONG ulDriveNum = 0; | ||
692 | ULONG ulDriveMap = 0; | ||
693 | ULONG cbzBufLen = SQLITE_TEMPNAME_SIZE; | ||
694 | char zDrive[2]; | ||
695 | char *zBuff; | ||
696 | |||
697 | zBuff = sqliteMalloc( cbzBufLen ); | ||
698 | if( zBuff != 0 ){ | ||
699 | DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); | ||
700 | if( DosQueryCurrentDir( ulDriveNum, (PBYTE)zBuff, &cbzBufLen ) == NO_ERROR ){ | ||
701 | sprintf( zDrive, "%c", (char)('A' + ulDriveNum - 1) ); | ||
702 | sqlite3SetString( &zFull, zDrive, ":\\", zBuff, | ||
703 | "\\", zRelative, (char*)0 ); | ||
704 | } | ||
705 | sqliteFree( zBuff ); | ||
706 | } | ||
707 | } | ||
708 | return zFull; | ||
709 | } | ||
710 | |||
711 | /* | ||
712 | ** The fullSync option is meaningless on os2, or correct me if I'm wrong. This is a no-op. | ||
713 | ** From os_unix.c: Change the value of the fullsync flag in the given file descriptor. | ||
714 | ** From os_unix.c: ((unixFile*)id)->fullSync = v; | ||
715 | */ | ||
716 | static void os2SetFullSync( OsFile *id, int v ){ | ||
717 | return; | ||
718 | } | ||
719 | |||
720 | /* | ||
721 | ** Return the underlying file handle for an OsFile | ||
722 | */ | ||
723 | static int os2FileHandle( OsFile *id ){ | ||
724 | return (int)((os2File*)id)->h; | ||
725 | } | ||
726 | |||
727 | /* | ||
728 | ** Return an integer that indices the type of lock currently held | ||
729 | ** by this handle. (Used for testing and analysis only.) | ||
730 | */ | ||
731 | static int os2LockState( OsFile *id ){ | ||
732 | return ((os2File*)id)->locktype; | ||
733 | } | ||
734 | |||
735 | /* | ||
736 | ** Return the sector size in bytes of the underlying block device for | ||
737 | ** the specified file. This is almost always 512 bytes, but may be | ||
738 | ** larger for some devices. | ||
739 | ** | ||
740 | ** SQLite code assumes this function cannot fail. It also assumes that | ||
741 | ** if two files are created in the same file-system directory (i.e. | ||
742 | ** a database and it's journal file) that the sector size will be the | ||
743 | ** same for both. | ||
744 | */ | ||
745 | static int os2SectorSize(OsFile *id){ | ||
746 | return SQLITE_DEFAULT_SECTOR_SIZE; | ||
747 | } | ||
748 | |||
749 | /* | ||
750 | ** This vector defines all the methods that can operate on an OsFile | ||
751 | ** for os2. | ||
752 | */ | ||
753 | static const IoMethod sqlite3Os2IoMethod = { | ||
754 | os2Close, | ||
755 | os2OpenDirectory, | ||
756 | os2Read, | ||
757 | os2Write, | ||
758 | os2Seek, | ||
759 | os2Truncate, | ||
760 | os2Sync, | ||
761 | os2SetFullSync, | ||
762 | os2FileHandle, | ||
763 | os2FileSize, | ||
764 | os2Lock, | ||
765 | os2Unlock, | ||
766 | os2LockState, | ||
767 | os2CheckReservedLock, | ||
768 | os2SectorSize, | ||
769 | }; | ||
770 | |||
771 | /* | ||
772 | ** Allocate memory for an OsFile. Initialize the new OsFile | ||
773 | ** to the value given in pInit and return a pointer to the new | ||
774 | ** OsFile. If we run out of memory, close the file and return NULL. | ||
775 | */ | ||
776 | int allocateOs2File( os2File *pInit, OsFile **pld ){ | ||
777 | os2File *pNew; | ||
778 | pNew = sqliteMalloc( sizeof(*pNew) ); | ||
779 | if( pNew==0 ){ | ||
780 | DosClose( pInit->h ); | ||
781 | *pld = 0; | ||
782 | return SQLITE_NOMEM; | ||
783 | }else{ | ||
784 | *pNew = *pInit; | ||
785 | pNew->pMethod = &sqlite3Os2IoMethod; | ||
786 | pNew->locktype = NO_LOCK; | ||
787 | *pld = (OsFile*)pNew; | ||
788 | OpenCounter(+1); | ||
789 | return SQLITE_OK; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | #endif /* SQLITE_OMIT_DISKIO */ | ||
794 | /*************************************************************************** | ||
795 | ** Everything above deals with file I/O. Everything that follows deals | ||
796 | ** with other miscellanous aspects of the operating system interface | ||
797 | ****************************************************************************/ | ||
798 | |||
799 | #ifndef SQLITE_OMIT_LOAD_EXTENSION | ||
800 | /* | ||
801 | ** Interfaces for opening a shared library, finding entry points | ||
802 | ** within the shared library, and closing the shared library. | ||
803 | */ | ||
804 | void *sqlite3Os2Dlopen(const char *zFilename){ | ||
805 | UCHAR loadErr[256]; | ||
806 | HMODULE hmod; | ||
807 | APIRET rc; | ||
808 | rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilename, &hmod); | ||
809 | if (rc != NO_ERROR) return 0; | ||
810 | return (void*)hmod; | ||
811 | } | ||
812 | void *sqlite3Os2Dlsym(void *pHandle, const char *zSymbol){ | ||
813 | PFN pfn; | ||
814 | APIRET rc; | ||
815 | rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn); | ||
816 | if (rc != NO_ERROR) { | ||
817 | /* if the symbol itself was not found, search again for the same | ||
818 | * symbol with an extra underscore, that might be needed depending | ||
819 | * on the calling convention */ | ||
820 | char _zSymbol[256] = "_"; | ||
821 | strncat(_zSymbol, zSymbol, 255); | ||
822 | rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn); | ||
823 | } | ||
824 | if (rc != NO_ERROR) return 0; | ||
825 | return (void *)pfn; | ||
826 | } | ||
827 | int sqlite3Os2Dlclose(void *pHandle){ | ||
828 | return DosFreeModule((HMODULE)pHandle); | ||
829 | } | ||
830 | #endif /* SQLITE_OMIT_LOAD_EXTENSION */ | ||
831 | |||
832 | |||
833 | /* | ||
834 | ** Get information to seed the random number generator. The seed | ||
835 | ** is written into the buffer zBuf[256]. The calling function must | ||
836 | ** supply a sufficiently large buffer. | ||
837 | */ | ||
838 | int sqlite3Os2RandomSeed( char *zBuf ){ | ||
839 | /* We have to initialize zBuf to prevent valgrind from reporting | ||
840 | ** errors. The reports issued by valgrind are incorrect - we would | ||
841 | ** prefer that the randomness be increased by making use of the | ||
842 | ** uninitialized space in zBuf - but valgrind errors tend to worry | ||
843 | ** some users. Rather than argue, it seems easier just to initialize | ||
844 | ** the whole array and silence valgrind, even if that means less randomness | ||
845 | ** in the random seed. | ||
846 | ** | ||
847 | ** When testing, initializing zBuf[] to zero is all we do. That means | ||
848 | ** that we always use the same random number sequence. This makes the | ||
849 | ** tests repeatable. | ||
850 | */ | ||
851 | memset( zBuf, 0, 256 ); | ||
852 | DosGetDateTime( (PDATETIME)zBuf ); | ||
853 | return SQLITE_OK; | ||
854 | } | ||
855 | |||
856 | /* | ||
857 | ** Sleep for a little while. Return the amount of time slept. | ||
858 | */ | ||
859 | int sqlite3Os2Sleep( int ms ){ | ||
860 | DosSleep( ms ); | ||
861 | return ms; | ||
862 | } | ||
863 | |||
864 | /* | ||
865 | ** Static variables used for thread synchronization | ||
866 | */ | ||
867 | static int inMutex = 0; | ||
868 | #ifdef SQLITE_OS2_THREADS | ||
869 | static ULONG mutexOwner; | ||
870 | #endif | ||
871 | |||
872 | /* | ||
873 | ** The following pair of routines implement mutual exclusion for | ||
874 | ** multi-threaded processes. Only a single thread is allowed to | ||
875 | ** executed code that is surrounded by EnterMutex() and LeaveMutex(). | ||
876 | ** | ||
877 | ** SQLite uses only a single Mutex. There is not much critical | ||
878 | ** code and what little there is executes quickly and without blocking. | ||
879 | */ | ||
880 | void sqlite3Os2EnterMutex(){ | ||
881 | #ifdef SQLITE_OS2_THREADS | ||
882 | PTIB ptib; | ||
883 | DosEnterCritSec(); | ||
884 | DosGetInfoBlocks( &ptib, NULL ); | ||
885 | mutexOwner = ptib->tib_ptib2->tib2_ultid; | ||
886 | #endif | ||
887 | assert( !inMutex ); | ||
888 | inMutex = 1; | ||
889 | } | ||
890 | void sqlite3Os2LeaveMutex(){ | ||
891 | #ifdef SQLITE_OS2_THREADS | ||
892 | PTIB ptib; | ||
893 | #endif | ||
894 | assert( inMutex ); | ||
895 | inMutex = 0; | ||
896 | #ifdef SQLITE_OS2_THREADS | ||
897 | DosGetInfoBlocks( &ptib, NULL ); | ||
898 | assert( mutexOwner == ptib->tib_ptib2->tib2_ultid ); | ||
899 | DosExitCritSec(); | ||
900 | #endif | ||
901 | } | ||
902 | |||
903 | /* | ||
904 | ** Return TRUE if the mutex is currently held. | ||
905 | ** | ||
906 | ** If the thisThreadOnly parameter is true, return true if and only if the | ||
907 | ** calling thread holds the mutex. If the parameter is false, return | ||
908 | ** true if any thread holds the mutex. | ||
909 | */ | ||
910 | int sqlite3Os2InMutex( int thisThreadOnly ){ | ||
911 | #ifdef SQLITE_OS2_THREADS | ||
912 | PTIB ptib; | ||
913 | DosGetInfoBlocks( &ptib, NULL ); | ||
914 | return inMutex>0 && (thisThreadOnly==0 || mutexOwner==ptib->tib_ptib2->tib2_ultid); | ||
915 | #else | ||
916 | return inMutex>0; | ||
917 | #endif | ||
918 | } | ||
919 | |||
920 | /* | ||
921 | ** The following variable, if set to a non-zero value, becomes the result | ||
922 | ** returned from sqlite3OsCurrentTime(). This is used for testing. | ||
923 | */ | ||
924 | #ifdef SQLITE_TEST | ||
925 | int sqlite3_current_time = 0; | ||
926 | #endif | ||
927 | |||
928 | /* | ||
929 | ** Find the current time (in Universal Coordinated Time). Write the | ||
930 | ** current time and date as a Julian Day number into *prNow and | ||
931 | ** return 0. Return 1 if the time and date cannot be found. | ||
932 | */ | ||
933 | int sqlite3Os2CurrentTime( double *prNow ){ | ||
934 | double now; | ||
935 | USHORT second, minute, hour, | ||
936 | day, month, year; | ||
937 | DATETIME dt; | ||
938 | DosGetDateTime( &dt ); | ||
939 | second = (USHORT)dt.seconds; | ||
940 | minute = (USHORT)dt.minutes + dt.timezone; | ||
941 | hour = (USHORT)dt.hours; | ||
942 | day = (USHORT)dt.day; | ||
943 | month = (USHORT)dt.month; | ||
944 | year = (USHORT)dt.year; | ||
945 | |||
946 | /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html | ||
947 | http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */ | ||
948 | /* Calculate the Julian days */ | ||
949 | now = day - 32076 + | ||
950 | 1461*(year + 4800 + (month - 14)/12)/4 + | ||
951 | 367*(month - 2 - (month - 14)/12*12)/12 - | ||
952 | 3*((year + 4900 + (month - 14)/12)/100)/4; | ||
953 | |||
954 | /* Add the fractional hours, mins and seconds */ | ||
955 | now += (hour + 12.0)/24.0; | ||
956 | now += minute/1440.0; | ||
957 | now += second/86400.0; | ||
958 | *prNow = now; | ||
959 | #ifdef SQLITE_TEST | ||
960 | if( sqlite3_current_time ){ | ||
961 | *prNow = sqlite3_current_time/86400.0 + 2440587.5; | ||
962 | } | ||
963 | #endif | ||
964 | return 0; | ||
965 | } | ||
966 | |||
967 | /* | ||
968 | ** Remember the number of thread-specific-data blocks allocated. | ||
969 | ** Use this to verify that we are not leaking thread-specific-data. | ||
970 | ** Ticket #1601 | ||
971 | */ | ||
972 | #ifdef SQLITE_TEST | ||
973 | int sqlite3_tsd_count = 0; | ||
974 | # define TSD_COUNTER_INCR InterlockedIncrement( &sqlite3_tsd_count ) | ||
975 | # define TSD_COUNTER_DECR InterlockedDecrement( &sqlite3_tsd_count ) | ||
976 | #else | ||
977 | # define TSD_COUNTER_INCR /* no-op */ | ||
978 | # define TSD_COUNTER_DECR /* no-op */ | ||
979 | #endif | ||
980 | |||
981 | /* | ||
982 | ** If called with allocateFlag>1, then return a pointer to thread | ||
983 | ** specific data for the current thread. Allocate and zero the | ||
984 | ** thread-specific data if it does not already exist necessary. | ||
985 | ** | ||
986 | ** If called with allocateFlag==0, then check the current thread | ||
987 | ** specific data. Return it if it exists. If it does not exist, | ||
988 | ** then return NULL. | ||
989 | ** | ||
990 | ** If called with allocateFlag<0, check to see if the thread specific | ||
991 | ** data is allocated and is all zero. If it is then deallocate it. | ||
992 | ** Return a pointer to the thread specific data or NULL if it is | ||
993 | ** unallocated or gets deallocated. | ||
994 | */ | ||
995 | ThreadData *sqlite3Os2ThreadSpecificData( int allocateFlag ){ | ||
996 | static ThreadData **s_ppTsd = NULL; | ||
997 | static const ThreadData zeroData = {0, 0, 0}; | ||
998 | ThreadData *pTsd; | ||
999 | |||
1000 | if( !s_ppTsd ){ | ||
1001 | sqlite3OsEnterMutex(); | ||
1002 | if( !s_ppTsd ){ | ||
1003 | PULONG pul; | ||
1004 | APIRET rc = DosAllocThreadLocalMemory(1, &pul); | ||
1005 | if( rc != NO_ERROR ){ | ||
1006 | sqlite3OsLeaveMutex(); | ||
1007 | return 0; | ||
1008 | } | ||
1009 | s_ppTsd = (ThreadData **)pul; | ||
1010 | } | ||
1011 | sqlite3OsLeaveMutex(); | ||
1012 | } | ||
1013 | pTsd = *s_ppTsd; | ||
1014 | if( allocateFlag>0 ){ | ||
1015 | if( !pTsd ){ | ||
1016 | pTsd = sqlite3OsMalloc( sizeof(zeroData) ); | ||
1017 | if( pTsd ){ | ||
1018 | *pTsd = zeroData; | ||
1019 | *s_ppTsd = pTsd; | ||
1020 | TSD_COUNTER_INCR; | ||
1021 | } | ||
1022 | } | ||
1023 | }else if( pTsd!=0 && allocateFlag<0 | ||
1024 | && memcmp( pTsd, &zeroData, sizeof(ThreadData) )==0 ){ | ||
1025 | sqlite3OsFree(pTsd); | ||
1026 | *s_ppTsd = NULL; | ||
1027 | TSD_COUNTER_DECR; | ||
1028 | pTsd = 0; | ||
1029 | } | ||
1030 | return pTsd; | ||
1031 | } | ||
1032 | #endif /* OS_OS2 */ | ||