-C Fix\stypo\son\shomepage\s(CVS\s1519)
-D 2004-06-01T12:59:50
+C Unix\sversion\sof\ssqlite3OsLock().\s(CVS\s1520)
+D 2004-06-01T14:09:29
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
F src/main.c 66c6c35e94f57a7505f7f44b5a9504fb60ca0730
F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481
-F src/os.h ab42f4a7c4c716f26b988e759b6e12085a3bfc67
+F src/os.h 833b9639720d1602d9bfa4ca69c615ec2bfe625a
F src/os_common.h 744286a27de55c52f1b18921e8d17abbf7fafc0f
F src/os_mac.c b823874690615ace0dd520d3ad1fe8bfd864b7e0
F src/os_mac.h 51d2445f47e182ed32d3bd6937f81070c6fd9bd4
-F src/os_unix.c 585665eccd31a9bb4dc090bc6b5e29d8d42899f0
+F src/os_unix.c 3dc2868d7ff477323f2eaedda0e05921afb6f124
F src/os_unix.h 426e1480f0847a7f8ba22aa9ac5115520875610b
F src/os_win.c 92b51a38437b98d8aa3ac05b57c71e1d1092e5be
F src/os_win.h 5d41af24caaef6c13a2d8e2399caa1c57d45c84d
F src/sqliteInt.h 8a3a6dc8ef5141563698a3b7a62fca7158cff1f5
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
F src/tclsqlite.c ed8663e7703346ace72ca3899dba15dbfc0883d7
-F src/test1.c 42c494918ecfab5a86586a28a66a73968312aad1
+F src/test1.c 4a3cc1b628a29f24c0a43227a035d0f2a96eb634
F src/test2.c 6195a1ca2c8d0d2d93644e86da3289b403486872
F src/test3.c 86117b74ec7353d76f5cd85c144c7cda23a7e11b
F src/test4.c caf675e443460ec76b04d78e1688986c17c82cec
F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 915cba57123f859c7f128bd52580573877c502ba
-R 869771be1ad6b0ff5d2cfdaa96e9bfc9
-U drh
-Z b8d78d36bfca5048d38c8cf79e8d6789
+P a84ece250035d02e399ec208aded524c20c12737
+R 3b5d7842c2050c5f20aa6a72a163fd62
+U danielk1977
+Z e93eb17e32e32c7486f10dc44fff52c2
-a84ece250035d02e399ec208aded524c20c12737
\ No newline at end of file
+023d1760c1a720632b25c98d14bf521ab91861e2
\ No newline at end of file
# define TEMP_FILE_PREFIX "sqlite_"
#endif
+/*
+** The following values may be passed as the second argument to
+** sqlite3OsLock().
+*/
+#define SHARED_LOCK 1
+#define RESERVED_LOCK 2
+#define PENDING_LOCK 3
+#define EXCLUSIVE_LOCK 4
int sqlite3OsDelete(const char*);
int sqlite3OsFileExists(const char*);
void sqlite3OsEnterMutex(void);
void sqlite3OsLeaveMutex(void);
char *sqlite3OsFullPathname(const char*);
+int sqlite3OsLock(OsFile*, int);
#endif /* _SQLITE_OS_H_ */
struct lockInfo {
struct lockKey key; /* The lookup key */
int cnt; /* 0: unlocked. -1: write lock. 1...: read lock. */
+ int locktype; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
int nRef; /* Number of pointers to this structure */
};
pLock->key = key1;
pLock->nRef = 1;
pLock->cnt = 0;
+ pLock->locktype = 0;
pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
if( pOld!=0 ){
assert( pOld==pLock );
*/
int sqlite3OsReadLock(OsFile *id){
int rc;
- sqlite3OsEnterMutex();
- if( id->pLock->cnt>0 ){
- if( !id->locked ){
- id->pLock->cnt++;
- id->locked = 1;
- id->pOpen->nLock++;
- }
- rc = SQLITE_OK;
- }else if( id->locked || id->pLock->cnt==0 ){
- struct flock lock;
- int s;
- lock.l_type = F_RDLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = lock.l_len = 0L;
- s = fcntl(id->fd, F_SETLK, &lock);
- if( s!=0 ){
- rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
- }else{
- rc = SQLITE_OK;
- if( !id->locked ){
- id->pOpen->nLock++;
- id->locked = 1;
- }
- id->pLock->cnt = 1;
- }
- }else{
- rc = SQLITE_BUSY;
- }
- sqlite3OsLeaveMutex();
- return rc;
+ return sqlite3OsLock(id, SHARED_LOCK);
}
/*
*/
int sqlite3OsWriteLock(OsFile *id){
int rc;
+ return sqlite3OsLock(id, EXCLUSIVE_LOCK);
+}
+
+/*
+** Lock the file with the lock specified by parameter locktype - one
+** of the following:
+**
+** SHARED_LOCK
+** RESERVED_LOCK
+** PENDING_LOCK
+** EXCLUSIVE_LOCK
+*/
+int sqlite3OsLock(OsFile *id, int locktype){
+ int rc = SQLITE_OK;
+ struct lockInfo *pLock = id->pLock;
+ struct flock lock;
+ int s;
+
+ /* It is an error to request any kind of lock before a shared lock */
+ if( locktype>SHARED_LOCK && id->locked==0 ){
+ rc = sqlite3OsLock(id, SHARED_LOCK);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ assert( locktype==SHARED_LOCK || id->locked!=0 );
+
+ /* If there is already a lock of this type or more restrictive on the
+ ** OsFile, do nothing. Don't use the end_lock: exit path, as
+ ** sqlite3OsEnterMutex() hasn't been called yet.
+ */
+ if( id->locked>=locktype ){
+ return SQLITE_OK;
+ }
+
sqlite3OsEnterMutex();
- if( id->pLock->cnt==0 || (id->pLock->cnt==1 && id->locked==1) ){
- struct flock lock;
- int s;
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = lock.l_len = 0L;
+
+ /* If some thread using this PID has a lock via a different OsFile*
+ ** handle that precludes the requested lock, return BUSY.
+ */
+ if( (id->locked!=pLock->locktype &&
+ (pLock->locktype>RESERVED_LOCK || locktype!=SHARED_LOCK)) ||
+ (locktype>RESERVED_LOCK && pLock->cnt>1)
+ ){
+ rc = SQLITE_BUSY;
+ goto end_lock;
+ }
+
+ /* If a SHARED lock is requested, and some thread using this PID already
+ ** has a SHARED or RESERVED lock, then increment reference counts and
+ ** return SQLITE_OK.
+ */
+ if( locktype==SHARED_LOCK &&
+ (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
+ assert( locktype==SHARED_LOCK );
+ assert( id->locked==0 );
+ id->locked = SHARED_LOCK;
+ pLock->cnt++;
+ id->pOpen->nLock++;
+ goto end_lock;
+ }
+
+ lock.l_len = 1L;
+ lock.l_whence = SEEK_SET;
+
+ /* If control gets to this point, then actually go ahead and make
+ ** operating system calls for the specified lock.
+ */
+ if( locktype==SHARED_LOCK ){
+ assert( pLock->cnt==0 );
+ assert( id->pOpen->nLock==0 );
+ assert( pLock->locktype==0 );
+
+ /* Grab a read-lock on byte 2. This ensures that no other process
+ ** has a PENDING lock.
+ */
+ lock.l_type = F_RDLCK;
+ lock.l_start = 2;
s = fcntl(id->fd, F_SETLK, &lock);
- if( s!=0 ){
+ if( s ){
+ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
+ goto end_lock;
+ }
+
+ /* Now get a read-lock on byte 0 and renege on the byte 2 lock. */
+ lock.l_start = 0;
+ s = fcntl(id->fd, F_SETLK, &lock);
+ lock.l_start = 2;
+ lock.l_type = F_UNLCK;
+ fcntl(id->fd, F_SETLK, &lock);
+ if( s ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
}else{
- rc = SQLITE_OK;
- if( !id->locked ){
- id->pOpen->nLock++;
- id->locked = 1;
- }
- id->pLock->cnt = -1;
+ id->locked = SHARED_LOCK;
+ id->pOpen->nLock = 1;
+ pLock->cnt = 1;
}
}else{
- rc = SQLITE_BUSY;
+ /* The request was for a RESERVED, PENDING or EXCLUSIVE lock. It is
+ ** assumed that there is a SHARED or greater lock on the file
+ ** already.
+ */
+ assert( 0!=id->locked );
+ lock.l_type = F_WRLCK;
+ switch( locktype ){
+ case RESERVED_LOCK:
+ lock.l_start = 1;
+ break;
+ case PENDING_LOCK:
+ lock.l_start = 2;
+ break;
+ case EXCLUSIVE_LOCK:
+ lock.l_start = 0;
+ break;
+ default:
+ assert(0);
+ }
+ s = fcntl(id->fd, F_SETLK, &lock);
+ if( s ){
+ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
+ }
}
+
+ id->locked = locktype;
+ pLock->locktype = locktype;
+ assert(pLock->locktype==RESERVED_LOCK||(id->pOpen->nLock==1&&pLock->cnt==1));
+
+end_lock:
sqlite3OsLeaveMutex();
return rc;
}
sqlite3OsEnterMutex();
assert( id->pLock->cnt!=0 );
if( id->pLock->cnt>1 ){
+ id->locked = 0;
id->pLock->cnt--;
rc = SQLITE_OK;
}else{
}else{
rc = SQLITE_OK;
id->pLock->cnt = 0;
+ id->pLock->locktype = 0;
+ id->locked = 0;
}
}
if( rc==SQLITE_OK ){
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test1.c,v 1.68 2004/05/31 23:56:43 danielk1977 Exp $
+** $Id: test1.c,v 1.69 2004/06/01 14:09:29 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
return TCL_OK;
}
+/*
+** Decode a pointer to an sqlite3_stmt object.
+*/
+static int getFilePointer(
+ Tcl_Interp *interp,
+ const char *zArg,
+ OsFile **ppFile
+){
+ if( sscanf(zArg, PTR_FMT, (void**)ppFile)!=1 ){
+ Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
/*
** Generate a text representation of a pointer that can be understood
** by the getDbPointer and getVmPointer routines above.
return TCL_OK;
}
+/*
+** Usage: sqlite3OsOpenReadWrite <filename>
+*/
+static int test_sqlite3OsOpenReadWrite(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ OsFile * pFile;
+ int rc;
+ int dummy;
+ char zBuf[100];
+
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " filename", 0);
+ return TCL_ERROR;
+ }
+
+ pFile = sqliteMalloc(sizeof(OsFile));
+ rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
+ if( rc!=SQLITE_OK ){
+ sqliteFree(pFile);
+ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ makePointerStr(interp, zBuf, pFile);
+ Tcl_SetResult(interp, zBuf, 0);
+ return TCL_ERROR;
+}
+
+/*
+** Usage: sqlite3OsClose <file handle>
+*/
+static int test_sqlite3OsClose(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ OsFile * pFile;
+ int rc;
+
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " filehandle", 0);
+ return TCL_ERROR;
+ }
+
+ if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
+ return TCL_ERROR;
+ }
+ rc = sqlite3OsClose(pFile);
+ if( rc!=SQLITE_OK ){
+ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ sqliteFree(pFile);
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3OsLock <file handle> <locktype>
+*/
+static int test_sqlite3OsLock(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ OsFile * pFile;
+ int rc;
+ if( objc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]),
+ " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
+ return TCL_ERROR;
+ }
+
+ if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
+ return TCL_ERROR;
+ }
+
+ if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){
+ rc = sqlite3OsLock(pFile, SHARED_LOCK);
+ }
+ else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){
+ rc = sqlite3OsLock(pFile, RESERVED_LOCK);
+ }
+ else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){
+ rc = sqlite3OsLock(pFile, PENDING_LOCK);
+ }
+ else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){
+ rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK);
+ }else{
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]),
+ " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
+ return TCL_ERROR;
+ }
+
+ if( rc!=SQLITE_OK ){
+ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3OsUnlock <file handle>
+*/
+static int test_sqlite3OsUnlock(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ OsFile * pFile;
+ int rc;
+
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " filehandle", 0);
+ return TCL_ERROR;
+ }
+
+ if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
+ return TCL_ERROR;
+ }
+ rc = sqlite3OsUnlock(pFile);
+ if( rc!=SQLITE_OK ){
+ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
/*
** Register commands with the TCL interpreter.
{ "sqlite3_column_decltype16", test_stmt_utf16,sqlite3_column_decltype16},
{ "sqlite3_column_name16", test_stmt_utf16, sqlite3_column_name16},
+ /* Functions from os.h */
+ { "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
+ { "sqlite3OsClose", test_sqlite3OsClose, 0 },
+ { "sqlite3OsLock", test_sqlite3OsLock, 0 },
+ { "sqlite3OsUnlock", test_sqlite3OsUnlock, 0 },
+
};
int i;