Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Trying to open a transaction in one thread and close it in another is a misuse with LinuxThreads. Doing so may cause memory and file-descriptors to be leaked. Update an assert() and some test cases to account for this. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
ef99eb57c536d82e7c19fd3d990c1779 |
User & Date: | dan 2009-09-09 18:46:53.000 |
Context
2009-09-10
| ||
02:54 | Reduce default SQLITE_MAX_TRIGGER_DEPTH when SQLITE_SMALL_STACK is defined. (check-in: 913fb70ea8 user: shane tags: trunk) | |
2009-09-09
| ||
18:46 | Trying to open a transaction in one thread and close it in another is a misuse with LinuxThreads. Doing so may cause memory and file-descriptors to be leaked. Update an assert() and some test cases to account for this. (check-in: ef99eb57c5 user: dan tags: trunk) | |
16:10 | Suppress some harmless compiler warnings. (check-in: f0c72a53c5 user: drh tags: trunk) | |
Changes
Changes to src/os_unix.c.
︙ | ︙ | |||
921 922 923 924 925 926 927 | assert( openList==pOpen ); openList = pOpen->pNext; } if( pOpen->pNext ){ assert( pOpen->pNext->pPrev==pOpen ); pOpen->pNext->pPrev = pOpen->pPrev; } | | > > > > > > > > | 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 | assert( openList==pOpen ); openList = pOpen->pNext; } if( pOpen->pNext ){ assert( pOpen->pNext->pPrev==pOpen ); pOpen->pNext->pPrev = pOpen->pPrev; } 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); } } } /* ** Given a file descriptor, locate unixLockInfo and unixOpenCnt structures that |
︙ | ︙ |
Changes to src/test4.c.
︙ | ︙ | |||
645 646 647 648 649 650 651 652 653 654 655 656 657 658 | } thread_wait(&threadset[i]); sqlite3TestMakePointerStr(interp, zBuf, threadset[i].db); threadset[i].db = 0; Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_OK; } /* ** Usage: thread_stmt_get ID ** ** Return the database stmt pointer for the given thread. Then ** remove the pointer from the thread itself. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 | } thread_wait(&threadset[i]); sqlite3TestMakePointerStr(interp, zBuf, threadset[i].db); threadset[i].db = 0; Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_OK; } /* ** 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 ** remove the pointer from the thread itself. */ |
︙ | ︙ | |||
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 | { "thread_result", (Tcl_CmdProc*)tcl_thread_result }, { "thread_error", (Tcl_CmdProc*)tcl_thread_error }, { "thread_compile", (Tcl_CmdProc*)tcl_thread_compile }, { "thread_step", (Tcl_CmdProc*)tcl_thread_step }, { "thread_finalize", (Tcl_CmdProc*)tcl_thread_finalize }, { "thread_swap", (Tcl_CmdProc*)tcl_thread_swap }, { "thread_db_get", (Tcl_CmdProc*)tcl_thread_db_get }, { "thread_stmt_get", (Tcl_CmdProc*)tcl_thread_stmt_get }, }; int i; for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); } return TCL_OK; } #else int Sqlitetest4_Init(Tcl_Interp *interp){ return TCL_OK; } #endif /* SQLITE_OS_UNIX */ | > | 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 | { "thread_result", (Tcl_CmdProc*)tcl_thread_result }, { "thread_error", (Tcl_CmdProc*)tcl_thread_error }, { "thread_compile", (Tcl_CmdProc*)tcl_thread_compile }, { "thread_step", (Tcl_CmdProc*)tcl_thread_step }, { "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; for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); } return TCL_OK; } #else int Sqlitetest4_Init(Tcl_Interp *interp){ return TCL_OK; } #endif /* SQLITE_OS_UNIX */ |
Changes to test/thread2.test.
︙ | ︙ | |||
188 189 190 191 192 193 194 | do_test thread2-3.20 { thread_create A test.db thread_compile A {SELECT a FROM t1 LIMIT 3} thread_step A set STMT [thread_stmt_get A] set DB [thread_db_get A] | < < < > | > | < < < | > | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | do_test thread2-3.20 { thread_create A test.db thread_compile A {SELECT a FROM t1 LIMIT 3} thread_step A set STMT [thread_stmt_get A] set DB [thread_db_get A] sqlite3_step $STMT } SQLITE_ROW do_test thread2-3.22 { sqlite3_column_int $STMT 0 } 2 do_test thread2-3.23 { # The unlock fails here. But because we never check the return # code from sqlite3OsUnlock (because we cannot do anything about it # if it fails) we do not realize that an error has occurred. breakpoint sqlite3_finalize $STMT } SQLITE_OK do_test thread2-3.25 { thread_db_put A $DB thread_halt A } {} do_test thread2-3.30 { thread_create A test.db thread_compile A {BEGIN} thread_step A thread_finalize A thread_compile A {SELECT a FROM t1 LIMIT 1} thread_step A thread_finalize A set DB [thread_db_get A] set STMT [sqlite3_prepare $DB {INSERT INTO t1 VALUES(99,'error')} -1 TAIL] sqlite3_step $STMT } SQLITE_ERROR do_test thread2-3.32 { sqlite3_finalize $STMT } SQLITE_MISUSE do_test thread2-3.33 { thread_db_put A $DB thread_halt A } {} # VERY important to set the override flag back to its true value. # set threadsOverrideEachOthersLocks $orig_threadOverride # Also important to halt the worker threads, which are using spin # locks and eating away CPU cycles. |
︙ | ︙ |