From daa674789c7b247e3002a595bd53c4ef44caa8ab Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 9 Mar 2009 00:55:55 +0000 Subject: [PATCH] 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 --- .../server/haiku/HaikuKernelFileSystem.cpp | 11 +- .../userlandfs/server/haiku/Jamfile | 33 +- .../userlandfs/server/haiku/block_cache.cpp | 2620 ----------------- .../userlandfs/server/haiku/block_cache.h | 20 - .../server/haiku/condition_variable.cpp | 254 -- .../server/haiku/condition_variable.h | 94 - .../userlandfs/server/haiku/file_map.cpp | 647 ---- .../server/haiku/haiku_kernel_emu.cpp | 73 - .../userlandfs/server/haiku/khash.cpp | 434 --- .../userlandfs/server/haiku/khash.h | 65 - .../userlandfs/server/haiku/lock.cpp | 264 -- .../userlandfs/server/haiku/lock.h | 139 - .../userlandfs/server/haiku/slab.cpp | 90 - .../userlandfs/server/haiku/slab.h | 59 - 14 files changed, 32 insertions(+), 4771 deletions(-) delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/block_cache.cpp delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/block_cache.h delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/condition_variable.cpp delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/condition_variable.h delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/file_map.cpp delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/khash.cpp delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/khash.h delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/lock.cpp delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/lock.h delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/slab.cpp delete mode 100644 src/add-ons/kernel/file_systems/userlandfs/server/haiku/slab.h diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp index 4e99539e7f..07135ac158 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp @@ -8,8 +8,9 @@ #include -#include "block_cache.h" -#include "condition_variable.h" +#include +#include + #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); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile index 3b05f6615f..283d74ace4 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/Jamfile @@ -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 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 ] ; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/block_cache.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/block_cache.cpp deleted file mode 100644 index 1858dd7a46..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/block_cache.cpp +++ /dev/null @@ -1,2620 +0,0 @@ -/* - * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. - * Distributed under the terms of the MIT License. - */ - -#include "block_cache.h" - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "condition_variable.h" -#include "khash.h" -#include "lock.h" -#include "slab.h" - - -// TODO: this is a naive but growing implementation to test the API: -// 1) block reading/writing is not at all optimized for speed, it will -// just read and write single blocks. -// 2) the locking could be improved; getting a block should not need to -// wait for blocks to be written -// TODO: the retrieval/copy of the original data could be delayed until the -// new data must be written, ie. in low memory situations. - - -//#define TRACE_BLOCK_CACHE -#undef TRACE /* undef TRACE from */ -#ifdef TRACE_BLOCK_CACHE -# define TRACE(x) dprintf x -#else -# define TRACE(x) ; -#endif - -// This macro is used for fatal situations that are acceptable in a running -// system, like out of memory situations - should only panic for debugging. -#define FATAL(x) panic x - - -static const bigtime_t kTransactionIdleTime = 2000000LL; - // a transaction is considered idle after 2 seconds of inactivity - - -struct cache_transaction; -struct cached_block; -struct block_cache; -typedef DoublyLinkedListLink block_link; - -struct cached_block { - cached_block* next; // next in hash - cached_block* transaction_next; - block_link link; - off_t block_number; - void* current_data; - void* original_data; - void* parent_data; -#if BLOCK_CACHE_DEBUG_CHANGED - void* compare; -#endif - int32 ref_count; - int32 accessed; - bool busy : 1; - bool is_writing : 1; - bool is_dirty : 1; - bool unused : 1; - bool discard : 1; - cache_transaction* transaction; - cache_transaction* previous_transaction; - - static int Compare(void* _cacheEntry, const void* _block); - static uint32 Hash(void* _cacheEntry, const void* _block, uint32 range); -}; - -typedef DoublyLinkedList > block_list; - -struct cache_notification : DoublyLinkedListLinkImpl { - int32 transaction_id; - int32 events_pending; - int32 events; - transaction_notification_hook hook; - void* data; - bool delete_after_event; -}; - -typedef DoublyLinkedList NotificationList; - -struct block_cache : DoublyLinkedListLinkImpl { - hash_table* hash; - mutex lock; - int fd; - off_t max_blocks; - size_t block_size; - int32 next_transaction_id; - cache_transaction* last_transaction; - hash_table* transaction_hash; - - object_cache* buffer_cache; - block_list unused_blocks; - - uint32 num_dirty_blocks; - bool read_only; - - NotificationList pending_notifications; - ConditionVariable condition_variable; - - block_cache(int fd, off_t numBlocks, size_t blockSize, - bool readOnly); - ~block_cache(); - - status_t Init(); - - void Free(void* buffer); - void* Allocate(); - void RemoveBlock(cached_block* block); - void DiscardBlock(cached_block* block); - void FreeBlock(cached_block* block); - cached_block* NewBlock(off_t blockNumber); - - -private: - cached_block* _GetUnusedBlock(); -}; - -struct cache_listener; -typedef DoublyLinkedListLink listener_link; - -struct cache_listener : cache_notification { - listener_link link; -}; - -typedef DoublyLinkedList > ListenerList; - -struct cache_transaction { - cache_transaction(); - - cache_transaction* next; - int32 id; - int32 num_blocks; - int32 main_num_blocks; - int32 sub_num_blocks; - cached_block* first_block; - block_list blocks; - ListenerList listeners; - bool open; - bool has_sub_transaction; - bigtime_t last_used; -}; - -#if BLOCK_CACHE_BLOCK_TRACING -namespace BlockTracing { - -class Action : public AbstractTraceEntry { -public: - Action(block_cache* cache, cached_block* block) - : - fCache(cache), - fBlockNumber(block->block_number), - fIsDirty(block->is_dirty), - fHasOriginal(block->original_data != NULL), - fHasParent(block->parent_data != NULL), - fTransactionID(-1), - fPreviousID(-1) - { - if (block->transaction != NULL) - fTransactionID = block->transaction->id; - if (block->previous_transaction != NULL) - fPreviousID = block->previous_transaction->id; - } - - virtual void AddDump(TraceOutput& out) - { - out.Print("block cache %p, %s %Ld, %c%c%c transaction %ld " - "(previous id %ld)\n", fCache, _Action(), fBlockNumber, - fIsDirty ? 'd' : '-', fHasOriginal ? 'o' : '-', - fHasParent ? 'p' : '-', fTransactionID, fPreviousID); - } - - virtual const char* _Action() const = 0; - -private: - block_cache* fCache; - uint64 fBlockNumber; - bool fIsDirty; - bool fHasOriginal; - bool fHasParent; - int32 fTransactionID; - int32 fPreviousID; -}; - -class Get : public Action { -public: - Get(block_cache* cache, cached_block* block) - : Action(cache, block) - { - Initialized(); - } - - virtual const char* _Action() const { return "get"; } -}; - -class Put : public Action { -public: - Put(block_cache* cache, cached_block* block) - : Action(cache, block) - { - Initialized(); - } - - virtual const char* _Action() const { return "put"; } -}; - -class Read : public Action { -public: - Read(block_cache* cache, cached_block* block) - : Action(cache, block) - { - Initialized(); - } - - virtual const char* _Action() const { return "read"; } -}; - -class Write : public Action { -public: - Write(block_cache* cache, cached_block* block) - : Action(cache, block) - { - Initialized(); - } - - virtual const char* _Action() const { return "write"; } -}; - -class Flush : public Action { -public: - Flush(block_cache* cache, cached_block* block, bool getUnused = false) - : Action(cache, block), - fGetUnused(getUnused) - { - Initialized(); - } - - virtual const char* _Action() const - { return fGetUnused ? "get-unused" : "flush"; } - -private: - bool fGetUnused; -}; - -class Error : public AbstractTraceEntry { -public: - Error(block_cache* cache, uint64 blockNumber, const char* message, - status_t status = B_OK) - : - fCache(cache), - fBlockNumber(blockNumber), - fMessage(message), - fStatus(status) - { - Initialized(); - } - - virtual void AddDump(TraceOutput& out) - { - out.Print("block cache %p, error %Ld, %s%s%s", - fCache, fBlockNumber, fMessage, fStatus != B_OK ? ": " : "", - fStatus != B_OK ? strerror(fStatus) : ""); - } - -private: - block_cache* fCache; - uint64 fBlockNumber; - const char* fMessage; - status_t fStatus; -}; - -} // namespace BlockTracing - -# define TB(x) new(std::nothrow) BlockTracing::x; -#else -# define TB(x) ; -#endif - -#if BLOCK_CACHE_TRANSACTION_TRACING -namespace TransactionTracing { - -class Action : public AbstractTraceEntry { - public: - Action(const char* label, block_cache* cache, - cache_transaction* transaction) - : - fCache(cache), - fTransaction(transaction), - fID(transaction->id), - fSub(transaction->has_sub_transaction), - fNumBlocks(transaction->num_blocks), - fSubNumBlocks(transaction->sub_num_blocks) - { - strlcpy(fLabel, label, sizeof(fLabel)); - Initialized(); - } - - virtual void AddDump(TraceOutput& out) - { - out.Print("block cache %p, %s transaction %p (id %ld)%s" - ", %ld/%ld blocks", fCache, fLabel, fTransaction, fID, - fSub ? " sub" : "", fNumBlocks, fSubNumBlocks); - } - - private: - char fLabel[12]; - block_cache *fCache; - cache_transaction *fTransaction; - int32 fID; - bool fSub; - int32 fNumBlocks; - int32 fSubNumBlocks; -}; - -class Detach : public AbstractTraceEntry { - public: - Detach(block_cache* cache, cache_transaction* transaction, - cache_transaction* newTransaction) - : - fCache(cache), - fTransaction(transaction), - fID(transaction->id), - fSub(transaction->has_sub_transaction), - fNewTransaction(newTransaction), - fNewID(newTransaction->id) - { - Initialized(); - } - - virtual void AddDump(TraceOutput& out) - { - out.Print("block cache %p, detach transaction %p (id %ld)" - "from transaction %p (id %ld)%s", - fCache, fNewTransaction, fNewID, fTransaction, fID, - fSub ? " sub" : ""); - } - - private: - block_cache *fCache; - cache_transaction *fTransaction; - int32 fID; - bool fSub; - cache_transaction *fNewTransaction; - int32 fNewID; -}; - -class Abort : public AbstractTraceEntry { - public: - Abort(block_cache* cache, cache_transaction* transaction) - : - fCache(cache), - fTransaction(transaction), - fID(transaction->id), - fNumBlocks(0) - { - bool isSub = transaction->has_sub_transaction; - fNumBlocks = isSub ? transaction->sub_num_blocks - : transaction->num_blocks; - fBlocks = (off_t*)alloc_tracing_buffer(fNumBlocks * sizeof(off_t)); - if (fBlocks != NULL) { - cached_block* block = transaction->first_block; - for (int32 i = 0; block != NULL && i < fNumBlocks; - block = block->transaction_next) { - fBlocks[i++] = block->block_number; - } - } else - fNumBlocks = 0; - Initialized(); - } - - virtual void AddDump(TraceOutput& out) - { - out.Print("block cache %p, abort transaction " - "%p (id %ld), blocks", fCache, fTransaction, fID); - for (int32 i = 0; i < fNumBlocks && !out.IsFull(); i++) - out.Print(" %Ld", fBlocks[i]); - } - - private: - block_cache *fCache; - cache_transaction *fTransaction; - int32 fID; - off_t *fBlocks; - int32 fNumBlocks; -}; - -} // namespace TransactionTracing - -# define T(x) new(std::nothrow) TransactionTracing::x; -#else -# define T(x) ; -#endif - - -static status_t write_cached_block(block_cache* cache, cached_block* block, - bool deleteTransaction = true); - - -static DoublyLinkedList sCaches; -static mutex sCachesLock = MUTEX_INITIALIZER("block caches"); -static sem_id sEventSemaphore; -static mutex sNotificationsLock = MUTEX_INITIALIZER("block cache notifications"); -static thread_id sNotifierWriterThread; -static DoublyLinkedListLink sMarkCache; - // TODO: this only works if the link is the first entry of block_cache -static object_cache* sBlockCache; - - -// #pragma mark - notifications/listener - - -/*! Checks wether or not this is an event that closes a transaction. */ -static inline bool -is_closing_event(int32 event) -{ - return (event & (TRANSACTION_ABORTED | TRANSACTION_ENDED)) != 0; -} - - -static inline bool -is_written_event(int32 event) -{ - return (event & TRANSACTION_WRITTEN) != 0; -} - - -/*! From the specified \a notification, it will remove the lowest pending - event, and return that one in \a _event. - If there is no pending event anymore, it will return \c false. -*/ -static bool -get_next_pending_event(cache_notification* notification, int32* _event) -{ - for (int32 eventMask = 1; eventMask <= TRANSACTION_IDLE; eventMask <<= 1) { - int32 pending = atomic_and(¬ification->events_pending, - ~eventMask); - - bool more = (pending & ~eventMask) != 0; - - if ((pending & eventMask) != 0) { - *_event = eventMask; - return more; - } - } - - return false; -} - - -static void -flush_pending_notifications(block_cache* cache) -{ - ASSERT_LOCKED_MUTEX(&sCachesLock); - - while (true) { - MutexLocker locker(sNotificationsLock); - - cache_notification* notification = cache->pending_notifications.Head(); - if (notification == NULL) - return; - - bool deleteAfterEvent = false; - int32 event = -1; - if (!get_next_pending_event(notification, &event)) { - // remove the notification if this was the last pending event - cache->pending_notifications.Remove(notification); - deleteAfterEvent = notification->delete_after_event; - } - - if (event >= 0) { - // Notify listener, we need to copy the notification, as it might - // be removed when we unlock the list. - cache_notification copy = *notification; - locker.Unlock(); - - copy.hook(copy.transaction_id, event, copy.data); - - locker.Lock(); - } - - if (deleteAfterEvent) - delete notification; - } -} - - -/*! Flushes all pending notifications by calling the appropriate hook - functions. - Must not be called with a cache lock held. -*/ -static void -flush_pending_notifications() -{ - MutexLocker _(sCachesLock); - - DoublyLinkedList::Iterator iterator = sCaches.GetIterator(); - while (iterator.HasNext()) { - block_cache* cache = iterator.Next(); - - flush_pending_notifications(cache); - } -} - - -/*! Initializes the \a notification as specified. */ -static void -set_notification(cache_transaction* transaction, - cache_notification ¬ification, int32 events, - transaction_notification_hook hook, void* data) -{ - notification.transaction_id = transaction != NULL ? transaction->id : -1; - notification.events_pending = 0; - notification.events = events; - notification.hook = hook; - notification.data = data; - notification.delete_after_event = false; -} - - -/*! Makes sure the notification is deleted. It either deletes it directly, - when possible, or marks it for deletion if the notification is pending. -*/ -static void -delete_notification(cache_notification* notification) -{ - MutexLocker locker(sNotificationsLock); - - if (notification->events_pending != 0) - notification->delete_after_event = true; - else - delete notification; -} - - -/*! Adds the notification to the pending notifications list, or, if it's - already part of it, updates its events_pending field. - Also marks the notification to be deleted if \a deleteNotification - is \c true. - Triggers the notifier thread to run. -*/ -static void -add_notification(block_cache* cache, cache_notification* notification, - int32 event, bool deleteNotification) -{ - if (notification->hook == NULL) - return; - - int32 pending = atomic_or(¬ification->events_pending, event); - if (pending == 0) { - // not yet part of the notification list - MutexLocker locker(sNotificationsLock); - if (deleteNotification) - notification->delete_after_event = true; - cache->pending_notifications.Add(notification); - } else if (deleteNotification) { - // we might need to delete it ourselves if we're late - delete_notification(notification); - } - - release_sem_etc(sEventSemaphore, 1, B_DO_NOT_RESCHEDULE); - // We're probably still holding some locks that makes rescheduling - // not a good idea at this point. -} - - -/*! Notifies all interested listeners of this transaction about the \a event. - If \a event is a closing event (ie. TRANSACTION_ENDED, and - TRANSACTION_ABORTED), all listeners except those listening to - TRANSACTION_WRITTEN will be removed. -*/ -static void -notify_transaction_listeners(block_cache* cache, cache_transaction* transaction, - int32 event) -{ - T(Action("notify", cache, transaction)); - - bool isClosing = is_closing_event(event); - bool isWritten = is_written_event(event); - - ListenerList::Iterator iterator = transaction->listeners.GetIterator(); - while (iterator.HasNext()) { - cache_listener* listener = iterator.Next(); - - bool remove = (isClosing && !is_written_event(listener->events)) - || (isWritten && is_written_event(listener->events)); - if (remove) - iterator.Remove(); - - if ((listener->events & event) != 0) - add_notification(cache, listener, event, remove); - else if (remove) - delete_notification(listener); - } -} - - -/*! Removes and deletes all listeners that are still monitoring this - transaction. -*/ -static void -remove_transaction_listeners(block_cache* cache, cache_transaction* transaction) -{ - ListenerList::Iterator iterator = transaction->listeners.GetIterator(); - while (iterator.HasNext()) { - cache_listener* listener = iterator.Next(); - iterator.Remove(); - - delete_notification(listener); - } -} - - -static status_t -add_transaction_listener(block_cache* cache, cache_transaction* transaction, - int32 events, transaction_notification_hook hookFunction, void* data) -{ - ListenerList::Iterator iterator = transaction->listeners.GetIterator(); - while (iterator.HasNext()) { - cache_listener* listener = iterator.Next(); - - if (listener->data == data && listener->hook == hookFunction) { - // this listener already exists, just update it - listener->events |= events; - return B_OK; - } - } - - cache_listener* listener = new(std::nothrow) cache_listener; - if (listener == NULL) - return B_NO_MEMORY; - - set_notification(transaction, *listener, events, hookFunction, data); - transaction->listeners.Add(listener); - return B_OK; -} - - -// #pragma mark - private transaction - - -cache_transaction::cache_transaction() -{ - num_blocks = 0; - main_num_blocks = 0; - sub_num_blocks = 0; - first_block = NULL; - open = true; - last_used = system_time(); -} - - -static int -transaction_compare(void* _transaction, const void* _id) -{ - cache_transaction* transaction = (cache_transaction*)_transaction; - const int32* id = (const int32*)_id; - - return transaction->id - *id; -} - - -static uint32 -transaction_hash(void* _transaction, const void* _id, uint32 range) -{ - cache_transaction* transaction = (cache_transaction*)_transaction; - const int32* id = (const int32*)_id; - - if (transaction != NULL) - return transaction->id % range; - - return (uint32)*id % range; -} - - -static void -delete_transaction(block_cache* cache, cache_transaction* transaction) -{ - if (cache->last_transaction == transaction) - cache->last_transaction = NULL; - - remove_transaction_listeners(cache, transaction); - delete transaction; -} - - -static cache_transaction* -lookup_transaction(block_cache* cache, int32 id) -{ - return (cache_transaction*)hash_lookup(cache->transaction_hash, &id); -} - - -// #pragma mark - cached_block - - -int -compare_blocks(const void* _blockA, const void* _blockB) -{ - cached_block* blockA = *(cached_block**)_blockA; - cached_block* blockB = *(cached_block**)_blockB; - - off_t diff = blockA->block_number - blockB->block_number; - if (diff > 0) - return 1; - - return diff < 0 ? -1 : 0; -} - - -/*static*/ int -cached_block::Compare(void* _cacheEntry, const void* _block) -{ - cached_block* cacheEntry = (cached_block*)_cacheEntry; - const off_t* block = (const off_t*)_block; - - off_t diff = cacheEntry->block_number - *block; - if (diff > 0) - return 1; - - return diff < 0 ? -1 : 0; -} - - - -/*static*/ uint32 -cached_block::Hash(void* _cacheEntry, const void* _block, uint32 range) -{ - cached_block* cacheEntry = (cached_block*)_cacheEntry; - const off_t* block = (const off_t*)_block; - - if (cacheEntry != NULL) - return cacheEntry->block_number % range; - - return (uint64)*block % range; -} - - -// #pragma mark - block_cache - - -block_cache::block_cache(int _fd, off_t numBlocks, size_t blockSize, - bool readOnly) - : - hash(NULL), - fd(_fd), - max_blocks(numBlocks), - block_size(blockSize), - next_transaction_id(1), - last_transaction(NULL), - transaction_hash(NULL), - buffer_cache(NULL), - num_dirty_blocks(0), - read_only(readOnly) -{ -} - - -/*! Should be called with the cache's lock held. */ -block_cache::~block_cache() -{ - hash_uninit(transaction_hash); - hash_uninit(hash); - - delete_object_cache(buffer_cache); - - mutex_destroy(&lock); -} - - -status_t -block_cache::Init() -{ - condition_variable.Init(this, "cache transaction sync"); - mutex_init(&lock, "block cache"); - - buffer_cache = create_object_cache_etc("block cache buffers", block_size, - 8, 0, CACHE_LARGE_SLAB, NULL, NULL, NULL, NULL); - if (buffer_cache == NULL) - return B_NO_MEMORY; - - cached_block dummyBlock; - hash = hash_init(1024, offset_of_member(dummyBlock, next), - &cached_block::Compare, &cached_block::Hash); - if (hash == NULL) - return B_NO_MEMORY; - - cache_transaction dummyTransaction; - transaction_hash = hash_init(16, offset_of_member(dummyTransaction, next), - &transaction_compare, &::transaction_hash); - if (transaction_hash == NULL) - return B_NO_MEMORY; - - return B_OK; -} - - -void -block_cache::Free(void* buffer) -{ - if (buffer != NULL) - object_cache_free(buffer_cache, buffer); -} - - -void* -block_cache::Allocate() -{ - return object_cache_alloc(buffer_cache, 0); -} - - -void -block_cache::FreeBlock(cached_block* block) -{ - Free(block->current_data); - - if (block->original_data != NULL || block->parent_data != NULL) { - panic("block_cache::FreeBlock(): %Ld, original %p, parent %p\n", - block->block_number, block->original_data, block->parent_data); - } - -#if BLOCK_CACHE_DEBUG_CHANGED - Free(block->compare); -#endif - - object_cache_free(sBlockCache, block); -} - - -/*! Allocates a new block for \a blockNumber, ready for use */ -cached_block* -block_cache::NewBlock(off_t blockNumber) -{ - cached_block* block = (cached_block*)object_cache_alloc(sBlockCache, 0); - if (block == NULL) { - TB(Error(this, blockNumber, "allocation failed")); - dprintf("block allocation failed, unused list is %sempty.\n", - unused_blocks.IsEmpty() ? "" : "not "); - - // allocation failed, try to reuse an unused block - block = _GetUnusedBlock(); - if (block == NULL) { - TB(Error(this, blockNumber, "get unused failed")); - FATAL(("could not allocate block!\n")); - return NULL; - } - } - - block->current_data = Allocate(); - if (block->current_data == NULL) { - object_cache_free(sBlockCache, block); - return NULL; - } - - block->block_number = blockNumber; - block->ref_count = 0; - block->accessed = 0; - block->transaction_next = NULL; - block->transaction = block->previous_transaction = NULL; - block->original_data = NULL; - block->parent_data = NULL; - block->is_dirty = false; - block->unused = false; - block->discard = false; -#if BLOCK_CACHE_DEBUG_CHANGED - block->compare = NULL; -#endif - - return block; -} - - -void -block_cache::RemoveBlock(cached_block* block) -{ - hash_remove(hash, block); - FreeBlock(block); -} - - -/*! Discards the block from a transaction (this method must not be called - for blocks not part of a transaction). -*/ -void -block_cache::DiscardBlock(cached_block* block) -{ - ASSERT(block->discard); - - if (block->parent_data != NULL && block->parent_data != block->current_data) - Free(block->parent_data); - - block->parent_data = NULL; - - if (block->original_data != NULL) { - Free(block->original_data); - block->original_data = NULL; - } - - RemoveBlock(block); -} - - -cached_block* -block_cache::_GetUnusedBlock() -{ - TRACE(("block_cache: get unused block\n")); - - for (block_list::Iterator iterator = unused_blocks.GetIterator(); - cached_block* block = iterator.Next();) { - TB(Flush(this, block, true)); - // this can only happen if no transactions are used - if (block->is_dirty) - write_cached_block(this, block, false); - - // remove block from lists - iterator.Remove(); - hash_remove(hash, block); - - // TODO: see if parent/compare data is handled correctly here! - if (block->parent_data != NULL - && block->parent_data != block->original_data) - Free(block->parent_data); - if (block->original_data != NULL) - Free(block->original_data); - - return block; - } - - return NULL; -} - - -// #pragma mark - private block functions - - -/*! Removes a reference from the specified \a block. If this was the last - reference, the block is moved into the unused list. - In low memory situations, it will also free some blocks from that list, - but not necessarily the \a block it just released. -*/ -static void -put_cached_block(block_cache* cache, cached_block* block) -{ -#if BLOCK_CACHE_DEBUG_CHANGED - if (!block->is_dirty && block->compare != NULL - && memcmp(block->current_data, block->compare, cache->block_size)) { - dprintf("new block:\n"); - dump_block((const char*)block->current_data, 256, " "); - dprintf("unchanged block:\n"); - dump_block((const char*)block->compare, 256, " "); - write_cached_block(cache, block); - panic("block_cache: supposed to be clean block was changed!\n"); - - cache->Free(block->compare); - block->compare = NULL; - } -#endif - TB(Put(cache, block)); - - if (block->ref_count < 1) { - panic("Invalid ref_count for block %p, cache %p\n", block, cache); - return; - } - - if (--block->ref_count == 0 - && block->transaction == NULL && block->previous_transaction == NULL) { - // This block is not used anymore, and not part of any transaction - if (block->discard) { - cache->RemoveBlock(block); - } else { - // put this block in the list of unused blocks - block->unused = true; - ASSERT(block->original_data == NULL - && block->parent_data == NULL); - cache->unused_blocks.Add(block); - } - } -} - - -static void -put_cached_block(block_cache* cache, off_t blockNumber) -{ - if (blockNumber < 0 || blockNumber >= cache->max_blocks) { - panic("put_cached_block: invalid block number %lld (max %lld)", - blockNumber, cache->max_blocks - 1); - } - - cached_block* block = (cached_block*)hash_lookup(cache->hash, &blockNumber); - if (block != NULL) - put_cached_block(cache, block); - else { - TB(Error(cache, blockNumber, "put unknown")); - } -} - - -/*! Retrieves the block \a blockNumber from the hash table, if it's already - there, or reads it from the disk. - - \param _allocated tells you wether or not a new block has been allocated - to satisfy your request. - \param readBlock if \c false, the block will not be read in case it was - not already in the cache. The block you retrieve may contain random - data. -*/ -static cached_block* -get_cached_block(block_cache* cache, off_t blockNumber, bool* _allocated, - bool readBlock = true) -{ - if (blockNumber < 0 || blockNumber >= cache->max_blocks) { - panic("get_cached_block: invalid block number %lld (max %lld)", - blockNumber, cache->max_blocks - 1); - return NULL; - } - - cached_block* block = (cached_block*)hash_lookup(cache->hash, - &blockNumber); - *_allocated = false; - - if (block == NULL) { - // read block into cache - block = cache->NewBlock(blockNumber); - if (block == NULL) - return NULL; - - hash_insert_grow(cache->hash, block); - *_allocated = true; - } - - if (*_allocated && readBlock) { - int32 blockSize = cache->block_size; - - ssize_t bytesRead = read_pos(cache->fd, blockNumber * blockSize, - block->current_data, blockSize); - if (bytesRead < blockSize) { - cache->RemoveBlock(block); - TB(Error(cache, blockNumber, "read failed", bytesRead)); - - FATAL(("could not read block %Ld: bytesRead: %ld, error: %s\n", - blockNumber, bytesRead, strerror(errno))); - return NULL; - } - TB(Read(cache, block)); - } - - if (block->unused) { - //TRACE(("remove block %Ld from unused\n", blockNumber)); - block->unused = false; - cache->unused_blocks.Remove(block); - } - - block->ref_count++; - block->accessed++; - - return block; -} - - -/*! Returns the writable block data for the requested blockNumber. - If \a cleared is true, the block is not read from disk; an empty block - is returned. - - This is the only method to insert a block into a transaction. It makes - sure that the previous block contents are preserved in that case. -*/ -static void* -get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base, - off_t length, int32 transactionID, bool cleared) -{ - TRACE(("get_writable_cached_block(blockNumber = %Ld, transaction = %ld)\n", - blockNumber, transactionID)); - - if (blockNumber < 0 || blockNumber >= cache->max_blocks) { - panic("get_writable_cached_block: invalid block number %lld (max %lld)", - blockNumber, cache->max_blocks - 1); - } - - bool allocated; - cached_block* block = get_cached_block(cache, blockNumber, &allocated, - !cleared); - if (block == NULL) - return NULL; - - block->discard = false; - - // if there is no transaction support, we just return the current block - if (transactionID == -1) { - if (cleared) - memset(block->current_data, 0, cache->block_size); - - if (!block->is_dirty) { - cache->num_dirty_blocks++; - block->is_dirty = true; - // mark the block as dirty - } - - TB(Get(cache, block)); - return block->current_data; - } - - cache_transaction* transaction = block->transaction; - - if (transaction != NULL && transaction->id != transactionID) { - // TODO: we have to wait here until the other transaction is done. - // Maybe we should even panic, since we can't prevent any deadlocks. - panic("get_writable_cached_block(): asked to get busy writable block (transaction %ld)\n", block->transaction->id); - put_cached_block(cache, block); - return NULL; - } - if (transaction == NULL && transactionID != -1) { - // get new transaction - transaction = lookup_transaction(cache, transactionID); - if (transaction == NULL) { - panic("get_writable_cached_block(): invalid transaction %ld!\n", - transactionID); - put_cached_block(cache, block); - return NULL; - } - if (!transaction->open) { - panic("get_writable_cached_block(): transaction already done!\n"); - put_cached_block(cache, block); - return NULL; - } - - block->transaction = transaction; - - // attach the block to the transaction block list - block->transaction_next = transaction->first_block; - transaction->first_block = block; - transaction->num_blocks++; - } - if (transaction != NULL) - transaction->last_used = system_time(); - - bool wasUnchanged = block->original_data == NULL - || block->previous_transaction != NULL; - - if (!(allocated && cleared) && block->original_data == NULL) { - // we already have data, so we need to preserve it - block->original_data = cache->Allocate(); - if (block->original_data == NULL) { - TB(Error(cache, blockNumber, "allocate original failed")); - FATAL(("could not allocate original_data\n")); - put_cached_block(cache, block); - return NULL; - } - - memcpy(block->original_data, block->current_data, cache->block_size); - } - if (block->parent_data == block->current_data) { - // remember any previous contents for the parent transaction - block->parent_data = cache->Allocate(); - if (block->parent_data == NULL) { - // TODO: maybe we should just continue the current transaction in this case... - TB(Error(cache, blockNumber, "allocate parent failed")); - FATAL(("could not allocate parent\n")); - put_cached_block(cache, block); - return NULL; - } - - memcpy(block->parent_data, block->current_data, cache->block_size); - transaction->sub_num_blocks++; - } else if (transaction != NULL && transaction->has_sub_transaction - && block->parent_data == NULL && wasUnchanged) - transaction->sub_num_blocks++; - - if (cleared) - memset(block->current_data, 0, cache->block_size); - - block->is_dirty = true; - TB(Get(cache, block)); - - return block->current_data; -} - - -/*! Writes the specified \a block back to disk. It will always only write back - the oldest change of the block if it is part of more than one transaction. - It will automatically send out TRANSACTION_WRITTEN notices, as well as - delete transactions when they are no longer used, and \a deleteTransaction - is \c true. -*/ -static status_t -write_cached_block(block_cache* cache, cached_block* block, - bool deleteTransaction) -{ - cache_transaction* previous = block->previous_transaction; - int32 blockSize = cache->block_size; - - void* data = previous && block->original_data - ? block->original_data : block->current_data; - // we first need to write back changes from previous transactions - - TRACE(("write_cached_block(block %Ld)\n", block->block_number)); - TB(Write(cache, block)); - - ssize_t written = write_pos(cache->fd, block->block_number * blockSize, - data, blockSize); - - if (written < blockSize) { - TB(Error(cache, block->block_number, "write failed", written)); - FATAL(("could not write back block %Ld (%s)\n", block->block_number, - strerror(errno))); - return B_IO_ERROR; - } - - if (cache->num_dirty_blocks > 0) - cache->num_dirty_blocks--; - - if (data == block->current_data) - block->is_dirty = false; - - if (previous != NULL) { - previous->blocks.Remove(block); - block->previous_transaction = NULL; - - if (block->original_data != NULL && block->transaction == NULL) { - // This block is not part of a transaction, so it does not need - // its original pointer anymore. - cache->Free(block->original_data); - block->original_data = NULL; - } - - // Has the previous transation been finished with that write? - if (--previous->num_blocks == 0) { - TRACE(("cache transaction %ld finished!\n", previous->id)); - T(Action("written", cache, previous)); - - notify_transaction_listeners(cache, previous, TRANSACTION_WRITTEN); - - if (deleteTransaction) { - hash_remove(cache->transaction_hash, previous); - delete_transaction(cache, previous); - } - } - } - if (block->transaction == NULL && block->ref_count == 0) { - // the block is no longer used - block->unused = true; - cache->unused_blocks.Add(block); - } - - return B_OK; -} - - -#if DEBUG_BLOCK_CACHE - -static void -dump_block(cached_block* block) -{ - kprintf("%08lx %9Ld %08lx %08lx %08lx %5ld %6ld %c%c%c%c%c %08lx %08lx\n", - (addr_t)block, block->block_number, - (addr_t)block->current_data, (addr_t)block->original_data, - (addr_t)block->parent_data, block->ref_count, block->accessed, - block->busy ? 'B' : '-', block->is_writing ? 'W' : '-', - block->is_dirty ? 'D' : '-', block->unused ? 'U' : '-', - block->discard ? 'D' : '-', - (addr_t)block->transaction, - (addr_t)block->previous_transaction); -} - - -static int -dump_cache(int argc, char** argv) -{ - bool showTransactions = false; - bool showBlocks = false; - int32 i = 1; - while (argv[i] != NULL && argv[i][0] == '-') { - for (char* arg = &argv[i][1]; arg[0]; arg++) { - switch (arg[0]) { - case 'b': - showBlocks = true; - break; - case 't': - showTransactions = true; - break; - default: - print_debugger_command_usage(argv[0]); - return 0; - } - } - i++; - } - - if (i >= argc) { - print_debugger_command_usage(argv[0]); - return 0; - } - - block_cache* cache = (struct block_cache*)parse_expression(argv[i]); - if (cache == NULL) { - kprintf("invalid cache address\n"); - return 0; - } - - off_t blockNumber = -1; - if (i + 1 < argc) { - blockNumber = parse_expression(argv[i + 1]); - cached_block* block = (cached_block*)hash_lookup(cache->hash, - &blockNumber); - if (block != NULL) { - kprintf("BLOCK %p\n", block); - kprintf(" current data: %p\n", block->current_data); - kprintf(" original data: %p\n", block->original_data); - kprintf(" parent data: %p\n", block->parent_data); - kprintf(" ref_count: %ld\n", block->ref_count); - kprintf(" accessed: %ld\n", block->accessed); - kprintf(" flags: "); - if (block->is_writing) - kprintf(" is-writing"); - if (block->is_dirty) - kprintf(" is-dirty"); - if (block->unused) - kprintf(" unused"); - if (block->discard) - kprintf(" discard"); - kprintf("\n"); - if (block->transaction != NULL) { - kprintf(" transaction: %p (%ld)\n", block->transaction, - block->transaction->id); - if (block->transaction_next != NULL) { - kprintf(" next in transaction: %Ld\n", - block->transaction_next->block_number); - } - } - if (block->previous_transaction != NULL) { - kprintf(" previous transaction: %p (%ld)\n", - block->previous_transaction, - block->previous_transaction->id); - } - - set_debug_variable("_current", (addr_t)block->current_data); - set_debug_variable("_original", (addr_t)block->original_data); - set_debug_variable("_parent", (addr_t)block->parent_data); - } else - kprintf("block %Ld not found\n", blockNumber); - return 0; - } - - kprintf("BLOCK CACHE: %p\n", cache); - - kprintf(" fd: %d\n", cache->fd); - kprintf(" max_blocks: %Ld\n", cache->max_blocks); - kprintf(" block_size: %lu\n", cache->block_size); - kprintf(" next_transaction_id: %ld\n", cache->next_transaction_id); - - if (!cache->pending_notifications.IsEmpty()) { - kprintf(" pending notifications:\n"); - - NotificationList::Iterator iterator - = cache->pending_notifications.GetIterator(); - while (iterator.HasNext()) { - cache_notification* notification = iterator.Next(); - - kprintf(" %p %5lx %p - %p\n", notification, - notification->events_pending, notification->hook, - notification->data); - } - } - - if (showTransactions) { - kprintf(" transactions:\n"); - kprintf("address id state blocks main sub\n"); - - hash_iterator iterator; - hash_open(cache->transaction_hash, &iterator); - - cache_transaction* transaction; - while ((transaction = (cache_transaction*)hash_next( - cache->transaction_hash, &iterator)) != NULL) { - kprintf("%p %5ld %-7s %5ld %5ld %5ld\n", transaction, - transaction->id, transaction->open ? "open" : "closed", - transaction->num_blocks, transaction->main_num_blocks, - transaction->sub_num_blocks); - } - } - - if (showBlocks) { - kprintf(" blocks:\n"); - kprintf("address block no. current original parent refs access " - "flags transact prev. trans\n"); - } - - uint32 referenced = 0; - uint32 count = 0; - uint32 dirty = 0; - uint32 discarded = 0; - hash_iterator iterator; - hash_open(cache->hash, &iterator); - cached_block* block; - while ((block = (cached_block*)hash_next(cache->hash, &iterator)) != NULL) { - if (showBlocks) - dump_block(block); - - if (block->is_dirty) - dirty++; - if (block->discard) - discarded++; - if (block->ref_count) - referenced++; - count++; - } - - kprintf(" %ld blocks total, %ld dirty, %ld discarded, %ld referenced, %ld " - "in unused.\n", count, dirty, discarded, referenced, - cache->unused_blocks.Size()); - - hash_close(cache->hash, &iterator, false); - return 0; -} - - -static int -dump_transaction(int argc, char** argv) -{ - bool showBlocks = false; - int i = 1; - if (argc > 1 && !strcmp(argv[1], "-b")) { - showBlocks = true; - i++; - } - - if (argc - i < 1 || argc - i > 2) { - print_debugger_command_usage(argv[0]); - return 0; - } - - cache_transaction* transaction = NULL; - - if (argc - i == 1) { - transaction = (cache_transaction*)parse_expression(argv[i]); - } else { - block_cache* cache = (block_cache*)parse_expression(argv[i]); - int32 id = parse_expression(argv[i + 1]); - transaction = lookup_transaction(cache, id); - if (transaction == NULL) { - kprintf("No transaction with ID %ld found.\n", id); - return 0; - } - } - - kprintf("TRANSACTION %p\n", transaction); - - kprintf(" id: %ld\n", transaction->id); - kprintf(" num block: %ld\n", transaction->num_blocks); - kprintf(" main num block: %ld\n", transaction->main_num_blocks); - kprintf(" sub num block: %ld\n", transaction->sub_num_blocks); - kprintf(" has sub: %d\n", transaction->has_sub_transaction); - kprintf(" state: %s\n", transaction->open ? "open" : "closed"); - kprintf(" idle: %Ld secs\n", - (system_time() - transaction->last_used) / 1000000); - - kprintf(" listeners:\n"); - - ListenerList::Iterator iterator = transaction->listeners.GetIterator(); - while (iterator.HasNext()) { - cache_listener* listener = iterator.Next(); - - kprintf(" %p %5lx %p - %p\n", listener, listener->events_pending, - listener->hook, listener->data); - } - - if (!showBlocks) - return 0; - - kprintf(" blocks:\n"); - kprintf("address block no. current original parent refs access " - "flags transact prev. trans\n"); - - cached_block* block = transaction->first_block; - while (block != NULL) { - dump_block(block); - block = block->transaction_next; - } - - kprintf("--\n"); - - block_list::Iterator blockIterator = transaction->blocks.GetIterator(); - while (blockIterator.HasNext()) { - block = blockIterator.Next(); - dump_block(block); - } - - return 0; -} - - -static int -dump_caches(int argc, char** argv) -{ - kprintf("Block caches:\n"); - DoublyLinkedList::Iterator i = sCaches.GetIterator(); - while (i.HasNext()) { - block_cache* cache = i.Next(); - if (cache == (block_cache*)&sMarkCache) - continue; - - kprintf(" %p\n", cache); - } - - return 0; -} - -#endif // DEBUG_BLOCK_CACHE - - -/*! Traverses through the block_cache list, and returns one cache after the - other. The cache returned is automatically locked when you get it, and - unlocked with the next call to this function. Ignores caches that are in - deletion state. - Returns \c NULL when the end of the list is reached. -*/ -static block_cache* -get_next_locked_block_cache(block_cache* last) -{ - MutexLocker _(sCachesLock); - - block_cache* cache; - if (last != NULL) { - mutex_unlock(&last->lock); - - cache = sCaches.GetNext((block_cache*)&sMarkCache); - sCaches.Remove((block_cache*)&sMarkCache); - } else - cache = sCaches.Head(); - - if (cache != NULL) { - mutex_lock(&cache->lock); - sCaches.Insert(sCaches.GetNext(cache), (block_cache*)&sMarkCache); - } - - return cache; -} - - -/*! Background thread that continuously checks for pending notifications of - all caches. - Every two seconds, it will also write back up to 64 blocks per cache. -*/ -static status_t -block_notifier_and_writer(void* /*data*/) -{ - const bigtime_t kTimeout = 2000000LL; - bigtime_t timeout = kTimeout; - - while (true) { - bigtime_t start = system_time(); - - status_t status = acquire_sem_etc(sEventSemaphore, 1, - B_RELATIVE_TIMEOUT, timeout); - if (status == B_OK) { - flush_pending_notifications(); - timeout -= system_time() - start; - continue; - } - - // write 64 blocks of each block_cache every two seconds - // TODO: change this once we have an I/O scheduler - timeout = kTimeout; - - block_cache* cache = NULL; - while ((cache = get_next_locked_block_cache(cache)) != NULL) { - const uint32 kMaxCount = 64; - cached_block* blocks[kMaxCount]; - uint32 count = 0; - - if (cache->num_dirty_blocks) { - // This cache is not using transactions, we'll scan the blocks - // directly - hash_iterator iterator; - hash_open(cache->hash, &iterator); - - cached_block* block; - while (count < kMaxCount - && (block = (cached_block*)hash_next(cache->hash, - &iterator)) != NULL) { - if (block->is_dirty) - blocks[count++] = block; - } - - hash_close(cache->hash, &iterator, false); - } else { - hash_iterator iterator; - hash_open(cache->transaction_hash, &iterator); - - cache_transaction* transaction; - while ((transaction = (cache_transaction*)hash_next( - cache->transaction_hash, &iterator)) != NULL - && count < kMaxCount) { - if (transaction->open) { - if (system_time() > transaction->last_used - + kTransactionIdleTime) { - // Transaction is open but idle - notify_transaction_listeners(cache, transaction, - TRANSACTION_IDLE); - } - continue; - } - - // sort blocks to speed up writing them back - // TODO: ideally, this should be handled by the I/O scheduler - block_list::Iterator iterator - = transaction->blocks.GetIterator(); - - for (; count < kMaxCount && iterator.HasNext(); count++) { - blocks[count] = iterator.Next(); - } - } - - hash_close(cache->transaction_hash, &iterator, false); - } - - qsort(blocks, count, sizeof(void*), &compare_blocks); - - for (uint32 i = 0; i < count; i++) { - if (write_cached_block(cache, blocks[i], true) != B_OK) - break; - } - } - } -} - - -/*! Notify function for wait_for_notifications(). */ -static void -notify_sync(int32 transactionID, int32 event, void* _cache) -{ - block_cache* cache = (block_cache*)_cache; - - cache->condition_variable.NotifyOne(); -} - - -/*! Must be called with the sCachesLock held. */ -static bool -is_valid_cache(block_cache* cache) -{ - ASSERT_LOCKED_MUTEX(&sCachesLock); - - DoublyLinkedList::Iterator iterator = sCaches.GetIterator(); - while (iterator.HasNext()) { - if (cache == iterator.Next()) - return true; - } - - return false; -} - - -/*! Waits until all pending notifications are carried out. - Safe to be called from the block writer/notifier thread. - You must not hold the \a cache lock when calling this function. -*/ -static void -wait_for_notifications(block_cache* cache) -{ - MutexLocker locker(sCachesLock); - - if (find_thread(NULL) == sNotifierWriterThread) { - // We're the notifier thread, don't wait, but flush all pending - // notifications directly. - if (is_valid_cache(cache)) - flush_pending_notifications(cache); - return; - } - - // add sync notification - cache_notification notification; - set_notification(NULL, notification, TRANSACTION_WRITTEN, notify_sync, - cache); - - ConditionVariableEntry entry; - cache->condition_variable.Add(&entry); - - add_notification(cache, ¬ification, TRANSACTION_WRITTEN, false); - locker.Unlock(); - - // wait for notification hook to be called - entry.Wait(); - - ASSERT(notification.GetDoublyLinkedListLink()->next == NULL - && notification.GetDoublyLinkedListLink()->previous == NULL - && cache->pending_notifications.Head() != ¬ification); -} - - -status_t -block_cache_init(void) -{ - sBlockCache = create_object_cache_etc("cached blocks", sizeof(cached_block), - 8, 0, CACHE_LARGE_SLAB, NULL, NULL, NULL, NULL); - if (sBlockCache == NULL) - return B_NO_MEMORY; - - new (&sCaches) DoublyLinkedList; - // manually call constructor - - sEventSemaphore = create_sem(0, "block cache event"); - if (sEventSemaphore < B_OK) - return sEventSemaphore; - - sNotifierWriterThread = spawn_kernel_thread(&block_notifier_and_writer, - "block notifier/writer", B_LOW_PRIORITY, NULL); - if (sNotifierWriterThread >= B_OK) - resume_thread(sNotifierWriterThread); - -#if DEBUG_BLOCK_CACHE - add_debugger_command_etc("block_caches", &dump_caches, - "dumps all block caches", "\n", 0); - add_debugger_command_etc("block_cache", &dump_cache, - "dumps a specific block cache", - "[-bt] [block-number]\n" - " -t lists the transactions\n" - " -b lists all blocks\n", 0); - add_debugger_command_etc("transaction", &dump_transaction, - "dumps a specific transaction", "[-b] (( ) | )\n" - "Either use a block cache pointer and an ID or a pointer to the transaction.\n" - " -b lists all blocks that are part of this transaction\n", 0); -#endif - - return B_OK; -} - - -size_t -block_cache_used_memory() -{ - size_t usedMemory = 0; - - MutexLocker _(sCachesLock); - - DoublyLinkedList::Iterator it = sCaches.GetIterator(); - while (block_cache* cache = it.Next()) { - if (cache == (block_cache*)&sMarkCache) - continue; - - size_t cacheUsedMemory; - object_cache_get_usage(cache->buffer_cache, &cacheUsedMemory); - usedMemory += cacheUsedMemory; - } - - return usedMemory; -} - - -// #pragma mark - public transaction API - - -int32 -cache_start_transaction(void* _cache) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - if (cache->last_transaction && cache->last_transaction->open) { - panic("last transaction (%ld) still open!\n", - cache->last_transaction->id); - } - - cache_transaction* transaction = new(nothrow) cache_transaction; - if (transaction == NULL) - return B_NO_MEMORY; - - transaction->id = atomic_add(&cache->next_transaction_id, 1); - cache->last_transaction = transaction; - - TRACE(("cache_start_transaction(): id %ld started\n", transaction->id)); - T(Action("start", cache, transaction)); - - hash_insert_grow(cache->transaction_hash, transaction); - - return transaction->id; -} - - -status_t -cache_sync_transaction(void* _cache, int32 id) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - status_t status = B_ENTRY_NOT_FOUND; - - TRACE(("cache_sync_transaction(id %ld)\n", id)); - - hash_iterator iterator; - hash_open(cache->transaction_hash, &iterator); - - cache_transaction* transaction; - while ((transaction = (cache_transaction*)hash_next( - cache->transaction_hash, &iterator)) != NULL) { - // close all earlier transactions which haven't been closed yet - - if (transaction->id <= id && !transaction->open) { - // write back all of their remaining dirty blocks - T(Action("sync", cache, transaction)); - while (transaction->num_blocks > 0) { - // sort blocks to speed up writing them back - // TODO: this should be handled by the I/O scheduler - block_list::Iterator iterator - = transaction->blocks.GetIterator(); - uint32 maxCount = transaction->num_blocks; - cached_block* buffer[16]; - cached_block** blocks = (cached_block**)malloc(maxCount - * sizeof(void*)); - if (blocks == NULL) { - maxCount = 16; - blocks = buffer; - } - - uint32 count = 0; - for (; count < maxCount && iterator.HasNext(); count++) { - blocks[count] = iterator.Next(); - } - qsort(blocks, count, sizeof(void*), &compare_blocks); - - for (uint32 i = 0; i < count; i++) { - status = write_cached_block(cache, blocks[i], false); - if (status != B_OK) - break; - } - - if (blocks != buffer) - free(blocks); - - if (status != B_OK) - return status; - } - - hash_remove_current(cache->transaction_hash, &iterator); - delete_transaction(cache, transaction); - } - } - - hash_close(cache->transaction_hash, &iterator, false); - locker.Unlock(); - - wait_for_notifications(cache); - // make sure that all pending TRANSACTION_WRITTEN notifications - // are handled after we return - return B_OK; -} - - -status_t -cache_end_transaction(void* _cache, int32 id, - transaction_notification_hook hook, void* data) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - TRACE(("cache_end_transaction(id = %ld)\n", id)); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) { - panic("cache_end_transaction(): invalid transaction ID\n"); - return B_BAD_VALUE; - } - - notify_transaction_listeners(cache, transaction, TRANSACTION_ENDED); - - if (add_transaction_listener(cache, transaction, TRANSACTION_WRITTEN, hook, - data) != B_OK) { - return B_NO_MEMORY; - } - - T(Action("end", cache, transaction)); - - // iterate through all blocks and free the unchanged original contents - - cached_block* block = transaction->first_block; - cached_block* next; - for (; block != NULL; block = next) { - next = block->transaction_next; - - if (block->previous_transaction != NULL) { - // need to write back pending changes - write_cached_block(cache, block); - } - if (block->discard) { - // This block has been discarded in the transaction - cache->DiscardBlock(block); - transaction->num_blocks--; - continue; - } - - if (block->original_data != NULL) { - cache->Free(block->original_data); - block->original_data = NULL; - } - if (transaction->has_sub_transaction) { - if (block->parent_data != block->current_data) - cache->Free(block->parent_data); - block->parent_data = NULL; - } - - // move the block to the previous transaction list - transaction->blocks.Add(block); - - block->previous_transaction = transaction; - block->transaction_next = NULL; - block->transaction = NULL; - } - - transaction->open = false; - return B_OK; -} - - -status_t -cache_abort_transaction(void* _cache, int32 id) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - TRACE(("cache_abort_transaction(id = %ld)\n", id)); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) { - panic("cache_abort_transaction(): invalid transaction ID\n"); - return B_BAD_VALUE; - } - - T(Abort(cache, transaction)); - notify_transaction_listeners(cache, transaction, TRANSACTION_ABORTED); - - // iterate through all blocks and restore their original contents - - cached_block* block = transaction->first_block; - cached_block* next; - for (; block != NULL; block = next) { - next = block->transaction_next; - - if (block->original_data != NULL) { - TRACE(("cache_abort_transaction(id = %ld): restored contents of block %Ld\n", - transaction->id, block->block_number)); - memcpy(block->current_data, block->original_data, cache->block_size); - cache->Free(block->original_data); - block->original_data = NULL; - } - if (transaction->has_sub_transaction) { - if (block->parent_data != block->current_data) - cache->Free(block->parent_data); - block->parent_data = NULL; - } - - block->transaction_next = NULL; - block->transaction = NULL; - block->discard = false; - } - - hash_remove(cache->transaction_hash, transaction); - delete_transaction(cache, transaction); - return B_OK; -} - - -/*! Acknowledges the current parent transaction, and starts a new transaction - from its sub transaction. - The new transaction also gets a new transaction ID. -*/ -int32 -cache_detach_sub_transaction(void* _cache, int32 id, - transaction_notification_hook hook, void* data) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - TRACE(("cache_detach_sub_transaction(id = %ld)\n", id)); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) { - panic("cache_detach_sub_transaction(): invalid transaction ID\n"); - return B_BAD_VALUE; - } - if (!transaction->has_sub_transaction) - return B_BAD_VALUE; - - // create a new transaction for the sub transaction - cache_transaction* newTransaction = new(nothrow) cache_transaction; - if (transaction == NULL) - return B_NO_MEMORY; - - newTransaction->id = atomic_add(&cache->next_transaction_id, 1); - T(Detach(cache, transaction, newTransaction)); - - notify_transaction_listeners(cache, transaction, TRANSACTION_ENDED); - - if (add_transaction_listener(cache, transaction, TRANSACTION_WRITTEN, hook, - data) != B_OK) { - delete newTransaction; - return B_NO_MEMORY; - } - - // iterate through all blocks and free the unchanged original contents - - cached_block* block = transaction->first_block; - cached_block* last = NULL; - cached_block* next; - for (; block != NULL; block = next) { - next = block->transaction_next; - - if (block->previous_transaction != NULL) { - // need to write back pending changes - write_cached_block(cache, block); - } - if (block->discard) { - cache->DiscardBlock(block); - transaction->main_num_blocks--; - continue; - } - - if (block->original_data != NULL && block->parent_data != NULL) { - // free the original data if the parent data of the transaction - // will be made current - but keep them otherwise - cache->Free(block->original_data); - block->original_data = NULL; - } - if (block->parent_data == NULL - || block->parent_data != block->current_data) { - // we need to move this block over to the new transaction - block->original_data = block->parent_data; - if (last == NULL) - newTransaction->first_block = block; - else - last->transaction_next = block; - - block->transaction = newTransaction; - last = block; - } else - block->transaction = NULL; - - if (block->parent_data != NULL) { - // move the block to the previous transaction list - transaction->blocks.Add(block); - block->previous_transaction = transaction; - block->parent_data = NULL; - } - - block->transaction_next = NULL; - } - - newTransaction->num_blocks = transaction->sub_num_blocks; - - transaction->open = false; - transaction->has_sub_transaction = false; - transaction->num_blocks = transaction->main_num_blocks; - transaction->sub_num_blocks = 0; - - hash_insert_grow(cache->transaction_hash, newTransaction); - cache->last_transaction = newTransaction; - - return newTransaction->id; -} - - -status_t -cache_abort_sub_transaction(void* _cache, int32 id) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - TRACE(("cache_abort_sub_transaction(id = %ld)\n", id)); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) { - panic("cache_abort_sub_transaction(): invalid transaction ID\n"); - return B_BAD_VALUE; - } - if (!transaction->has_sub_transaction) - return B_BAD_VALUE; - - T(Abort(cache, transaction)); - notify_transaction_listeners(cache, transaction, TRANSACTION_ABORTED); - - // revert all changes back to the version of the parent - - cached_block* block = transaction->first_block; - cached_block* next; - for (; block != NULL; block = next) { - next = block->transaction_next; - - if (block->parent_data == NULL) { - if (block->original_data != NULL) { - // the parent transaction didn't change the block, but the sub - // transaction did - we need to revert from the original data - memcpy(block->current_data, block->original_data, - cache->block_size); - } - } else if (block->parent_data != block->current_data) { - // the block has been changed and must be restored - TRACE(("cache_abort_sub_transaction(id = %ld): restored contents of block %Ld\n", - transaction->id, block->block_number)); - memcpy(block->current_data, block->parent_data, cache->block_size); - cache->Free(block->parent_data); - } - - block->parent_data = NULL; - block->discard = false; - } - - // all subsequent changes will go into the main transaction - transaction->has_sub_transaction = false; - transaction->sub_num_blocks = 0; - - return B_OK; -} - - -status_t -cache_start_sub_transaction(void* _cache, int32 id) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - TRACE(("cache_start_sub_transaction(id = %ld)\n", id)); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) { - panic("cache_start_sub_transaction(): invalid transaction ID %ld\n", id); - return B_BAD_VALUE; - } - - notify_transaction_listeners(cache, transaction, TRANSACTION_ENDED); - - // move all changed blocks up to the parent - - cached_block* block = transaction->first_block; - cached_block* last = NULL; - cached_block* next; - for (; block != NULL; block = next) { - next = block->transaction_next; - - if (block->discard) { - // This block has been discarded in the parent transaction - if (last != NULL) - last->transaction_next = next; - else - transaction->first_block = next; - - cache->DiscardBlock(block); - transaction->num_blocks--; - continue; - } - if (transaction->has_sub_transaction - && block->parent_data != NULL - && block->parent_data != block->current_data) { - // there already is an older sub transaction - we acknowledge - // its changes and move its blocks up to the parent - cache->Free(block->parent_data); - } - - // we "allocate" the parent data lazily, that means, we don't copy - // the data (and allocate memory for it) until we need to - block->parent_data = block->current_data; - last = block; - } - - // all subsequent changes will go into the sub transaction - transaction->has_sub_transaction = true; - transaction->main_num_blocks = transaction->num_blocks; - transaction->sub_num_blocks = 0; - T(Action("start-sub", cache, transaction)); - - return B_OK; -} - - -/*! Adds a transaction listener that gets notified when the transaction - is ended, aborted, written, or idle as specified by \a events. - The listener gets automatically removed when the transaction ends. -*/ -status_t -cache_add_transaction_listener(void* _cache, int32 id, int32 events, - transaction_notification_hook hook, void* data) -{ - block_cache* cache = (block_cache*)_cache; - - MutexLocker locker(&cache->lock); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) - return B_BAD_VALUE; - - return add_transaction_listener(cache, transaction, events, hook, data); -} - - -status_t -cache_remove_transaction_listener(void* _cache, int32 id, - transaction_notification_hook hookFunction, void* data) -{ - block_cache* cache = (block_cache*)_cache; - - MutexLocker locker(&cache->lock); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) - return B_BAD_VALUE; - - ListenerList::Iterator iterator = transaction->listeners.GetIterator(); - while (iterator.HasNext()) { - cache_listener* listener = iterator.Next(); - if (listener->data == data && listener->hook == hookFunction) { - iterator.Remove(); - - if (listener->events_pending != 0) { - MutexLocker _(sNotificationsLock); - if (listener->events_pending != 0) - cache->pending_notifications.Remove(listener); - } - delete listener; - return B_OK; - } - } - - return B_ENTRY_NOT_FOUND; -} - - -status_t -cache_next_block_in_transaction(void* _cache, int32 id, bool mainOnly, - long* _cookie, off_t* _blockNumber, void** _data, void** _unchangedData) -{ - cached_block* block = (cached_block*)*_cookie; - block_cache* cache = (block_cache*)_cache; - - MutexLocker locker(&cache->lock); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL || !transaction->open) - return B_BAD_VALUE; - - if (block == NULL) - block = transaction->first_block; - else - block = block->transaction_next; - - if (transaction->has_sub_transaction) { - if (mainOnly) { - // find next block that the parent changed - while (block != NULL && block->parent_data == NULL) - block = block->transaction_next; - } else { - // find next non-discarded block - while (block != NULL && block->discard) - block = block->transaction_next; - } - } - - if (block == NULL) - return B_ENTRY_NOT_FOUND; - - if (_blockNumber) - *_blockNumber = block->block_number; - if (_data) - *_data = mainOnly ? block->parent_data : block->current_data; - if (_unchangedData) - *_unchangedData = block->original_data; - - *_cookie = (addr_t)block; - return B_OK; -} - - -int32 -cache_blocks_in_transaction(void* _cache, int32 id) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) - return B_BAD_VALUE; - - return transaction->num_blocks; -} - - -int32 -cache_blocks_in_main_transaction(void* _cache, int32 id) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) - return B_BAD_VALUE; - - return transaction->main_num_blocks; -} - - -int32 -cache_blocks_in_sub_transaction(void* _cache, int32 id) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - cache_transaction* transaction = lookup_transaction(cache, id); - if (transaction == NULL) - return B_BAD_VALUE; - - return transaction->sub_num_blocks; -} - - -// #pragma mark - public block cache API - - -void -block_cache_delete(void* _cache, bool allowWrites) -{ - block_cache* cache = (block_cache*)_cache; - - if (allowWrites) - block_cache_sync(cache); - - mutex_lock(&sCachesLock); - sCaches.Remove(cache); - mutex_unlock(&sCachesLock); - - mutex_lock(&cache->lock); - - // free all blocks - - uint32 cookie = 0; - cached_block* block; - while ((block = (cached_block*)hash_remove_first(cache->hash, - &cookie)) != NULL) { - cache->FreeBlock(block); - } - - // free all transactions (they will all be aborted) - - cookie = 0; - cache_transaction* transaction; - while ((transaction = (cache_transaction*)hash_remove_first( - cache->transaction_hash, &cookie)) != NULL) { - delete transaction; - } - - delete cache; -} - - -void* -block_cache_create(int fd, off_t numBlocks, size_t blockSize, bool readOnly) -{ - block_cache* cache = new(nothrow) block_cache(fd, numBlocks, blockSize, - readOnly); - if (cache == NULL) - return NULL; - - if (cache->Init() != B_OK) { - delete cache; - return NULL; - } - - MutexLocker _(sCachesLock); - sCaches.Add(cache); - - return cache; -} - - -status_t -block_cache_sync(void* _cache) -{ - block_cache* cache = (block_cache*)_cache; - - // we will sync all dirty blocks to disk that have a completed - // transaction or no transaction only - - MutexLocker locker(&cache->lock); - hash_iterator iterator; - hash_open(cache->hash, &iterator); - - cached_block* block; - while ((block = (cached_block*)hash_next(cache->hash, &iterator)) != NULL) { - if (block->previous_transaction != NULL - || (block->transaction == NULL && block->is_dirty)) { - status_t status = write_cached_block(cache, block); - if (status != B_OK) - return status; - } - } - - hash_close(cache->hash, &iterator, false); - locker.Unlock(); - - wait_for_notifications(cache); - // make sure that all pending TRANSACTION_WRITTEN notifications - // are handled after we return - return B_OK; -} - - -status_t -block_cache_sync_etc(void* _cache, off_t blockNumber, size_t numBlocks) -{ - block_cache* cache = (block_cache*)_cache; - - // we will sync all dirty blocks to disk that have a completed - // transaction or no transaction only - - if (blockNumber < 0 || blockNumber >= cache->max_blocks) { - panic("block_cache_sync_etc: invalid block number %Ld (max %Ld)", - blockNumber, cache->max_blocks - 1); - return B_BAD_VALUE; - } - - MutexLocker locker(&cache->lock); - - for (; numBlocks > 0; numBlocks--, blockNumber++) { - cached_block* block = (cached_block*)hash_lookup(cache->hash, - &blockNumber); - if (block == NULL) - continue; - - if (block->previous_transaction != NULL - || (block->transaction == NULL && block->is_dirty)) { - status_t status = write_cached_block(cache, block); - if (status != B_OK) - return status; - } - } - - locker.Unlock(); - - wait_for_notifications(cache); - // make sure that all pending TRANSACTION_WRITTEN notifications - // are handled after we return - return B_OK; -} - - -void -block_cache_discard(void* _cache, off_t blockNumber, size_t numBlocks) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - for (; numBlocks > 0; numBlocks--, blockNumber++) { - cached_block* block = (cached_block*)hash_lookup(cache->hash, - &blockNumber); - if (block == NULL) - continue; - - if (block->previous_transaction != NULL) - write_cached_block(cache, block); - - if (block->unused) { - cache->unused_blocks.Remove(block); - cache->RemoveBlock(block); - } else { - if (block->transaction != NULL && block->parent_data != NULL - && block->parent_data != block->current_data) { - panic("Discarded block %Ld has already been changed in this " - "transaction!", blockNumber); - } - - // mark it as discarded (in the current transaction only, if any) - block->discard = true; - } - } -} - - -status_t -block_cache_make_writable(void* _cache, off_t blockNumber, int32 transaction) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - if (cache->read_only) - panic("tried to make block writable on a read-only cache!"); - - // TODO: this can be done better! - void* block = get_writable_cached_block(cache, blockNumber, - blockNumber, 1, transaction, false); - if (block != NULL) { - put_cached_block((block_cache*)_cache, blockNumber); - return B_OK; - } - - return B_ERROR; -} - - -void* -block_cache_get_writable_etc(void* _cache, off_t blockNumber, off_t base, - off_t length, int32 transaction) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - TRACE(("block_cache_get_writable_etc(block = %Ld, transaction = %ld)\n", - blockNumber, transaction)); - if (cache->read_only) - panic("tried to get writable block on a read-only cache!"); - - return get_writable_cached_block(cache, blockNumber, base, length, - transaction, false); -} - - -void* -block_cache_get_writable(void* _cache, off_t blockNumber, int32 transaction) -{ - return block_cache_get_writable_etc(_cache, blockNumber, - blockNumber, 1, transaction); -} - - -void* -block_cache_get_empty(void* _cache, off_t blockNumber, int32 transaction) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - TRACE(("block_cache_get_empty(block = %Ld, transaction = %ld)\n", - blockNumber, transaction)); - if (cache->read_only) - panic("tried to get empty writable block on a read-only cache!"); - - return get_writable_cached_block((block_cache*)_cache, blockNumber, - blockNumber, 1, transaction, true); -} - - -const void* -block_cache_get_etc(void* _cache, off_t blockNumber, off_t base, off_t length) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - bool allocated; - - cached_block* block = get_cached_block(cache, blockNumber, &allocated); - if (block == NULL) - return NULL; - -#if BLOCK_CACHE_DEBUG_CHANGED - if (block->compare == NULL) - block->compare = cache->Allocate(); - if (block->compare != NULL) - memcpy(block->compare, block->current_data, cache->block_size); -#endif - TB(Get(cache, block)); - - return block->current_data; -} - - -const void* -block_cache_get(void* _cache, off_t blockNumber) -{ - return block_cache_get_etc(_cache, blockNumber, blockNumber, 1); -} - - -/*! Changes the internal status of a writable block to \a dirty. This can be - helpful in case you realize you don't need to change that block anymore - for whatever reason. - - Note, you must only use this function on blocks that were acquired - writable! -*/ -status_t -block_cache_set_dirty(void* _cache, off_t blockNumber, bool dirty, - int32 transaction) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - cached_block* block = (cached_block*)hash_lookup(cache->hash, - &blockNumber); - if (block == NULL) - return B_BAD_VALUE; - if (block->is_dirty == dirty) { - // there is nothing to do for us - return B_OK; - } - - // TODO: not yet implemented - if (dirty) - panic("block_cache_set_dirty(): not yet implemented that way!\n"); - - return B_OK; -} - - -void -block_cache_put(void* _cache, off_t blockNumber) -{ - block_cache* cache = (block_cache*)_cache; - MutexLocker locker(&cache->lock); - - put_cached_block(cache, blockNumber); -} diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/block_cache.h b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/block_cache.h deleted file mode 100644 index c39f9f43a9..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/block_cache.h +++ /dev/null @@ -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 - - -extern "C" { - -status_t block_cache_init(void); -size_t block_cache_used_memory(); - -} - - -#endif // USERLAND_FS_HAIKU_BLOCK_CACHE_H diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/condition_variable.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/condition_variable.cpp deleted file mode 100644 index d845f17834..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/condition_variable.cpp +++ /dev/null @@ -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 -#include -#include - -#include -#include - -// libroot -#include - -// system -#include -#include - -#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* GetLink(ConditionVariable* variable) const - { return variable; } -}; - -typedef OpenHashTable 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; -} diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/condition_variable.h b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/condition_variable.h deleted file mode 100644 index 708e1984aa..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/condition_variable.h +++ /dev/null @@ -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 - -#include -#include - - -class ConditionVariable; - - -struct ConditionVariableEntry - : DoublyLinkedListLinkImpl { -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 { -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 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 diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/file_map.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/file_map.cpp deleted file mode 100644 index a10d413530..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/file_map.cpp +++ /dev/null @@ -1,647 +0,0 @@ -/* - * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. - * Distributed under the terms of the MIT License. - */ - -#include -#include -#include - -#include - -#include -#include - -#include - -#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 -#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 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] \n" - " -p - causes the file extents to be printed as well.\n" - " - 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); -} - diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp index f4de1b7148..d672c6bc06 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/haiku_kernel_emu.cpp @@ -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); -} diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/khash.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/khash.cpp deleted file mode 100644 index 2f4aef9db1..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/khash.cpp +++ /dev/null @@ -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 -#include - -#include -#include -#include - - -#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"); - } - } -} diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/khash.h b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/khash.h deleted file mode 100644 index 59bac09de8..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/khash.h +++ /dev/null @@ -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 - - -// 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 */ diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/lock.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/lock.cpp deleted file mode 100644 index 76cea38d34..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/lock.cpp +++ /dev/null @@ -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 - - -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); -} diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/lock.h b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/lock.h deleted file mode 100644 index 4f97ef6919..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/lock.h +++ /dev/null @@ -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 - - -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 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 RecursiveLocker; - - -#endif /* USERLAND_FS_HAIKU_LOCK_H */ diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/slab.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/slab.cpp deleted file mode 100644 index 466bb659ac..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/slab.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ - -#include "slab.h" - -#include - -#include - - -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; -} diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/slab.h b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/slab.h deleted file mode 100644 index 0b3ab6d04c..0000000000 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/slab.h +++ /dev/null @@ -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 - - -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