/ Check-in [b9d29ea3]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Retry selected system calls on unix when they fail with EINTR.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b9d29ea385bafcf87c7dd07822ce9ec3d3892bd1
User & Date: drh 2011-02-23 13:33:46
References
2011-02-23
14:33
Automatically retry system calls that fail with EINTR. This is a backport of the changes from [b9d29ea385bafc] and [af9ba2a6d2c379]. Leaf check-in: 8609a15d user: drh tags: branch-3.7.4
Context
2011-02-23
14:00
Fix a typo in the robust_flock() macro for systems without EINTR. check-in: af9ba2a6 user: drh tags: trunk
13:53
The robust_flock() fix that accidently included some unrelated, though harmless changes. I should follow my own checklist! Closed-Leaf check-in: e701efbd user: drh tags: mistake
13:33
Retry selected system calls on unix when they fail with EINTR. check-in: b9d29ea3 user: drh tags: trunk
2011-02-22
03:34
When a stale schema-cookie is seen, expire only the one statement that encountered the bad cookie, not every statement on the database connection. Ticket [b72787b1a7cea1f] check-in: 1bca0a7e user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

   392    392     errno = savedErrno;
   393    393     return s;
   394    394   }
   395    395   #define fcntl lockTrace
   396    396   #endif /* SQLITE_LOCK_TRACE */
   397    397   
   398    398   
          399  +/*
          400  +** Retry ftruncate() calls that fail due to EINTR
          401  +*/
          402  +#ifdef EINTR
          403  +static int robust_ftruncate(int h, sqlite3_int64 sz){
          404  +  int rc;
          405  +  do{ rc = ftruncate(h,sz); }while( rc<0 && errno==EINTR );
          406  +  return rc;
          407  +}
          408  +#else
          409  +# define robust_ftruncate(a,b) ftruncate(a,b)
          410  +#endif 
          411  +
   399    412   
   400    413   /*
   401    414   ** This routine translates a standard POSIX errno code into something
   402    415   ** useful to the clients of the sqlite3 functions.  Specifically, it is
   403    416   ** intended to translate a variety of "try again" errors into SQLITE_BUSY
   404    417   ** and a variety of "please close the file descriptor NOW" errors into 
   405    418   ** SQLITE_IOERR
................................................................................
   910    923     ** prior to accessing the inode number.  The one byte written is
   911    924     ** an ASCII 'S' character which also happens to be the first byte
   912    925     ** in the header of every SQLite database.  In this way, if there
   913    926     ** is a race condition such that another thread has already populated
   914    927     ** the first page of the database, no damage is done.
   915    928     */
   916    929     if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
   917         -    rc = write(fd, "S", 1);
          930  +    do{ rc = write(fd, "S", 1); }while( rc<0 && errno==EINTR );
   918    931       if( rc!=1 ){
   919    932         pFile->lastErrno = errno;
   920    933         return SQLITE_IOERR;
   921    934       }
   922    935       rc = fstat(fd, &statbuf);
   923    936       if( rc!=0 ){
   924    937         pFile->lastErrno = errno;
................................................................................
  1786   1799   ** only a single process can be reading the database at a time.
  1787   1800   **
  1788   1801   ** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if
  1789   1802   ** compiling for VXWORKS.
  1790   1803   */
  1791   1804   #if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
  1792   1805   
         1806  +/*
         1807  +** Retry flock() calls that fail with EINTR
         1808  +*/
         1809  +#ifdef EINTR
         1810  +static int robust_flock(int fd, int op){
         1811  +  int rc;
         1812  +  do{ rc = flock(fd,op); }while( rc<0 && errno==EINTR );
         1813  +  return rc;
         1814  +}
         1815  +#else
         1816  +# define robust_flock(a,b) fclose(a,b)
         1817  +#endif
         1818  +     
         1819  +
  1793   1820   /*
  1794   1821   ** This routine checks if there is a RESERVED lock held on the specified
  1795   1822   ** file by this or any other process. If such a lock is held, set *pResOut
  1796   1823   ** to a non-zero value otherwise *pResOut is set to zero.  The return value
  1797   1824   ** is set to SQLITE_OK unless an I/O error occurs during lock checking.
  1798   1825   */
  1799   1826   static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
................................................................................
  1809   1836     if( pFile->eFileLock>SHARED_LOCK ){
  1810   1837       reserved = 1;
  1811   1838     }
  1812   1839     
  1813   1840     /* Otherwise see if some other process holds it. */
  1814   1841     if( !reserved ){
  1815   1842       /* attempt to get the lock */
  1816         -    int lrc = flock(pFile->h, LOCK_EX | LOCK_NB);
         1843  +    int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
  1817   1844       if( !lrc ){
  1818   1845         /* got the lock, unlock it */
  1819         -      lrc = flock(pFile->h, LOCK_UN);
         1846  +      lrc = robust_flock(pFile->h, LOCK_UN);
  1820   1847         if ( lrc ) {
  1821   1848           int tErrno = errno;
  1822   1849           /* unlock failed with an error */
  1823   1850           lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); 
  1824   1851           if( IS_LOCK_ERROR(lrc) ){
  1825   1852             pFile->lastErrno = tErrno;
  1826   1853             rc = lrc;
................................................................................
  1889   1916     if (pFile->eFileLock > NO_LOCK) {
  1890   1917       pFile->eFileLock = eFileLock;
  1891   1918       return SQLITE_OK;
  1892   1919     }
  1893   1920     
  1894   1921     /* grab an exclusive lock */
  1895   1922     
  1896         -  if (flock(pFile->h, LOCK_EX | LOCK_NB)) {
         1923  +  if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
  1897   1924       int tErrno = errno;
  1898   1925       /* didn't get, must be busy */
  1899   1926       rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
  1900   1927       if( IS_LOCK_ERROR(rc) ){
  1901   1928         pFile->lastErrno = tErrno;
  1902   1929       }
  1903   1930     } else {
................................................................................
  1938   1965     /* shared can just be set because we always have an exclusive */
  1939   1966     if (eFileLock==SHARED_LOCK) {
  1940   1967       pFile->eFileLock = eFileLock;
  1941   1968       return SQLITE_OK;
  1942   1969     }
  1943   1970     
  1944   1971     /* no, really, unlock. */
  1945         -  int rc = flock(pFile->h, LOCK_UN);
         1972  +  int rc = robust_flock(pFile->h, LOCK_UN);
  1946   1973     if (rc) {
  1947   1974       int r, tErrno = errno;
  1948   1975       r = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
  1949   1976       if( IS_LOCK_ERROR(r) ){
  1950   1977         pFile->lastErrno = tErrno;
  1951   1978       }
  1952   1979   #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
................................................................................
  2675   2702   static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
  2676   2703     int got;
  2677   2704   #if (!defined(USE_PREAD) && !defined(USE_PREAD64))
  2678   2705     i64 newOffset;
  2679   2706   #endif
  2680   2707     TIMER_START;
  2681   2708   #if defined(USE_PREAD)
  2682         -  got = pread(id->h, pBuf, cnt, offset);
         2709  +  do{ got = pread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
  2683   2710     SimulateIOError( got = -1 );
  2684   2711   #elif defined(USE_PREAD64)
  2685         -  got = pread64(id->h, pBuf, cnt, offset);
         2712  +  do{ got = pread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
  2686   2713     SimulateIOError( got = -1 );
  2687   2714   #else
  2688   2715     newOffset = lseek(id->h, offset, SEEK_SET);
  2689   2716     SimulateIOError( newOffset-- );
  2690   2717     if( newOffset!=offset ){
  2691   2718       if( newOffset == -1 ){
  2692   2719         ((unixFile*)id)->lastErrno = errno;
  2693   2720       }else{
  2694   2721         ((unixFile*)id)->lastErrno = 0;			
  2695   2722       }
  2696   2723       return -1;
  2697   2724     }
  2698         -  got = read(id->h, pBuf, cnt);
         2725  +  do{ got = read(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
  2699   2726   #endif
  2700   2727     TIMER_END;
  2701   2728     if( got<0 ){
  2702   2729       ((unixFile*)id)->lastErrno = errno;
  2703   2730     }
  2704   2731     OSTRACE(("READ    %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
  2705   2732     return got;
................................................................................
  2753   2780   static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
  2754   2781     int got;
  2755   2782   #if (!defined(USE_PREAD) && !defined(USE_PREAD64))
  2756   2783     i64 newOffset;
  2757   2784   #endif
  2758   2785     TIMER_START;
  2759   2786   #if defined(USE_PREAD)
  2760         -  got = pwrite(id->h, pBuf, cnt, offset);
         2787  +  do{ got = pwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
  2761   2788   #elif defined(USE_PREAD64)
  2762         -  got = pwrite64(id->h, pBuf, cnt, offset);
         2789  +  do{ got = pwrite64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
  2763   2790   #else
  2764   2791     newOffset = lseek(id->h, offset, SEEK_SET);
  2765   2792     if( newOffset!=offset ){
  2766   2793       if( newOffset == -1 ){
  2767   2794         ((unixFile*)id)->lastErrno = errno;
  2768   2795       }else{
  2769   2796         ((unixFile*)id)->lastErrno = 0;			
  2770   2797       }
  2771   2798       return -1;
  2772   2799     }
  2773         -  got = write(id->h, pBuf, cnt);
         2800  +  do{ got = write(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
  2774   2801   #endif
  2775   2802     TIMER_END;
  2776   2803     if( got<0 ){
  2777   2804       ((unixFile*)id)->lastErrno = errno;
  2778   2805     }
  2779   2806   
  2780   2807     OSTRACE(("WRITE   %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
................................................................................
  3057   3084     ** actual file size after the operation may be larger than the requested
  3058   3085     ** size).
  3059   3086     */
  3060   3087     if( pFile->szChunk ){
  3061   3088       nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
  3062   3089     }
  3063   3090   
  3064         -  rc = ftruncate(pFile->h, (off_t)nByte);
         3091  +  rc = robust_ftruncate(pFile->h, (off_t)nByte);
  3065   3092     if( rc ){
  3066   3093       pFile->lastErrno = errno;
  3067   3094       return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
  3068   3095     }else{
  3069   3096   #ifndef NDEBUG
  3070   3097       /* If we are doing a normal write to a database file (as opposed to
  3071   3098       ** doing a hot-journal rollback or a write to some file other than a
................................................................................
  3132   3159       struct stat buf;              /* Used to hold return values of fstat() */
  3133   3160      
  3134   3161       if( fstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
  3135   3162   
  3136   3163       nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
  3137   3164       if( nSize>(i64)buf.st_size ){
  3138   3165   #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
  3139         -      if( posix_fallocate(pFile->h, buf.st_size, nSize-buf.st_size) ){
  3140         -        return SQLITE_IOERR_WRITE;
  3141         -      }
         3166  +      int rc;
         3167  +      do{
         3168  +        rc = posix_fallocate(pFile-.h, buf.st_size, nSize-buf.st_size;
         3169  +      }while( rc<0 && errno=EINTR );
         3170  +      if( rc ) return SQLITE_IOERR_WRITE;
  3142   3171   #else
  3143   3172         /* If the OS does not have posix_fallocate(), fake it. First use
  3144   3173         ** ftruncate() to set the file size, then write a single byte to
  3145   3174         ** the last byte in each block within the extended region. This
  3146   3175         ** is the same technique used by glibc to implement posix_fallocate()
  3147   3176         ** on systems that do not have a real fallocate() system call.
  3148   3177         */
  3149   3178         int nBlk = buf.st_blksize;  /* File-system block size */
  3150   3179         i64 iWrite;                 /* Next offset to write to */
  3151   3180         int nWrite;                 /* Return value from seekAndWrite() */
  3152   3181   
  3153         -      if( ftruncate(pFile->h, nSize) ){
         3182  +      if( robust_ftruncate(pFile->h, nSize) ){
  3154   3183           pFile->lastErrno = errno;
  3155   3184           return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
  3156   3185         }
  3157   3186         iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
  3158   3187         do {
  3159   3188           nWrite = seekAndWrite(pFile, iWrite, "", 1);
  3160   3189           iWrite += nBlk;
................................................................................
  3506   3535       }
  3507   3536   
  3508   3537       /* Check to see if another process is holding the dead-man switch.
  3509   3538       ** If not, truncate the file to zero length. 
  3510   3539       */
  3511   3540       rc = SQLITE_OK;
  3512   3541       if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
  3513         -      if( ftruncate(pShmNode->h, 0) ){
         3542  +      if( robust_ftruncate(pShmNode->h, 0) ){
  3514   3543           rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
  3515   3544         }
  3516   3545       }
  3517   3546       if( rc==SQLITE_OK ){
  3518   3547         rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
  3519   3548       }
  3520   3549       if( rc ) goto shm_open_err;
................................................................................
  3612   3641         /* The requested memory region does not exist. If bExtend is set to
  3613   3642         ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
  3614   3643         **
  3615   3644         ** Alternatively, if bExtend is true, use ftruncate() to allocate
  3616   3645         ** the requested memory region.
  3617   3646         */
  3618   3647         if( !bExtend ) goto shmpage_out;
  3619         -      if( ftruncate(pShmNode->h, nByte) ){
         3648  +      if( robust_ftruncate(pShmNode->h, nByte) ){
  3620   3649           rc = unixLogError(SQLITE_IOERR_SHMSIZE,"ftruncate",pShmNode->zFilename);
  3621   3650           goto shmpage_out;
  3622   3651         }
  3623   3652       }
  3624   3653   
  3625   3654       /* Map the requested memory region into this processes address space. */
  3626   3655       apNew = (char **)sqlite3_realloc(
................................................................................
  5009   5038         time(&t);
  5010   5039         memcpy(zBuf, &t, sizeof(t));
  5011   5040         pid = getpid();
  5012   5041         memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
  5013   5042         assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
  5014   5043         nBuf = sizeof(t) + sizeof(pid);
  5015   5044       }else{
  5016         -      nBuf = read(fd, zBuf, nBuf);
         5045  +      do{ nBuf = read(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
  5017   5046         close(fd);
  5018   5047       }
  5019   5048     }
  5020   5049   #endif
  5021   5050     return nBuf;
  5022   5051   }
  5023   5052   
................................................................................
  5770   5799           memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
  5771   5800           if( pCtx->lockProxyPath!=NULL ){
  5772   5801             strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN);
  5773   5802           }else{
  5774   5803             strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN);
  5775   5804           }
  5776   5805           writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
  5777         -        ftruncate(conchFile->h, writeSize);
         5806  +        robust_ftruncate(conchFile->h, writeSize);
  5778   5807           rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
  5779   5808           fsync(conchFile->h);
  5780   5809           /* If we created a new conch file (not just updated the contents of a 
  5781   5810            ** valid conch file), try to match the permissions of the database 
  5782   5811            */
  5783   5812           if( rc==SQLITE_OK && createConch ){
  5784   5813             struct stat buf;
         5814  +          int rc;
  5785   5815             int err = fstat(pFile->h, &buf);
  5786   5816             if( err==0 ){
  5787   5817               mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP |
  5788   5818                                           S_IROTH|S_IWOTH);
  5789   5819               /* try to match the database file R/W permissions, ignore failure */
  5790   5820   #ifndef SQLITE_PROXY_DEBUG
  5791   5821               fchmod(conchFile->h, cmode);
  5792   5822   #else
  5793         -            if( fchmod(conchFile->h, cmode)!=0 ){
         5823  +            do{
         5824  +              rc = fchmod(conchFile->h, cmode);
         5825  +            }while( rc==(-1) && errno==EINTR );
         5826  +            if( rc!=0 ){
  5794   5827                 int code = errno;
  5795   5828                 fprintf(stderr, "fchmod %o FAILED with %d %s\n",
  5796   5829                         cmode, code, strerror(code));
  5797   5830               } else {
  5798   5831                 fprintf(stderr, "fchmod %o SUCCEDED\n",cmode);
  5799   5832               }
  5800   5833             }else{