diff options
author | Tom <tomut@yahoo.com> | 2020-06-05 22:01:30 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-01 12:07:01 +0200 |
commit | 3ac6d31b453edc9a4e3b54e5a5bd2e7c9dae3eca (patch) | |
tree | 74ce370f2f433841fc20a1d1c114a1491b90927a /Kernel | |
parent | 1da7fea602f99a10efa65152d5e9921014c3d328 (diff) | |
download | serenity-3ac6d31b453edc9a4e3b54e5a5bd2e7c9dae3eca.zip |
Kernel: Serialize debug output
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Forward.h | 2 | ||||
-rw-r--r-- | Kernel/Heap/SlabAllocator.cpp | 26 | ||||
-rw-r--r-- | Kernel/Heap/kmalloc.cpp | 26 | ||||
-rw-r--r-- | Kernel/SpinLock.h | 136 | ||||
-rw-r--r-- | Kernel/kprintf.cpp | 7 |
5 files changed, 177 insertions, 20 deletions
diff --git a/Kernel/Forward.h b/Kernel/Forward.h index 4b89adb116..5644a37388 100644 --- a/Kernel/Forward.h +++ b/Kernel/Forward.h @@ -58,6 +58,8 @@ class Region; class Scheduler; class SharedBuffer; class Socket; +template <typename BaseType> class SpinLock; +template <typename BaseType, typename LockType> class ScopedSpinLock; class TCPSocket; class TTY; class Thread; diff --git a/Kernel/Heap/SlabAllocator.cpp b/Kernel/Heap/SlabAllocator.cpp index 2910e0a56c..c27b86857e 100644 --- a/Kernel/Heap/SlabAllocator.cpp +++ b/Kernel/Heap/SlabAllocator.cpp @@ -28,6 +28,7 @@ #include <AK/Memory.h> #include <Kernel/Heap/SlabAllocator.h> #include <Kernel/Heap/kmalloc.h> +#include <Kernel/SpinLock.h> #include <Kernel/VM/Region.h> #define SANITIZE_SLABS @@ -50,22 +51,22 @@ public: } slabs[0].next = nullptr; m_freelist = &slabs[slab_count - 1]; - m_num_allocated = 0; - m_num_free = slab_count; + m_num_allocated.store(0, AK::MemoryOrder::memory_order_release); + m_num_free.store(slab_count, AK::MemoryOrder::memory_order_release); } constexpr size_t slab_size() const { return templated_slab_size; } void* alloc() { - InterruptDisabler disabler; + ScopedSpinLock lock(m_lock); if (!m_freelist) return kmalloc(slab_size()); ASSERT(m_freelist); void* ptr = m_freelist; m_freelist = m_freelist->next; - ++m_num_allocated; - --m_num_free; + m_num_allocated.fetch_add(1, AK::MemoryOrder::memory_order_acq_rel); + m_num_free.fetch_sub(1, AK::MemoryOrder::memory_order_acq_rel); #ifdef SANITIZE_SLABS memset(ptr, SLAB_ALLOC_SCRUB_BYTE, slab_size()); #endif @@ -74,7 +75,7 @@ public: void dealloc(void* ptr) { - InterruptDisabler disabler; + ScopedSpinLock lock(m_lock); ASSERT(ptr); if (ptr < m_base || ptr >= m_end) { kfree(ptr); @@ -86,12 +87,12 @@ public: memset(((FreeSlab*)ptr)->padding, SLAB_DEALLOC_SCRUB_BYTE, sizeof(FreeSlab::padding)); #endif m_freelist = (FreeSlab*)ptr; - ++m_num_allocated; - --m_num_free; + m_num_allocated.fetch_sub(1, AK::MemoryOrder::memory_order_acq_rel); + m_num_free.fetch_add(1, AK::MemoryOrder::memory_order_acq_rel); } - size_t num_allocated() const { return m_num_allocated; } - size_t num_free() const { return m_num_free; } + size_t num_allocated() const { return m_num_allocated.load(AK::MemoryOrder::memory_order_consume); } + size_t num_free() const { return m_num_free.load(AK::MemoryOrder::memory_order_consume); } private: struct FreeSlab { @@ -101,10 +102,11 @@ private: // NOTE: These are not default-initialized to prevent an init-time constructor from overwriting them FreeSlab* m_freelist; - size_t m_num_allocated; - size_t m_num_free; + Atomic<size_t> m_num_allocated; + Atomic<size_t> m_num_free; void* m_base; void* m_end; + SpinLock<u32> m_lock; static_assert(sizeof(FreeSlab) == templated_slab_size); }; diff --git a/Kernel/Heap/kmalloc.cpp b/Kernel/Heap/kmalloc.cpp index 32a1562c04..083d5313a8 100644 --- a/Kernel/Heap/kmalloc.cpp +++ b/Kernel/Heap/kmalloc.cpp @@ -38,6 +38,7 @@ #include <Kernel/KSyms.h> #include <Kernel/Process.h> #include <Kernel/Scheduler.h> +#include <Kernel/SpinLock.h> #include <Kernel/StdLib.h> #define SANITIZE_KMALLOC @@ -66,10 +67,13 @@ bool g_dump_kmalloc_stacks; static u8* s_next_eternal_ptr; static u8* s_end_of_eternal_range; +static SpinLock s_lock; + void kmalloc_init() { memset(&alloc_map, 0, sizeof(alloc_map)); memset((void*)BASE_PHYSICAL, 0, POOL_SIZE); + s_lock.initialize(); g_kmalloc_bytes_eternal = 0; g_kmalloc_bytes_allocated = 0; @@ -81,6 +85,7 @@ void kmalloc_init() void* kmalloc_eternal(size_t size) { + ScopedSpinLock lock(s_lock); void* ptr = s_next_eternal_ptr; s_next_eternal_ptr += size; ASSERT(s_next_eternal_ptr < s_end_of_eternal_range); @@ -129,7 +134,7 @@ inline void* kmalloc_allocate(size_t first_chunk, size_t chunks_needed) void* kmalloc_impl(size_t size) { - Kernel::InterruptDisabler disabler; + ScopedSpinLock lock(s_lock); ++g_kmalloc_call_count; if (g_dump_kmalloc_stacks && Kernel::g_kernel_symbols_available) { @@ -168,12 +173,8 @@ void* kmalloc_impl(size_t size) return kmalloc_allocate(first_chunk.value(), chunks_needed); } -void kfree(void* ptr) +static inline void kfree_impl(void* ptr) { - if (!ptr) - return; - - Kernel::InterruptDisabler disabler; ++g_kfree_call_count; auto* a = (AllocationHeader*)((((u8*)ptr) - sizeof(AllocationHeader))); @@ -190,12 +191,21 @@ void kfree(void* ptr) #endif } +void kfree(void* ptr) +{ + if (!ptr) + return; + + ScopedSpinLock lock(s_lock); + kfree_impl(ptr); +} + void* krealloc(void* ptr, size_t new_size) { if (!ptr) return kmalloc(new_size); - Kernel::InterruptDisabler disabler; + ScopedSpinLock lock(s_lock); auto* a = (AllocationHeader*)((((u8*)ptr) - sizeof(AllocationHeader))); size_t old_size = a->allocation_size_in_chunks * CHUNK_SIZE; @@ -205,7 +215,7 @@ void* krealloc(void* ptr, size_t new_size) auto* new_ptr = kmalloc(new_size); memcpy(new_ptr, ptr, min(old_size, new_size)); - kfree(ptr); + kfree_impl(ptr); return new_ptr; } diff --git a/Kernel/SpinLock.h b/Kernel/SpinLock.h new file mode 100644 index 0000000000..fa2c5d9dfc --- /dev/null +++ b/Kernel/SpinLock.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <AK/Types.h> +#include <AK/Atomic.h> +#include <Kernel/Forward.h> +#include <Kernel/Arch/i386/CPU.h> + +namespace Kernel { + +template <typename BaseType = u32> +class SpinLock +{ + AK::Atomic<BaseType> m_lock{0}; + +public: + SpinLock() = default; + SpinLock(const SpinLock&) = delete; + SpinLock(SpinLock&&) = delete; + + ALWAYS_INLINE void lock() + { + BaseType expected; + do { + expected = 0; + } while (!m_lock.compare_exchange_strong(expected, 1, AK::memory_order_acq_rel)); + + } + + ALWAYS_INLINE void unlock() + { + ASSERT(is_locked()); + m_lock.store(0, AK::memory_order_release); + } + + ALWAYS_INLINE bool is_locked() const + { + return m_lock.load(AK::memory_order_consume) != 0; + } + + ALWAYS_INLINE void initialize() + { + m_lock.store(0, AK::memory_order_release); + } +}; + +template <typename BaseType = u32, typename LockType = SpinLock<BaseType>> +class ScopedSpinLock +{ + LockType* m_lock; + bool m_have_lock{false}; + bool m_flag{false}; + +public: + ScopedSpinLock() = delete; + + ScopedSpinLock(LockType& lock): + m_lock(&lock) + { + ASSERT(m_lock); + m_flag = cli_and_save_interrupt_flag(); + m_lock->lock(); + m_have_lock = true; + } + + ScopedSpinLock(ScopedSpinLock&& from): + m_lock(from.m_lock), + m_have_lock(from.m_have_lock), + m_flag(from.m_flag) + { + from.m_lock = nullptr; + from.m_have_lock = false; + from.m_flag = false; + } + + ScopedSpinLock(const ScopedSpinLock&) = delete; + + ~ScopedSpinLock() + { + if (m_lock && m_have_lock) { + m_lock->unlock(); + restore_interrupt_flag(m_flag); + } + } + + ALWAYS_INLINE void lock() + { + ASSERT(m_lock); + ASSERT(!m_have_lock); + m_flag = cli_and_save_interrupt_flag(); + m_lock->lock(); + m_have_lock = true; + } + + ALWAYS_INLINE void unlock() + { + ASSERT(m_lock); + ASSERT(m_have_lock); + m_lock->unlock(); + m_have_lock = false; + restore_interrupt_flag(m_flag); + m_flag = false; + } + + ALWAYS_INLINE bool have_lock() const + { + return m_have_lock; + } +}; + +} diff --git a/Kernel/kprintf.cpp b/Kernel/kprintf.cpp index 3a0a4a439a..ea386054f2 100644 --- a/Kernel/kprintf.cpp +++ b/Kernel/kprintf.cpp @@ -29,11 +29,13 @@ #include <Kernel/Console.h> #include <Kernel/IO.h> #include <Kernel/Process.h> +#include <Kernel/SpinLock.h> #include <Kernel/kstdio.h> #include <LibC/stdarg.h> static bool serial_debug; +static SpinLock s_log_lock; void set_serial_debug(bool on_or_off) { @@ -114,6 +116,7 @@ static void console_putch(char*&, char ch) int kprintf(const char* fmt, ...) { + ScopedSpinLock lock(s_log_lock); color_on(); va_list ap; va_start(ap, fmt); @@ -130,6 +133,7 @@ static void buffer_putch(char*& bufptr, char ch) int sprintf(char* buffer, const char* fmt, ...) { + ScopedSpinLock lock(s_log_lock); va_list ap; va_start(ap, fmt); int ret = printf_internal(buffer_putch, buffer, fmt, ap); @@ -154,6 +158,7 @@ extern "C" int dbgputstr(const char* characters, int length) { if (!characters) return 0; + ScopedSpinLock lock(s_log_lock); for (int i = 0; i < length; ++i) debugger_out(characters[i]); return 0; @@ -163,6 +168,7 @@ extern "C" int kernelputstr(const char* characters, int length) { if (!characters) return 0; + ScopedSpinLock lock(s_log_lock); for (int i = 0; i < length; ++i) console_out(characters[i]); return 0; @@ -170,6 +176,7 @@ extern "C" int kernelputstr(const char* characters, int length) extern "C" int dbgprintf(const char* fmt, ...) { + ScopedSpinLock lock(s_log_lock); color_on(); va_list ap; va_start(ap, fmt); |