mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-24 22:22:08 +03:00
Try to get threads working again on Linux. (CVS 1755)
FossilOrigin-Name: a8417cb83e9d070f46e7505f92a95f057b992658
This commit is contained in:
18
manifest
18
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
|
||||
|
@ -1 +1 @@
|
||||
332921041040b343b6b568685ff55d21a624f502
|
||||
a8417cb83e9d070f46e7505f92a95f057b992658
|
108
src/os_unix.c
108
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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user