⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_os2.c

📁 sqlite 3.3.8 支持加密的版本
💻 C
📖 第 1 页 / 共 2 页
字号:
  ** the PENDING_LOCK byte is temporary.
  */
  newLocktype = pFile->locktype;
  if( pFile->locktype==NO_LOCK
   || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
  ){
    int cnt = 3;

    LockArea.lOffset = PENDING_BYTE;
    LockArea.lRange = 1L;
    UnlockArea.lOffset = 0L;
    UnlockArea.lRange = 0L;

    while( cnt-->0 && (res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L) )!=NO_ERROR ){
      /* Try 3 times to get the pending lock.  The pending lock might be
      ** held by another reader process who will release it momentarily.
      */
      TRACE2( "could not get a PENDING lock. cnt=%d\n", cnt );
      DosSleep(1);
    }
    gotPendingLock = res;
  }

  /* Acquire a shared lock
  */
  if( locktype==SHARED_LOCK && res ){
    assert( pFile->locktype==NO_LOCK );
    res = getReadLock(pFile);
    if( res == NO_ERROR ){
      newLocktype = SHARED_LOCK;
    }
  }

  /* Acquire a RESERVED lock
  */
  if( locktype==RESERVED_LOCK && res ){
    assert( pFile->locktype==SHARED_LOCK );
    LockArea.lOffset = RESERVED_BYTE;
    LockArea.lRange = 1L;
    UnlockArea.lOffset = 0L;
    UnlockArea.lRange = 0L;
    res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
    if( res == NO_ERROR ){
      newLocktype = RESERVED_LOCK;
    }
  }

  /* Acquire a PENDING lock
  */
  if( locktype==EXCLUSIVE_LOCK && res ){
    newLocktype = PENDING_LOCK;
    gotPendingLock = 0;
  }

  /* Acquire an EXCLUSIVE lock
  */
  if( locktype==EXCLUSIVE_LOCK && res ){
    assert( pFile->locktype>=SHARED_LOCK );
    res = unlockReadLock(pFile);
    TRACE2( "unreadlock = %d\n", res );
    LockArea.lOffset = SHARED_FIRST;
    LockArea.lRange = SHARED_SIZE;
    UnlockArea.lOffset = 0L;
    UnlockArea.lRange = 0L;
    res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
    if( res == NO_ERROR ){
      newLocktype = EXCLUSIVE_LOCK;
    }else{
      TRACE2( "error-code = %d\n", res );
    }
  }

  /* If we are holding a PENDING lock that ought to be released, then
  ** release it now.
  */
  if( gotPendingLock && locktype==SHARED_LOCK ){
    LockArea.lOffset = 0L;
    LockArea.lRange = 0L;
    UnlockArea.lOffset = PENDING_BYTE;
    UnlockArea.lRange = 1L;
    DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
  }

  /* Update the state of the lock has held in the file descriptor then
  ** return the appropriate result code.
  */
  if( res == NO_ERROR ){
    rc = SQLITE_OK;
  }else{
    TRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
           locktype, newLocktype );
    rc = SQLITE_BUSY;
  }
  pFile->locktype = newLocktype;
  return rc;
}

/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If such a lock is held, return
** non-zero, otherwise zero.
*/
int os2CheckReservedLock( OsFile *id ){
  APIRET rc = NO_ERROR;
  os2File *pFile = (os2File*)id;
  assert( pFile!=0 );
  if( pFile->locktype>=RESERVED_LOCK ){
    rc = 1;
    TRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, rc );
  }else{
    FILELOCK  LockArea,
              UnlockArea;
    memset(&LockArea, 0, sizeof(LockArea));
    memset(&UnlockArea, 0, sizeof(UnlockArea));
    LockArea.lOffset = RESERVED_BYTE;
    LockArea.lRange = 1L;
    UnlockArea.lOffset = 0L;
    UnlockArea.lRange = 0L;
    rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
    if( rc == NO_ERROR ){
      LockArea.lOffset = 0L;
      LockArea.lRange = 0L;
      UnlockArea.lOffset = RESERVED_BYTE;
      UnlockArea.lRange = 1L;
      rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
    }
    TRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, rc );
  }
  return rc;
}

/*
** Lower the locking level on file descriptor id to locktype.  locktype
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
**
** It is not possible for this routine to fail if the second argument
** is NO_LOCK.  If the second argument is SHARED_LOCK then this routine
** might return SQLITE_IOERR;
*/
int os2Unlock( OsFile *id, int locktype ){
  int type;
  APIRET rc = SQLITE_OK;
  os2File *pFile = (os2File*)id;
  FILELOCK  LockArea,
            UnlockArea;
  memset(&LockArea, 0, sizeof(LockArea));
  memset(&UnlockArea, 0, sizeof(UnlockArea));
  assert( pFile!=0 );
  assert( locktype<=SHARED_LOCK );
  TRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype );
  type = pFile->locktype;
  if( type>=EXCLUSIVE_LOCK ){
    LockArea.lOffset = 0L;
    LockArea.lRange = 0L;
    UnlockArea.lOffset = SHARED_FIRST;
    UnlockArea.lRange = SHARED_SIZE;
    DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
    if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
      /* This should never happen.  We should always be able to
      ** reacquire the read lock */
      rc = SQLITE_IOERR;
    }
  }
  if( type>=RESERVED_LOCK ){
    LockArea.lOffset = 0L;
    LockArea.lRange = 0L;
    UnlockArea.lOffset = RESERVED_BYTE;
    UnlockArea.lRange = 1L;
    DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
  }
  if( locktype==NO_LOCK && type>=SHARED_LOCK ){
    unlockReadLock(pFile);
  }
  if( type>=PENDING_LOCK ){
    LockArea.lOffset = 0L;
    LockArea.lRange = 0L;
    UnlockArea.lOffset = PENDING_BYTE;
    UnlockArea.lRange = 1L;
    DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L );
  }
  pFile->locktype = locktype;
  return rc;
}

/*
** Turn a relative pathname into a full pathname.  Return a pointer
** to the full pathname stored in space obtained from sqliteMalloc().
** The calling function is responsible for freeing this space once it
** is no longer needed.
*/
char *sqlite3Os2FullPathname( const char *zRelative ){
  char *zFull = 0;
  if( strchr(zRelative, ':') ){
    sqlite3SetString( &zFull, zRelative, (char*)0 );
  }else{
    char zBuff[SQLITE_TEMPNAME_SIZE - 2] = {0};
    char zDrive[1] = {0};
    ULONG cbzFullLen = SQLITE_TEMPNAME_SIZE;
    ULONG ulDriveNum = 0;
    ULONG ulDriveMap = 0;
    DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap );
    DosQueryCurrentDir( 0L, zBuff, &cbzFullLen );
    zFull = sqliteMalloc( cbzFullLen );
    sprintf( zDrive, "%c", (char)('A' + ulDriveNum - 1) );
    sqlite3SetString( &zFull, zDrive, ":\\", zBuff, "\\", zRelative, (char*)0 );
  }
  return zFull;
}

/*
** The fullSync option is meaningless on os2, or correct me if I'm wrong.  This is a no-op.
** From os_unix.c: Change the value of the fullsync flag in the given file descriptor.
** From os_unix.c: ((unixFile*)id)->fullSync = v;
*/
static void os2SetFullSync( OsFile *id, int v ){
  return;
}

/*
** Return the underlying file handle for an OsFile
*/
static int os2FileHandle( OsFile *id ){
  return (int)((os2File*)id)->h;
}

/*
** Return an integer that indices the type of lock currently held
** by this handle.  (Used for testing and analysis only.)
*/
static int os2LockState( OsFile *id ){
  return ((os2File*)id)->locktype;
}

/*
** This vector defines all the methods that can operate on an OsFile
** for os2.
*/
static const IoMethod sqlite3Os2IoMethod = {
  os2Close,
  os2OpenDirectory,
  os2Read,
  os2Write,
  os2Seek,
  os2Truncate,
  os2Sync,
  os2SetFullSync,
  os2FileHandle,
  os2FileSize,
  os2Lock,
  os2Unlock,
  os2LockState,
  os2CheckReservedLock,
};

/*
** Allocate memory for an OsFile.  Initialize the new OsFile
** to the value given in pInit and return a pointer to the new
** OsFile.  If we run out of memory, close the file and return NULL.
*/
int allocateOs2File( os2File *pInit, OsFile **pld ){
  os2File *pNew;
  pNew = sqliteMalloc( sizeof(*pNew) );
  if( pNew==0 ){
    DosClose( pInit->h );
    *pld = 0;
    return SQLITE_NOMEM;
  }else{
    *pNew = *pInit;
    pNew->pMethod = &sqlite3Os2IoMethod;
    pNew->locktype = NO_LOCK;
    *pld = (OsFile*)pNew;
    OpenCounter(+1);
    return SQLITE_OK;
  }
}

#endif /* SQLITE_OMIT_DISKIO */
/***************************************************************************
** Everything above deals with file I/O.  Everything that follows deals
** with other miscellanous aspects of the operating system interface
****************************************************************************/

/*
** Get information to seed the random number generator.  The seed
** is written into the buffer zBuf[256].  The calling function must
** supply a sufficiently large buffer.
*/
int sqlite3Os2RandomSeed( char *zBuf ){
  /* We have to initialize zBuf to prevent valgrind from reporting
  ** errors.  The reports issued by valgrind are incorrect - we would
  ** prefer that the randomness be increased by making use of the
  ** uninitialized space in zBuf - but valgrind errors tend to worry
  ** some users.  Rather than argue, it seems easier just to initialize
  ** the whole array and silence valgrind, even if that means less randomness
  ** in the random seed.
  **
  ** When testing, initializing zBuf[] to zero is all we do.  That means
  ** that we always use the same random number sequence. This makes the
  ** tests repeatable.
  */
  memset( zBuf, 0, 256 );
  DosGetDateTime( (PDATETIME)zBuf );
  return SQLITE_OK;
}

/*
** Sleep for a little while.  Return the amount of time slept.
*/
int sqlite3Os2Sleep( int ms ){
  DosSleep( ms );
  return ms;
}

/*
** Static variables used for thread synchronization
*/
static int inMutex = 0;
#ifdef SQLITE_OS2_THREADS
static ULONG mutexOwner;
#endif

/*
** The following pair of routines implement mutual exclusion for
** multi-threaded processes.  Only a single thread is allowed to
** executed code that is surrounded by EnterMutex() and LeaveMutex().
**
** SQLite uses only a single Mutex.  There is not much critical
** code and what little there is executes quickly and without blocking.
*/
void sqlite3Os2EnterMutex(){
  PTIB ptib;
#ifdef SQLITE_OS2_THREADS
  DosEnterCritSec();
  DosGetInfoBlocks( &ptib, NULL );
  mutexOwner = ptib->tib_ptib2->tib2_ultid;
#endif
  assert( !inMutex );
  inMutex = 1;
}
void sqlite3Os2LeaveMutex(){
  PTIB ptib;
  assert( inMutex );
  inMutex = 0;
#ifdef SQLITE_OS2_THREADS
  DosGetInfoBlocks( &ptib, NULL );
  assert( mutexOwner == ptib->tib_ptib2->tib2_ultid );
  DosExitCritSec();
#endif
}

/*
** Return TRUE if the mutex is currently held.
**
** If the thisThreadOnly parameter is true, return true if and only if the
** calling thread holds the mutex.  If the parameter is false, return
** true if any thread holds the mutex.
*/
int sqlite3Os2InMutex( int thisThreadOnly ){
#ifdef SQLITE_OS2_THREADS
  PTIB ptib;
  DosGetInfoBlocks( &ptib, NULL );
  return inMutex>0 && (thisThreadOnly==0 || mutexOwner==ptib->tib_ptib2->tib2_ultid);
#else
  return inMutex>0;
#endif
}

/*
** The following variable, if set to a non-zero value, becomes the result
** returned from sqlite3OsCurrentTime().  This is used for testing.
*/
#ifdef SQLITE_TEST
int sqlite3_current_time = 0;
#endif

/*
** Find the current time (in Universal Coordinated Time).  Write the
** current time and date as a Julian Day number into *prNow and
** return 0.  Return 1 if the time and date cannot be found.
*/
int sqlite3Os2CurrentTime( double *prNow ){
  double now;
  USHORT second, minute, hour,
         day, month, year;
  DATETIME dt;
  DosGetDateTime( &dt );
  second = (USHORT)dt.seconds;
  minute = (USHORT)dt.minutes + dt.timezone;
  hour = (USHORT)dt.hours;
  day = (USHORT)dt.day;
  month = (USHORT)dt.month;
  year = (USHORT)dt.year;

  /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
     http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */
  /* Calculate the Julian days */
  now = day - 32076 +
    1461*(year + 4800 + (month - 14)/12)/4 +
    367*(month - 2 - (month - 14)/12*12)/12 -
    3*((year + 4900 + (month - 14)/12)/100)/4;

  /* Add the fractional hours, mins and seconds */
  now += (hour + 12.0)/24.0;
  now += minute/1440.0;
  now += second/86400.0;
  *prNow = now;
#ifdef SQLITE_TEST
  if( sqlite3_current_time ){
    *prNow = sqlite3_current_time/86400.0 + 2440587.5;
  }
#endif
  return 0;
}

/*
** Remember the number of thread-specific-data blocks allocated.
** Use this to verify that we are not leaking thread-specific-data.
** Ticket #1601
*/
#ifdef SQLITE_TEST
int sqlite3_tsd_count = 0;
# define TSD_COUNTER_INCR InterlockedIncrement( &sqlite3_tsd_count )
# define TSD_COUNTER_DECR InterlockedDecrement( &sqlite3_tsd_count )
#else
# define TSD_COUNTER_INCR  /* no-op */
# define TSD_COUNTER_DECR  /* no-op */
#endif

/*
** If called with allocateFlag>1, then return a pointer to thread
** specific data for the current thread.  Allocate and zero the
** thread-specific data if it does not already exist necessary.
**
** If called with allocateFlag==0, then check the current thread
** specific data.  Return it if it exists.  If it does not exist,
** then return NULL.
**
** If called with allocateFlag<0, check to see if the thread specific
** data is allocated and is all zero.  If it is then deallocate it.
** Return a pointer to the thread specific data or NULL if it is
** unallocated or gets deallocated.
*/
ThreadData *sqlite3Os2ThreadSpecificData( int allocateFlag ){
  static ThreadData **s_ppTsd = NULL;
  static const ThreadData zeroData = {0, 0, 0};
  ThreadData *pTsd;

  if( !s_ppTsd ){
    sqlite3OsEnterMutex();
    if( !s_ppTsd ){
      PULONG pul;
      APIRET rc = DosAllocThreadLocalMemory(1, &pul);
      if( rc != NO_ERROR ){
        sqlite3OsLeaveMutex();
        return 0;
      }
      s_ppTsd = (ThreadData **)pul;
    }
    sqlite3OsLeaveMutex();
  }
  pTsd = *s_ppTsd;
  if( allocateFlag>0 ){
    if( !pTsd ){
      pTsd = sqlite3OsMalloc( sizeof(zeroData) );
      if( pTsd ){
        *pTsd = zeroData;
        *s_ppTsd = pTsd;
        TSD_COUNTER_INCR;
      }
    }
  }else if( pTsd!=0 && allocateFlag<0
              && memcmp( pTsd, &zeroData, sizeof(ThreadData) )==0 ){
    sqlite3OsFree(pTsd);
    *s_ppTsd = NULL;
    TSD_COUNTER_DECR;
    pTsd = 0;
  }
  return pTsd;
}
#endif /* OS_OS2 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -