From 52c8e07fde35f1bea1e53f5df1dabfc6f523b8fd Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 8 Mar 2009 17:55:36 +0000 Subject: [PATCH] Broke kernelland_emu.cpp into several source files. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29447 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/tests/add-ons/kernel/Jamfile | 25 +- .../file_systems/userlandfs/bfs/Jamfile | 9 +- .../add-ons/kernel/kernelland_emu/Jamfile | 27 + .../kernelland_emu/condition_variable.cpp | 115 +++ .../add-ons/kernel/kernelland_emu/lock.cpp | 287 +++++++ .../add-ons/kernel/kernelland_emu/misc.cpp | 346 +++++++++ .../module.cpp} | 722 +----------------- 7 files changed, 783 insertions(+), 748 deletions(-) create mode 100644 src/tests/add-ons/kernel/kernelland_emu/Jamfile create mode 100644 src/tests/add-ons/kernel/kernelland_emu/condition_variable.cpp create mode 100644 src/tests/add-ons/kernel/kernelland_emu/lock.cpp create mode 100644 src/tests/add-ons/kernel/kernelland_emu/misc.cpp rename src/tests/add-ons/kernel/{kernelland_emu.cpp => kernelland_emu/module.cpp} (56%) diff --git a/src/tests/add-ons/kernel/Jamfile b/src/tests/add-ons/kernel/Jamfile index c824d92ce9..334b039272 100644 --- a/src/tests/add-ons/kernel/Jamfile +++ b/src/tests/add-ons/kernel/Jamfile @@ -1,32 +1,9 @@ SubDir HAIKU_TOP src tests add-ons kernel ; -UsePrivateHeaders [ FDirName kernel ] ; -UsePrivateHeaders shared ; -UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ; - -SharedLibrary libkernelland_emu.so : - kernelland_emu.cpp - strlcpy.c - khash.c - list.c - - : be $(TARGET_LIBSTDC++) ; - -AbsSymLink libkernelland_emu.so : libkernelland_emu.so - : /boot/home/config/lib : false ; - -SEARCH on [ FGristFiles - strlcpy.c - ] = [ FDirName $(HAIKU_TOP) src system libroot posix string ] ; - -SEARCH on [ FGristFiles - list.c khash.c - ] = [ FDirName $(HAIKU_TOP) src system kernel util ] ; - SubInclude HAIKU_TOP src tests add-ons kernel bus_managers ; SubInclude HAIKU_TOP src tests add-ons kernel busses ; SubInclude HAIKU_TOP src tests add-ons kernel debugger ; -# SubInclude HAIKU_TOP src tests add-ons kernel disk_scanner ; SubInclude HAIKU_TOP src tests add-ons kernel drivers ; SubInclude HAIKU_TOP src tests add-ons kernel file_systems ; +SubInclude HAIKU_TOP src tests add-ons kernel kernelland_emu ; SubInclude HAIKU_TOP src tests add-ons kernel network ; diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/bfs/Jamfile b/src/tests/add-ons/kernel/file_systems/userlandfs/bfs/Jamfile index 36bcac78e8..82cf5476eb 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/bfs/Jamfile +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/bfs/Jamfile @@ -21,12 +21,13 @@ SEARCH_SOURCE += $(bfsTop) ; SubDirC++Flags $(defines) -Wall -Wno-multichar -fno-rtti ; } -UsePrivateHeaders [ FDirName kernel ] ; -UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; -UsePrivateHeaders [ FDirName storage ] ; +UsePrivateKernelHeaders ; +UsePrivateHeaders shared ; +#UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; +#UsePrivateHeaders [ FDirName storage ] ; Addon bfs - : + : BlockAllocator.cpp BPlusTree.cpp Attribute.cpp diff --git a/src/tests/add-ons/kernel/kernelland_emu/Jamfile b/src/tests/add-ons/kernel/kernelland_emu/Jamfile new file mode 100644 index 0000000000..aa602ffa8f --- /dev/null +++ b/src/tests/add-ons/kernel/kernelland_emu/Jamfile @@ -0,0 +1,27 @@ +SubDir HAIKU_TOP src tests add-ons kernel kernelland_emu ; + +UsePrivateKernelHeaders ; +UsePrivateHeaders shared ; + +SharedLibrary libkernelland_emu.so : + condition_variable.cpp + lock.cpp + misc.cpp + module.cpp + + strlcpy.c + khash.c + list.c + + : be $(TARGET_LIBSTDC++) ; + +AbsSymLink libkernelland_emu.so : libkernelland_emu.so + : /boot/home/config/lib : false ; + +SEARCH on [ FGristFiles + strlcpy.c + ] = [ FDirName $(HAIKU_TOP) src system libroot posix string ] ; + +SEARCH on [ FGristFiles + list.c khash.c + ] = [ FDirName $(HAIKU_TOP) src system kernel util ] ; diff --git a/src/tests/add-ons/kernel/kernelland_emu/condition_variable.cpp b/src/tests/add-ons/kernel/kernelland_emu/condition_variable.cpp new file mode 100644 index 0000000000..a79e0e0246 --- /dev/null +++ b/src/tests/add-ons/kernel/kernelland_emu/condition_variable.cpp @@ -0,0 +1,115 @@ +/* + * Copyright 2002-2009, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * Ingo Weinhold, bonefish@cs.tu-berlin.de. + * Axel Dörfler, axeld@pinc-software.de. + */ + +#include + +#include + +#include + + +#define STATUS_ADDED 1 +#define STATUS_WAITING 2 + + +struct condition_private { + mutex lock; + sem_id wait_sem; + const void* object; +}; + + +status_t +ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout) +{ + if (fVariable == NULL) + return fWaitStatus; + + condition_private* condition = (condition_private*)fVariable->fObject; + fWaitStatus = STATUS_WAITING; + + status_t status; + do { + status = acquire_sem_etc(condition->wait_sem, 1, flags, timeout); + } while (status == B_INTERRUPTED); + + mutex_lock(&condition->lock); + + // remove entry from variable, if not done yet + if (fVariable != NULL) { + fVariable->fEntries.Remove(this); + fVariable = NULL; + } + + mutex_unlock(&condition->lock); + + return status; +} + + +inline void +ConditionVariableEntry::AddToVariable(ConditionVariable* variable) +{ + fVariable = variable; + fWaitStatus = STATUS_ADDED; + fVariable->fEntries.Add(this); +} + + +// #pragma mark - + + +void +ConditionVariable::Init(const void* object, const char* objectType) +{ + fObjectType = objectType; + new(&fEntries) EntryList; + + condition_private* condition = new condition_private; + mutex_init(&condition->lock, objectType); + condition->wait_sem = create_sem(0, "condition variable wait"); + if (condition->wait_sem < B_OK) + panic("cannot create condition variable."); + + condition->object = object; + + fObject = condition; +} + + +void +ConditionVariable::Add(ConditionVariableEntry* entry) +{ + entry->AddToVariable(this); +} + + +void +ConditionVariable::_Notify(bool all, bool threadsLocked) +{ + condition_private* condition = (condition_private*)fObject; + mutex_lock(&condition->lock); + + uint32 count = 0; + + while (ConditionVariableEntry* entry = fEntries.RemoveHead()) { + entry->fVariable = NULL; + if (entry->fWaitStatus <= 0) + continue; + + entry->fWaitStatus = B_OK; + count++; + + if (!all) + break; + } + + release_sem_etc(condition->wait_sem, count, 0); + mutex_unlock(&condition->lock); +} diff --git a/src/tests/add-ons/kernel/kernelland_emu/lock.cpp b/src/tests/add-ons/kernel/kernelland_emu/lock.cpp new file mode 100644 index 0000000000..0d1a4c9741 --- /dev/null +++ b/src/tests/add-ons/kernel/kernelland_emu/lock.cpp @@ -0,0 +1,287 @@ +/* + * Copyright 2002-2009, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * Ingo Weinhold, bonefish@cs.tu-berlin.de. + * Axel Dörfler, axeld@pinc-software.de. + */ + +#include + + +#define RW_MAX_READERS 10000 + + +int32 +recursive_lock_get_recursion(recursive_lock *lock) +{ + thread_id thread = find_thread(NULL); + +#if !KDEBUG + if (lock->holder == thread) + return lock->recursion; +#else + if (lock->lock.holder == thread) + return lock->recursion; +#endif + + return -1; +} + + +void +recursive_lock_init_etc(recursive_lock *lock, const char *name, uint32 flags) +{ + if (lock == NULL) + return; + + if (name == NULL) + name = "recursive lock"; + +#if !KDEBUG + lock->holder = -1; +#else + lock->lock.holder = -1; +#endif + lock->recursion = 0; + lock->lock.waiters = (mutex_waiter*)create_sem(1, name); + + if ((sem_id)lock->lock.waiters < B_OK) + panic("recursive lock creation failed: %s\n", name); +} + + +void +recursive_lock_init(recursive_lock *lock, const char *name) +{ + recursive_lock_init_etc(lock, name, 0); +} + + +void +recursive_lock_destroy(recursive_lock *lock) +{ + if (lock == NULL) + return; + + delete_sem((sem_id)lock->lock.waiters); + lock->lock.waiters = (mutex_waiter*)-1; +} + + +status_t +recursive_lock_lock(recursive_lock *lock) +{ + thread_id thread = find_thread(NULL); + +#if !KDEBUG + if (thread != lock->holder) { + status_t status; + do { + status = acquire_sem((sem_id)lock->lock.waiters); + } while (status == B_INTERRUPTED); + if (status < B_OK) + return status; + + lock->holder = thread; + } +#else + if (thread != lock->lock.holder) { + status_t status; + do { + status = acquire_sem((sem_id)lock->lock.waiters); + } while (status == B_INTERRUPTED); + if (status < B_OK) + return status; + + lock->lock.holder = thread; + } +#endif + lock->recursion++; + return B_OK; +} + + +void +recursive_lock_unlock(recursive_lock *lock) +{ +#if !KDEBUG + if (find_thread(NULL) != lock->holder) + panic("recursive_lock %p unlocked by non-holder thread!\n", lock); +#else + if (find_thread(NULL) != lock->lock.holder) + panic("recursive_lock %p unlocked by non-holder thread!\n", lock); +#endif + + if (--lock->recursion == 0) { +#if !KDEBUG + lock->holder = -1; +#else + lock->lock.holder = -1; +#endif + release_sem_etc((sem_id)lock->lock.waiters, 1, 0); + } +} + + +// #pragma mark - + + +void +mutex_init(mutex *m, const char *name) +{ + if (m == NULL) + return; + + if (name == NULL) + name = "mutex_sem"; + + // We need to store the semaphore in "waiters", as it is no sem anymore + // Also, kernel mutex creation cannot fail anymore, but we could... + m->waiters = (struct mutex_waiter *)create_sem(1, name); + if ((sem_id)m->waiters < B_OK) + debugger("semaphore creation failed"); +} + + +void +mutex_init_etc(mutex *m, const char *name, uint32 flags) +{ + if (m == NULL) + return; + + if (name == NULL) + name = "mutex_sem"; + + m->waiters = (struct mutex_waiter *)create_sem(1, name); + if ((sem_id)m->waiters < B_OK) + debugger("semaphore creation failed"); +} + + +void +mutex_destroy(mutex *mutex) +{ + if (mutex == NULL) + return; + + if ((sem_id)mutex->waiters >= 0) { + delete_sem((sem_id)mutex->waiters); + mutex->waiters = (struct mutex_waiter *)-1; + } +} + + +status_t +_mutex_trylock(mutex *mutex) +{ + status_t status; + do { + status = acquire_sem_etc((sem_id)mutex->waiters, 1, B_RELATIVE_TIMEOUT, + 0); + } while (status == B_INTERRUPTED); + return status; +} + + +status_t +_mutex_lock(mutex *mutex, bool threadsLocked) +{ + if (mutex->waiters == NULL) { + // MUTEX_INITIALIZER has been used; this is not thread-safe! + mutex_init(mutex, mutex->name); + } + + status_t status; + do { + status = acquire_sem((sem_id)mutex->waiters); + } while (status == B_INTERRUPTED); + +#if KDEBUG + if (status == B_OK) + mutex->holder = find_thread(NULL); +#endif + return status; +} + + +void +_mutex_unlock(mutex *mutex, bool threadsLocked) +{ +#if KDEBUG + mutex->holder = -1; +#endif + release_sem((sem_id)mutex->waiters); +} + + +// #pragma mark - + + +void +rw_lock_init_etc(rw_lock *lock, const char *name, uint32 flags) +{ + if (lock == NULL) + return; + + if (name == NULL) + name = "r/w lock"; + + lock->waiters = (rw_lock_waiter*)create_sem(RW_MAX_READERS, name); + if ((sem_id)lock->waiters < B_OK) + panic("r/w lock \"%s\" creation failed.", name); +} + + +void +rw_lock_init(rw_lock *lock, const char *name) +{ + rw_lock_init_etc(lock, name, 0); +} + + +void +rw_lock_destroy(rw_lock *lock) +{ + if (lock == NULL) + return; + + delete_sem((sem_id)lock->waiters); +} + + +status_t +rw_lock_read_lock(rw_lock *lock) +{ + status_t status; + do { + status = acquire_sem((sem_id)lock->waiters); + } while (status == B_INTERRUPTED); + return status; +} + + +status_t +rw_lock_read_unlock(rw_lock *lock) +{ + return release_sem((sem_id)lock->waiters); +} + + +status_t +rw_lock_write_lock(rw_lock *lock) +{ + status_t status; + do { + status = acquire_sem_etc((sem_id)lock->waiters, RW_MAX_READERS, 0, 0); + } while (status == B_INTERRUPTED); + return status; +} + + +status_t +rw_lock_write_unlock(rw_lock *lock) +{ + return release_sem_etc((sem_id)lock->waiters, RW_MAX_READERS, 0); +} diff --git a/src/tests/add-ons/kernel/kernelland_emu/misc.cpp b/src/tests/add-ons/kernel/kernelland_emu/misc.cpp new file mode 100644 index 0000000000..903f7f1c24 --- /dev/null +++ b/src/tests/add-ons/kernel/kernelland_emu/misc.cpp @@ -0,0 +1,346 @@ +/* + * Copyright 2002-2008, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * Ingo Weinhold, bonefish@cs.tu-berlin.de. + * Axel Dörfler, axeld@pinc-software.de. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + +bool gDebugOutputEnabled = true; + + +thread_id +spawn_kernel_thread(thread_func func, const char *name, int32 priority, + void *data) +{ + return spawn_thread(func, name, priority, data); +} + + +extern "C" status_t +devfs_unpublish_partition(const char *path) +{ + printf("unpublish partition: %s\n", path); + return B_OK; +} + + +extern "C" status_t +devfs_publish_partition(const char *path, const partition_info *info) +{ + if (info == NULL) + return B_BAD_VALUE; + + printf("publish partition: %s (device \"%s\", size %Ld)\n", path, info->device, info->size); + return B_OK; +} + + +extern "C" int32 +atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst) +{ +#if __INTEL__ + int32 oldValue; + asm volatile("lock; cmpxchg %%ecx, (%%edx)" + : "=a" (oldValue) : "a" (testAgainst), "c" (newValue), "d" (value)); + return oldValue; +#else +#warn "atomic_test_and_set() won't work correctly!" + int32 oldValue = *value; + if (oldValue == testAgainst) + *value = newValue; + + return oldValue; +#endif +} + + +extern "C" int +send_signal_etc(pid_t thread, uint signal, uint32 flags) +{ + return send_signal(thread, signal); +} + + +extern "C" int32 +low_resource_state(uint32 resources) +{ + return B_NO_LOW_RESOURCE; +} + + +extern "C" void +low_resource(uint32 resource, uint64 requirements, uint32 flags, + uint32 timeout) +{ +} + + +extern "C" status_t +register_low_resource_handler(low_resource_func function, void *data, + uint32 resources, int32 priority) +{ + return B_OK; +} + + +extern "C" status_t +unregister_low_resource_handler(low_resource_func function, void *data) +{ + return B_OK; +} + + +extern "C" void +panic(const char *format, ...) +{ + va_list args; + + puts("*** PANIC ***"); + va_start(args, format); + vprintf(format, args); + va_end(args); + + putchar('\n'); + debugger("Kernel Panic"); +} + + +extern "C" void +dprintf(const char *format,...) +{ + if (!gDebugOutputEnabled) + return; + + va_list args; + va_start(args, format); + printf("\33[34m"); + vprintf(format, args); + printf("\33[0m"); + fflush(stdout); + va_end(args); +} + + +extern "C" void +kprintf(const char *format,...) +{ + va_list args; + va_start(args, format); + printf("\33[35m"); + vprintf(format, args); + printf("\33[0m"); + fflush(stdout); + va_end(args); +} + + +extern "C" void +dump_block(const char *buffer, int size, const char *prefix) +{ + const int DUMPED_BLOCK_SIZE = 16; + int i; + + for (i = 0; i < size;) { + int start = i; + + dprintf(prefix); + for (; i < start + DUMPED_BLOCK_SIZE; i++) { + if (!(i % 4)) + dprintf(" "); + + if (i >= size) + dprintf(" "); + else + dprintf("%02x", *(unsigned char *)(buffer + i)); + } + dprintf(" "); + + for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) { + if (i < size) { + char c = buffer[i]; + + if (c < 30) + dprintf("."); + else + dprintf("%c", c); + } else + break; + } + dprintf("\n"); + } +} + + +extern "C" status_t +user_memcpy(void *to, const void *from, size_t size) +{ + char *tmp = (char *)to; + char *s = (char *)from; + + while (size--) + *tmp++ = *s++; + + return 0; +} + + +extern "C" int +user_strcpy(char *to, const char *from) +{ + while ((*to++ = *from++) != '\0') + ; + return 0; +} + + +/*! \brief Copies at most (\a size - 1) characters from the string in \a from to + the string in \a to, NULL-terminating the result. + + \param to Pointer to the destination C-string. + \param from Pointer to the source C-string. + \param size Size in bytes of the string buffer pointed to by \a to. + + \return strlen(\a from). +*/ +extern "C" ssize_t +user_strlcpy(char *to, const char *from, size_t size) +{ + int from_length = 0; + + if (size > 0) { + to[--size] = '\0'; + // copy + for ( ; size; size--, from_length++, to++, from++) { + if ((*to = *from) == '\0') + break; + } + } + // count any leftover from chars + while (*from++ != '\0') + from_length++; + + return from_length; +} + + +// #pragma mark - Debugger + + +extern "C" uint64 +parse_expression(const char* arg) +{ + return strtoull(arg, NULL, 0); +} + + +extern "C" bool +set_debug_variable(const char* variableName, uint64 value) +{ + return true; +} + + +extern "C" bool +print_debugger_command_usage(const char* command) +{ + return true; +} + + +extern "C" status_t +add_debugger_command_etc(const char* name, debugger_command_hook func, + const char* description, const char* usage, uint32 flags) +{ + return B_OK; +} + + +extern "C" int +add_debugger_command(const char *name, int (*func)(int, char **), + const char *desc) +{ + return B_OK; +} + + +extern "C" int +remove_debugger_command(const char * name, int (*func)(int, char **)) +{ + return B_OK; +} + + +// #pragma mark - Slab allocator + + +extern "C" void * +object_cache_alloc(object_cache *cache, uint32 flags) +{ + return malloc((size_t)cache); +} + + +extern "C" void +object_cache_free(object_cache *cache, void *object) +{ + free(object); +} + + +extern "C" 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 (object_cache*)objectSize; +} + + +extern "C" object_cache * +create_object_cache(const char *name, size_t objectSize, + size_t alignment, void *cookie, object_cache_constructor constructor, + object_cache_destructor) +{ + return (object_cache*)objectSize; +} + + +extern "C" void +delete_object_cache(object_cache *cache) +{ +} + + +extern "C" void +object_cache_get_usage(object_cache *cache, size_t *_allocatedMemory) +{ + *_allocatedMemory = 100; +} + + +// #pragma mark - Thread/scheduler functions + + +struct scheduler_ops kScheduler = { + NULL, + NULL, + NULL, + NULL, +}; +struct scheduler_ops* gScheduler = &kScheduler; diff --git a/src/tests/add-ons/kernel/kernelland_emu.cpp b/src/tests/add-ons/kernel/kernelland_emu/module.cpp similarity index 56% rename from src/tests/add-ons/kernel/kernelland_emu.cpp rename to src/tests/add-ons/kernel/kernelland_emu/module.cpp index 322c1bf9c9..7ccca8726f 100644 --- a/src/tests/add-ons/kernel/kernelland_emu.cpp +++ b/src/tests/add-ons/kernel/kernelland_emu/module.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008, Haiku Inc. All Rights Reserved. + * Copyright 2002-2009, Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT license. * * Authors: @@ -8,7 +8,6 @@ */ #include -#include #include #include @@ -23,31 +22,18 @@ #include #include -#ifdef ASSERT -# undef ASSERT -#endif - -#include -#include -#include -#include -#include -#include - #ifdef TRACE # undef TRACE #endif #define TRACE(x) //#define TRACE(x) printf x -#define RW_MAX_READERS 10000 static const char *gModuleDirs[] = { "distro/x86.R1/beos/system/add-ons/userland", NULL }; -bool gDebugOutputEnabled = true; struct module_name_list { set names; @@ -552,7 +538,7 @@ ModuleManager::CloseModuleList(module_name_list *list) } -status_t +status_t ModuleManager::AddBuiltInModule(module_info *info) { BAutolock _lock(fModules); @@ -811,707 +797,3 @@ close_module_list(void *cookie) return ModuleManager::Default()->CloseModuleList( (module_name_list*)cookie); } - - -thread_id -spawn_kernel_thread(thread_func func, const char *name, int32 priority, - void *data) -{ - return spawn_thread(func, name, priority, data); -} - - -extern "C" status_t -devfs_unpublish_partition(const char *path) -{ - printf("unpublish partition: %s\n", path); - return B_OK; -} - - -extern "C" status_t -devfs_publish_partition(const char *path, const partition_info *info) -{ - if (info == NULL) - return B_BAD_VALUE; - - printf("publish partition: %s (device \"%s\", size %Ld)\n", path, info->device, info->size); - return B_OK; -} - - -extern "C" int32 -atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst) -{ -#if __INTEL__ - int32 oldValue; - asm volatile("lock; cmpxchg %%ecx, (%%edx)" - : "=a" (oldValue) : "a" (testAgainst), "c" (newValue), "d" (value)); - return oldValue; -#else -#warn "atomic_test_and_set() won't work correctly!" - int32 oldValue = *value; - if (oldValue == testAgainst) - *value = newValue; - - return oldValue; -#endif -} - - -extern "C" int -send_signal_etc(pid_t thread, uint signal, uint32 flags) -{ - return send_signal(thread, signal); -} - - -extern "C" int32 -low_resource_state(uint32 resources) -{ - return B_NO_LOW_RESOURCE; -} - - -extern "C" void -low_resource(uint32 resource, uint64 requirements, uint32 flags, - uint32 timeout) -{ -} - - -extern "C" status_t -register_low_resource_handler(low_resource_func function, void *data, - uint32 resources, int32 priority) -{ - return B_OK; -} - - -extern "C" status_t -unregister_low_resource_handler(low_resource_func function, void *data) -{ - return B_OK; -} - - -extern "C" void -panic(const char *format, ...) -{ - va_list args; - - puts("*** PANIC ***"); - va_start(args, format); - vprintf(format, args); - va_end(args); - - putchar('\n'); - debugger("Kernel Panic"); -} - - -extern "C" void -dprintf(const char *format,...) -{ - if (!gDebugOutputEnabled) - return; - - va_list args; - va_start(args, format); - printf("\33[34m"); - vprintf(format, args); - printf("\33[0m"); - fflush(stdout); - va_end(args); -} - - -extern "C" void -kprintf(const char *format,...) -{ - va_list args; - va_start(args, format); - printf("\33[35m"); - vprintf(format, args); - printf("\33[0m"); - fflush(stdout); - va_end(args); -} - - -extern "C" void -dump_block(const char *buffer, int size, const char *prefix) -{ - const int DUMPED_BLOCK_SIZE = 16; - int i; - - for (i = 0; i < size;) { - int start = i; - - dprintf(prefix); - for (; i < start + DUMPED_BLOCK_SIZE; i++) { - if (!(i % 4)) - dprintf(" "); - - if (i >= size) - dprintf(" "); - else - dprintf("%02x", *(unsigned char *)(buffer + i)); - } - dprintf(" "); - - for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) { - if (i < size) { - char c = buffer[i]; - - if (c < 30) - dprintf("."); - else - dprintf("%c", c); - } else - break; - } - dprintf("\n"); - } -} - - -extern "C" status_t -user_memcpy(void *to, const void *from, size_t size) -{ - char *tmp = (char *)to; - char *s = (char *)from; - - while (size--) - *tmp++ = *s++; - - return 0; -} - - -extern "C" int -user_strcpy(char *to, const char *from) -{ - while ((*to++ = *from++) != '\0') - ; - return 0; -} - - -/*! \brief Copies at most (\a size - 1) characters from the string in \a from to - the string in \a to, NULL-terminating the result. - - \param to Pointer to the destination C-string. - \param from Pointer to the source C-string. - \param size Size in bytes of the string buffer pointed to by \a to. - - \return strlen(\a from). -*/ -extern "C" ssize_t -user_strlcpy(char *to, const char *from, size_t size) -{ - int from_length = 0; - - if (size > 0) { - to[--size] = '\0'; - // copy - for ( ; size; size--, from_length++, to++, from++) { - if ((*to = *from) == '\0') - break; - } - } - // count any leftover from chars - while (*from++ != '\0') - from_length++; - - return from_length; -} - - -// #pragma mark - Debugger - - -extern "C" uint64 -parse_expression(const char* arg) -{ - return strtoull(arg, NULL, 0); -} - - -extern "C" bool -set_debug_variable(const char* variableName, uint64 value) -{ - return true; -} - - -extern "C" bool -print_debugger_command_usage(const char* command) -{ - return true; -} - - -extern "C" status_t -add_debugger_command_etc(const char* name, debugger_command_hook func, - const char* description, const char* usage, uint32 flags) -{ - return B_OK; -} - - -extern "C" int -add_debugger_command(char *name, int (*func)(int, char **), char *desc) -{ - return B_OK; -} - - -extern "C" int -remove_debugger_command(char * name, int (*func)(int, char **)) -{ - return B_OK; -} - - -// #pragma mark - Slab allocator - - -extern "C" void * -object_cache_alloc(object_cache *cache, uint32 flags) -{ - return malloc((size_t)cache); -} - - -extern "C" void -object_cache_free(object_cache *cache, void *object) -{ - free(object); -} - - -extern "C" 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 (object_cache*)objectSize; -} - - -extern "C" object_cache * -create_object_cache(const char *name, size_t objectSize, - size_t alignment, void *cookie, object_cache_constructor constructor, - object_cache_destructor) -{ - return (object_cache*)objectSize; -} - - -extern "C" void -delete_object_cache(object_cache *cache) -{ -} - - -extern "C" void -object_cache_get_usage(object_cache *cache, size_t *_allocatedMemory) -{ - *_allocatedMemory = 100; -} - - -// #pragma mark - Thread/scheduler functions - - -struct scheduler_ops kScheduler = { - NULL, - NULL, - NULL, - NULL, -}; -struct scheduler_ops* gScheduler = &kScheduler; - - -// #pragma mark - Private locking functions - - -int32 -recursive_lock_get_recursion(recursive_lock *lock) -{ - thread_id thread = find_thread(NULL); - -#if !KDEBUG - if (lock->holder == thread) - return lock->recursion; -#else - if (lock->lock.holder == thread) - return lock->recursion; -#endif - - return -1; -} - - -void -recursive_lock_init_etc(recursive_lock *lock, const char *name, uint32 flags) -{ - if (lock == NULL) - return; - - if (name == NULL) - name = "recursive lock"; - -#if !KDEBUG - lock->holder = -1; -#else - lock->lock.holder = -1; -#endif - lock->recursion = 0; - lock->lock.waiters = (mutex_waiter*)create_sem(1, name); - - if ((sem_id)lock->lock.waiters < B_OK) - panic("recursive lock creation failed: %s\n", name); -} - - -void -recursive_lock_init(recursive_lock *lock, const char *name) -{ - recursive_lock_init_etc(lock, name, 0); -} - - -void -recursive_lock_destroy(recursive_lock *lock) -{ - if (lock == NULL) - return; - - delete_sem((sem_id)lock->lock.waiters); - lock->lock.waiters = (mutex_waiter*)-1; -} - - -status_t -recursive_lock_lock(recursive_lock *lock) -{ - thread_id thread = find_thread(NULL); - -#if !KDEBUG - if (thread != lock->holder) { - status_t status; - do { - status = acquire_sem((sem_id)lock->lock.waiters); - } while (status == B_INTERRUPTED); - if (status < B_OK) - return status; - - lock->holder = thread; - } -#else - if (thread != lock->lock.holder) { - status_t status; - do { - status = acquire_sem((sem_id)lock->lock.waiters); - } while (status == B_INTERRUPTED); - if (status < B_OK) - return status; - - lock->lock.holder = thread; - } -#endif - lock->recursion++; - return B_OK; -} - - -void -recursive_lock_unlock(recursive_lock *lock) -{ -#if !KDEBUG - if (find_thread(NULL) != lock->holder) - panic("recursive_lock %p unlocked by non-holder thread!\n", lock); -#else - if (find_thread(NULL) != lock->lock.holder) - panic("recursive_lock %p unlocked by non-holder thread!\n", lock); -#endif - - if (--lock->recursion == 0) { -#if !KDEBUG - lock->holder = -1; -#else - lock->lock.holder = -1; -#endif - release_sem_etc((sem_id)lock->lock.waiters, 1, 0); - } -} - - -// #pragma mark - - - -void -mutex_init(mutex *m, const char *name) -{ - if (m == NULL) - return; - - if (name == NULL) - name = "mutex_sem"; - - // We need to store the semaphore in "waiters", as it is no sem anymore - // Also, kernel mutex creation cannot fail anymore, but we could... - m->waiters = (struct mutex_waiter *)create_sem(1, name); - if ((sem_id)m->waiters < B_OK) - debugger("semaphore creation failed"); -} - - -void -mutex_init_etc(mutex *m, const char *name, uint32 flags) -{ - if (m == NULL) - return; - - if (name == NULL) - name = "mutex_sem"; - - m->waiters = (struct mutex_waiter *)create_sem(1, name); - if ((sem_id)m->waiters < B_OK) - debugger("semaphore creation failed"); -} - - -void -mutex_destroy(mutex *mutex) -{ - if (mutex == NULL) - return; - - if ((sem_id)mutex->waiters >= 0) { - delete_sem((sem_id)mutex->waiters); - mutex->waiters = (struct mutex_waiter *)-1; - } -} - - -status_t -_mutex_trylock(mutex *mutex) -{ - status_t status; - do { - status = acquire_sem_etc((sem_id)mutex->waiters, 1, B_RELATIVE_TIMEOUT, - 0); - } while (status == B_INTERRUPTED); - return status; -} - - -status_t -_mutex_lock(mutex *mutex, bool threadsLocked) -{ - if (mutex->waiters == NULL) { - // MUTEX_INITIALIZER has been used; this is not thread-safe! - mutex_init(mutex, mutex->name); - } - - status_t status; - do { - status = acquire_sem((sem_id)mutex->waiters); - } while (status == B_INTERRUPTED); - -#if KDEBUG - if (status == B_OK) - mutex->holder = find_thread(NULL); -#endif - return status; -} - - -void -_mutex_unlock(mutex *mutex, bool threadsLocked) -{ -#if KDEBUG - mutex->holder = -1; -#endif - release_sem((sem_id)mutex->waiters); -} - - -// #pragma mark - - - -void -rw_lock_init_etc(rw_lock *lock, const char *name, uint32 flags) -{ - if (lock == NULL) - return; - - if (name == NULL) - name = "r/w lock"; - - lock->waiters = (rw_lock_waiter*)create_sem(RW_MAX_READERS, name); - if ((sem_id)lock->waiters < B_OK) - panic("r/w lock \"%s\" creation failed.", name); -} - - -void -rw_lock_init(rw_lock *lock, const char *name) -{ - rw_lock_init_etc(lock, name, 0); -} - - -void -rw_lock_destroy(rw_lock *lock) -{ - if (lock == NULL) - return; - - delete_sem((sem_id)lock->waiters); -} - - -status_t -rw_lock_read_lock(rw_lock *lock) -{ - status_t status; - do { - status = acquire_sem((sem_id)lock->waiters); - } while (status == B_INTERRUPTED); - return status; -} - - -status_t -rw_lock_read_unlock(rw_lock *lock) -{ - return release_sem((sem_id)lock->waiters); -} - - -status_t -rw_lock_write_lock(rw_lock *lock) -{ - status_t status; - do { - status = acquire_sem_etc((sem_id)lock->waiters, RW_MAX_READERS, 0, 0); - } while (status == B_INTERRUPTED); - return status; -} - - -status_t -rw_lock_write_unlock(rw_lock *lock) -{ - return release_sem_etc((sem_id)lock->waiters, RW_MAX_READERS, 0); -} - - -// #pragma mark - Condition variables (anonymous only) - - -#define STATUS_ADDED 1 -#define STATUS_WAITING 2 - - -struct condition_private { - mutex lock; - sem_id wait_sem; - const void* object; -}; - - -status_t -ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout) -{ - if (fVariable == NULL) - return fWaitStatus; - - condition_private* condition = (condition_private*)fVariable->fObject; - fWaitStatus = STATUS_WAITING; - - status_t status; - do { - status = acquire_sem_etc(condition->wait_sem, 1, flags, timeout); - } while (status == B_INTERRUPTED); - - mutex_lock(&condition->lock); - - // remove entry from variable, if not done yet - if (fVariable != NULL) { - fVariable->fEntries.Remove(this); - fVariable = NULL; - } - - mutex_unlock(&condition->lock); - - return status; -} - - -inline void -ConditionVariableEntry::AddToVariable(ConditionVariable* variable) -{ - fVariable = variable; - fWaitStatus = STATUS_ADDED; - fVariable->fEntries.Add(this); -} - - -// #pragma mark - - - -void -ConditionVariable::Init(const void* object, const char* objectType) -{ - fObjectType = objectType; - new(&fEntries) EntryList; - - condition_private* condition = new condition_private; - mutex_init(&condition->lock, objectType); - condition->wait_sem = create_sem(0, "condition variable wait"); - if (condition->wait_sem < B_OK) - panic("cannot create condition variable."); - - condition->object = object; - - fObject = condition; -} - - -void -ConditionVariable::Add(ConditionVariableEntry* entry) -{ - entry->AddToVariable(this); -} - - -void -ConditionVariable::_Notify(bool all, bool threadsLocked) -{ - condition_private* condition = (condition_private*)fObject; - mutex_lock(&condition->lock); - - uint32 count = 0; - - while (ConditionVariableEntry* entry = fEntries.RemoveHead()) { - entry->fVariable = NULL; - if (entry->fWaitStatus <= 0) - continue; - - entry->fWaitStatus = B_OK; - count++; - - if (!all) - break; - } - - release_sem_etc(condition->wait_sem, count, 0); - mutex_unlock(&condition->lock); -} -