diff options
author | drh <drh@noemail.net> | 2004-06-29 03:29:00 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2004-06-29 03:29:00 +0000 |
commit | 5fdae7711a2fb3b367dba5b740fc0827f658ef5a (patch) | |
tree | ae0ea9727c593129b82ecc694da2afd424c881da | |
parent | f46188911d103c4a1f0e9f182783c5f1ec39294b (diff) | |
download | sqlite-5fdae7711a2fb3b367dba5b740fc0827f658ef5a.tar.gz sqlite-5fdae7711a2fb3b367dba5b740fc0827f658ef5a.zip |
Try to get threads working again on Linux. (CVS 1755)
FossilOrigin-Name: a8417cb83e9d070f46e7505f92a95f057b992658
-rw-r--r-- | manifest | 18 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/os_unix.c | 108 | ||||
-rw-r--r-- | test/threadtest1.c | 44 | ||||
-rw-r--r-- | test/threadtest2.c | 20 |
5 files changed, 139 insertions, 53 deletions
@@ -1,5 +1,5 @@ -C More\scoverage\stesting.\s(CVS\s1754) -D 2004-06-28T13:09:11 +C Try\sto\sget\sthreads\sworking\sagain\son\sLinux.\s(CVS\s1755) +D 2004-06-29T03:29:00 F Makefile.in cb7a9889c38723f72b2506c4236ff30a05ff172b F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -46,7 +46,7 @@ F src/os_mac.c 3d31e26be1411acfb7961033098631b4f3486fdf F src/os_mac.h 51d2445f47e182ed32d3bd6937f81070c6fd9bd4 F src/os_test.c ef353f73a2ad85a239d7a77c4a5df2e1377f3848 F src/os_test.h 6a26a4978492e4bbdbf385554958418ff02db162 -F src/os_unix.c 295d0d4fe8a3f531ae39623e2c8766b1823c0acd +F src/os_unix.c 2d787fd91a1b202ec6d0930b70982bc1ab816bb8 F src/os_unix.h 00c1f82b526ab2fb7ee5ddd555ea4ed68363c93a F src/os_win.c 84549f6cc815237533c5d0eb3697352b03478d96 F src/os_win.h babd4e912967c6b09088cfe38a45e8005a07ba44 @@ -162,8 +162,8 @@ F test/tclsqlite.test 2517b10ee2c806fb700548f54540aec7d62ed14a F test/temptable.test 63a16e3ad19adf073cfbcdf7624c92ac5236522c F test/tester.tcl f36cc22d0532725073ca78272d7834d56dceb6d9 F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35 -F test/threadtest1.c f5c7d628d5b23a1418816351b3cd8fe06e146250 -F test/threadtest2.c d94ca4114fd1504f7e0ae724bcd83d4b40931d86 +F test/threadtest1.c 1dd597369021ed72cd71c138a14a561d443f6edf +F test/threadtest2.c c38c9c1769725ebe240317dcc6bbed13c600ac98 F test/trans.test 29645b344d2b9b6792793562b12340177ddd8f96 F test/trigger1.test dc015c410161f1a6109fd52638dfac852e2a34de F test/trigger2.test 0767ab30cb5a2c8402c8524f3d566b410b6f5263 @@ -231,7 +231,7 @@ F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 563ba3ac02f64da27ab17f3edbe8e56bfd0293fb F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 168112c8b76af132c675a6508d3ee7764ef7a845 -R 00c6e5e0864fee373c498713d6bf3097 -U danielk1977 -Z c7d1e1ed337b1cd26cb4eaf2ffbfdf15 +P 332921041040b343b6b568685ff55d21a624f502 +R bdedb5a03f87b2291e0c7bb98d11a6cb +U drh +Z 23b6d4864c82370d472ac66ee3391b29 diff --git a/manifest.uuid b/manifest.uuid index a0ef54f1f..e7412246b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -332921041040b343b6b568685ff55d21a624f502
\ No newline at end of file +a8417cb83e9d070f46e7505f92a95f057b992658
\ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 61e8976c3..c2309495e 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -148,19 +148,38 @@ ** key because close() clears lock on all threads, not just the current ** thread. Were it not for this goofiness in linux threads, we could ** combine the lockInfo and openCnt structures into a single structure. +** +** 2004-Jun-28: +** On some versions of linux, threads can override each others locks. +** On others not. Sometimes you can change the behavior on the same +** system by setting the LD_ASSUME_KERNEL environment variable. The +** POSIX standard is silent as to which behavior is correct, as far +** as I can tell, so other versions of unix might show the same +** inconsistency. There is no little doubt in my mind that posix +** advisory locks and linux threads are profoundly broken. +** +** To work around the inconsistencies, we have to test at runtime +** whether or not threads can override each others locks. This test +** is run once, the first time any lock is attempted. A static +** variable is set to record the results of this test for future +** use. */ /* ** An instance of the following structure serves as the key used -** to locate a particular lockInfo structure given its inode. Note -** that we have to include the process ID as part of the key. On some -** threading implementations (ex: linux), each thread has a separate -** process ID. +** to locate a particular lockInfo structure given its inode. +** +** If threads cannot override each others locks, then we set the +** lockKey.tid field to the thread ID. If threads can override +** each others locks then tid is always set to zero. tid is also +** set to zero if we compile without threading support. */ struct lockKey { - dev_t dev; /* Device number */ - ino_t ino; /* Inode number */ - pid_t pid; /* Process ID */ + dev_t dev; /* Device number */ + ino_t ino; /* Inode number */ +#ifdef SQLITE_UNIX_THREADS + pthread_t tid; /* Thread ID or zero if threads cannot override each other */ +#endif }; /* @@ -182,7 +201,7 @@ struct lockInfo { /* ** An instance of the following structure serves as the key used ** to locate a particular openCnt structure given its inode. This -** is the same as the lockKey except that the process ID is omitted. +** is the same as the lockKey except that the thread ID is omitted. */ struct openKey { dev_t dev; /* Device number */ @@ -211,6 +230,70 @@ struct openCnt { static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; + +#ifdef SQLITE_UNIX_THREADS +/* +** This variable records whether or not threads can override each others +** locks. +** +** 0: No. Threads cannot override each others locks. +** 1: Yes. Threads can override each others locks. +** -1: We don't know yet. +*/ +static int threadsOverrideEachOthersLocks = -1; + +/* +** This structure holds information passed into individual test +** threads by the testThreadLockingBehavior() routine. +*/ +struct threadTestData { + int fd; /* File to be locked */ + struct flock lock; /* The locking operation */ + int result; /* Result of the locking operation */ +}; + +/* +** The testThreadLockingBehavior() routine launches two separate +** threads on this routine. This routine attempts to lock a file +** descriptor then returns. The success or failure of that attempt +** allows the testThreadLockingBehavior() procedure to determine +** whether or not threads can override each others locks. +*/ +static void *threadLockingTest(void *pArg){ + struct threadTestData *pData = (struct threadTestData*)pArg; + pData->result = fcntl(pData->fd, F_SETLK, &pData->lock); + return pArg; +} + +/* +** This procedure attempts to determine whether or not threads +** can override each others locks then sets the +** threadsOverrideEachOthersLocks variable appropriately. +*/ +static void testThreadLockingBehavior(fd_orig){ + int fd; + struct threadTestData d[2]; + pthread_t t[2]; + + fd = dup(fd_orig); + if( fd<0 ) return; + memset(d, 0, sizeof(d)); + d[0].fd = fd; + d[0].lock.l_type = F_RDLCK; + d[0].lock.l_len = 1; + d[0].lock.l_start = 0; + d[0].lock.l_whence = SEEK_SET; + d[1] = d[0]; + d[1].lock.l_type = F_WRLCK; + pthread_create(&t[0], 0, threadLockingTest, &d[0]); + pthread_create(&t[1], 0, threadLockingTest, &d[1]); + pthread_join(t[0], 0); + pthread_join(t[1], 0); + close(fd); + threadsOverrideEachOthersLocks = d[0].result==0 && d[1].result==0; +} +#endif /* SQLITE_UNIX_THREADS */ + /* ** Release a lockInfo structure previously allocated by findLockInfo(). */ @@ -244,7 +327,7 @@ static void releaseOpenCnt(struct openCnt *pOpen){ static int findLockInfo( int fd, /* The file descriptor used in the key */ struct lockInfo **ppLock, /* Return the lockInfo structure here */ - struct openCnt **ppOpen /* Return the openCnt structure here */ + struct openCnt **ppOpen /* Return the openCnt structure here */ ){ int rc; struct lockKey key1; @@ -257,7 +340,12 @@ static int findLockInfo( memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev; key1.ino = statbuf.st_ino; - key1.pid = getpid(); +#ifdef SQLITE_UNIX_THREADS + if( threadsOverrideEachOthersLocks<0 ){ + testThreadLockingBehavior(fd); + } + key1.tid = threadsOverrideEachOthersLocks ? 0 : pthread_self(); +#endif memset(&key2, 0, sizeof(key2)); key2.dev = statbuf.st_dev; key2.ino = statbuf.st_ino; diff --git a/test/threadtest1.c b/test/threadtest1.c index 5aad85ee3..f5ff112e6 100644 --- a/test/threadtest1.c +++ b/test/threadtest1.c @@ -41,17 +41,17 @@ static void Exit(int rc){ exit(rc); } -extern char *sqlite_mprintf(const char *zFormat, ...); -extern char *sqlite_vmprintf(const char *zFormat, va_list); +extern char *sqlite3_mprintf(const char *zFormat, ...); +extern char *sqlite3_vmprintf(const char *zFormat, va_list); /* ** When a lock occurs, yield. */ -static int db_is_locked(void *NotUsed, int iNotUsed){ +static int db_is_locked(void *NotUsed, int iCount){ /* sched_yield(); */ - if( verbose ) printf("BUSY %s\n", (char*)NotUsed); + if( verbose ) printf("BUSY %s #%d\n", (char*)NotUsed, iCount); usleep(100); - return 1; + return iCount<25; } /* @@ -90,7 +90,7 @@ static int db_query_callback( if( azArg==0 ) return 0; for(i=0; i<nArg; i++){ pResult->azElem[pResult->nElem++] = - sqlite_mprintf("%s",azArg[i] ? azArg[i] : ""); + sqlite3_mprintf("%s",azArg[i] ? azArg[i] : ""); } return 0; } @@ -106,15 +106,15 @@ char **db_query(sqlite *db, const char *zFile, const char *zFormat, ...){ va_list ap; struct QueryResult sResult; va_start(ap, zFormat); - zSql = sqlite_vmprintf(zFormat, ap); + zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); memset(&sResult, 0, sizeof(sResult)); sResult.zFile = zFile; if( verbose ) printf("QUERY %s: %s\n", zFile, zSql); - rc = sqlite_exec(db, zSql, db_query_callback, &sResult, &zErrMsg); + rc = sqlite3_exec(db, zSql, db_query_callback, &sResult, &zErrMsg); if( rc==SQLITE_SCHEMA ){ if( zErrMsg ) free(zErrMsg); - rc = sqlite_exec(db, zSql, db_query_callback, &sResult, &zErrMsg); + rc = sqlite3_exec(db, zSql, db_query_callback, &sResult, &zErrMsg); } if( verbose ) printf("DONE %s %s\n", zFile, zSql); if( zErrMsg ){ @@ -123,7 +123,7 @@ char **db_query(sqlite *db, const char *zFile, const char *zFormat, ...){ free(zSql); Exit(1); } - sqlite_freemem(zSql); + sqlite3_free(zSql); if( sResult.azElem==0 ){ db_query_callback(&sResult, 0, 0, 0); } @@ -140,22 +140,20 @@ void db_execute(sqlite *db, const char *zFile, const char *zFormat, ...){ char *zErrMsg = 0; va_list ap; va_start(ap, zFormat); - zSql = sqlite_vmprintf(zFormat, ap); + zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( verbose ) printf("EXEC %s: %s\n", zFile, zSql); - rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg); - while( rc==SQLITE_SCHEMA ){ - if( zErrMsg ) free(zErrMsg); - rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg); - } + do{ + rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg); + }while( rc==SQLITE_BUSY ); if( verbose ) printf("DONE %s: %s\n", zFile, zSql); if( zErrMsg ){ fprintf(stdout,"%s: command failed: %s - %s\n", zFile, zSql, zErrMsg); free(zErrMsg); - sqlite_freemem(zSql); + sqlite3_free(zSql); Exit(1); } - sqlite_freemem(zSql); + sqlite3_free(zSql); } /* @@ -164,7 +162,7 @@ void db_execute(sqlite *db, const char *zFile, const char *zFormat, ...){ void db_query_free(char **az){ int i; for(i=0; az[i]; i++){ - sqlite_freemem(az[i]); + sqlite3_free(az[i]); } free(az); } @@ -207,12 +205,12 @@ static void *worker_bee(void *pArg){ printf("%s: START\n", zFilename); fflush(stdout); for(cnt=0; cnt<10; cnt++){ - db = sqlite_open(&zFilename[2], 0, &azErr); + sqlite3_open(&zFilename[2], &db); if( db==0 ){ fprintf(stdout,"%s: can't open\n", zFilename); Exit(1); } - sqlite_busy_handler(db, db_is_locked, zFilename); + sqlite3_busy_handler(db, db_is_locked, zFilename); db_execute(db, zFilename, "CREATE TABLE t%d(a,b,c);", t); for(i=1; i<=100; i++){ db_execute(db, zFilename, "INSERT INTO t%d VALUES(%d,%d,%d);", @@ -233,7 +231,7 @@ static void *worker_bee(void *pArg){ db_check(zFilename, "readback", az, z1, z2, 0); } db_execute(db, zFilename, "DROP TABLE t%d;", t); - sqlite_close(db); + sqlite3_close(db); } printf("%s: END\n", zFilename); /* unlink(zFilename); */ @@ -263,7 +261,7 @@ int main(int argc, char **argv){ unlink(zBuf); } for(i=0; i<n; i++){ - zFile = sqlite_mprintf("%d.testdb-%d", i%2+1, (i+2)/2); + zFile = sqlite3_mprintf("%d.testdb-%d", i%2+1, (i+2)/2); unlink(zFile); pthread_create(&id, 0, worker_bee, (void*)zFile); pthread_detach(id); diff --git a/test/threadtest2.c b/test/threadtest2.c index 7b08d37b9..deaffdaf0 100644 --- a/test/threadtest2.c +++ b/test/threadtest2.c @@ -57,12 +57,12 @@ int integrity_check(sqlite *db){ int rc; if( all_stop ) return 0; /* fprintf(stderr,"pid=%d: CHECK\n", getpid()); */ - rc = sqlite_exec(db, "pragma integrity_check", check_callback, 0, 0); + rc = sqlite3_exec(db, "pragma integrity_check", check_callback, 0, 0); if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ fprintf(stderr,"pid=%d, Integrity check returns %d\n", getpid(), rc); } if( all_stop ){ - sqlite_exec(db, "pragma integrity_check", check_callback, 0, 0); + sqlite3_exec(db, "pragma integrity_check", check_callback, 0, 0); } return 0; } @@ -76,14 +76,14 @@ void *worker(void *notUsed){ int cnt = 0; while( !all_stop && cnt++<10000 ){ if( cnt%1000==0 ) printf("pid=%d: %d\n", getpid(), cnt); - while( (db = sqlite_open(DB_FILE, 0, 0))==0 ) sched_yield(); - sqlite_exec(db, "PRAGMA synchronous=OFF", 0, 0, 0); + while( (sqlite3_open(DB_FILE, &db))!=SQLITE_OK ) sched_yield(); + sqlite3_exec(db, "PRAGMA synchronous=OFF", 0, 0, 0); integrity_check(db); - if( all_stop ){ sqlite_close(db); break; } + if( all_stop ){ sqlite3_close(db); break; } /* fprintf(stderr, "pid=%d: BEGIN\n", getpid()); */ - rc = sqlite_exec(db, "INSERT INTO t1 VALUES('bogus data')", 0, 0, 0); + rc = sqlite3_exec(db, "INSERT INTO t1 VALUES('bogus data')", 0, 0, 0); /* fprintf(stderr, "pid=%d: END rc=%d\n", getpid(), rc); */ - sqlite_close(db); + sqlite3_close(db); } return 0; } @@ -97,17 +97,17 @@ int main(int argc, char **argv){ pthread_t aThread[5]; if( strcmp(DB_FILE,":memory:") ) unlink(DB_FILE); - db = sqlite_open(DB_FILE, 0, 0); + sqlite3_open(DB_FILE, &db); if( db==0 ){ fprintf(stderr,"unable to initialize database\n"); exit(1); } - rc = sqlite_exec(db, "CREATE TABLE t1(x);", 0,0,0); + rc = sqlite3_exec(db, "CREATE TABLE t1(x);", 0,0,0); if( rc ){ fprintf(stderr,"cannot create table t1: %d\n", rc); exit(1); } - sqlite_close(db); + sqlite3_close(db); for(i=0; i<sizeof(aThread)/sizeof(aThread[0]); i++){ pthread_create(&aThread[i], 0, worker, 0); } |