* Replaced BFS's ReadWriteLock implementation with the kernel's rw_lock.

* The BlockAllocator now uses the new mutex_transfer_lock() function instead
  of clobbering the mutex directly.
* Removed Lock.h - it's no longer needed.
* Minor white space cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26317 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-07-08 08:04:37 +00:00
parent 78b32dd026
commit 1bde8b03e7
10 changed files with 47 additions and 385 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007, Axel Dörfler, [email protected].
* Copyright 2004-2008, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License.
*/
@@ -71,7 +71,7 @@ Attribute::CheckAccess(const char *name, int openMode)
}
status_t
status_t
Attribute::Get(const char *name)
{
Put();
@@ -119,7 +119,7 @@ Attribute::Create(const char *name, type_code type, int openMode, attr_cookie **
attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie));
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
RETURN_ERROR(B_NO_MEMORY);
fName = name;
@@ -152,7 +152,7 @@ Attribute::Open(const char *name, int openMode, attr_cookie **_cookie)
attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie));
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
RETURN_ERROR(B_NO_MEMORY);
// initialize the cookie
strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
@@ -222,7 +222,7 @@ Attribute::_Truncate()
}
if (fAttribute != NULL) {
WriteLocked locked(fAttribute->Lock());
WriteLocker locker(fAttribute->Lock());
Transaction transaction(fAttribute->GetVolume(), fAttribute->BlockNumber());
status_t status = fAttribute->SetFileSize(transaction, 0);
@@ -1259,7 +1259,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
#endif
// lock access to stream
WriteLocked locked(fStream->Lock());
WriteLocker locker(fStream->Lock());
Stack<node_and_key> stack;
if (_SeekDown(stack, key, keyLength) != B_OK)
@@ -1653,7 +1653,7 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
RETURN_ERROR(B_BAD_VALUE);
// lock access to stream
WriteLocked locked(fStream->Lock());
WriteLocker locker(fStream->Lock());
Stack<node_and_key> stack;
if (_SeekDown(stack, key, keyLength) != B_OK)
@@ -1771,7 +1771,7 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key,
RETURN_ERROR(B_BAD_TYPE);
// lock access to stream (a read lock is okay for this purpose)
ReadLocked locked(fStream->Lock());
ReadLocker locker(fStream->Lock());
off_t nodeOffset = fHeader->RootNode();
CachedNode cached(this);
@@ -1825,7 +1825,7 @@ BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
RETURN_ERROR(B_BAD_TYPE);
// lock access to stream
ReadLocked locked(fStream->Lock());
ReadLocker locker(fStream->Lock());
off_t nodeOffset = fHeader->RootNode();
CachedNode cached(this);
@@ -1889,7 +1889,7 @@ TreeIterator::Goto(int8 to)
RETURN_ERROR(B_BAD_VALUE);
// lock access to stream
ReadLocked locked(fTree->fStream->Lock());
ReadLocker locker(fTree->fStream->Lock());
off_t nodeOffset = fTree->fHeader->RootNode();
CachedNode cached(fTree);
@@ -1959,7 +1959,7 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength,
return B_ENTRY_NOT_FOUND;
// lock access to stream
ReadLocked locked(fTree->fStream->Lock());
ReadLocker locker(fTree->fStream->Lock());
CachedNode cached(fTree);
const bplustree_node *node;
@@ -2095,7 +2095,7 @@ TreeIterator::Find(const uint8 *key, uint16 keyLength)
RETURN_ERROR(B_BAD_VALUE);
// lock access to stream
ReadLocked locked(fTree->fStream->Lock());
ReadLocker locker(fTree->fStream->Lock());
off_t nodeOffset = fTree->fHeader->RootNode();
@@ -474,10 +474,8 @@ BlockAllocator::Initialize(bool full)
"bfs block allocator", B_LOW_PRIORITY, (void *)this);
if (id < B_OK)
return _Initialize(this);
#ifdef KDEBUG
else
fLock.holder = id;
#endif
mutex_transfer_lock(&fLock, id);
return resume_thread(id);
}
@@ -12,7 +12,6 @@
#include "Volume.h"
#include "Journal.h"
#include "Lock.h"
#include "Chain.h"
#include "Debug.h"
@@ -96,7 +95,7 @@ CachedBlock::CachedBlock(Volume *volume, block_run run)
}
inline
inline
CachedBlock::CachedBlock(CachedBlock *cached)
:
fVolume(cached->fVolume),
@@ -161,7 +160,7 @@ CachedBlock::SetToWritable(Transaction &transaction, off_t block, off_t base,
{
Unset();
fBlockNumber = block;
if (empty) {
fBlock = (uint8 *)block_cache_get_empty(fVolume->BlockCache(),
block, transaction.ID());
@@ -1,5 +1,5 @@
/*
* Copyright 2001-2007, Axel Dörfler, axeld@pinc-software.de.
/*
* Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
@@ -63,7 +63,7 @@ Index::SetTo(const char *name)
{
// remove the old node, if the index is set for the second time
Unset();
fName = name;
// only stores the pointer, so it assumes that it will stay constant
// in further comparisons (currently only used in Index::Update())
@@ -138,7 +138,7 @@ Index::KeySize()
{
if (fNode == NULL)
return 0;
int32 mode = fNode->Mode() & (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX
| S_LONG_LONG_INDEX | S_ULONG_LONG_INDEX | S_FLOAT_INDEX
| S_DOUBLE_INDEX);
+13 -13
View File
@@ -328,7 +328,7 @@ Inode::Inode(Volume *volume, ino_t id)
char lockName[B_OS_NAME_LENGTH];
snprintf(lockName, sizeof(lockName), "bfs inode %d.%d",
(int)BlockRun().AllocationGroup(), BlockRun().Start());
fLock.Initialize(lockName);
rw_lock_init_etc(&fLock, lockName, RW_LOCK_FLAG_CLONE_NAME);
recursive_lock_init(&fSmallDataLock, "bfs inode small data");
@@ -361,7 +361,7 @@ Inode::Inode(Volume *volume, Transaction &transaction, ino_t id, mode_t mode,
char lockName[B_OS_NAME_LENGTH];
snprintf(lockName, sizeof(lockName), "bfs inode+%d.%d",
(int)run.AllocationGroup(), run.Start());
fLock.Initialize(lockName);
rw_lock_init_etc(&fLock, lockName, RW_LOCK_FLAG_CLONE_NAME);
recursive_lock_init(&fSmallDataLock, "bfs inode small data");
@@ -399,6 +399,8 @@ Inode::~Inode()
file_cache_delete(FileCache());
file_map_delete(Map());
delete fTree;
rw_lock_destroy(&fLock);
}
@@ -429,9 +431,7 @@ Inode::InitCheck(bool checkNode)
}
}
// it's more important to know that the inode is corrupt
// so we check for the lock not until here
return fLock.InitCheck();
return B_OK;
}
@@ -1055,7 +1055,7 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
}
if (attribute != NULL) {
if (attribute->Lock().LockWrite() == B_OK) {
if (rw_lock_write_lock(&attribute->Lock()) == B_OK) {
// Save the old attribute data (if this fails, oldLength will
// reflect it)
if (fVolume->CheckForLiveQuery(name) && attribute->Size() > 0) {
@@ -1071,14 +1071,14 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
if (status == B_OK) {
// it does - remove its file
attribute->Lock().UnlockWrite();
rw_lock_write_unlock(&attribute->Lock());
status = _RemoveAttribute(transaction, name, false, NULL);
} else {
// The attribute type might have been changed - we need to
// adopt the new one
attribute->Node().type = HOST_ENDIAN_TO_BFS_INT32(type);
status = attribute->WriteBack(transaction);
attribute->Lock().UnlockWrite();
rw_lock_write_unlock(&attribute->Lock());
if (status == B_OK) {
status = attribute->WriteAt(transaction, pos, buffer,
@@ -1376,7 +1376,7 @@ Inode::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
if (pos < 0)
return B_BAD_VALUE;
ReadLocked locker(Lock());
ReadLocker locker(Lock());
if (pos >= Size() || length == 0) {
*_length = 0;
@@ -1393,8 +1393,8 @@ status_t
Inode::WriteAt(Transaction &transaction, off_t pos, const uint8 *buffer,
size_t *_length)
{
WriteLocked locker(Lock());
if (locker.IsLocked() < B_OK)
WriteLocker locker(Lock());
if (!locker.IsLocked())
RETURN_ERROR(B_ERROR);
// update the last modification time in memory, it will be written
@@ -2310,7 +2310,7 @@ Inode::Create(Transaction &transaction, Inode *parent, const char *name,
RETURN_ERROR(B_BAD_VALUE);
}
WriteLocked locker(parent != NULL ? &parent->Lock() : NULL);
WriteLocker locker(parent != NULL ? &parent->Lock() : NULL);
// the parent directory is locked during the whole inode creation
if (parent != NULL && parent->IsDirectory()) {
@@ -2354,7 +2354,7 @@ Inode::Create(Transaction &transaction, Inode *parent, const char *name,
return status;
// truncate the existing file
WriteLocked locked(inode->Lock());
WriteLocker _(inode->Lock());
status_t status = inode->SetFileSize(transaction, 0);
if (status >= B_OK)
+2 -3
View File
@@ -10,7 +10,6 @@
#include "Volume.h"
#include "Journal.h"
#include "Lock.h"
#include "Chain.h"
#include "Debug.h"
#include "CachedBlock.h"
@@ -45,7 +44,7 @@ class Inode {
ino_t ID() const { return fID; }
off_t BlockNumber() const { return fVolume->VnodeToBlock(fID); }
ReadWriteLock &Lock() { return fLock; }
rw_lock &Lock() { return fLock; }
recursive_lock &SmallDataLock() { return fSmallDataLock; }
status_t WriteBack(Transaction &transaction);
@@ -193,7 +192,7 @@ class Inode {
status_t _ShrinkStream(Transaction &transaction, off_t size);
private:
ReadWriteLock fLock;
rw_lock fLock;
Volume *fVolume;
ino_t fID;
BPlusTree *fTree;
@@ -14,7 +14,6 @@
#include "Volume.h"
#include "Chain.h"
#include "Lock.h"
#include "Utility.h"
-332
View File
@@ -1,332 +0,0 @@
/*
* Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
#ifndef LOCK_H
#define LOCK_H
/*! Simple semaphores, read/write lock implementation
Roughly based on a Be sample code written by Nathan Schrenk.
*/
#include "system_dependencies.h"
#include "Utility.h"
#include "Debug.h"
// Configure here if and when real benaphores should be used
//#define USE_BENAPHORE
// if defined, benaphores are used for the Semaphore/RecursiveLock classes
//# define FAST_LOCK
// the ReadWriteLock class uses a second Semaphore to
// speed up locking - only makes sense if USE_BENAPHORE
// is defined, too.
#ifdef FAST_LOCK
# error implement recursive write locking first
#endif
// #pragma mark - Many Reader/Single Writer Lock
// This is a "fast" implementation of a single writer/many reader
// locking scheme. It's fast because it uses the benaphore idea
// to do lazy semaphore locking - in most cases it will only have
// to do some simple integer arithmetic.
// The second semaphore (fWriteLock) is needed to prevent the situation
// that a second writer can acquire the lock when there are still readers
// holding it.
#define MAX_READERS 100000
// Note: this code will break if you actually have 100000 readers
// at once. With the current thread/... limits in BeOS you can't
// touch that value, but it might be possible in the future.
// Also, you can only have about 20000 concurrent writers until
// the semaphore count exceeds the int32 bounds
// Timeouts:
// It may be a good idea to have timeouts for the WriteLocked class,
// in case something went wrong - we'll see if this is necessary,
// but it would be a somewhat poor work-around for a deadlock...
// But the only real problem with timeouts could be for things like
// "chkbfs" - because such a tool may need to lock for some more time
// define if you want to have fast locks as the foundation for the
// ReadWriteLock class - the benefit is that acquire_sem() doesn't
// have to be called when there is no one waiting.
// The disadvantage is the use of 2 real semaphores which is quite
// expensive regarding that BeOS only allows for a total of 64k
// semaphores (since every open BFS inode has such a lock).
#ifdef FAST_LOCK
class ReadWriteLock {
public:
ReadWriteLock(const char *name)
:
fWriteLock(name)
{
Initialize(name);
}
ReadWriteLock()
:
fWriteLock("bfs r/w w-lock")
{
}
~ReadWriteLock()
{
delete_sem(fSemaphore);
}
status_t Initialize(const char *name = "bfs r/w lock")
{
fSemaphore = create_sem(0, name);
fCount = MAX_READERS;
return fSemaphore;
}
status_t InitCheck()
{
if (fSemaphore < B_OK)
return fSemaphore;
return B_OK;
}
status_t Lock()
{
if (atomic_add(&fCount, -1) <= 0)
return acquire_sem(fSemaphore);
return B_OK;
}
void Unlock()
{
if (atomic_add(&fCount, 1) < 0)
release_sem(fSemaphore);
}
status_t LockWrite()
{
if (fWriteLock.Lock() < B_OK)
return B_ERROR;
int32 readers = atomic_add(&fCount, -MAX_READERS);
status_t status = B_OK;
if (readers < MAX_READERS) {
// Acquire sem for all readers currently not using a semaphore.
// But if we are not the only write lock in the queue, just get
// the one for us
status = acquire_sem_etc(fSemaphore, readers <= 0 ? 1 : MAX_READERS - readers, 0, 0);
}
fWriteLock.Unlock();
return status;
}
void UnlockWrite()
{
int32 readers = atomic_add(&fCount, MAX_READERS);
if (readers < 0) {
// release sem for all readers only when we were the only writer
release_sem_etc(fSemaphore, readers <= -MAX_READERS ? 1 : -readers, 0);
}
}
private:
friend class ReadLocked;
friend class WriteLocked;
sem_id fSemaphore;
vint32 fCount;
Semaphore fWriteLock;
};
#else // FAST_LOCK
class ReadWriteLock {
public:
ReadWriteLock(const char *name)
:
fOwner(-1)
{
Initialize(name);
}
ReadWriteLock()
:
fSemaphore(-1),
fOwner(-1)
{
}
~ReadWriteLock()
{
delete_sem(fSemaphore);
}
status_t Initialize(const char *name = "bfs r/w lock")
{
fSemaphore = create_sem(MAX_READERS, name);
return fSemaphore;
}
status_t InitCheck()
{
if (fSemaphore < B_OK)
return fSemaphore;
return B_OK;
}
status_t Lock()
{
// This allows nested locking when holding a write lock
thread_id currentThread = find_thread(NULL);
if (currentThread == fOwner) {
fOwnerCount++;
return B_OK;
}
return acquire_sem(fSemaphore);
}
status_t TryLock()
{
// This allows nested locking when holding a write lock
thread_id currentThread = find_thread(NULL);
if (currentThread == fOwner) {
fOwnerCount++;
return B_OK;
}
return acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT, 0);
}
void Unlock()
{
thread_id currentThread = find_thread(NULL);
if (fOwner == currentThread && --fOwnerCount > 0)
return;
release_sem(fSemaphore);
}
status_t LockWrite()
{
thread_id currentThread = find_thread(NULL);
if (currentThread == fOwner) {
fOwnerCount++;
return B_OK;
}
status_t status = acquire_sem_etc(fSemaphore, MAX_READERS, 0, 0);
if (status >= B_OK) {
fOwner = currentThread;
fOwnerCount = 1;
}
return status;
}
void UnlockWrite()
{
if (--fOwnerCount == 0) {
fOwner = -1;
release_sem_etc(fSemaphore, MAX_READERS, 0);
}
}
private:
friend class ReadLocked;
friend class WriteLocked;
sem_id fSemaphore;
thread_id fOwner;
int32 fOwnerCount;
};
#endif // FAST_LOCK
class ReadLocked {
public:
ReadLocked(ReadWriteLock &lock)
:
fLock(lock)
{
fStatus = lock.Lock();
}
~ReadLocked()
{
if (fStatus == B_OK)
fLock.Unlock();
}
status_t
IsLocked()
{
return fStatus;
}
void
Unlock()
{
fLock.Unlock();
fStatus = B_NO_INIT;
}
private:
ReadWriteLock &fLock;
status_t fStatus;
};
class WriteLocked {
public:
WriteLocked(ReadWriteLock &lock)
:
fLock(&lock)
{
fStatus = lock.LockWrite();
}
WriteLocked(ReadWriteLock *lock)
:
fLock(lock)
{
fStatus = lock != NULL ? lock->LockWrite() : B_NO_INIT;
}
~WriteLocked()
{
if (fStatus == B_OK)
fLock->UnlockWrite();
}
status_t
Lock()
{
if (fStatus == B_OK)
return B_ERROR;
return fStatus = fLock->LockWrite();
}
status_t
IsLocked()
{
return fStatus;
}
void
Unlock()
{
if (fStatus == B_OK)
fLock->UnlockWrite();
fStatus = B_ERROR;
}
private:
ReadWriteLock *fLock;
status_t fStatus;
};
#endif /* LOCK_H */
@@ -339,7 +339,7 @@ bfs_read_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie,
RETURN_ERROR(B_BAD_VALUE);
if (!reenter)
inode->Lock().Lock();
rw_lock_read_lock(&inode->Lock());
uint32 vecIndex = 0;
size_t vecOffset = 0;
@@ -368,7 +368,7 @@ bfs_read_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie,
}
if (!reenter)
inode->Lock().Unlock();
rw_lock_read_unlock(&inode->Lock());
return status;
}
@@ -388,7 +388,7 @@ bfs_write_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie,
RETURN_ERROR(B_BAD_VALUE);
if (!reenter)
inode->Lock().Lock();
rw_lock_read_lock(&inode->Lock());
uint32 vecIndex = 0;
size_t vecOffset = 0;
@@ -417,7 +417,7 @@ bfs_write_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie,
}
if (!reenter)
inode->Lock().Unlock();
rw_lock_read_unlock(&inode->Lock());
return status;
}
@@ -646,11 +646,10 @@ bfs_fsync(fs_volume *_volume, fs_vnode *_node)
return B_BAD_VALUE;
Inode *inode = (Inode *)_node->private_node;
ReadLocked locked(inode->Lock());
ReadLocker locker(inode->Lock());
status_t status = locked.IsLocked();
if (status < B_OK)
RETURN_ERROR(status);
if (!locker.IsLocked())
RETURN_ERROR(B_ERROR);
return inode->Sync();
}
@@ -689,8 +688,8 @@ bfs_write_stat(fs_volume *_volume, fs_vnode *_node, const struct stat *stat,
Transaction transaction(volume, inode->BlockNumber());
WriteLocked locked(inode->Lock());
if (locked.IsLocked() < B_OK)
WriteLocker locker(inode->Lock());
if (!locker.IsLocked())
RETURN_ERROR(B_ERROR);
bfs_inode &node = inode->Node();
@@ -1150,7 +1149,7 @@ bfs_open(fs_volume *_volume, fs_vnode *_node, int openMode, void **_cookie)
// Should we truncate the file?
if (openMode & O_TRUNC) {
Transaction transaction(volume, inode->BlockNumber());
WriteLocked locked(inode->Lock());
WriteLocker locker(inode->Lock());
status_t status = inode->SetFileSize(transaction, 0);
if (status >= B_OK)
@@ -1219,7 +1218,7 @@ bfs_write(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
transaction.Done();
if (status == B_OK) {
ReadLocked locker(inode->Lock());
ReadLocker locker(inode->Lock());
// periodically notify if the file size has changed
// TODO: should we better test for a change in the last_modified time only?
@@ -1258,7 +1257,7 @@ bfs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
bool needsTrimming = false;
if (!volume->IsReadOnly()) {
ReadLocked locker(inode->Lock());
ReadLocker locker(inode->Lock());
needsTrimming = inode->NeedsTrimming();
if ((cookie->open_mode & O_RWMASK) != 0
@@ -1274,7 +1273,7 @@ bfs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
status_t status = transaction.IsStarted() ? B_OK : B_ERROR;
if (status == B_OK) {
WriteLocked locker(inode->Lock());
WriteLocker locker(inode->Lock());
// trim the preallocated blocks and update the size,
// and last_modified indices if needed