Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Changes to the unix OS layer aimed at finding and fixing tickets #1272 and #1285. (CVS 2517) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
006dda3119f025d703da4e0215c37820 |
User & Date: | drh 2005-06-15 17:47:56.000 |
Context
2005-06-15
| ||
18:07 | Fix to the "make doc" makefile target. Ticket #1289. (CVS 2518) (check-in: 4713b1e104 user: drh tags: trunk) | |
17:47 | Changes to the unix OS layer aimed at finding and fixing tickets #1272 and #1285. (CVS 2517) (check-in: 006dda3119 user: drh tags: trunk) | |
2005-06-14
| ||
17:47 | Fix an NDEBUG versus SQLITE_DEBUG confusion issue. (CVS 2516) (check-in: 833c016023 user: drh tags: trunk) | |
Changes
Changes to src/os_unix.c.
︙ | ︙ | |||
51 52 53 54 55 56 57 | ** lacks the fcntl() system call. So redefine fcntl() to be something ** that always succeeds. This means that locking does not occur under ** DJGPP. But its DOS - what did you expect? */ #ifdef __DJGPP__ # define fcntl(A,B,C) 0 #endif | < < < < < < < < < < < < > > > > > > > > > | > > > > > > > > > > | > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | ** lacks the fcntl() system call. So redefine fcntl() to be something ** that always succeeds. This means that locking does not occur under ** DJGPP. But its DOS - what did you expect? */ #ifdef __DJGPP__ # define fcntl(A,B,C) 0 #endif /* ** Include code that is common to all os_*.c files */ #include "os_common.h" /* ** The threadid macro resolves to the thread-id or to 0. Used for ** testing and debugging only. */ #ifdef SQLITE_UNIX_THREADS #define threadid pthread_self() #else #define threadid 0 #endif /* ** Set or check the OsFile.tid field. This field is set when an OsFile ** is first opened. All subsequent uses of the OsFile verify that the ** same thread is operating on the OsFile. Some operating systems do ** not allow locks to be overridden by other threads and that restriction ** means that sqlite3* database handles cannot be moved from one thread ** to another. This logic makes sure a user does not try to do that ** by mistake. */ #ifdef SQLITE_UNIX_THREADS # define SET_THREADID(X) X->tid = pthread_self() # define CHECK_THREADID(X) (!pthread_equal(X->tid, pthread_self())) #else # define SET_THREADID(X) # define CHECK_THREADID(X) 0 #endif /* ** Here is the dirt on POSIX advisory locks: ANSI STD 1003.1 (1996) ** section 6.5.2.2 lines 483 through 490 specify that when a process ** sets or clears a lock, that operation overrides any prior locks set ** by the same process. It does not explicitly say so, but this implies |
︙ | ︙ | |||
260 261 262 263 264 265 266 267 268 269 270 271 272 273 | */ 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. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | */ struct threadTestData { int fd; /* File to be locked */ struct flock lock; /* The locking operation */ int result; /* Result of the locking operation */ }; #ifdef SQLITE_LOCK_TRACE /* ** Print out information about all locking operations. ** ** This routine is used for troubleshooting locks on multithreaded ** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE ** command-line option on the compiler. This code is normally ** turnned off. */ static int lockTrace(int fd, int op, struct flock *p){ char *zOpName, *zType; int s; int savedErrno; if( op==F_GETLK ){ zOpName = "GETLK"; }else if( op==F_SETLK ){ zOpName = "SETLK"; }else{ s = fcntl(fd, op, p); sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s); return s; } if( p->l_type==F_RDLCK ){ zType = "RDLCK"; }else if( p->l_type==F_WRLCK ){ zType = "WRLCK"; }else if( p->l_type==F_UNLCK ){ zType = "UNLCK"; }else{ assert( 0 ); } assert( p->l_whence==SEEK_SET ); s = fcntl(fd, op, p); savedErrno = errno; sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, (int)p->l_pid, s); if( s && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ struct flock l2; l2 = *p; fcntl(fd, F_GETLK, &l2); if( l2.l_type==F_RDLCK ){ zType = "RDLCK"; }else if( l2.l_type==F_WRLCK ){ zType = "WRLCK"; }else if( l2.l_type==F_UNLCK ){ zType = "UNLCK"; }else{ assert( 0 ); } sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n", zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid); } errno = savedErrno; return s; } #define fcntl lockTrace #endif /* SQLITE_LOCK_TRACE */ /* ** 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. */ |
︙ | ︙ | |||
439 440 441 442 443 444 445 446 447 448 449 450 451 452 | const char *zFilename, OsFile *id, int *pReadonly ){ int rc; assert( !id->isOpen ); id->dirfd = -1; id->h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, SQLITE_DEFAULT_FILE_PERMISSIONS); if( id->h<0 ){ #ifdef EISDIR if( errno==EISDIR ){ return SQLITE_CANTOPEN; } | > | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 | const char *zFilename, OsFile *id, int *pReadonly ){ int rc; assert( !id->isOpen ); id->dirfd = -1; SET_THREADID(id); id->h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, SQLITE_DEFAULT_FILE_PERMISSIONS); if( id->h<0 ){ #ifdef EISDIR if( errno==EISDIR ){ return SQLITE_CANTOPEN; } |
︙ | ︙ | |||
490 491 492 493 494 495 496 497 498 499 500 501 502 503 | */ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ int rc; assert( !id->isOpen ); if( access(zFilename, 0)==0 ){ return SQLITE_CANTOPEN; } id->dirfd = -1; id->h = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600); if( id->h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); | > | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | */ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ int rc; assert( !id->isOpen ); if( access(zFilename, 0)==0 ){ return SQLITE_CANTOPEN; } SET_THREADID(id); id->dirfd = -1; id->h = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600); if( id->h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); |
︙ | ︙ | |||
524 525 526 527 528 529 530 531 532 533 534 535 536 537 | ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ int rc; assert( !id->isOpen ); id->dirfd = -1; id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( id->h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); rc = findLockInfo(id->h, &id->pLock, &id->pOpen); | > | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 | ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ int rc; assert( !id->isOpen ); SET_THREADID(id); id->dirfd = -1; id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( id->h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); rc = findLockInfo(id->h, &id->pLock, &id->pOpen); |
︙ | ︙ | |||
568 569 570 571 572 573 574 575 576 577 578 579 580 581 | OsFile *id ){ if( !id->isOpen ){ /* Do not open the directory if the corresponding file is not already ** open. */ return SQLITE_CANTOPEN; } assert( id->dirfd<0 ); id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0); if( id->dirfd<0 ){ return SQLITE_CANTOPEN; } TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname); return SQLITE_OK; | > | 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 | OsFile *id ){ if( !id->isOpen ){ /* Do not open the directory if the corresponding file is not already ** open. */ return SQLITE_CANTOPEN; } SET_THREADID(id); assert( id->dirfd<0 ); id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0); if( id->dirfd<0 ){ return SQLITE_CANTOPEN; } TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname); return SQLITE_OK; |
︙ | ︙ | |||
835 836 837 838 839 840 841 842 843 844 845 846 847 848 | ** non-zero. If the file is unlocked or holds only SHARED locks, then ** return zero. */ int sqlite3OsCheckReservedLock(OsFile *id){ int r = 0; assert( id->isOpen ); sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ if( id->pLock->locktype>SHARED_LOCK ){ r = 1; } | > | 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 | ** non-zero. If the file is unlocked or holds only SHARED locks, then ** return zero. */ int sqlite3OsCheckReservedLock(OsFile *id){ int r = 0; assert( id->isOpen ); if( CHECK_THREADID(id) ) return SQLITE_MISUSE; sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ if( id->pLock->locktype>SHARED_LOCK ){ r = 1; } |
︙ | ︙ | |||
952 953 954 955 956 957 958 959 960 961 962 963 964 965 | struct flock lock; int s; assert( id->isOpen ); TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype), locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt ,getpid() ); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ if( id->locktype>=locktype ){ TRACE3("LOCK %d %s ok (already held)\n", id->h, locktypeName(locktype)); | > | 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 | struct flock lock; int s; assert( id->isOpen ); TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype), locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt ,getpid() ); if( CHECK_THREADID(id) ) return SQLITE_MISUSE; /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ if( id->locktype>=locktype ){ TRACE3("LOCK %d %s ok (already held)\n", id->h, locktypeName(locktype)); |
︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 | id->locktype = SHARED_LOCK; pLock->cnt++; id->pOpen->nLock++; goto end_lock; } lock.l_len = 1L; lock.l_whence = SEEK_SET; /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ if( locktype==SHARED_LOCK | > | 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 | id->locktype = SHARED_LOCK; pLock->cnt++; id->pOpen->nLock++; goto end_lock; } lock.l_len = 1L; lock.l_whence = SEEK_SET; /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ if( locktype==SHARED_LOCK |
︙ | ︙ | |||
1033 1034 1035 1036 1037 1038 1039 | lock.l_len = SHARED_SIZE; s = fcntl(id->h, F_SETLK, &lock); /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; lock.l_type = F_UNLCK; | | > > > | 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | lock.l_len = SHARED_SIZE; s = fcntl(id->h, F_SETLK, &lock); /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; lock.l_type = F_UNLCK; if( fcntl(id->h, F_SETLK, &lock)!=0 ){ rc = SQLITE_IOERR; /* This should never happen */ goto end_lock; } if( s ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; }else{ id->locktype = SHARED_LOCK; id->pOpen->nLock++; pLock->cnt = 1; } |
︙ | ︙ | |||
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 | struct lockInfo *pLock; struct flock lock; int rc = SQLITE_OK; assert( id->isOpen ); TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype, id->pLock->locktype, id->pLock->cnt, getpid()); assert( locktype<=SHARED_LOCK ); if( id->locktype<=locktype ){ return SQLITE_OK; } sqlite3OsEnterMutex(); pLock = id->pLock; | > | 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 | struct lockInfo *pLock; struct flock lock; int rc = SQLITE_OK; assert( id->isOpen ); TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype, id->pLock->locktype, id->pLock->cnt, getpid()); if( CHECK_THREADID(id) ) return SQLITE_MISUSE; assert( locktype<=SHARED_LOCK ); if( id->locktype<=locktype ){ return SQLITE_OK; } sqlite3OsEnterMutex(); pLock = id->pLock; |
︙ | ︙ | |||
1127 1128 1129 1130 1131 1132 1133 | rc = SQLITE_IOERR; } } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); | | | > > > | | > > > | 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 | rc = SQLITE_IOERR; } } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); if( fcntl(id->h, F_SETLK, &lock)==0 ){ pLock->locktype = SHARED_LOCK; }else{ rc = SQLITE_IOERR; /* This should never happen */ } } if( locktype==NO_LOCK ){ struct openCnt *pOpen; /* Decrement the shared lock counter. Release the lock using an ** OS call only when all threads in this same process have released ** the lock. */ pLock->cnt--; if( pLock->cnt==0 ){ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; if( fcntl(id->h, F_SETLK, &lock)==0 ){ pLock->locktype = NO_LOCK; }else{ rc = SQLITE_IOERR; /* This should never happen */ } } /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. */ pOpen = id->pOpen; |
︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 | } /* ** Close a file. */ int sqlite3OsClose(OsFile *id){ if( !id->isOpen ) return SQLITE_OK; sqlite3OsUnlock(id, NO_LOCK); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; sqlite3OsEnterMutex(); if( id->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file | > | 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 | } /* ** Close a file. */ int sqlite3OsClose(OsFile *id){ if( !id->isOpen ) return SQLITE_OK; if( CHECK_THREADID(id) ) return SQLITE_MISUSE; sqlite3OsUnlock(id, NO_LOCK); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; sqlite3OsEnterMutex(); if( id->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file |
︙ | ︙ |
Changes to src/os_unix.h.
︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | ** standard include files. */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> /* ** The OsFile structure is a operating-system independing representation ** of an open file handle. It is defined differently for each architecture. ** ** This is the definition for Unix. ** ** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK, ** PENDING_LOCK or EXCLUSIVE_LOCK. */ typedef struct OsFile OsFile; struct OsFile { struct Pager *pPager; /* The pager that owns this OsFile. Might be 0 */ struct openCnt *pOpen; /* Info about all open fd's on this inode */ struct lockInfo *pLock; /* Info about locks on this inode */ int h; /* The file descriptor */ unsigned char locktype; /* The type of lock held on this fd */ unsigned char isOpen; /* True if needs to be closed */ unsigned char fullSync; /* Use F_FULLSYNC if available */ int dirfd; /* File descriptor for the directory */ }; /* ** A macro to set the OsFile.fullSync flag, if it exists. */ #define SET_FULLSYNC(x,y) ((x).fullSync = (y)) | > > > > > > > > > > > > > > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | ** standard include files. */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> /* ** Macros used to determine whether or not to use threads. The ** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for ** Posix threads and SQLITE_W32_THREADS is defined if we are ** synchronizing using Win32 threads. */ #if defined(THREADSAFE) && THREADSAFE # include <pthread.h> # define SQLITE_UNIX_THREADS 1 #endif /* ** The OsFile structure is a operating-system independing representation ** of an open file handle. It is defined differently for each architecture. ** ** This is the definition for Unix. ** ** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK, ** PENDING_LOCK or EXCLUSIVE_LOCK. */ typedef struct OsFile OsFile; struct OsFile { struct Pager *pPager; /* The pager that owns this OsFile. Might be 0 */ struct openCnt *pOpen; /* Info about all open fd's on this inode */ struct lockInfo *pLock; /* Info about locks on this inode */ int h; /* The file descriptor */ unsigned char locktype; /* The type of lock held on this fd */ unsigned char isOpen; /* True if needs to be closed */ unsigned char fullSync; /* Use F_FULLSYNC if available */ int dirfd; /* File descriptor for the directory */ #ifdef SQLITE_UNIX_THREADS pthread_t tid; /* The thread authorized to use this OsFile */ #endif }; /* ** A macro to set the OsFile.fullSync flag, if it exists. */ #define SET_FULLSYNC(x,y) ((x).fullSync = (y)) |
︙ | ︙ |