* 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:
@@ -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.
|
* 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)
|
Attribute::Get(const char *name)
|
||||||
{
|
{
|
||||||
Put();
|
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));
|
attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie));
|
||||||
if (cookie == NULL)
|
if (cookie == NULL)
|
||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
fName = name;
|
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));
|
attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie));
|
||||||
if (cookie == NULL)
|
if (cookie == NULL)
|
||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
// initialize the cookie
|
// initialize the cookie
|
||||||
strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
|
strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
|
||||||
@@ -222,7 +222,7 @@ Attribute::_Truncate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fAttribute != NULL) {
|
if (fAttribute != NULL) {
|
||||||
WriteLocked locked(fAttribute->Lock());
|
WriteLocker locker(fAttribute->Lock());
|
||||||
Transaction transaction(fAttribute->GetVolume(), fAttribute->BlockNumber());
|
Transaction transaction(fAttribute->GetVolume(), fAttribute->BlockNumber());
|
||||||
|
|
||||||
status_t status = fAttribute->SetFileSize(transaction, 0);
|
status_t status = fAttribute->SetFileSize(transaction, 0);
|
||||||
|
|||||||
@@ -1259,7 +1259,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// lock access to stream
|
// lock access to stream
|
||||||
WriteLocked locked(fStream->Lock());
|
WriteLocker locker(fStream->Lock());
|
||||||
|
|
||||||
Stack<node_and_key> stack;
|
Stack<node_and_key> stack;
|
||||||
if (_SeekDown(stack, key, keyLength) != B_OK)
|
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);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
// lock access to stream
|
// lock access to stream
|
||||||
WriteLocked locked(fStream->Lock());
|
WriteLocker locker(fStream->Lock());
|
||||||
|
|
||||||
Stack<node_and_key> stack;
|
Stack<node_and_key> stack;
|
||||||
if (_SeekDown(stack, key, keyLength) != B_OK)
|
if (_SeekDown(stack, key, keyLength) != B_OK)
|
||||||
@@ -1771,7 +1771,7 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key,
|
|||||||
RETURN_ERROR(B_BAD_TYPE);
|
RETURN_ERROR(B_BAD_TYPE);
|
||||||
|
|
||||||
// lock access to stream (a read lock is okay for this purpose)
|
// 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();
|
off_t nodeOffset = fHeader->RootNode();
|
||||||
CachedNode cached(this);
|
CachedNode cached(this);
|
||||||
@@ -1825,7 +1825,7 @@ BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
|
|||||||
RETURN_ERROR(B_BAD_TYPE);
|
RETURN_ERROR(B_BAD_TYPE);
|
||||||
|
|
||||||
// lock access to stream
|
// lock access to stream
|
||||||
ReadLocked locked(fStream->Lock());
|
ReadLocker locker(fStream->Lock());
|
||||||
|
|
||||||
off_t nodeOffset = fHeader->RootNode();
|
off_t nodeOffset = fHeader->RootNode();
|
||||||
CachedNode cached(this);
|
CachedNode cached(this);
|
||||||
@@ -1889,7 +1889,7 @@ TreeIterator::Goto(int8 to)
|
|||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
// lock access to stream
|
// lock access to stream
|
||||||
ReadLocked locked(fTree->fStream->Lock());
|
ReadLocker locker(fTree->fStream->Lock());
|
||||||
|
|
||||||
off_t nodeOffset = fTree->fHeader->RootNode();
|
off_t nodeOffset = fTree->fHeader->RootNode();
|
||||||
CachedNode cached(fTree);
|
CachedNode cached(fTree);
|
||||||
@@ -1959,7 +1959,7 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength,
|
|||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
// lock access to stream
|
// lock access to stream
|
||||||
ReadLocked locked(fTree->fStream->Lock());
|
ReadLocker locker(fTree->fStream->Lock());
|
||||||
|
|
||||||
CachedNode cached(fTree);
|
CachedNode cached(fTree);
|
||||||
const bplustree_node *node;
|
const bplustree_node *node;
|
||||||
@@ -2095,7 +2095,7 @@ TreeIterator::Find(const uint8 *key, uint16 keyLength)
|
|||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
// lock access to stream
|
// lock access to stream
|
||||||
ReadLocked locked(fTree->fStream->Lock());
|
ReadLocker locker(fTree->fStream->Lock());
|
||||||
|
|
||||||
off_t nodeOffset = fTree->fHeader->RootNode();
|
off_t nodeOffset = fTree->fHeader->RootNode();
|
||||||
|
|
||||||
|
|||||||
@@ -474,10 +474,8 @@ BlockAllocator::Initialize(bool full)
|
|||||||
"bfs block allocator", B_LOW_PRIORITY, (void *)this);
|
"bfs block allocator", B_LOW_PRIORITY, (void *)this);
|
||||||
if (id < B_OK)
|
if (id < B_OK)
|
||||||
return _Initialize(this);
|
return _Initialize(this);
|
||||||
#ifdef KDEBUG
|
|
||||||
else
|
else
|
||||||
fLock.holder = id;
|
mutex_transfer_lock(&fLock, id);
|
||||||
#endif
|
|
||||||
|
|
||||||
return resume_thread(id);
|
return resume_thread(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include "Volume.h"
|
#include "Volume.h"
|
||||||
#include "Journal.h"
|
#include "Journal.h"
|
||||||
#include "Lock.h"
|
|
||||||
#include "Chain.h"
|
#include "Chain.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
|
|
||||||
@@ -96,7 +95,7 @@ CachedBlock::CachedBlock(Volume *volume, block_run run)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline
|
inline
|
||||||
CachedBlock::CachedBlock(CachedBlock *cached)
|
CachedBlock::CachedBlock(CachedBlock *cached)
|
||||||
:
|
:
|
||||||
fVolume(cached->fVolume),
|
fVolume(cached->fVolume),
|
||||||
@@ -161,7 +160,7 @@ CachedBlock::SetToWritable(Transaction &transaction, off_t block, off_t base,
|
|||||||
{
|
{
|
||||||
Unset();
|
Unset();
|
||||||
fBlockNumber = block;
|
fBlockNumber = block;
|
||||||
|
|
||||||
if (empty) {
|
if (empty) {
|
||||||
fBlock = (uint8 *)block_cache_get_empty(fVolume->BlockCache(),
|
fBlock = (uint8 *)block_cache_get_empty(fVolume->BlockCache(),
|
||||||
block, transaction.ID());
|
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.
|
* 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
|
// remove the old node, if the index is set for the second time
|
||||||
Unset();
|
Unset();
|
||||||
|
|
||||||
fName = name;
|
fName = name;
|
||||||
// only stores the pointer, so it assumes that it will stay constant
|
// only stores the pointer, so it assumes that it will stay constant
|
||||||
// in further comparisons (currently only used in Index::Update())
|
// in further comparisons (currently only used in Index::Update())
|
||||||
@@ -138,7 +138,7 @@ Index::KeySize()
|
|||||||
{
|
{
|
||||||
if (fNode == NULL)
|
if (fNode == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int32 mode = fNode->Mode() & (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX
|
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_LONG_LONG_INDEX | S_ULONG_LONG_INDEX | S_FLOAT_INDEX
|
||||||
| S_DOUBLE_INDEX);
|
| S_DOUBLE_INDEX);
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ Inode::Inode(Volume *volume, ino_t id)
|
|||||||
char lockName[B_OS_NAME_LENGTH];
|
char lockName[B_OS_NAME_LENGTH];
|
||||||
snprintf(lockName, sizeof(lockName), "bfs inode %d.%d",
|
snprintf(lockName, sizeof(lockName), "bfs inode %d.%d",
|
||||||
(int)BlockRun().AllocationGroup(), BlockRun().Start());
|
(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");
|
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];
|
char lockName[B_OS_NAME_LENGTH];
|
||||||
snprintf(lockName, sizeof(lockName), "bfs inode+%d.%d",
|
snprintf(lockName, sizeof(lockName), "bfs inode+%d.%d",
|
||||||
(int)run.AllocationGroup(), run.Start());
|
(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");
|
recursive_lock_init(&fSmallDataLock, "bfs inode small data");
|
||||||
|
|
||||||
@@ -399,6 +399,8 @@ Inode::~Inode()
|
|||||||
file_cache_delete(FileCache());
|
file_cache_delete(FileCache());
|
||||||
file_map_delete(Map());
|
file_map_delete(Map());
|
||||||
delete fTree;
|
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
|
return B_OK;
|
||||||
// so we check for the lock not until here
|
|
||||||
return fLock.InitCheck();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1055,7 +1055,7 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (attribute != NULL) {
|
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
|
// Save the old attribute data (if this fails, oldLength will
|
||||||
// reflect it)
|
// reflect it)
|
||||||
if (fVolume->CheckForLiveQuery(name) && attribute->Size() > 0) {
|
if (fVolume->CheckForLiveQuery(name) && attribute->Size() > 0) {
|
||||||
@@ -1071,14 +1071,14 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
|
|||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
// it does - remove its file
|
// it does - remove its file
|
||||||
attribute->Lock().UnlockWrite();
|
rw_lock_write_unlock(&attribute->Lock());
|
||||||
status = _RemoveAttribute(transaction, name, false, NULL);
|
status = _RemoveAttribute(transaction, name, false, NULL);
|
||||||
} else {
|
} else {
|
||||||
// The attribute type might have been changed - we need to
|
// The attribute type might have been changed - we need to
|
||||||
// adopt the new one
|
// adopt the new one
|
||||||
attribute->Node().type = HOST_ENDIAN_TO_BFS_INT32(type);
|
attribute->Node().type = HOST_ENDIAN_TO_BFS_INT32(type);
|
||||||
status = attribute->WriteBack(transaction);
|
status = attribute->WriteBack(transaction);
|
||||||
attribute->Lock().UnlockWrite();
|
rw_lock_write_unlock(&attribute->Lock());
|
||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
status = attribute->WriteAt(transaction, pos, buffer,
|
status = attribute->WriteAt(transaction, pos, buffer,
|
||||||
@@ -1376,7 +1376,7 @@ Inode::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
|||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
ReadLocked locker(Lock());
|
ReadLocker locker(Lock());
|
||||||
|
|
||||||
if (pos >= Size() || length == 0) {
|
if (pos >= Size() || length == 0) {
|
||||||
*_length = 0;
|
*_length = 0;
|
||||||
@@ -1393,8 +1393,8 @@ status_t
|
|||||||
Inode::WriteAt(Transaction &transaction, off_t pos, const uint8 *buffer,
|
Inode::WriteAt(Transaction &transaction, off_t pos, const uint8 *buffer,
|
||||||
size_t *_length)
|
size_t *_length)
|
||||||
{
|
{
|
||||||
WriteLocked locker(Lock());
|
WriteLocker locker(Lock());
|
||||||
if (locker.IsLocked() < B_OK)
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
// update the last modification time in memory, it will be written
|
// 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);
|
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
|
// the parent directory is locked during the whole inode creation
|
||||||
|
|
||||||
if (parent != NULL && parent->IsDirectory()) {
|
if (parent != NULL && parent->IsDirectory()) {
|
||||||
@@ -2354,7 +2354,7 @@ Inode::Create(Transaction &transaction, Inode *parent, const char *name,
|
|||||||
return status;
|
return status;
|
||||||
|
|
||||||
// truncate the existing file
|
// truncate the existing file
|
||||||
WriteLocked locked(inode->Lock());
|
WriteLocker _(inode->Lock());
|
||||||
|
|
||||||
status_t status = inode->SetFileSize(transaction, 0);
|
status_t status = inode->SetFileSize(transaction, 0);
|
||||||
if (status >= B_OK)
|
if (status >= B_OK)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "Volume.h"
|
#include "Volume.h"
|
||||||
#include "Journal.h"
|
#include "Journal.h"
|
||||||
#include "Lock.h"
|
|
||||||
#include "Chain.h"
|
#include "Chain.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "CachedBlock.h"
|
#include "CachedBlock.h"
|
||||||
@@ -45,7 +44,7 @@ class Inode {
|
|||||||
ino_t ID() const { return fID; }
|
ino_t ID() const { return fID; }
|
||||||
off_t BlockNumber() const { return fVolume->VnodeToBlock(fID); }
|
off_t BlockNumber() const { return fVolume->VnodeToBlock(fID); }
|
||||||
|
|
||||||
ReadWriteLock &Lock() { return fLock; }
|
rw_lock &Lock() { return fLock; }
|
||||||
recursive_lock &SmallDataLock() { return fSmallDataLock; }
|
recursive_lock &SmallDataLock() { return fSmallDataLock; }
|
||||||
status_t WriteBack(Transaction &transaction);
|
status_t WriteBack(Transaction &transaction);
|
||||||
|
|
||||||
@@ -193,7 +192,7 @@ class Inode {
|
|||||||
status_t _ShrinkStream(Transaction &transaction, off_t size);
|
status_t _ShrinkStream(Transaction &transaction, off_t size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReadWriteLock fLock;
|
rw_lock fLock;
|
||||||
Volume *fVolume;
|
Volume *fVolume;
|
||||||
ino_t fID;
|
ino_t fID;
|
||||||
BPlusTree *fTree;
|
BPlusTree *fTree;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include "Volume.h"
|
#include "Volume.h"
|
||||||
#include "Chain.h"
|
#include "Chain.h"
|
||||||
#include "Lock.h"
|
|
||||||
#include "Utility.h"
|
#include "Utility.h"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
if (!reenter)
|
if (!reenter)
|
||||||
inode->Lock().Lock();
|
rw_lock_read_lock(&inode->Lock());
|
||||||
|
|
||||||
uint32 vecIndex = 0;
|
uint32 vecIndex = 0;
|
||||||
size_t vecOffset = 0;
|
size_t vecOffset = 0;
|
||||||
@@ -368,7 +368,7 @@ bfs_read_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!reenter)
|
if (!reenter)
|
||||||
inode->Lock().Unlock();
|
rw_lock_read_unlock(&inode->Lock());
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -388,7 +388,7 @@ bfs_write_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie,
|
|||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
if (!reenter)
|
if (!reenter)
|
||||||
inode->Lock().Lock();
|
rw_lock_read_lock(&inode->Lock());
|
||||||
|
|
||||||
uint32 vecIndex = 0;
|
uint32 vecIndex = 0;
|
||||||
size_t vecOffset = 0;
|
size_t vecOffset = 0;
|
||||||
@@ -417,7 +417,7 @@ bfs_write_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!reenter)
|
if (!reenter)
|
||||||
inode->Lock().Unlock();
|
rw_lock_read_unlock(&inode->Lock());
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -646,11 +646,10 @@ bfs_fsync(fs_volume *_volume, fs_vnode *_node)
|
|||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
Inode *inode = (Inode *)_node->private_node;
|
Inode *inode = (Inode *)_node->private_node;
|
||||||
ReadLocked locked(inode->Lock());
|
ReadLocker locker(inode->Lock());
|
||||||
|
|
||||||
status_t status = locked.IsLocked();
|
if (!locker.IsLocked())
|
||||||
if (status < B_OK)
|
RETURN_ERROR(B_ERROR);
|
||||||
RETURN_ERROR(status);
|
|
||||||
|
|
||||||
return inode->Sync();
|
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());
|
Transaction transaction(volume, inode->BlockNumber());
|
||||||
|
|
||||||
WriteLocked locked(inode->Lock());
|
WriteLocker locker(inode->Lock());
|
||||||
if (locked.IsLocked() < B_OK)
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
bfs_inode &node = inode->Node();
|
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?
|
// Should we truncate the file?
|
||||||
if (openMode & O_TRUNC) {
|
if (openMode & O_TRUNC) {
|
||||||
Transaction transaction(volume, inode->BlockNumber());
|
Transaction transaction(volume, inode->BlockNumber());
|
||||||
WriteLocked locked(inode->Lock());
|
WriteLocker locker(inode->Lock());
|
||||||
|
|
||||||
status_t status = inode->SetFileSize(transaction, 0);
|
status_t status = inode->SetFileSize(transaction, 0);
|
||||||
if (status >= B_OK)
|
if (status >= B_OK)
|
||||||
@@ -1219,7 +1218,7 @@ bfs_write(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
|
|||||||
transaction.Done();
|
transaction.Done();
|
||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
ReadLocked locker(inode->Lock());
|
ReadLocker locker(inode->Lock());
|
||||||
|
|
||||||
// periodically notify if the file size has changed
|
// periodically notify if the file size has changed
|
||||||
// TODO: should we better test for a change in the last_modified time only?
|
// 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;
|
bool needsTrimming = false;
|
||||||
|
|
||||||
if (!volume->IsReadOnly()) {
|
if (!volume->IsReadOnly()) {
|
||||||
ReadLocked locker(inode->Lock());
|
ReadLocker locker(inode->Lock());
|
||||||
needsTrimming = inode->NeedsTrimming();
|
needsTrimming = inode->NeedsTrimming();
|
||||||
|
|
||||||
if ((cookie->open_mode & O_RWMASK) != 0
|
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;
|
status_t status = transaction.IsStarted() ? B_OK : B_ERROR;
|
||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
WriteLocked locker(inode->Lock());
|
WriteLocker locker(inode->Lock());
|
||||||
|
|
||||||
// trim the preallocated blocks and update the size,
|
// trim the preallocated blocks and update the size,
|
||||||
// and last_modified indices if needed
|
// and last_modified indices if needed
|
||||||
|
|||||||
Reference in New Issue
Block a user