📄 os_os2.c
字号:
/*** 2006 Feb 14**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.************************************************************************************ This file contains code that is specific to OS/2.**** $Id: os_os2.c,v 1.56 2008/08/22 13:47:57 pweilbacher Exp $*/#include "sqliteInt.h"#if SQLITE_OS_OS2/*** A Note About Memory Allocation:**** This driver uses malloc()/free() directly rather than going through** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers** are designed for use on embedded systems where memory is scarce and** malloc failures happen frequently. OS/2 does not typically run on** embedded systems, and when it does the developers normally have bigger** problems to worry about than running out of memory. So there is not** a compelling need to use the wrappers.**** But there is a good reason to not use the wrappers. If we use the** wrappers then we will get simulated malloc() failures within this** driver. And that causes all kinds of problems for our tests. We** could enhance SQLite to deal with simulated malloc failures within** the OS driver, but the code to deal with those failure would not** be exercised on Linux (which does not need to malloc() in the driver)** and so we would have difficulty writing coverage tests for that** code. Better to leave the code out, we think.**** The point of this discussion is as follows: When creating a new** OS layer for an embedded system, if you use this file as an example,** avoid the use of malloc()/free(). Those routines work ok on OS/2** desktops but not so well in embedded systems.*//*** Macros used to determine whether or not to use threads.*/#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE# define SQLITE_OS2_THREADS 1#endif/*** Include code that is common to all os_*.c files*/#include "os_common.h"/*** The os2File structure is subclass of sqlite3_file specific for the OS/2** protability layer.*/typedef struct os2File os2File;struct os2File { const sqlite3_io_methods *pMethod; /* Always the first entry */ HFILE h; /* Handle for accessing the file */ char* pathToDel; /* Name of file to delete on close, NULL if not */ unsigned char locktype; /* Type of lock currently held on this file */};#define LOCK_TIMEOUT 10L /* the default locking timeout *//******************************************************************************* The next group of routines implement the I/O methods specified** by the sqlite3_io_methods object.******************************************************************************//*** Close a file.*/static int os2Close( sqlite3_file *id ){ APIRET rc = NO_ERROR; os2File *pFile; if( id && (pFile = (os2File*)id) != 0 ){ OSTRACE2( "CLOSE %d\n", pFile->h ); rc = DosClose( pFile->h ); pFile->locktype = NO_LOCK; if( pFile->pathToDel != NULL ){ rc = DosForceDelete( (PSZ)pFile->pathToDel ); free( pFile->pathToDel ); pFile->pathToDel = NULL; } id = 0; OpenCounter( -1 ); } return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;}/*** Read data from a file into a buffer. Return SQLITE_OK if all** bytes were read successfully and SQLITE_IOERR if anything goes** wrong.*/static int os2Read( sqlite3_file *id, /* File to read from */ void *pBuf, /* Write content into this buffer */ int amt, /* Number of bytes to read */ sqlite3_int64 offset /* Begin reading at this offset */){ ULONG fileLocation = 0L; ULONG got; os2File *pFile = (os2File*)id; assert( id!=0 ); SimulateIOError( return SQLITE_IOERR_READ ); OSTRACE3( "READ %d lock=%d\n", pFile->h, pFile->locktype ); if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){ return SQLITE_IOERR; } if( DosRead( pFile->h, pBuf, amt, &got ) != NO_ERROR ){ return SQLITE_IOERR_READ; } if( got == (ULONG)amt ) return SQLITE_OK; else { memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; }}/*** Write data from a buffer into a file. Return SQLITE_OK on success** or some other error code on failure.*/static int os2Write( sqlite3_file *id, /* File to write into */ const void *pBuf, /* The bytes to be written */ int amt, /* Number of bytes to write */ sqlite3_int64 offset /* Offset into the file to begin writing at */){ ULONG fileLocation = 0L; APIRET rc = NO_ERROR; ULONG wrote; os2File *pFile = (os2File*)id; assert( id!=0 ); SimulateIOError( return SQLITE_IOERR_WRITE ); SimulateDiskfullError( return SQLITE_FULL ); OSTRACE3( "WRITE %d lock=%d\n", pFile->h, pFile->locktype ); if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){ return SQLITE_IOERR; } assert( amt>0 ); while( amt > 0 && ( rc = DosWrite( pFile->h, (PVOID)pBuf, amt, &wrote ) ) == NO_ERROR && wrote > 0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK;}/*** Truncate an open file to a specified size*/static int os2Truncate( sqlite3_file *id, i64 nByte ){ APIRET rc = NO_ERROR; os2File *pFile = (os2File*)id; OSTRACE3( "TRUNCATE %d %lld\n", pFile->h, nByte ); SimulateIOError( return SQLITE_IOERR_TRUNCATE ); rc = DosSetFileSize( pFile->h, nByte ); return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;}#ifdef SQLITE_TEST/*** Count the number of fullsyncs and normal syncs. This is used to test** that syncs and fullsyncs are occuring at the right times.*/int sqlite3_sync_count = 0;int sqlite3_fullsync_count = 0;#endif/*** Make sure all writes to a particular file are committed to disk.*/static int os2Sync( sqlite3_file *id, int flags ){ os2File *pFile = (os2File*)id; OSTRACE3( "SYNC %d lock=%d\n", pFile->h, pFile->locktype );#ifdef SQLITE_TEST if( flags & SQLITE_SYNC_FULL){ sqlite3_fullsync_count++; } sqlite3_sync_count++;#endif return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;}/*** Determine the current size of a file in bytes*/static int os2FileSize( sqlite3_file *id, sqlite3_int64 *pSize ){ APIRET rc = NO_ERROR; FILESTATUS3 fsts3FileInfo; memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo)); assert( id!=0 ); SimulateIOError( return SQLITE_IOERR ); rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) ); if( rc == NO_ERROR ){ *pSize = fsts3FileInfo.cbFile; return SQLITE_OK; }else{ return SQLITE_IOERR; }}/*** Acquire a reader lock.*/static int getReadLock( os2File *pFile ){ FILELOCK LockArea, UnlockArea; APIRET res; memset(&LockArea, 0, sizeof(LockArea)); memset(&UnlockArea, 0, sizeof(UnlockArea)); LockArea.lOffset = SHARED_FIRST; LockArea.lRange = SHARED_SIZE; UnlockArea.lOffset = 0L; UnlockArea.lRange = 0L; res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L ); OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res ); return res;}/*** Undo a readlock*/static int unlockReadLock( os2File *id ){ FILELOCK LockArea, UnlockArea; APIRET res; memset(&LockArea, 0, sizeof(LockArea)); memset(&UnlockArea, 0, sizeof(UnlockArea)); LockArea.lOffset = 0L; LockArea.lRange = 0L; UnlockArea.lOffset = SHARED_FIRST; UnlockArea.lRange = SHARED_SIZE; res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L ); OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res ); return res;}/*** Lock the file with the lock specified by parameter locktype - one** of the following:**** (1) SHARED_LOCK** (2) RESERVED_LOCK** (3) PENDING_LOCK** (4) EXCLUSIVE_LOCK**** Sometimes when requesting one lock state, additional lock states** are inserted in between. The locking might fail on one of the later** transitions leaving the lock state different from what it started but** still short of its goal. The following chart shows the allowed** transitions and the inserted intermediate states:**** UNLOCKED -> SHARED** SHARED -> RESERVED** SHARED -> (PENDING) -> EXCLUSIVE** RESERVED -> (PENDING) -> EXCLUSIVE** PENDING -> EXCLUSIVE**** This routine will only increase a lock. The os2Unlock() routine** erases all locks at once and returns us immediately to locking level 0.** It is not possible to lower the locking level one step at a time. You** must go straight to locking level 0.*/static int os2Lock( sqlite3_file *id, int locktype ){ int rc = SQLITE_OK; /* Return code from subroutines */ APIRET res = NO_ERROR; /* Result of an OS/2 lock call */ int newLocktype; /* Set pFile->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ FILELOCK LockArea, UnlockArea; os2File *pFile = (os2File*)id; memset(&LockArea, 0, sizeof(LockArea)); memset(&UnlockArea, 0, sizeof(UnlockArea)); assert( pFile!=0 ); OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ); /* If there is already a lock of this type or more restrictive on the ** os2File, do nothing. Don't use the end_lock: exit path, as ** sqlite3_mutex_enter() hasn't been called yet. */ if( pFile->locktype>=locktype ){ OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype ); return SQLITE_OK; } /* Make sure the locking sequence is correct */ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of ** the PENDING_LOCK byte is temporary. */ newLocktype = pFile->locktype; if( pFile->locktype==NO_LOCK || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) ){ LockArea.lOffset = PENDING_BYTE; LockArea.lRange = 1L; UnlockArea.lOffset = 0L; UnlockArea.lRange = 0L; /* wait longer than LOCK_TIMEOUT here not to have to try multiple times */ res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L ); if( res == NO_ERROR ){ gotPendingLock = 1; OSTRACE3( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res ); } } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res == NO_ERROR ){ assert( pFile->locktype==NO_LOCK ); res = getReadLock(pFile); if( res == NO_ERROR ){ newLocktype = SHARED_LOCK; } OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res ); } /* Acquire a RESERVED lock */ if( locktype==RESERVED_LOCK && res == NO_ERROR ){ assert( pFile->locktype==SHARED_LOCK ); LockArea.lOffset = RESERVED_BYTE; LockArea.lRange = 1L; UnlockArea.lOffset = 0L; UnlockArea.lRange = 0L; res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); if( res == NO_ERROR ){ newLocktype = RESERVED_LOCK; } OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res ); } /* Acquire a PENDING lock */ if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){ newLocktype = PENDING_LOCK; gotPendingLock = 0; OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h ); } /* Acquire an EXCLUSIVE lock */ if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){ assert( pFile->locktype>=SHARED_LOCK ); res = unlockReadLock(pFile); OSTRACE2( "unreadlock = %d\n", res ); LockArea.lOffset = SHARED_FIRST; LockArea.lRange = SHARED_SIZE; UnlockArea.lOffset = 0L;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -