?? os_unix.c
字號:
int i;
for(i=0; i<pOpen->nPending; i++){
close(pOpen->aPending[i]);
}
free(pOpen->aPending);
pOpen->nPending = 0;
pOpen->aPending = 0;
}
}
sqlite3OsLeaveMutex();
pFile->locktype = locktype;
return rc;
}
/*
** Close a file.
*/
static int unixClose(OsFile **pId){
unixFile *id = (unixFile*)*pId;
if( !id ) return SQLITE_OK;
unixUnlock(*pId, 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
** descriptor to pOpen->aPending. It will be automatically closed when
** the last lock is cleared.
*/
int *aNew;
struct openCnt *pOpen = id->pOpen;
aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
if( aNew==0 ){
/* If a malloc fails, just leak the file descriptor */
}else{
pOpen->aPending = aNew;
pOpen->aPending[pOpen->nPending] = id->h;
pOpen->nPending++;
}
}else{
/* There are no outstanding locks so we can close the file immediately */
close(id->h);
}
releaseLockInfo(id->pLock);
releaseOpenCnt(id->pOpen);
sqlite3OsLeaveMutex();
id->isOpen = 0;
TRACE2("CLOSE %-3d\n", id->h);
OpenCounter(-1);
sqlite3ThreadSafeFree(id);
*pId = 0;
return SQLITE_OK;
}
#ifdef SQLITE_ENABLE_LOCKING_STYLE
#pragma mark AFP Support
/*
** The afpLockingContext structure contains all afp lock specific state
*/
typedef struct afpLockingContext afpLockingContext;
struct afpLockingContext {
unsigned long long sharedLockByte;
char *filePath;
};
struct ByteRangeLockPB2
{
unsigned long long offset; /* offset to first byte to lock */
unsigned long long length; /* nbr of bytes to lock */
unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */
unsigned char unLockFlag; /* 1 = unlock, 0 = lock */
unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */
int fd; /* file desc to assoc this lock with */
};
#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2)
/* return 0 on success, 1 on failure. To match the behavior of the
normal posix file locking (used in unixLock for example), we should
provide 'richer' return codes - specifically to differentiate between
'file busy' and 'file system error' results */
static int _AFPFSSetLock(const char *path, int fd, unsigned long long offset,
unsigned long long length, int setLockFlag)
{
struct ByteRangeLockPB2 pb;
int err;
pb.unLockFlag = setLockFlag ? 0 : 1;
pb.startEndFlag = 0;
pb.offset = offset;
pb.length = length;
pb.fd = fd;
TRACE5("AFPLOCK setting lock %s for %d in range %llx:%llx\n",
(setLockFlag?"ON":"OFF"), fd, offset, length);
err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
if ( err==-1 ) {
TRACE4("AFPLOCK failed to fsctl() '%s' %d %s\n", path, errno,
strerror(errno));
return 1; // error
} else {
return 0;
}
}
/*
** 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. If the file is unlocked or holds only SHARED locks, then
** return zero.
*/
static int afpUnixCheckReservedLock(OsFile *id){
int r = 0;
unixFile *pFile = (unixFile*)id;
assert( pFile );
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
/* Check if a thread in this process holds such a lock */
if( pFile->locktype>SHARED_LOCK ){
r = 1;
}
/* Otherwise see if some other process holds it.
*/
if ( !r ) {
// lock the byte
int failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1);
if (failed) {
/* if we failed to get the lock then someone else must have it */
r = 1;
} else {
/* if we succeeded in taking the reserved lock, unlock it to restore
** the original state */
_AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0);
}
}
TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
return r;
}
/* AFP-style locking following the behavior of unixLock, see the unixLock
** function comments for details of lock management. */
static int afpUnixLock(OsFile *id, int locktype)
{
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
int gotPendingLock = 0;
assert( pFile );
TRACE5("LOCK %d %s was %s pid=%d\n", pFile->h,
locktypeName(locktype), locktypeName(pFile->locktype), getpid());
/* If there is already a lock of this type or more restrictive on the
** OsFile, do nothing. Don't use the afp_end_lock: exit path, as
** sqlite3OsEnterMutex() hasn't been called yet.
*/
if( pFile->locktype>=locktype ){
TRACE3("LOCK %d %s ok (already held)\n", pFile->h,
locktypeName(locktype));
return SQLITE_OK;
}
/* Make sure the locking sequence is correct
*/
assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
assert( locktype!=PENDING_LOCK );
assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
/* This mutex is needed because pFile->pLock is shared across threads
*/
sqlite3OsEnterMutex();
/* Make sure the current thread owns the pFile.
*/
rc = transferOwnership(pFile);
if( rc!=SQLITE_OK ){
sqlite3OsLeaveMutex();
return rc;
}
/* 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
|| (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK)
){
int failed = _AFPFSSetLock(context->filePath, pFile->h,
PENDING_BYTE, 1, 1);
if (failed) {
rc = SQLITE_BUSY;
goto afp_end_lock;
}
}
/* If control gets to this point, then actually go ahead and make
** operating system calls for the specified lock.
*/
if( locktype==SHARED_LOCK ){
int lk, failed;
int tries = 0;
/* Now get the read-lock */
/* note that the quality of the randomness doesn't matter that much */
lk = random();
context->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
failed = _AFPFSSetLock(context->filePath, pFile->h,
SHARED_FIRST+context->sharedLockByte, 1, 1);
/* Drop the temporary PENDING lock */
if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)) {
rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
goto afp_end_lock;
}
if( failed ){
rc = SQLITE_BUSY;
} else {
pFile->locktype = SHARED_LOCK;
}
}else{
/* The request was for a RESERVED or EXCLUSIVE lock. It is
** assumed that there is a SHARED or greater lock on the file
** already.
*/
int failed = 0;
assert( 0!=pFile->locktype );
if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) {
/* Acquire a RESERVED lock */
failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1);
}
if (!failed && locktype == EXCLUSIVE_LOCK) {
/* Acquire an EXCLUSIVE lock */
/* Remove the shared lock before trying the range. we'll need to
** reestablish the shared lock if we can't get the afpUnixUnlock
*/
if (!_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST +
context->sharedLockByte, 1, 0)) {
/* now attemmpt to get the exclusive lock range */
failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST,
SHARED_SIZE, 1);
if (failed && _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST +
context->sharedLockByte, 1, 1)) {
rc = SQLITE_IOERR_RDLOCK; /* this should never happen */
}
} else {
/* */
rc = SQLITE_IOERR_UNLOCK; /* this should never happen */
}
}
if( failed && rc == SQLITE_OK){
rc = SQLITE_BUSY;
}
}
if( rc==SQLITE_OK ){
pFile->locktype = locktype;
}else if( locktype==EXCLUSIVE_LOCK ){
pFile->locktype = PENDING_LOCK;
}
afp_end_lock:
sqlite3OsLeaveMutex();
TRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
rc==SQLITE_OK ? "ok" : "failed");
return rc;
}
/*
** Lower the locking level on file descriptor pFile 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.
*/
static int afpUnixUnlock(OsFile *id, int locktype) {
struct flock lock;
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
assert( pFile );
TRACE5("UNLOCK %d %d was %d pid=%d\n", pFile->h, locktype,
pFile->locktype, getpid());
assert( locktype<=SHARED_LOCK );
if( pFile->locktype<=locktype ){
return SQLITE_OK;
}
if( CHECK_THREADID(pFile) ){
return SQLITE_MISUSE;
}
sqlite3OsEnterMutex();
if( pFile->locktype>SHARED_LOCK ){
if( locktype==SHARED_LOCK ){
int failed = 0;
/* unlock the exclusive range - then re-establish the shared lock */
if (pFile->locktype==EXCLUSIVE_LOCK) {
failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST,
SHARED_SIZE, 0);
if (!failed) {
/* successfully removed the exclusive lock */
if (_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST+
context->sharedLockByte, 1, 1)) {
/* failed to re-establish our shared lock */
rc = SQLITE_IOERR_RDLOCK; /* This should never happen */
}
} else {
/* This should never happen - failed to unlock the exclusive range */
rc = SQLITE_IOERR_UNLOCK;
}
}
}
if (rc == SQLITE_OK && pFile->locktype>=PENDING_LOCK) {
if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)){
/* failed to release the pending lock */
rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
}
}
if (rc == SQLITE_OK && pFile->locktype>=RESERVED_LOCK) {
if (_AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0)) {
/* failed to release the reserved lock */
rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
}
}
}
if( locktype==NO_LOCK ){
int failed = _AFPFSSetLock(context->filePath, pFile->h,
SHARED_FIRST + context->sharedLockByte, 1, 0);
if (failed) {
rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
}
}
if (rc == SQLITE_OK)
pFile->locktype = locktype;
sqlite3OsLeaveMutex();
return rc;
}
/*
** Close a file & cleanup AFP specific locking context
*/
static int afpUnixClose(OsFile **pId) {
unixFile *id = (unixFile*)*pId;
if( !id ) return SQLITE_OK;
afpUnixUnlock(*pId, NO_LOCK);
/* free the AFP locking structure */
if (id->lockingContext != NULL) {
if (((afpLockingContext *)id->lockingContext)->filePath != NULL)
sqlite3ThreadSafeFree(((afpLockingContext*)id->lockingContext)->filePath);
sqlite3ThreadSafeFree(id->lockingContext);
}
if( id->dirfd>=0 ) close(id->dirfd);
id->dirfd = -1;
close(id->h);
id->isOpen = 0;
TRACE2("CLOSE %-3d\n", id->h);
OpenCounter(-1);
sqlite3ThreadSafeFree(id);
*pId = 0;
return SQLITE_OK;
}
#pragma mark flock() style locking
/*
** The flockLockingContext is not used
*/
typedef void flockLockingContext;
static int flockUnixCheckReservedLock(OsFile *id) {
unixFile *pFile = (unixFile*)id;
if (pFile->locktype == RESERVED_LOCK) {
return 1; // already have a reserved lock
} else {
// attempt to get the lock
int rc = flock(pFile->h, LOCK_EX | LOCK_NB);
if (!rc) {
// got the lock, unlock it
flock(pFile->h, LOCK_UN);
return 0; // no one has it reserved
}
return 1; // someone else might have it reserved
}
}
static int flockUnixLock(OsFile
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -