summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorDaniel Bertalan <dani@danielbertalan.dev>2021-07-15 12:08:35 +0200
committerAndreas Kling <kling@serenityos.org>2021-07-16 20:51:13 +0200
commitdd4ed4d22dc96737d8b0342886e24c9544fc1a63 (patch)
tree5787378768e639c34a6c2988c26ee2e28ba1a13c /Kernel
parentc176680443eb81161c888ecf023709d19745ec85 (diff)
downloadserenity-dd4ed4d22dc96737d8b0342886e24c9544fc1a63.zip
Kernel: Implement aligned `operator new` and use it
The compiler will use these to allocate objects that have alignment requirements greater than that of our normal `operator new` (4/8 byte aligned). This means we can now use smart pointers for over-aligned types. Fixes a FIXME.
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/Heap/kmalloc.cpp27
-rw-r--r--Kernel/Heap/kmalloc.h8
-rw-r--r--Kernel/Thread.cpp12
-rw-r--r--Kernel/Thread.h4
4 files changed, 41 insertions, 10 deletions
diff --git a/Kernel/Heap/kmalloc.cpp b/Kernel/Heap/kmalloc.cpp
index 2d9c808e8b..4546f43c15 100644
--- a/Kernel/Heap/kmalloc.cpp
+++ b/Kernel/Heap/kmalloc.cpp
@@ -301,6 +301,16 @@ size_t kmalloc_good_size(size_t size)
return size;
}
+[[gnu::malloc, gnu::alloc_size(1), gnu::alloc_align(2)]] static void* kmalloc_aligned_cxx(size_t size, size_t alignment)
+{
+ VERIFY(alignment <= 4096);
+ void* ptr = kmalloc(size + alignment + sizeof(ptrdiff_t));
+ size_t max_addr = (size_t)ptr + alignment;
+ void* aligned_ptr = (void*)(max_addr - (max_addr % alignment));
+ ((ptrdiff_t*)aligned_ptr)[-1] = (ptrdiff_t)((u8*)aligned_ptr - (u8*)ptr);
+ return aligned_ptr;
+}
+
void* operator new(size_t size)
{
void* ptr = kmalloc(size);
@@ -313,6 +323,18 @@ void* operator new(size_t size, const std::nothrow_t&) noexcept
return kmalloc(size);
}
+void* operator new(size_t size, std::align_val_t al)
+{
+ void* ptr = kmalloc_aligned_cxx(size, (size_t)al);
+ VERIFY(ptr);
+ return ptr;
+}
+
+void* operator new(size_t size, std::align_val_t al, const std::nothrow_t&) noexcept
+{
+ return kmalloc_aligned_cxx(size, (size_t)al);
+}
+
void* operator new[](size_t size)
{
void* ptr = kmalloc(size);
@@ -336,6 +358,11 @@ void operator delete(void* ptr, size_t size) noexcept
return kfree_sized(ptr, size);
}
+void operator delete(void* ptr, size_t, std::align_val_t) noexcept
+{
+ return kfree_aligned(ptr);
+}
+
void operator delete[](void*) noexcept
{
// All deletes in kernel code should have a known size.
diff --git a/Kernel/Heap/kmalloc.h b/Kernel/Heap/kmalloc.h
index 72fdb2e3b7..2c005d2a80 100644
--- a/Kernel/Heap/kmalloc.h
+++ b/Kernel/Heap/kmalloc.h
@@ -34,6 +34,8 @@ struct nothrow_t {
};
extern const nothrow_t nothrow;
+
+enum class align_val_t : size_t {};
};
void kmalloc_init();
@@ -59,10 +61,16 @@ inline void* operator new[](size_t, void* p) { return p; }
[[nodiscard]] void* operator new(size_t size);
[[nodiscard]] void* operator new(size_t size, const std::nothrow_t&) noexcept;
+[[nodiscard]] void* operator new(size_t size, std::align_val_t);
+[[nodiscard]] void* operator new(size_t size, std::align_val_t, const std::nothrow_t&) noexcept;
+
void operator delete(void* ptr) noexcept;
void operator delete(void* ptr, size_t) noexcept;
+void operator delete(void* ptr, size_t, std::align_val_t) noexcept;
+
[[nodiscard]] void* operator new[](size_t size);
[[nodiscard]] void* operator new[](size_t size, const std::nothrow_t&) noexcept;
+
void operator delete[](void* ptrs) noexcept;
void operator delete[](void* ptr, size_t) noexcept;
diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp
index d28f8af155..fc1fec3bdb 100644
--- a/Kernel/Thread.cpp
+++ b/Kernel/Thread.cpp
@@ -38,11 +38,9 @@ UNMAP_AFTER_INIT void Thread::initialize()
KResultOr<NonnullRefPtr<Thread>> Thread::try_create(NonnullRefPtr<Process> process)
{
- // FIXME: Once we have aligned + nothrow operator new, we can avoid the manual kfree.
- FPUState* fpu_state = (FPUState*)kmalloc_aligned<16>(sizeof(FPUState));
+ auto fpu_state = try_make<FPUState>();
if (!fpu_state)
return ENOMEM;
- ArmedScopeGuard fpu_guard([fpu_state]() { kfree_aligned(fpu_state); });
auto kernel_stack_region = MM.allocate_kernel_region(default_kernel_stack_size, {}, Region::Access::Read | Region::Access::Write, AllocationStrategy::AllocateNow);
if (!kernel_stack_region)
@@ -53,18 +51,17 @@ KResultOr<NonnullRefPtr<Thread>> Thread::try_create(NonnullRefPtr<Process> proce
if (!block_timer)
return ENOMEM;
- auto thread = adopt_ref_if_nonnull(new (nothrow) Thread(move(process), kernel_stack_region.release_nonnull(), block_timer.release_nonnull(), fpu_state));
+ auto thread = adopt_ref_if_nonnull(new (nothrow) Thread(move(process), kernel_stack_region.release_nonnull(), block_timer.release_nonnull(), fpu_state.release_nonnull()));
if (!thread)
return ENOMEM;
- fpu_guard.disarm();
return thread.release_nonnull();
}
-Thread::Thread(NonnullRefPtr<Process> process, NonnullOwnPtr<Region> kernel_stack_region, NonnullRefPtr<Timer> block_timer, FPUState* fpu_state)
+Thread::Thread(NonnullRefPtr<Process> process, NonnullOwnPtr<Region> kernel_stack_region, NonnullRefPtr<Timer> block_timer, NonnullOwnPtr<FPUState> fpu_state)
: m_process(move(process))
, m_kernel_stack_region(move(kernel_stack_region))
- , m_fpu_state(fpu_state)
+ , m_fpu_state(move(fpu_state))
, m_name(m_process->name())
, m_block_timer(block_timer)
, m_global_procfs_inode_index(ProcFSComponentRegistry::the().allocate_inode_index())
@@ -533,7 +530,6 @@ void Thread::finalize()
if (m_dump_backtrace_on_finalization)
dbgln("{}", backtrace());
- kfree_aligned(m_fpu_state);
drop_thread_count(false);
}
diff --git a/Kernel/Thread.h b/Kernel/Thread.h
index 7b75b2a2b4..da5bcd751a 100644
--- a/Kernel/Thread.h
+++ b/Kernel/Thread.h
@@ -1192,7 +1192,7 @@ public:
String backtrace();
private:
- Thread(NonnullRefPtr<Process>, NonnullOwnPtr<Region>, NonnullRefPtr<Timer>, FPUState*);
+ Thread(NonnullRefPtr<Process>, NonnullOwnPtr<Region>, NonnullRefPtr<Timer>, NonnullOwnPtr<FPUState>);
IntrusiveListNode<Thread> m_process_thread_list_node;
int m_runnable_priority { -1 };
@@ -1318,7 +1318,7 @@ private:
unsigned m_ipv4_socket_read_bytes { 0 };
unsigned m_ipv4_socket_write_bytes { 0 };
- FPUState* m_fpu_state { nullptr };
+ OwnPtr<FPUState> m_fpu_state;
State m_state { Invalid };
String m_name;
u32 m_priority { THREAD_PRIORITY_NORMAL };