diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/Additions/haiku/SharedFolders/lock.h | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/src/VBox/Additions/haiku/SharedFolders/lock.h b/src/VBox/Additions/haiku/SharedFolders/lock.h new file mode 100644 index 00000000..4bca6a3f --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/lock.h @@ -0,0 +1,315 @@ +/* $Id: lock.h $ */ +/** @file + * Lock.h - Haiku, private locking internals. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * + * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_lock_h +#define GA_INCLUDED_SRC_haiku_SharedFolders_lock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <OS.h> + + +struct mutex_waiter; + +typedef struct mutex { + const char* name; + struct mutex_waiter* waiters; +#if KDEBUG + thread_id holder; +#else + int32 count; + uint16 ignore_unlock_count; +#endif + uint8 flags; +} mutex; + +#define MUTEX_FLAG_CLONE_NAME 0x1 + + +typedef struct recursive_lock { + mutex lock; +#if !KDEBUG + thread_id holder; +#endif + int recursion; +} recursive_lock; + + +struct rw_lock_waiter; + +typedef struct rw_lock { + const char* name; + struct rw_lock_waiter* waiters; + thread_id holder; + vint32 count; + int32 owner_count; + int16 active_readers; + // Only > 0 while a writer is waiting: number + // of active readers when the first waiting + // writer started waiting. + int16 pending_readers; + // Number of readers that have already + // incremented "count", but have not yet started + // to wait at the time the last writer unlocked. + uint32 flags; +} rw_lock; + +#define RW_LOCK_WRITER_COUNT_BASE 0x10000 + +#define RW_LOCK_FLAG_CLONE_NAME 0x1 + + +#if KDEBUG +# define KDEBUG_RW_LOCK_DEBUG 0 + // Define to 1 if you want to use ASSERT_READ_LOCKED_RW_LOCK(). + // The rw_lock will just behave like a recursive locker then. +# define ASSERT_LOCKED_RECURSIVE(r) \ + { ASSERT(find_thread(NULL) == (r)->lock.holder); } +# define ASSERT_LOCKED_MUTEX(m) { ASSERT(find_thread(NULL) == (m)->holder); } +# define ASSERT_WRITE_LOCKED_RW_LOCK(l) \ + { ASSERT(find_thread(NULL) == (l)->holder); } +# if KDEBUG_RW_LOCK_DEBUG +# define ASSERT_READ_LOCKED_RW_LOCK(l) \ + { ASSERT(find_thread(NULL) == (l)->holder); } +# else +# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false) +# endif +#else +# 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) +#endif + + +// static initializers +#if KDEBUG +# define MUTEX_INITIALIZER(name) { name, NULL, -1, 0 } +# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), 0 } +#else +# define MUTEX_INITIALIZER(name) { name, NULL, 0, 0, 0 } +# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), -1, 0 } +#endif + +#define RW_LOCK_INITIALIZER(name) { name, NULL, -1, 0, 0, 0 } + + +#if KDEBUG +# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->lock.holder) +#else +# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->holder) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +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 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_write_lock(rw_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". +extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to); + // Like mutex_switch_lock(), just for a switching from a read-locked + // rw_lock. + + +// implementation private: + +extern status_t _rw_lock_read_lock(rw_lock* lock); +extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock, + uint32 timeoutFlags, bigtime_t timeout); +extern void _rw_lock_read_unlock(rw_lock* lock, bool threadsLocked); +extern void _rw_lock_write_unlock(rw_lock* lock, bool threadsLocked); + +extern status_t _mutex_lock(mutex* lock, bool threadsLocked); +extern void _mutex_unlock(mutex* lock, bool threadsLocked); +extern status_t _mutex_trylock(mutex* lock); +extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, + bigtime_t timeout); + + +static inline status_t +rw_lock_read_lock(rw_lock* lock) +{ +#if KDEBUG_RW_LOCK_DEBUG + return rw_lock_write_lock(lock); +#else + int32 oldCount = atomic_add(&lock->count, 1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + return _rw_lock_read_lock(lock); + return B_OK; +#endif +} + + +static inline status_t +rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags, + bigtime_t timeout) +{ +#if KDEBUG_RW_LOCK_DEBUG + return mutex_lock_with_timeout(lock, timeoutFlags, timeout); +#else + int32 oldCount = atomic_add(&lock->count, 1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + return _rw_lock_read_lock_with_timeout(lock, timeoutFlags, timeout); + return B_OK; +#endif +} + + +static inline void +rw_lock_read_unlock(rw_lock* lock) +{ +#if KDEBUG_RW_LOCK_DEBUG + rw_lock_write_unlock(lock); +#else + int32 oldCount = atomic_add(&lock->count, -1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + _rw_lock_read_unlock(lock, false); +#endif +} + + +static inline void +rw_lock_write_unlock(rw_lock* lock) +{ + _rw_lock_write_unlock(lock, false); +} + + +static inline status_t +mutex_lock(mutex* lock) +{ +#if KDEBUG + return _mutex_lock(lock, false); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock(lock, false); + return B_OK; +#endif +} + + +static inline status_t +mutex_lock_threads_locked(mutex* lock) +{ +#if KDEBUG + return _mutex_lock(lock, true); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock(lock, true); + return B_OK; +#endif +} + + +static inline status_t +mutex_trylock(mutex* lock) +{ +#if KDEBUG + return _mutex_trylock(lock); +#else + if (atomic_test_and_set(&lock->count, -1, 0) != 0) + return B_WOULD_BLOCK; + return B_OK; +#endif +} + + +static inline status_t +mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout) +{ +#if KDEBUG + return _mutex_lock_with_timeout(lock, timeoutFlags, timeout); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock_with_timeout(lock, timeoutFlags, timeout); + return B_OK; +#endif +} + + +static inline void +mutex_unlock(mutex* lock) +{ +#if !KDEBUG + if (atomic_add(&lock->count, 1) < -1) +#endif + _mutex_unlock(lock, false); +} + + +static inline void +mutex_transfer_lock(mutex* lock, thread_id thread) +{ +#if KDEBUG + lock->holder = thread; +#endif +} + + +extern void lock_debug_init(); + +#ifdef __cplusplus +} +#endif + +#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_lock_h */ |