Removed the khash, condition variable, lock, block cache, and slab
implementations and instead use the kernel sources directly or the libkernelland_emu sources. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29456 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -8,8 +8,9 @@
|
||||
|
||||
#include <fs_interface.h>
|
||||
|
||||
#include "block_cache.h"
|
||||
#include "condition_variable.h"
|
||||
#include <block_cache.h>
|
||||
#include <condition_variable.h>
|
||||
|
||||
#include "HaikuKernelVolume.h"
|
||||
|
||||
|
||||
@@ -36,13 +37,11 @@ status_t
|
||||
HaikuKernelFileSystem::Init()
|
||||
{
|
||||
// init condition variables
|
||||
status_t error = condition_variable_init();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
condition_variable_init();
|
||||
// TODO: Call the cleanup methods, if something goes wrong!
|
||||
|
||||
// init block cache
|
||||
error = block_cache_init();
|
||||
status_t error = block_cache_init();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@ SubDirSysHdrs [ FDirName $(userlandFSIncludes) ] ;
|
||||
SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ;
|
||||
SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ;
|
||||
|
||||
UsePrivateSystemHeaders ;
|
||||
UsePrivateHeaders kernel libroot shared ;
|
||||
UsePrivateKernelHeaders ;
|
||||
UsePrivateHeaders libroot shared ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(userlandFSTop) private ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(userlandFSTop) shared ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src tests add-ons kernel
|
||||
kernelland_emu ] ;
|
||||
|
||||
DEFINES += USER=1 ;
|
||||
DEFINES += DEBUG_APP="\\\"libuserlandfs_haiku\\\"" ;
|
||||
@@ -21,15 +23,25 @@ DEFINES += BUILDING_USERLAND_FS_SERVER=1 ;
|
||||
# the library providing the Haiku kernel interface for add-ons
|
||||
SharedLibrary libuserlandfs_haiku_kernel.so
|
||||
:
|
||||
block_cache.cpp
|
||||
# kernelland_emu
|
||||
condition_variable.cpp
|
||||
file_cache.cpp
|
||||
file_map.cpp
|
||||
khash.cpp
|
||||
debug.cpp
|
||||
lock.cpp
|
||||
low_resource_manager.cpp
|
||||
misc.cpp
|
||||
scheduler.cpp
|
||||
slab.cpp
|
||||
|
||||
# kernel
|
||||
block_cache.cpp
|
||||
file_map.cpp
|
||||
khash.c
|
||||
|
||||
# emulation
|
||||
file_cache.cpp
|
||||
haiku_kernel_emu.cpp
|
||||
|
||||
# UserlandFS server interface
|
||||
HaikuKernelFileSystem.cpp
|
||||
HaikuKernelVolume.cpp
|
||||
|
||||
@@ -37,3 +49,12 @@ SharedLibrary libuserlandfs_haiku_kernel.so
|
||||
<nogrist>userlandfs_server
|
||||
be # for BLocker only
|
||||
;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
block_cache.cpp
|
||||
file_map.cpp
|
||||
] = [ FDirName $(HAIKU_TOP) src system kernel cache ] ;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
khash.c
|
||||
] = [ FDirName $(HAIKU_TOP) src system kernel util ] ;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef USERLAND_FS_HAIKU_BLOCK_CACHE_H
|
||||
#define USERLAND_FS_HAIKU_BLOCK_CACHE_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
status_t block_cache_init(void);
|
||||
size_t block_cache_used_memory();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // USERLAND_FS_HAIKU_BLOCK_CACHE_H
|
||||
@@ -1,254 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "condition_variable.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Debug.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
// libroot
|
||||
#include <user_thread.h>
|
||||
|
||||
// system
|
||||
#include <syscalls.h>
|
||||
#include <user_thread_defs.h>
|
||||
|
||||
#include "lock.h"
|
||||
|
||||
|
||||
#define STATUS_ADDED 1
|
||||
#define STATUS_WAITING 2
|
||||
|
||||
|
||||
static const int kConditionVariableHashSize = 512;
|
||||
|
||||
|
||||
struct ConditionVariableHashDefinition {
|
||||
typedef const void* KeyType;
|
||||
typedef ConditionVariable ValueType;
|
||||
|
||||
size_t HashKey(const void* key) const
|
||||
{ return (size_t)key; }
|
||||
size_t Hash(ConditionVariable* variable) const
|
||||
{ return (size_t)variable->fObject; }
|
||||
bool Compare(const void* key, ConditionVariable* variable) const
|
||||
{ return key == variable->fObject; }
|
||||
HashTableLink<ConditionVariable>* GetLink(ConditionVariable* variable) const
|
||||
{ return variable; }
|
||||
};
|
||||
|
||||
typedef OpenHashTable<ConditionVariableHashDefinition> ConditionVariableHash;
|
||||
static ConditionVariableHash sConditionVariableHash;
|
||||
static mutex sConditionVariablesLock;
|
||||
static mutex sThreadsLock;
|
||||
|
||||
|
||||
// #pragma mark - ConditionVariableEntry
|
||||
|
||||
|
||||
bool
|
||||
ConditionVariableEntry::Add(const void* object)
|
||||
{
|
||||
ASSERT(object != NULL);
|
||||
|
||||
fThread = find_thread(NULL);
|
||||
|
||||
MutexLocker _(sConditionVariablesLock);
|
||||
|
||||
fVariable = sConditionVariableHash.Lookup(object);
|
||||
|
||||
if (fVariable == NULL) {
|
||||
fWaitStatus = B_ENTRY_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
fWaitStatus = STATUS_ADDED;
|
||||
fVariable->fEntries.Add(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout)
|
||||
{
|
||||
MutexLocker conditionLocker(sConditionVariablesLock);
|
||||
|
||||
if (fVariable == NULL)
|
||||
return fWaitStatus;
|
||||
|
||||
user_thread* userThread = get_user_thread();
|
||||
|
||||
userThread->wait_status = 1;
|
||||
fWaitStatus = STATUS_WAITING;
|
||||
|
||||
conditionLocker.Unlock();
|
||||
|
||||
MutexLocker threadLocker(sThreadsLock);
|
||||
|
||||
status_t error;
|
||||
if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0)
|
||||
error = _kern_block_thread(flags, timeout);
|
||||
else
|
||||
error = _kern_block_thread(0, 0);
|
||||
threadLocker.Unlock();
|
||||
|
||||
conditionLocker.Lock();
|
||||
|
||||
// remove entry from variable, if not done yet
|
||||
if (fVariable != NULL) {
|
||||
fVariable->fEntries.Remove(this);
|
||||
fVariable = NULL;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConditionVariableEntry::Wait(const void* object, uint32 flags,
|
||||
bigtime_t timeout)
|
||||
{
|
||||
if (Add(object))
|
||||
return Wait(flags, timeout);
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
ConditionVariableEntry::AddToVariable(ConditionVariable* variable)
|
||||
{
|
||||
fThread = find_thread(NULL);
|
||||
|
||||
MutexLocker _(sConditionVariablesLock);
|
||||
|
||||
fVariable = variable;
|
||||
fWaitStatus = STATUS_ADDED;
|
||||
fVariable->fEntries.Add(this);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ConditionVariable
|
||||
|
||||
|
||||
/*! Initialization method for anonymous (unpublished) condition variables.
|
||||
*/
|
||||
void
|
||||
ConditionVariable::Init(const void* object, const char* objectType)
|
||||
{
|
||||
fObject = object;
|
||||
fObjectType = objectType;
|
||||
new(&fEntries) EntryList;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConditionVariable::Publish(const void* object, const char* objectType)
|
||||
{
|
||||
ASSERT(object != NULL);
|
||||
|
||||
fObject = object;
|
||||
fObjectType = objectType;
|
||||
new(&fEntries) EntryList;
|
||||
|
||||
MutexLocker locker(sConditionVariablesLock);
|
||||
|
||||
ASSERT(sConditionVariableHash.Lookup(object) == NULL);
|
||||
|
||||
sConditionVariableHash.InsertUnchecked(this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConditionVariable::Unpublish(bool threadsLocked)
|
||||
{
|
||||
ASSERT(fObject != NULL);
|
||||
|
||||
MutexLocker threadLocker(threadsLocked ? NULL : &sThreadsLock);
|
||||
MutexLocker locker(sConditionVariablesLock);
|
||||
|
||||
sConditionVariableHash.RemoveUnchecked(this);
|
||||
fObject = NULL;
|
||||
fObjectType = NULL;
|
||||
|
||||
if (!fEntries.IsEmpty())
|
||||
_NotifyChecked(true, B_ENTRY_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConditionVariable::Add(ConditionVariableEntry* entry)
|
||||
{
|
||||
entry->AddToVariable(this);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConditionVariable::Wait(uint32 flags, bigtime_t timeout)
|
||||
{
|
||||
ConditionVariableEntry entry;
|
||||
Add(&entry);
|
||||
return entry.Wait(flags, timeout);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConditionVariable::_Notify(bool all, bool threadsLocked)
|
||||
{
|
||||
MutexLocker threadLocker(threadsLocked ? NULL : &sThreadsLock);
|
||||
MutexLocker locker(sConditionVariablesLock);
|
||||
|
||||
if (!fEntries.IsEmpty())
|
||||
_NotifyChecked(all, B_OK);
|
||||
}
|
||||
|
||||
|
||||
/*! Called with interrupts disabled and the condition variable spinlock and
|
||||
thread lock held.
|
||||
*/
|
||||
void
|
||||
ConditionVariable::_NotifyChecked(bool all, status_t result)
|
||||
{
|
||||
// dequeue and wake up the blocked threads
|
||||
while (ConditionVariableEntry* entry = fEntries.RemoveHead()) {
|
||||
entry->fVariable = NULL;
|
||||
|
||||
if (entry->fWaitStatus <= 0)
|
||||
continue;
|
||||
|
||||
if (entry->fWaitStatus == STATUS_WAITING)
|
||||
_kern_unblock_thread(entry->fThread, result);
|
||||
|
||||
entry->fWaitStatus = result;
|
||||
|
||||
if (!all)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
condition_variable_init()
|
||||
{
|
||||
mutex_init(&sConditionVariablesLock, "condition variables");
|
||||
mutex_init(&sThreadsLock, "threads");
|
||||
|
||||
new(&sConditionVariableHash) ConditionVariableHash;
|
||||
|
||||
status_t error = sConditionVariableHash.Init(kConditionVariableHashSize);
|
||||
if (error != B_OK) {
|
||||
panic("condition_variable_init(): Failed to init hash table: %s",
|
||||
strerror(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef USERLAND_FS_HAIKU_CONDITION_VARIABLE_H
|
||||
#define USERLAND_FS_HAIKU_CONDITION_VARIABLE_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <kernel/util/DoublyLinkedList.h>
|
||||
#include <kernel/util/OpenHashTable.h>
|
||||
|
||||
|
||||
class ConditionVariable;
|
||||
|
||||
|
||||
struct ConditionVariableEntry
|
||||
: DoublyLinkedListLinkImpl<ConditionVariableEntry> {
|
||||
public:
|
||||
bool Add(const void* object);
|
||||
status_t Wait(uint32 flags = 0, bigtime_t timeout = 0);
|
||||
status_t Wait(const void* object, uint32 flags = 0,
|
||||
bigtime_t timeout = 0);
|
||||
|
||||
inline ConditionVariable* Variable() const { return fVariable; }
|
||||
|
||||
private:
|
||||
inline void AddToVariable(ConditionVariable* variable);
|
||||
|
||||
private:
|
||||
ConditionVariable* fVariable;
|
||||
thread_id fThread;
|
||||
status_t fWaitStatus;
|
||||
|
||||
friend class ConditionVariable;
|
||||
};
|
||||
|
||||
|
||||
class ConditionVariable : protected HashTableLink<ConditionVariable> {
|
||||
public:
|
||||
void Init(const void* object,
|
||||
const char* objectType);
|
||||
// for anonymous (unpublished) cvars
|
||||
|
||||
void Publish(const void* object,
|
||||
const char* objectType);
|
||||
void Unpublish(bool threadsLocked = false);
|
||||
|
||||
inline void NotifyOne(bool threadsLocked = false);
|
||||
inline void NotifyAll(bool threadsLocked = false);
|
||||
|
||||
void Add(ConditionVariableEntry* entry);
|
||||
|
||||
status_t Wait(uint32 flags = 0, bigtime_t timeout = 0);
|
||||
// all-in one, i.e. doesn't need a
|
||||
// ConditionVariableEntry
|
||||
|
||||
const void* Object() const { return fObject; }
|
||||
const char* ObjectType() const { return fObjectType; }
|
||||
|
||||
private:
|
||||
void _Notify(bool all, bool threadsLocked);
|
||||
void _NotifyChecked(bool all, status_t result);
|
||||
|
||||
protected:
|
||||
typedef DoublyLinkedList<ConditionVariableEntry> EntryList;
|
||||
|
||||
const void* fObject;
|
||||
const char* fObjectType;
|
||||
EntryList fEntries;
|
||||
|
||||
friend class ConditionVariableEntry;
|
||||
friend class ConditionVariableHashDefinition;
|
||||
};
|
||||
|
||||
|
||||
inline void
|
||||
ConditionVariable::NotifyOne(bool threadsLocked)
|
||||
{
|
||||
_Notify(false, threadsLocked);
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
ConditionVariable::NotifyAll(bool threadsLocked)
|
||||
{
|
||||
_Notify(true, threadsLocked);
|
||||
}
|
||||
|
||||
|
||||
status_t condition_variable_init();
|
||||
|
||||
|
||||
#endif // USERLAND_FS_HAIKU_CONDITION_VARIABLE_H
|
||||
@@ -1,647 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <fs_cache.h>
|
||||
|
||||
#include <kernel/util/DoublyLinkedList.h>
|
||||
|
||||
#include "lock.h"
|
||||
#include "vfs.h"
|
||||
|
||||
|
||||
//#define TRACE_FILE_MAP
|
||||
#ifdef TRACE_FILE_MAP
|
||||
# define TRACE(x...) dprintf_no_syslog(x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
// TODO: use a sparse array - eventually, the unused BlockMap would be something
|
||||
// to reuse for this. We could also have an upperbound of memory consumption
|
||||
// for the whole map.
|
||||
// TODO: it would be nice if we could free a file map in low memory situations.
|
||||
|
||||
|
||||
#define CACHED_FILE_EXTENTS 2
|
||||
// must be smaller than MAX_FILE_IO_VECS
|
||||
// TODO: find out how much of these are typically used
|
||||
|
||||
struct file_extent {
|
||||
off_t offset;
|
||||
file_io_vec disk;
|
||||
};
|
||||
|
||||
struct file_extent_array {
|
||||
file_extent* array;
|
||||
size_t max_count;
|
||||
};
|
||||
|
||||
class FileMap
|
||||
#if DEBUG_FILE_MAP
|
||||
: public DoublyLinkedListLinkImpl<FileMap>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
FileMap(struct vnode* vnode, off_t size);
|
||||
~FileMap();
|
||||
|
||||
void Invalidate(off_t offset, off_t size);
|
||||
void SetSize(off_t size);
|
||||
|
||||
status_t Translate(off_t offset, size_t size,
|
||||
file_io_vec* vecs, size_t* _count,
|
||||
size_t align);
|
||||
|
||||
file_extent* ExtentAt(uint32 index);
|
||||
|
||||
size_t Count() const { return fCount; }
|
||||
struct vnode* Vnode() const { return fVnode; }
|
||||
off_t Size() const { return fSize; }
|
||||
|
||||
status_t SetMode(uint32 mode);
|
||||
|
||||
private:
|
||||
file_extent* _FindExtent(off_t offset, uint32* _index);
|
||||
status_t _MakeSpace(size_t count);
|
||||
status_t _Add(file_io_vec* vecs, size_t vecCount,
|
||||
off_t& lastOffset);
|
||||
status_t _Cache(off_t offset, off_t size);
|
||||
void _InvalidateAfter(off_t offset);
|
||||
void _Free();
|
||||
|
||||
union {
|
||||
file_extent fDirect[CACHED_FILE_EXTENTS];
|
||||
file_extent_array fIndirect;
|
||||
};
|
||||
mutex fLock;
|
||||
size_t fCount;
|
||||
struct vnode* fVnode;
|
||||
off_t fSize;
|
||||
bool fCacheAll;
|
||||
};
|
||||
|
||||
#if DEBUG_FILE_MAP
|
||||
typedef DoublyLinkedList<FileMap> FileMapList;
|
||||
|
||||
static FileMapList sList;
|
||||
static mutex sLock;
|
||||
#endif
|
||||
|
||||
|
||||
FileMap::FileMap(struct vnode* vnode, off_t size)
|
||||
:
|
||||
fCount(0),
|
||||
fVnode(vnode),
|
||||
fSize(size),
|
||||
fCacheAll(false)
|
||||
{
|
||||
mutex_init(&fLock, "file map");
|
||||
|
||||
#if DEBUG_FILE_MAP
|
||||
MutexLocker _(sLock);
|
||||
sList.Add(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
FileMap::~FileMap()
|
||||
{
|
||||
_Free();
|
||||
mutex_destroy(&fLock);
|
||||
|
||||
#if DEBUG_FILE_MAP
|
||||
MutexLocker _(sLock);
|
||||
sList.Remove(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
file_extent*
|
||||
FileMap::ExtentAt(uint32 index)
|
||||
{
|
||||
if (index >= fCount)
|
||||
return NULL;
|
||||
|
||||
if (fCount > CACHED_FILE_EXTENTS)
|
||||
return &fIndirect.array[index];
|
||||
|
||||
return &fDirect[index];
|
||||
}
|
||||
|
||||
|
||||
file_extent*
|
||||
FileMap::_FindExtent(off_t offset, uint32 *_index)
|
||||
{
|
||||
int32 left = 0;
|
||||
int32 right = fCount - 1;
|
||||
|
||||
while (left <= right) {
|
||||
int32 index = (left + right) / 2;
|
||||
file_extent* extent = ExtentAt(index);
|
||||
|
||||
if (extent->offset > offset) {
|
||||
// search in left part
|
||||
right = index - 1;
|
||||
} else if (extent->offset + extent->disk.length <= offset) {
|
||||
// search in right part
|
||||
left = index + 1;
|
||||
} else {
|
||||
// found extent
|
||||
if (_index)
|
||||
*_index = index;
|
||||
|
||||
return extent;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileMap::_MakeSpace(size_t count)
|
||||
{
|
||||
if (count <= CACHED_FILE_EXTENTS) {
|
||||
// just use the reserved area in the file_cache_ref structure
|
||||
if (fCount > CACHED_FILE_EXTENTS) {
|
||||
// the new size is smaller than the minimal array size
|
||||
file_extent *array = fIndirect.array;
|
||||
memcpy(fDirect, array, sizeof(file_extent) * count);
|
||||
free(array);
|
||||
}
|
||||
} else {
|
||||
// resize array if needed
|
||||
file_extent* oldArray = NULL;
|
||||
size_t maxCount = CACHED_FILE_EXTENTS;
|
||||
if (fCount > CACHED_FILE_EXTENTS) {
|
||||
oldArray = fIndirect.array;
|
||||
maxCount = fIndirect.max_count;
|
||||
}
|
||||
|
||||
if (count > maxCount) {
|
||||
// allocate new array
|
||||
while (maxCount < count) {
|
||||
if (maxCount < 32768)
|
||||
maxCount <<= 1;
|
||||
else
|
||||
maxCount += 32768;
|
||||
}
|
||||
|
||||
file_extent* newArray = (file_extent *)realloc(oldArray,
|
||||
maxCount * sizeof(file_extent));
|
||||
if (newArray == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (fCount > 0 && fCount <= CACHED_FILE_EXTENTS)
|
||||
memcpy(newArray, fDirect, sizeof(file_extent) * fCount);
|
||||
|
||||
fIndirect.array = newArray;
|
||||
fIndirect.max_count = maxCount;
|
||||
}
|
||||
}
|
||||
|
||||
fCount = count;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileMap::_Add(file_io_vec* vecs, size_t vecCount, off_t& lastOffset)
|
||||
{
|
||||
TRACE("FileMap@%p::Add(vecCount = %ld)\n", this, vecCount);
|
||||
|
||||
uint32 start = fCount;
|
||||
off_t offset = 0;
|
||||
|
||||
status_t status = _MakeSpace(fCount + vecCount);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
file_extent* lastExtent = NULL;
|
||||
if (start != 0) {
|
||||
lastExtent = ExtentAt(start - 1);
|
||||
offset = lastExtent->offset + lastExtent->disk.length;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < vecCount; i++) {
|
||||
if (lastExtent != NULL) {
|
||||
if (lastExtent->disk.offset + lastExtent->disk.length
|
||||
== vecs[i].offset
|
||||
|| (lastExtent->disk.offset == -1 && vecs[i].offset == -1)) {
|
||||
lastExtent->disk.length += vecs[i].length;
|
||||
offset += vecs[i].length;
|
||||
start--;
|
||||
_MakeSpace(fCount - 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
file_extent* extent = ExtentAt(start + i);
|
||||
extent->offset = offset;
|
||||
extent->disk = vecs[i];
|
||||
|
||||
offset += extent->disk.length;
|
||||
lastExtent = extent;
|
||||
}
|
||||
|
||||
#ifdef TRACE_FILE_MAP
|
||||
for (uint32 i = 0; i < fCount; i++) {
|
||||
file_extent* extent = ExtentAt(i);
|
||||
TRACE("[%ld] extent offset %Ld, disk offset %Ld, length %Ld\n",
|
||||
i, extent->offset, extent->disk.offset, extent->disk.length);
|
||||
}
|
||||
#endif
|
||||
|
||||
lastOffset = offset;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FileMap::_InvalidateAfter(off_t offset)
|
||||
{
|
||||
uint32 index;
|
||||
file_extent* extent = _FindExtent(offset, &index);
|
||||
if (extent != NULL) {
|
||||
_MakeSpace(index + 1);
|
||||
|
||||
if (extent->offset + extent->disk.length > offset) {
|
||||
extent->disk.length = offset - extent->offset;
|
||||
if (extent->disk.length == 0)
|
||||
_MakeSpace(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! Invalidates or removes the specified part of the file map.
|
||||
*/
|
||||
void
|
||||
FileMap::Invalidate(off_t offset, off_t size)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
|
||||
// TODO: honour size, we currently always remove everything after "offset"
|
||||
if (offset == 0) {
|
||||
_Free();
|
||||
return;
|
||||
}
|
||||
|
||||
_InvalidateAfter(offset);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FileMap::SetSize(off_t size)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
|
||||
if (size < fSize)
|
||||
_InvalidateAfter(size);
|
||||
|
||||
fSize = size;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FileMap::_Free()
|
||||
{
|
||||
if (fCount > CACHED_FILE_EXTENTS)
|
||||
free(fIndirect.array);
|
||||
|
||||
fCount = 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileMap::_Cache(off_t offset, off_t size)
|
||||
{
|
||||
file_extent* lastExtent = NULL;
|
||||
if (fCount > 0)
|
||||
lastExtent = ExtentAt(fCount - 1);
|
||||
|
||||
off_t mapEnd = 0;
|
||||
if (lastExtent != NULL)
|
||||
mapEnd = lastExtent->offset + lastExtent->disk.length;
|
||||
|
||||
off_t end = offset + size;
|
||||
|
||||
if (fCacheAll && mapEnd < end)
|
||||
return B_ERROR;
|
||||
|
||||
status_t status = B_OK;
|
||||
file_io_vec vecs[8];
|
||||
const size_t kMaxVecs = 8;
|
||||
|
||||
while (status == B_OK && mapEnd < end) {
|
||||
// We don't have the requested extents yet, retrieve them
|
||||
size_t vecCount = kMaxVecs;
|
||||
status = vfs_get_file_map(Vnode(), mapEnd, ~0UL, vecs, &vecCount);
|
||||
if (status == B_OK || status == B_BUFFER_OVERFLOW)
|
||||
status = _Add(vecs, vecCount, mapEnd);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileMap::SetMode(uint32 mode)
|
||||
{
|
||||
if (mode != FILE_MAP_CACHE_ALL && mode != FILE_MAP_CACHE_ON_DEMAND)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
MutexLocker _(fLock);
|
||||
|
||||
if ((mode == FILE_MAP_CACHE_ALL && fCacheAll)
|
||||
|| (mode == FILE_MAP_CACHE_ON_DEMAND && !fCacheAll))
|
||||
return B_OK;
|
||||
|
||||
if (mode == FILE_MAP_CACHE_ALL) {
|
||||
status_t status = _Cache(0, fSize);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
fCacheAll = true;
|
||||
} else
|
||||
fCacheAll = false;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileMap::Translate(off_t offset, size_t size, file_io_vec* vecs, size_t* _count,
|
||||
size_t align)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
|
||||
size_t maxVecs = *_count;
|
||||
size_t padLastVec = 0;
|
||||
|
||||
if (offset >= Size()) {
|
||||
*_count = 0;
|
||||
return B_OK;
|
||||
}
|
||||
if (offset + size > fSize) {
|
||||
if (align > 1) {
|
||||
off_t alignedSize = (fSize + align - 1) & ~(off_t)(align - 1);
|
||||
if (offset + size >= alignedSize)
|
||||
padLastVec = alignedSize - fSize;
|
||||
}
|
||||
size = fSize - offset;
|
||||
}
|
||||
|
||||
// First, we need to make sure that we have already cached all file
|
||||
// extents needed for this request.
|
||||
|
||||
status_t status = _Cache(offset, size);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// We now have cached the map of this file as far as we need it, now
|
||||
// we need to translate it for the requested access.
|
||||
|
||||
uint32 index;
|
||||
file_extent* fileExtent = _FindExtent(offset, &index);
|
||||
|
||||
offset -= fileExtent->offset;
|
||||
if (fileExtent->disk.offset != -1)
|
||||
vecs[0].offset = fileExtent->disk.offset + offset;
|
||||
else
|
||||
vecs[0].offset = -1;
|
||||
vecs[0].length = fileExtent->disk.length - offset;
|
||||
|
||||
if (vecs[0].length >= size) {
|
||||
vecs[0].length = size + padLastVec;
|
||||
*_count = 1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// copy the rest of the vecs
|
||||
|
||||
size -= vecs[0].length;
|
||||
uint32 vecIndex = 1;
|
||||
|
||||
while (true) {
|
||||
fileExtent++;
|
||||
|
||||
vecs[vecIndex++] = fileExtent->disk;
|
||||
|
||||
if (size <= fileExtent->disk.length) {
|
||||
vecs[vecIndex - 1].length = size + padLastVec;
|
||||
break;
|
||||
}
|
||||
|
||||
if (vecIndex >= maxVecs) {
|
||||
*_count = vecIndex;
|
||||
return B_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
size -= fileExtent->disk.length;
|
||||
}
|
||||
|
||||
*_count = vecIndex;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
#if DEBUG_FILE_MAP
|
||||
|
||||
static int
|
||||
dump_file_map(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
print_debugger_command_usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool printExtents = false;
|
||||
if (argc > 2 && !strcmp(argv[1], "-p"))
|
||||
printExtents = true;
|
||||
|
||||
FileMap* map = (FileMap*)parse_expression(argv[argc - 1]);
|
||||
if (map == NULL) {
|
||||
kprintf("invalid file map!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
kprintf("FileMap %p\n", map);
|
||||
kprintf(" size %Ld\n", map->Size());
|
||||
kprintf(" count %lu\n", map->Count());
|
||||
|
||||
if (!printExtents)
|
||||
return 0;
|
||||
|
||||
for (uint32 i = 0; i < map->Count(); i++) {
|
||||
file_extent* extent = map->ExtentAt(i);
|
||||
|
||||
kprintf(" [%lu] offset %Ld, disk offset %Ld, length %Ld\n",
|
||||
i, extent->offset, extent->disk.offset, extent->disk.length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_file_map_stats(int argc, char** argv)
|
||||
{
|
||||
off_t minSize = 0;
|
||||
off_t maxSize = -1;
|
||||
|
||||
if (argc == 2) {
|
||||
maxSize = parse_expression(argv[1]);
|
||||
} else if (argc > 2) {
|
||||
minSize = parse_expression(argv[1]);
|
||||
maxSize = parse_expression(argv[2]);
|
||||
}
|
||||
|
||||
FileMapList::Iterator iterator = sList.GetIterator();
|
||||
off_t size = 0;
|
||||
off_t mapSize = 0;
|
||||
uint32 extents = 0;
|
||||
uint32 count = 0;
|
||||
uint32 emptyCount = 0;
|
||||
|
||||
while (iterator.HasNext()) {
|
||||
FileMap* map = iterator.Next();
|
||||
|
||||
if (minSize > map->Size() || (maxSize != -1 && maxSize < map->Size()))
|
||||
continue;
|
||||
|
||||
if (map->Count() != 0) {
|
||||
file_extent* extent = map->ExtentAt(map->Count() - 1);
|
||||
if (extent != NULL)
|
||||
mapSize += extent->offset + extent->disk.length;
|
||||
|
||||
extents += map->Count();
|
||||
} else
|
||||
emptyCount++;
|
||||
|
||||
size += map->Size();
|
||||
count++;
|
||||
}
|
||||
|
||||
kprintf("%ld file maps (%ld empty), %Ld file bytes in total, %Ld bytes "
|
||||
"cached, %lu extents\n", count, emptyCount, size, mapSize, extents);
|
||||
kprintf("average %lu extents per map for %Ld bytes.\n",
|
||||
extents / (count - emptyCount), mapSize / (count - emptyCount));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // DEBUG_FILE_MAP
|
||||
|
||||
|
||||
// #pragma mark - private kernel API
|
||||
|
||||
|
||||
extern "C" status_t
|
||||
file_map_init(void)
|
||||
{
|
||||
#if DEBUG_FILE_MAP
|
||||
add_debugger_command_etc("file_map", &dump_file_map,
|
||||
"Dumps the specified file map.",
|
||||
"[-p] <file-map>\n"
|
||||
" -p - causes the file extents to be printed as well.\n"
|
||||
" <file-map> - pointer to the file map.\n", 0);
|
||||
add_debugger_command("file_map_stats", &dump_file_map_stats,
|
||||
"Dumps some file map statistics.");
|
||||
|
||||
mutex_init(&sLock, "file map list");
|
||||
#endif
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - public FS API
|
||||
|
||||
|
||||
extern "C" void*
|
||||
file_map_create(dev_t mountID, ino_t vnodeID, off_t size)
|
||||
{
|
||||
TRACE("file_map_create(mountID = %ld, vnodeID = %Ld, size = %Ld)\n",
|
||||
mountID, vnodeID, size);
|
||||
|
||||
// Get the vnode for the object
|
||||
// (note, this does not grab a reference to the node)
|
||||
struct vnode* vnode;
|
||||
if (vfs_lookup_vnode(mountID, vnodeID, &vnode) != B_OK)
|
||||
return NULL;
|
||||
|
||||
return new(std::nothrow) FileMap(vnode, size);
|
||||
}
|
||||
|
||||
|
||||
extern "C" void
|
||||
file_map_delete(void* _map)
|
||||
{
|
||||
FileMap* map = (FileMap*)_map;
|
||||
if (map == NULL)
|
||||
return;
|
||||
|
||||
TRACE("file_map_delete(map = %p)\n", map);
|
||||
delete map;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void
|
||||
file_map_set_size(void* _map, off_t size)
|
||||
{
|
||||
FileMap* map = (FileMap*)_map;
|
||||
if (map == NULL)
|
||||
return;
|
||||
|
||||
map->SetSize(size);
|
||||
}
|
||||
|
||||
|
||||
extern "C" void
|
||||
file_map_invalidate(void* _map, off_t offset, off_t size)
|
||||
{
|
||||
FileMap* map = (FileMap*)_map;
|
||||
if (map == NULL)
|
||||
return;
|
||||
|
||||
map->Invalidate(offset, size);
|
||||
}
|
||||
|
||||
|
||||
extern "C" status_t
|
||||
file_map_set_mode(void* _map, uint32 mode)
|
||||
{
|
||||
FileMap* map = (FileMap*)_map;
|
||||
if (map == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return map->SetMode(mode);
|
||||
}
|
||||
|
||||
|
||||
extern "C" status_t
|
||||
file_map_translate(void* _map, off_t offset, size_t size, file_io_vec* vecs,
|
||||
size_t* _count, size_t align)
|
||||
{
|
||||
TRACE("file_map_translate(map %p, offset %Ld, size %ld)\n",
|
||||
_map, offset, size);
|
||||
|
||||
FileMap* map = (FileMap*)_map;
|
||||
if (map == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return map->Translate(offset, size, vecs, _count, align);
|
||||
}
|
||||
|
||||
@@ -279,76 +279,3 @@ vfs_lookup_vnode(dev_t mountID, ino_t vnodeID, struct vnode **_vnode)
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Misc
|
||||
|
||||
|
||||
// kernel_debugger
|
||||
void
|
||||
kernel_debugger(const char *message)
|
||||
{
|
||||
UserlandFS::KernelEmu::kernel_debugger(message);
|
||||
}
|
||||
|
||||
// panic
|
||||
void
|
||||
panic(const char *format, ...)
|
||||
{
|
||||
char buffer[1024];
|
||||
strcpy(buffer, "PANIC: ");
|
||||
int32 prefixLen = strlen(buffer);
|
||||
int bufferSize = sizeof(buffer) - prefixLen;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(buffer + prefixLen, bufferSize - 1, format, args);
|
||||
va_end(args);
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
debugger(buffer);
|
||||
}
|
||||
|
||||
// add_debugger_command
|
||||
int
|
||||
add_debugger_command(char *name, debugger_command_hook hook, char *help)
|
||||
{
|
||||
return UserlandFS::KernelEmu::add_debugger_command(name, hook, help);
|
||||
}
|
||||
|
||||
// remove_debugger_command
|
||||
int
|
||||
remove_debugger_command(char *name, debugger_command_hook hook)
|
||||
{
|
||||
return UserlandFS::KernelEmu::remove_debugger_command(name, hook);
|
||||
}
|
||||
|
||||
// parse_expression
|
||||
uint64
|
||||
parse_expression(const char *string)
|
||||
{
|
||||
return UserlandFS::KernelEmu::parse_expression(string);
|
||||
}
|
||||
|
||||
// dprintf
|
||||
void
|
||||
dprintf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
UserlandFS::KernelEmu::vdprintf(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// kprintf
|
||||
void
|
||||
kprintf(const char *format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
// spawn_kernel_thread
|
||||
thread_id
|
||||
spawn_kernel_thread(thread_func function, const char *threadName,
|
||||
int32 priority, void *arg)
|
||||
{
|
||||
return UserlandFS::KernelEmu::spawn_kernel_thread(function, threadName,
|
||||
priority, arg);
|
||||
}
|
||||
|
||||
@@ -1,434 +0,0 @@
|
||||
/* Generic hash table
|
||||
**
|
||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
#include "khash.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Debug.h>
|
||||
#include <Errors.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
|
||||
#undef TRACE
|
||||
#define TRACE_HASH 0
|
||||
#if TRACE_HASH
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
// TODO: the hashtable is not expanded when necessary (no load factor, nothing)
|
||||
// resizing should be optional, though, in case the hash is used at times
|
||||
// that forbid resizing.
|
||||
|
||||
struct hash_table {
|
||||
struct hash_element **table;
|
||||
int next_ptr_offset;
|
||||
uint32 table_size;
|
||||
int num_elements;
|
||||
int flags;
|
||||
int (*compare_func)(void *e, const void *key);
|
||||
uint32 (*hash_func)(void *e, const void *key, uint32 range);
|
||||
};
|
||||
|
||||
// XXX gross hack
|
||||
#define NEXT_ADDR(t, e) ((void *)(((unsigned long)(e)) + (t)->next_ptr_offset))
|
||||
#define NEXT(t, e) ((void *)(*(unsigned long *)NEXT_ADDR(t, e)))
|
||||
#define PUT_IN_NEXT(t, e, val) (*(unsigned long *)NEXT_ADDR(t, e) = (long)(val))
|
||||
|
||||
|
||||
const uint32 kPrimes [] = {
|
||||
13, 31, 61, 127, 251,
|
||||
509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
|
||||
524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
|
||||
134217689, 268435399, 536870909, 1073741789, 2147483647, 0
|
||||
};
|
||||
|
||||
|
||||
static uint32
|
||||
get_prime_table_size(uint32 size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; kPrimes[i] != 0; i++) {
|
||||
if (kPrimes[i] > size)
|
||||
return kPrimes[i];
|
||||
}
|
||||
|
||||
return kPrimes[i - 1];
|
||||
}
|
||||
|
||||
|
||||
static inline void *
|
||||
next_element(hash_table *table, void *element)
|
||||
{
|
||||
// ToDo: should we use this instead of the NEXT() macro?
|
||||
return (void *)(*(unsigned long *)NEXT_ADDR(table, element));
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
hash_grow(struct hash_table *table)
|
||||
{
|
||||
uint32 newSize = get_prime_table_size(table->num_elements);
|
||||
struct hash_element **newTable;
|
||||
uint32 index;
|
||||
|
||||
if (table->table_size >= newSize)
|
||||
return B_OK;
|
||||
|
||||
newTable = (struct hash_element **)malloc(sizeof(void *) * newSize);
|
||||
if (newTable == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset(newTable, 0, sizeof(void *) * newSize);
|
||||
|
||||
// rehash all the entries and add them to the new table
|
||||
for (index = 0; index < table->table_size; index++) {
|
||||
void *element;
|
||||
void *next;
|
||||
|
||||
for (element = table->table[index]; element != NULL; element = next) {
|
||||
uint32 hash = table->hash_func(element, NULL, newSize);
|
||||
next = NEXT(table, element);
|
||||
PUT_IN_NEXT(table, element, newTable[hash]);
|
||||
newTable[hash] = (struct hash_element *)element;
|
||||
}
|
||||
}
|
||||
|
||||
free(table->table);
|
||||
|
||||
table->table = newTable;
|
||||
table->table_size = newSize;
|
||||
|
||||
TRACE(("hash_grow: grown table %p, new size %lu\n", table, newSize));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - kernel private API
|
||||
|
||||
|
||||
struct hash_table *
|
||||
hash_init(uint32 tableSize, int nextPointerOffset,
|
||||
int compareFunc(void *e, const void *key),
|
||||
uint32 hashFunc(void *e, const void *key, uint32 range))
|
||||
{
|
||||
struct hash_table *t;
|
||||
uint32 i;
|
||||
|
||||
tableSize = get_prime_table_size(tableSize);
|
||||
|
||||
if (compareFunc == NULL || hashFunc == NULL) {
|
||||
dprintf("hash_init() called with NULL function pointer\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t = (struct hash_table *)malloc(sizeof(struct hash_table));
|
||||
if (t == NULL)
|
||||
return NULL;
|
||||
|
||||
t->table = (struct hash_element **)malloc(sizeof(void *) * tableSize);
|
||||
if (t->table == NULL) {
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < tableSize; i++)
|
||||
t->table[i] = NULL;
|
||||
|
||||
t->table_size = tableSize;
|
||||
t->next_ptr_offset = nextPointerOffset;
|
||||
t->flags = 0;
|
||||
t->num_elements = 0;
|
||||
t->compare_func = compareFunc;
|
||||
t->hash_func = hashFunc;
|
||||
|
||||
TRACE(("hash_init: created table %p, next_ptr_offset %d, compare_func %p, hash_func %p\n",
|
||||
t, nextPointerOffset, compareFunc, hashFunc));
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
hash_uninit(struct hash_table *table)
|
||||
{
|
||||
ASSERT(table->num_elements == 0);
|
||||
|
||||
free(table->table);
|
||||
free(table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
hash_insert(struct hash_table *table, void *element)
|
||||
{
|
||||
uint32 hash;
|
||||
|
||||
ASSERT(table != NULL && element != NULL);
|
||||
TRACE(("hash_insert: table %p, element %p\n", table, element));
|
||||
|
||||
hash = table->hash_func(element, NULL, table->table_size);
|
||||
PUT_IN_NEXT(table, element, table->table[hash]);
|
||||
table->table[hash] = (struct hash_element *)element;
|
||||
table->num_elements++;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
hash_insert_grow(struct hash_table *table, void *element)
|
||||
{
|
||||
uint32 hash;
|
||||
|
||||
ASSERT(table != NULL && element != NULL);
|
||||
TRACE(("hash_insert_grow: table %p, element %p\n", table, element));
|
||||
|
||||
hash = table->hash_func(element, NULL, table->table_size);
|
||||
PUT_IN_NEXT(table, element, table->table[hash]);
|
||||
table->table[hash] = (struct hash_element *)element;
|
||||
table->num_elements++;
|
||||
|
||||
if ((uint32)table->num_elements > table->table_size) {
|
||||
//dprintf("hash_insert: table has grown too much: %d in %d\n", table->num_elements, (int)table->table_size);
|
||||
hash_grow(table);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
hash_remove(struct hash_table *table, void *_element)
|
||||
{
|
||||
uint32 hash = table->hash_func(_element, NULL, table->table_size);
|
||||
void *element, *lastElement = NULL;
|
||||
|
||||
for (element = table->table[hash]; element != NULL;
|
||||
lastElement = element, element = NEXT(table, element)) {
|
||||
if (element == _element) {
|
||||
if (lastElement != NULL) {
|
||||
// connect the previous entry with the next one
|
||||
PUT_IN_NEXT(table, lastElement, NEXT(table, element));
|
||||
} else
|
||||
table->table[hash] = (struct hash_element *)NEXT(table, element);
|
||||
table->num_elements--;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hash_remove_current(struct hash_table *table, struct hash_iterator *iterator)
|
||||
{
|
||||
uint32 index = iterator->bucket;
|
||||
void *element;
|
||||
void *lastElement = NULL;
|
||||
|
||||
if (iterator->current == NULL || (element = table->table[index]) == NULL) {
|
||||
panic("hash_remove_current(): invalid iteration state");
|
||||
return;
|
||||
}
|
||||
|
||||
while (element != NULL) {
|
||||
if (element == iterator->current) {
|
||||
iterator->current = lastElement;
|
||||
|
||||
if (lastElement != NULL) {
|
||||
// connect the previous entry with the next one
|
||||
PUT_IN_NEXT(table, lastElement, NEXT(table, element));
|
||||
} else {
|
||||
table->table[index] = (struct hash_element *)NEXT(table,
|
||||
element);
|
||||
}
|
||||
|
||||
table->num_elements--;
|
||||
return;
|
||||
}
|
||||
|
||||
lastElement = element;
|
||||
element = NEXT(table, element);
|
||||
}
|
||||
|
||||
panic("hash_remove_current(): current element not found!");
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
hash_remove_first(struct hash_table *table, uint32 *_cookie)
|
||||
{
|
||||
uint32 index;
|
||||
|
||||
for (index = _cookie ? *_cookie : 0; index < table->table_size; index++) {
|
||||
void *element = table->table[index];
|
||||
if (element != NULL) {
|
||||
// remove the first element we find
|
||||
table->table[index] = (struct hash_element *)NEXT(table, element);
|
||||
table->num_elements--;
|
||||
if (_cookie)
|
||||
*_cookie = index;
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
hash_find(struct hash_table *table, void *searchedElement)
|
||||
{
|
||||
uint32 hash = table->hash_func(searchedElement, NULL, table->table_size);
|
||||
void *element;
|
||||
|
||||
for (element = table->table[hash]; element != NULL; element = NEXT(table, element)) {
|
||||
if (element == searchedElement)
|
||||
return element;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
hash_lookup(struct hash_table *table, const void *key)
|
||||
{
|
||||
uint32 hash = table->hash_func(NULL, key, table->table_size);
|
||||
void *element;
|
||||
|
||||
for (element = table->table[hash]; element != NULL; element = NEXT(table, element)) {
|
||||
if (table->compare_func(element, key) == 0)
|
||||
return element;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct hash_iterator *
|
||||
hash_open(struct hash_table *table, struct hash_iterator *iterator)
|
||||
{
|
||||
if (iterator == NULL) {
|
||||
iterator = (struct hash_iterator *)malloc(sizeof(struct hash_iterator));
|
||||
if (iterator == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hash_rewind(table, iterator);
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hash_close(struct hash_table *table, struct hash_iterator *iterator, bool freeIterator)
|
||||
{
|
||||
if (freeIterator)
|
||||
free(iterator);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hash_rewind(struct hash_table *table, struct hash_iterator *iterator)
|
||||
{
|
||||
iterator->current = NULL;
|
||||
iterator->bucket = -1;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
hash_next(struct hash_table *table, struct hash_iterator *iterator)
|
||||
{
|
||||
uint32 index;
|
||||
|
||||
restart:
|
||||
if (iterator->current == NULL) {
|
||||
// get next bucket
|
||||
for (index = (uint32)(iterator->bucket + 1); index < table->table_size; index++) {
|
||||
if (table->table[index]) {
|
||||
iterator->bucket = index;
|
||||
iterator->current = table->table[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iterator->current = NEXT(table, iterator->current);
|
||||
if (!iterator->current)
|
||||
goto restart;
|
||||
}
|
||||
|
||||
return iterator->current;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
hash_hash_string(const char *string)
|
||||
{
|
||||
uint32 hash = 0;
|
||||
char c;
|
||||
|
||||
// we assume hash to be at least 32 bits
|
||||
while ((c = *string++) != 0) {
|
||||
hash ^= hash >> 28;
|
||||
hash <<= 4;
|
||||
hash ^= c;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
hash_count_elements(struct hash_table *table)
|
||||
{
|
||||
return table->num_elements;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
hash_count_used_slots(struct hash_table *table)
|
||||
{
|
||||
uint32 usedSlots = 0;
|
||||
uint32 i;
|
||||
for (i = 0; i < table->table_size; i++) {
|
||||
if (table->table[i] != NULL)
|
||||
usedSlots++;
|
||||
}
|
||||
|
||||
return usedSlots;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hash_dump_table(struct hash_table* table)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
dprintf("hash table %p, table size: %lu, elements: %u\n", table,
|
||||
table->table_size, table->num_elements);
|
||||
|
||||
for (i = 0; i < table->table_size; i++) {
|
||||
struct hash_element* element = table->table[i];
|
||||
if (element != NULL) {
|
||||
dprintf("%6lu:", i);
|
||||
while (element != NULL) {
|
||||
dprintf(" %p", element);
|
||||
element = (hash_element*)NEXT(table, element);
|
||||
}
|
||||
dprintf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
#ifndef USERLAND_FS_HAIKU_HASH_H
|
||||
#define USERLAND_FS_HAIKU_HASH_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
// The use of offsetof() on non-PODs is invalid. Since many structs use
|
||||
// templated members (i.e. DoublyLinkedList) which makes them non-PODs we
|
||||
// can't use offsetof() anymore. This macro does the same, but requires an
|
||||
// instance of the object in question.
|
||||
#define offset_of_member(OBJECT, MEMBER) \
|
||||
((size_t)((char*)&OBJECT.MEMBER - (char*)&OBJECT))
|
||||
|
||||
// can be allocated on the stack
|
||||
typedef struct hash_iterator {
|
||||
void *current;
|
||||
int bucket;
|
||||
} hash_iterator;
|
||||
|
||||
typedef struct hash_table hash_table;
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct hash_table *hash_init(uint32 table_size, int next_ptr_offset,
|
||||
int compare_func(void *element, const void *key),
|
||||
uint32 hash_func(void *element, const void *key, uint32 range));
|
||||
int hash_uninit(struct hash_table *table);
|
||||
status_t hash_insert(struct hash_table *table, void *_element);
|
||||
status_t hash_insert_grow(struct hash_table *table, void *_element);
|
||||
status_t hash_remove(struct hash_table *table, void *_element);
|
||||
void hash_remove_current(struct hash_table *table, struct hash_iterator *iterator);
|
||||
void *hash_remove_first(struct hash_table *table, uint32 *_cookie);
|
||||
void *hash_find(struct hash_table *table, void *e);
|
||||
void *hash_lookup(struct hash_table *table, const void *key);
|
||||
struct hash_iterator *hash_open(struct hash_table *table, struct hash_iterator *i);
|
||||
void hash_close(struct hash_table *table, struct hash_iterator *i, bool free_iterator);
|
||||
void *hash_next(struct hash_table *table, struct hash_iterator *i);
|
||||
void hash_rewind(struct hash_table *table, struct hash_iterator *i);
|
||||
uint32 hash_count_elements(struct hash_table *table);
|
||||
uint32 hash_count_used_slots(struct hash_table *table);
|
||||
void hash_dump_table(struct hash_table* table);
|
||||
|
||||
/* function pointers must look like this:
|
||||
*
|
||||
* uint32 hash_func(void *e, const void *key, uint32 range);
|
||||
* hash function should calculate hash on either e or key,
|
||||
* depending on which one is not NULL - they also need
|
||||
* to make sure the returned value is within range.
|
||||
* int compare_func(void *e, const void *key);
|
||||
* compare function should compare the element with
|
||||
* the key, returning 0 if equal, other if not
|
||||
*/
|
||||
|
||||
uint32 hash_hash_string(const char *str);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif /* USERLAND_FS_HAIKU_HASH_H */
|
||||
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
/* Mutex and recursive_lock code */
|
||||
|
||||
#include "lock.h"
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
|
||||
sem_id
|
||||
_init_semaphore(int32 count, const char* name)
|
||||
{
|
||||
sem_id sem = create_sem(count, name);
|
||||
if (sem < 0)
|
||||
panic("_init_semaphore(): Failed to create semaphore!\n");
|
||||
return sem;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
recursive_lock_init(recursive_lock *lock, const char *name)
|
||||
{
|
||||
recursive_lock_init_etc(lock, name, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
recursive_lock_init_etc(recursive_lock *lock, const char *name, uint32 flags)
|
||||
{
|
||||
if (lock == NULL)
|
||||
panic("recursive_lock_init_etc(): NULL lock\n");
|
||||
|
||||
if (name == NULL)
|
||||
name = "recursive lock";
|
||||
|
||||
lock->holder = -1;
|
||||
lock->recursion = 0;
|
||||
lock->sem = _init_semaphore(1, name);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
recursive_lock_destroy(recursive_lock *lock)
|
||||
{
|
||||
if (lock == NULL)
|
||||
return;
|
||||
|
||||
delete_sem(lock->sem);
|
||||
lock->sem = -1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
recursive_lock_lock(recursive_lock *lock)
|
||||
{
|
||||
thread_id thread = find_thread(NULL);
|
||||
|
||||
if (thread != lock->holder) {
|
||||
status_t status = acquire_sem(lock->sem);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
lock->holder = thread;
|
||||
}
|
||||
lock->recursion++;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
recursive_lock_trylock(recursive_lock *lock)
|
||||
{
|
||||
thread_id thread = find_thread(NULL);
|
||||
|
||||
if (thread != lock->holder) {
|
||||
status_t status = acquire_sem_etc(lock->sem, 1, B_RELATIVE_TIMEOUT, 0);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
lock->holder = thread;
|
||||
}
|
||||
lock->recursion++;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
recursive_lock_unlock(recursive_lock *lock)
|
||||
{
|
||||
if (find_thread(NULL) != lock->holder)
|
||||
panic("recursive_lock %p unlocked by non-holder thread!\n", lock);
|
||||
|
||||
if (--lock->recursion == 0) {
|
||||
lock->holder = -1;
|
||||
release_sem(lock->sem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
recursive_lock_get_recursion(recursive_lock *lock)
|
||||
{
|
||||
if (lock->holder == find_thread(NULL))
|
||||
return lock->recursion;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
mutex_init(mutex *lock, const char *name)
|
||||
{
|
||||
mutex_init_etc(lock, name, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mutex_init_etc(mutex* lock, const char* name, uint32 flags)
|
||||
{
|
||||
if (lock == NULL)
|
||||
panic("mutex_init_etc(): NULL lock\n");
|
||||
|
||||
if (name == NULL)
|
||||
name = "mutex_sem";
|
||||
|
||||
lock->holder = -1;
|
||||
|
||||
lock->sem = _init_semaphore(1, name);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mutex_destroy(mutex *mutex)
|
||||
{
|
||||
if (mutex == NULL)
|
||||
return;
|
||||
|
||||
if (mutex->sem >= 0) {
|
||||
delete_sem(mutex->sem);
|
||||
mutex->sem = -1;
|
||||
}
|
||||
mutex->holder = -1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
mutex_lock(mutex *mutex)
|
||||
{
|
||||
thread_id me = find_thread(NULL);
|
||||
status_t status;
|
||||
|
||||
status = acquire_sem(mutex->sem);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (me == mutex->holder)
|
||||
panic("mutex_lock failure: mutex %p (sem = 0x%lx) acquired twice by thread 0x%lx\n", mutex, mutex->sem, me);
|
||||
|
||||
mutex->holder = me;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
mutex_trylock(mutex *mutex)
|
||||
{
|
||||
thread_id me = find_thread(NULL);
|
||||
status_t status;
|
||||
|
||||
status = acquire_sem_etc(mutex->sem, 1, B_RELATIVE_TIMEOUT, 0);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (me == mutex->holder)
|
||||
panic("mutex_lock failure: mutex %p (sem = 0x%lx) acquired twice by thread 0x%lx\n", mutex, mutex->sem, me);
|
||||
|
||||
mutex->holder = me;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mutex_unlock(mutex *mutex)
|
||||
{
|
||||
thread_id me = find_thread(NULL);
|
||||
|
||||
if (me != mutex->holder) {
|
||||
panic("mutex_unlock failure: thread 0x%lx is trying to release mutex %p (current holder 0x%lx)\n",
|
||||
me, mutex, mutex->holder);
|
||||
}
|
||||
|
||||
mutex->holder = -1;
|
||||
release_sem(mutex->sem);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
rw_lock_init(rw_lock *lock, const char *name)
|
||||
{
|
||||
rw_lock_init_etc(lock, name, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags)
|
||||
{
|
||||
if (lock == NULL)
|
||||
panic("rw_lock_init_etc(): NULL lock\n");
|
||||
|
||||
if (name == NULL)
|
||||
name = "r/w lock";
|
||||
|
||||
lock->sem = _init_semaphore(RW_MAX_READERS, name);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rw_lock_destroy(rw_lock *lock)
|
||||
{
|
||||
if (lock == NULL)
|
||||
return;
|
||||
|
||||
delete_sem(lock->sem);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
rw_lock_read_lock(rw_lock *lock)
|
||||
{
|
||||
return acquire_sem(lock->sem);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
rw_lock_read_unlock(rw_lock *lock)
|
||||
{
|
||||
return release_sem(lock->sem);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
rw_lock_write_lock(rw_lock *lock)
|
||||
{
|
||||
return acquire_sem_etc(lock->sem, RW_MAX_READERS, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
rw_lock_write_unlock(rw_lock *lock)
|
||||
{
|
||||
return release_sem_etc(lock->sem, RW_MAX_READERS, 0);
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
#ifndef USERLAND_FS_HAIKU_LOCK_H
|
||||
#define USERLAND_FS_HAIKU_LOCK_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
typedef struct recursive_lock {
|
||||
sem_id sem;
|
||||
thread_id holder;
|
||||
int recursion;
|
||||
} recursive_lock;
|
||||
|
||||
|
||||
|
||||
typedef struct mutex {
|
||||
sem_id sem;
|
||||
thread_id holder;
|
||||
} mutex;
|
||||
|
||||
#define MUTEX_FLAG_CLONE_NAME 0x1
|
||||
|
||||
|
||||
typedef struct rw_lock {
|
||||
sem_id sem;
|
||||
} rw_lock;
|
||||
|
||||
#define RW_MAX_READERS 1000000
|
||||
#define RW_LOCK_FLAG_CLONE_NAME 0x1
|
||||
|
||||
|
||||
#define ASSERT_LOCKED_RECURSIVE(r) do {} while (false)
|
||||
#define ASSERT_LOCKED_MUTEX(m) do {} while (false)
|
||||
#define ASSERT_WRITE_LOCKED_RW_LOCK(m) do {} while (false)
|
||||
#define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false)
|
||||
|
||||
|
||||
// static initializers
|
||||
#define MUTEX_INITIALIZER(name) { _init_semaphore(1, name), -1 }
|
||||
#define RECURSIVE_LOCK_INITIALIZER(name) { _init_semaphore(1, name), -1, 0 }
|
||||
#define RW_LOCK_INITIALIZER(name) \
|
||||
{ _init_semaphore(RW_MAX_READERS, name) }
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
||||
sem_id _init_semaphore(int32 count, const char* name);
|
||||
// implementation private
|
||||
|
||||
|
||||
extern void recursive_lock_init(recursive_lock *lock, const char *name);
|
||||
// name is *not* cloned nor freed in recursive_lock_destroy()
|
||||
extern void recursive_lock_init_etc(recursive_lock *lock, const char *name,
|
||||
uint32 flags);
|
||||
extern void recursive_lock_destroy(recursive_lock *lock);
|
||||
extern status_t recursive_lock_lock(recursive_lock *lock);
|
||||
extern status_t recursive_lock_trylock(recursive_lock *lock);
|
||||
extern void recursive_lock_unlock(recursive_lock *lock);
|
||||
extern int32 recursive_lock_get_recursion(recursive_lock *lock);
|
||||
|
||||
|
||||
extern void mutex_init(mutex* lock, const char* name);
|
||||
// name is *not* cloned nor freed in mutex_destroy()
|
||||
extern void mutex_init_etc(mutex* lock, const char* name, uint32 flags);
|
||||
extern void mutex_destroy(mutex* lock);
|
||||
//extern status_t mutex_switch_lock(mutex* from, mutex* to);
|
||||
// Unlocks "from" and locks "to" such that unlocking and starting to wait
|
||||
// for the lock is atomically. I.e. if "from" guards the object "to" belongs
|
||||
// to, the operation is safe as long as "from" is held while destroying
|
||||
// "to".
|
||||
|
||||
status_t mutex_lock(mutex* lock);
|
||||
//status_t mutex_lock_threads_locked(mutex* lock);
|
||||
status_t mutex_trylock(mutex* lock);
|
||||
void mutex_unlock(mutex* lock);
|
||||
//void mutex_transfer_lock(mutex* lock, thread_id thread);
|
||||
|
||||
|
||||
extern void rw_lock_init(rw_lock* lock, const char* name);
|
||||
// name is *not* cloned nor freed in rw_lock_destroy()
|
||||
extern void rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags);
|
||||
extern void rw_lock_destroy(rw_lock* lock);
|
||||
extern status_t rw_lock_read_lock(rw_lock* lock);
|
||||
extern status_t rw_lock_read_unlock(rw_lock* lock);
|
||||
extern status_t rw_lock_write_lock(rw_lock* lock);
|
||||
extern status_t rw_lock_write_unlock(rw_lock* lock);
|
||||
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
/* C++ Auto Locking */
|
||||
|
||||
#include "AutoLocker.h"
|
||||
|
||||
|
||||
// MutexLocking
|
||||
class MutexLocking {
|
||||
public:
|
||||
inline bool Lock(mutex *lockable)
|
||||
{
|
||||
return mutex_lock(lockable) == B_OK;
|
||||
}
|
||||
|
||||
inline void Unlock(mutex *lockable)
|
||||
{
|
||||
mutex_unlock(lockable);
|
||||
}
|
||||
};
|
||||
|
||||
// MutexLocker
|
||||
typedef AutoLocker<mutex, MutexLocking> MutexLocker;
|
||||
|
||||
// RecursiveLockLocking
|
||||
class RecursiveLockLocking {
|
||||
public:
|
||||
inline bool Lock(recursive_lock *lockable)
|
||||
{
|
||||
return recursive_lock_lock(lockable) == B_OK;
|
||||
}
|
||||
|
||||
inline void Unlock(recursive_lock *lockable)
|
||||
{
|
||||
recursive_lock_unlock(lockable);
|
||||
}
|
||||
};
|
||||
|
||||
// RecursiveLocker
|
||||
typedef AutoLocker<recursive_lock, RecursiveLockLocking> RecursiveLocker;
|
||||
|
||||
|
||||
#endif /* USERLAND_FS_HAIKU_LOCK_H */
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "slab.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
|
||||
struct object_cache {
|
||||
object_cache(const char *name, size_t objectSize,
|
||||
size_t alignment, size_t maxByteUsage, uint32 flags, void *cookie,
|
||||
object_cache_constructor constructor,
|
||||
object_cache_destructor destructor, object_cache_reclaimer reclaimer)
|
||||
:
|
||||
objectSize(objectSize),
|
||||
objectConstructor(constructor),
|
||||
objectDestructor(destructor)
|
||||
{
|
||||
}
|
||||
|
||||
size_t objectSize;
|
||||
object_cache_constructor objectConstructor;
|
||||
object_cache_destructor objectDestructor;
|
||||
};
|
||||
|
||||
|
||||
object_cache *
|
||||
create_object_cache(const char *name, size_t objectSize,
|
||||
size_t alignment, void *cookie, object_cache_constructor constructor,
|
||||
object_cache_destructor destructor)
|
||||
{
|
||||
return new(std::nothrow) object_cache(name, objectSize, alignment,
|
||||
0, 0, cookie, constructor, destructor, NULL);
|
||||
}
|
||||
|
||||
|
||||
object_cache *
|
||||
create_object_cache_etc(const char *name, size_t objectSize,
|
||||
size_t alignment, size_t maxByteUsage, uint32 flags, void *cookie,
|
||||
object_cache_constructor constructor, object_cache_destructor destructor,
|
||||
object_cache_reclaimer reclaimer)
|
||||
{
|
||||
return new(std::nothrow) object_cache(name, objectSize, alignment,
|
||||
maxByteUsage, flags, cookie, constructor, destructor, reclaimer);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
delete_object_cache(object_cache *cache)
|
||||
{
|
||||
delete cache;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
object_cache_set_minimum_reserve(object_cache *cache, size_t objectCount)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
object_cache_alloc(object_cache *cache, uint32 flags)
|
||||
{
|
||||
return cache != NULL ? malloc(cache->objectSize) : NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
object_cache_free(object_cache *cache, void *object)
|
||||
{
|
||||
free(object);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
object_cache_reserve(object_cache *cache, size_t object_count, uint32 flags)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void object_cache_get_usage(object_cache *cache, size_t *_allocatedMemory)
|
||||
{
|
||||
*_allocatedMemory = 0;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008, Axel Dörfler. All Rights Reserved.
|
||||
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef USERLAND_FS_HAIKU_SLAB_SLAB_H
|
||||
#define USERLAND_FS_HAIKU_SLAB_SLAB_H
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
enum {
|
||||
/* create_object_cache_etc flags */
|
||||
CACHE_NO_DEPOT = 1 << 0,
|
||||
CACHE_UNLOCKED_PAGES = 1 << 1,
|
||||
CACHE_LARGE_SLAB = 1 << 2,
|
||||
|
||||
/* object_cache_alloc flags */
|
||||
CACHE_DONT_SLEEP = 1 << 8,
|
||||
|
||||
/* internal */
|
||||
CACHE_DURING_BOOT = 1 << 31
|
||||
};
|
||||
|
||||
typedef struct object_cache object_cache;
|
||||
|
||||
typedef status_t (*object_cache_constructor)(void *cookie, void *object);
|
||||
typedef void (*object_cache_destructor)(void *cookie, void *object);
|
||||
typedef void (*object_cache_reclaimer)(void *cookie, int32 level);
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
object_cache *create_object_cache(const char *name, size_t object_size,
|
||||
size_t alignment, void *cookie, object_cache_constructor constructor,
|
||||
object_cache_destructor);
|
||||
object_cache *create_object_cache_etc(const char *name, size_t object_size,
|
||||
size_t alignment, size_t max_byte_usage, uint32 flags, void *cookie,
|
||||
object_cache_constructor constructor, object_cache_destructor destructor,
|
||||
object_cache_reclaimer reclaimer);
|
||||
|
||||
void delete_object_cache(object_cache *cache);
|
||||
|
||||
status_t object_cache_set_minimum_reserve(object_cache *cache,
|
||||
size_t objectCount);
|
||||
|
||||
void *object_cache_alloc(object_cache *cache, uint32 flags);
|
||||
void object_cache_free(object_cache *cache, void *object);
|
||||
|
||||
status_t object_cache_reserve(object_cache *cache, size_t object_count,
|
||||
uint32 flags);
|
||||
|
||||
void object_cache_get_usage(object_cache *cache, size_t *_allocatedMemory);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // USERLAND_FS_HAIKU_SLAB_SLAB_H
|
||||
Reference in New Issue
Block a user