aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2004-06-29 03:29:00 +0000
committerdrh <drh@noemail.net>2004-06-29 03:29:00 +0000
commit5fdae7711a2fb3b367dba5b740fc0827f658ef5a (patch)
treeae0ea9727c593129b82ecc694da2afd424c881da
parentf46188911d103c4a1f0e9f182783c5f1ec39294b (diff)
downloadsqlite-5fdae7711a2fb3b367dba5b740fc0827f658ef5a.tar.gz
sqlite-5fdae7711a2fb3b367dba5b740fc0827f658ef5a.zip
Try to get threads working again on Linux. (CVS 1755)
FossilOrigin-Name: a8417cb83e9d070f46e7505f92a95f057b992658
-rw-r--r--manifest18
-rw-r--r--manifest.uuid2
-rw-r--r--src/os_unix.c108
-rw-r--r--test/threadtest1.c44
-rw-r--r--test/threadtest2.c20
5 files changed, 139 insertions, 53 deletions
diff --git a/manifest b/manifest
index 9efc7f1ab..52290c4f5 100644
--- a/manifest
+++ b/manifest
@@ -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);
}