]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Try to get threads working again on Linux. (CVS 1755)
authordrh <drh@noemail.net>
Tue, 29 Jun 2004 03:29:00 +0000 (03:29 +0000)
committerdrh <drh@noemail.net>
Tue, 29 Jun 2004 03:29:00 +0000 (03:29 +0000)
FossilOrigin-Name: a8417cb83e9d070f46e7505f92a95f057b992658

manifest
manifest.uuid
src/os_unix.c
test/threadtest1.c
test/threadtest2.c

index 9efc7f1ab1deca2b22fbabae297575700efaf684..52290c4f506c996884b6db98662b3a2b64d52fda 100644 (file)
--- 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
index a0ef54f1f9f6da8d9b518d31671ed1f79eb7a2e6..e7412246b0a89d8591e79ad55049e26b6305ab30 100644 (file)
@@ -1 +1 @@
-332921041040b343b6b568685ff55d21a624f502
\ No newline at end of file
+a8417cb83e9d070f46e7505f92a95f057b992658
\ No newline at end of file
index 61e8976c3f0dfed533ef5e8246de8675fc3de763..c2309495eb44e7609f7305146a9011ec98af16f2 100644 (file)
 ** 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;
index 5aad85ee3c90b3e5a4adbf321db604fae15c9111..f5ff112e60dbe2c40603ff4f5d5b1c62fea4cb47 100644 (file)
@@ -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);
index 7b08d37b9bf1e584441aefd17a231862ebfbd029..deaffdaf092098a8c916d8b0297978855ffd5129 100644 (file)
@@ -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);
   }