aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/os_unix.c10
-rw-r--r--src/test4.c31
2 files changed, 40 insertions, 1 deletions
diff --git a/src/os_unix.c b/src/os_unix.c
index 9b6afe537..a45aaa1d7 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -925,7 +925,15 @@ static void releaseOpenCnt(struct unixOpenCnt *pOpen){
assert( pOpen->pNext->pPrev==pOpen );
pOpen->pNext->pPrev = pOpen->pPrev;
}
- assert( !pOpen->pUnused );
+ assert( !pOpen->pUnused || threadsOverrideEachOthersLocks==0 );
+
+ /* If pOpen->pUnused is not null, then memory and file-descriptors
+ ** are leaked.
+ **
+ ** This will only happen if, under Linuxthreads, the user has opened
+ ** a transaction in one thread, then attempts to close the database
+ ** handle from another thread (without first unlocking the db file).
+ ** This is a misuse. */
sqlite3_free(pOpen);
}
}
diff --git a/src/test4.c b/src/test4.c
index c51d2a640..654b572db 100644
--- a/src/test4.c
+++ b/src/test4.c
@@ -651,6 +651,36 @@ static int tcl_thread_db_get(
}
/*
+** Usage: thread_db_put ID DB
+**
+*/
+static int tcl_thread_db_put(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ const char **argv /* Text of each argument */
+){
+ int i;
+ extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*);
+ extern void *sqlite3TestTextToPtr(const char *);
+ if( argc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ID DB", 0);
+ return TCL_ERROR;
+ }
+ i = parse_thread_id(interp, argv[1]);
+ if( i<0 ) return TCL_ERROR;
+ if( !threadset[i].busy ){
+ Tcl_AppendResult(interp, "no such thread", 0);
+ return TCL_ERROR;
+ }
+ thread_wait(&threadset[i]);
+ assert( !threadset[i].db );
+ threadset[i].db = (sqlite3*)sqlite3TestTextToPtr(argv[2]);
+ return TCL_OK;
+}
+
+/*
** Usage: thread_stmt_get ID
**
** Return the database stmt pointer for the given thread. Then
@@ -704,6 +734,7 @@ int Sqlitetest4_Init(Tcl_Interp *interp){
{ "thread_finalize", (Tcl_CmdProc*)tcl_thread_finalize },
{ "thread_swap", (Tcl_CmdProc*)tcl_thread_swap },
{ "thread_db_get", (Tcl_CmdProc*)tcl_thread_db_get },
+ { "thread_db_put", (Tcl_CmdProc*)tcl_thread_db_put },
{ "thread_stmt_get", (Tcl_CmdProc*)tcl_thread_stmt_get },
};
int i;