2020-01-18 08:38:21 +00:00
/*
2021-03-09 21:35:13 +00:00
* Copyright ( c ) 2018 - 2021 , Andreas Kling < kling @ serenityos . org >
2020-01-18 08:38:21 +00:00
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 08:38:21 +00:00
*/
2021-01-01 05:45:16 +00:00
# include <AK/ScopeGuard.h>
2021-08-15 10:38:02 +00:00
# include <AK/Singleton.h>
2019-07-25 19:02:19 +00:00
# include <AK/StringBuilder.h>
2020-11-15 18:58:19 +00:00
# include <AK/Time.h>
2021-10-14 21:53:48 +00:00
# include <Kernel/Arch/SmapDisabler.h>
2021-10-12 22:37:52 +00:00
# include <Kernel/Arch/x86/InterruptDisabler.h>
2021-06-21 15:34:09 +00:00
# include <Kernel/Arch/x86/TrapFrame.h>
2021-01-25 15:07:10 +00:00
# include <Kernel/Debug.h>
2021-06-06 23:15:07 +00:00
# include <Kernel/Devices/KCOVDevice.h>
2021-09-07 11:39:11 +00:00
# include <Kernel/FileSystem/OpenFileDescription.h>
2020-02-16 00:27:42 +00:00
# include <Kernel/KSyms.h>
2021-08-06 08:45:34 +00:00
# include <Kernel/Memory/MemoryManager.h>
# include <Kernel/Memory/PageDirectory.h>
2021-09-06 15:22:36 +00:00
# include <Kernel/Memory/ScopedAddressSpaceSwitcher.h>
2021-03-09 21:35:13 +00:00
# include <Kernel/Panic.h>
2021-01-11 08:52:18 +00:00
# include <Kernel/PerformanceEventBuffer.h>
2019-06-07 09:43:58 +00:00
# include <Kernel/Process.h>
Kernel: Introduce the new ProcFS design
The new ProcFS design consists of two main parts:
1. The representative ProcFS class, which is derived from the FS class.
The ProcFS and its inodes are much more lean - merely 3 classes to
represent the common type of inodes - regular files, symbolic links and
directories. They're backed by a ProcFSExposedComponent object, which
is responsible for the functional operation behind the scenes.
2. The backend of the ProcFS - the ProcFSComponentsRegistrar class
and all derived classes from the ProcFSExposedComponent class. These
together form the entire backend and handle all the functions you can
expect from the ProcFS.
The ProcFSExposedComponent derived classes split to 3 types in the
manner of lifetime in the kernel:
1. Persistent objects - this category includes all basic objects, like
the root folder, /proc/bus folder, main blob files in the root folders,
etc. These objects are persistent and cannot die ever.
2. Semi-persistent objects - this category includes all PID folders,
and subdirectories to the PID folders. It also includes exposed objects
like the unveil JSON'ed blob. These object are persistent as long as the
the responsible process they represent is still alive.
3. Dynamic objects - this category includes files in the subdirectories
of a PID folder, like /proc/PID/fd/* or /proc/PID/stacks/*. Essentially,
these objects are always created dynamically and when no longer in need
after being used, they're deallocated.
Nevertheless, the new allocated backend objects and inodes try to use
the same InodeIndex if possible - this might change only when a thread
dies and a new thread is born with a new thread stack, or when a file
descriptor is closed and a new one within the same file descriptor
number is opened. This is needed to actually be able to do something
useful with these objects.
The new design assures that many ProcFS instances can be used at once,
with one backend for usage for all instances.
2021-06-12 01:23:58 +00:00
# include <Kernel/ProcessExposed.h>
2019-06-07 09:43:58 +00:00
# include <Kernel/Scheduler.h>
2021-06-22 15:40:16 +00:00
# include <Kernel/Sections.h>
2019-06-07 09:43:58 +00:00
# include <Kernel/Thread.h>
2020-03-28 08:47:16 +00:00
# include <Kernel/ThreadTracer.h>
2020-04-26 09:32:37 +00:00
# include <Kernel/TimerQueue.h>
2019-03-23 21:03:17 +00:00
# include <LibC/signal_numbers.h>
2020-02-16 00:27:42 +00:00
namespace Kernel {
2021-08-21 23:37:17 +00:00
static Singleton < SpinlockProtected < Thread : : GlobalList > > s_list ;
2021-01-28 05:58:24 +00:00
2021-08-21 23:37:17 +00:00
SpinlockProtected < Thread : : GlobalList > & Thread : : all_instances ( )
2021-01-28 05:58:24 +00:00
{
2021-08-15 10:38:02 +00:00
return * s_list ;
}
2021-11-07 23:51:39 +00:00
ErrorOr < NonnullRefPtr < Thread > > Thread : : try_create ( NonnullRefPtr < Process > process )
2021-02-07 17:13:51 +00:00
{
2021-09-05 23:36:14 +00:00
auto kernel_stack_region = TRY ( MM . allocate_kernel_region ( default_kernel_stack_size , { } , Memory : : Region : : Access : : ReadWrite , AllocationStrategy : : AllocateNow ) ) ;
2021-02-07 19:13:51 +00:00
kernel_stack_region - > set_stack ( true ) ;
2021-05-11 10:53:38 +00:00
2021-09-02 22:07:29 +00:00
auto block_timer = try_make_ref_counted < Timer > ( ) ;
2021-05-19 22:41:51 +00:00
if ( ! block_timer )
return ENOMEM ;
2021-09-06 17:24:54 +00:00
auto name = TRY ( KString : : try_create ( process - > name ( ) ) ) ;
return adopt_nonnull_ref_or_enomem ( new ( nothrow ) Thread ( move ( process ) , move ( kernel_stack_region ) , block_timer . release_nonnull ( ) , move ( name ) ) ) ;
2021-02-07 17:13:51 +00:00
}
2021-09-06 10:44:27 +00:00
Thread : : Thread ( NonnullRefPtr < Process > process , NonnullOwnPtr < Memory : : Region > kernel_stack_region , NonnullRefPtr < Timer > block_timer , NonnullOwnPtr < KString > name )
2020-08-02 02:04:56 +00:00
: m_process ( move ( process ) )
2021-02-07 17:13:51 +00:00
, m_kernel_stack_region ( move ( kernel_stack_region ) )
2021-08-05 20:22:26 +00:00
, m_name ( move ( name ) )
2021-08-22 08:44:43 +00:00
, m_block_timer ( move ( block_timer ) )
2019-05-18 16:31:36 +00:00
{
2021-01-23 06:24:33 +00:00
bool is_first_thread = m_process - > add_thread ( * this ) ;
2021-01-01 05:45:16 +00:00
if ( is_first_thread ) {
2019-12-22 10:51:24 +00:00
// First thread gets TID == PID
2020-08-08 15:32:34 +00:00
m_tid = m_process - > pid ( ) . value ( ) ;
2019-12-22 10:51:24 +00:00
} else {
2020-08-08 15:32:34 +00:00
m_tid = Process : : allocate_pid ( ) . value ( ) ;
2019-12-22 10:51:24 +00:00
}
2021-02-07 17:13:51 +00:00
2021-12-28 08:38:41 +00:00
// FIXME: Handle KString allocation failure.
m_kernel_stack_region - > set_name ( MUST ( KString : : formatted ( " Kernel stack (thread {}) " , m_tid . value ( ) ) ) ) ;
2021-02-07 17:13:51 +00:00
2021-08-16 19:52:42 +00:00
Thread : : all_instances ( ) . with ( [ & ] ( auto & list ) {
2021-08-15 10:38:02 +00:00
list . append ( * this ) ;
} ) ;
2021-01-23 22:59:27 +00:00
if constexpr ( THREAD_DEBUG )
2021-01-12 21:30:52 +00:00
dbgln ( " Created new thread {}({}:{}) " , m_process - > name ( ) , m_process - > pid ( ) . value ( ) , m_tid . value ( ) ) ;
2021-02-21 10:03:49 +00:00
2020-02-18 12:44:27 +00:00
reset_fpu_state ( ) ;
2019-03-23 21:03:17 +00:00
// Only IF is set when a process boots.
2021-08-19 19:53:53 +00:00
m_regs . set_flags ( 0x0202 ) ;
2019-03-23 21:03:17 +00:00
2021-08-19 19:53:53 +00:00
# if ARCH(I386)
2020-09-10 15:46:24 +00:00
if ( m_process - > is_kernel_process ( ) ) {
2021-06-26 17:57:16 +00:00
m_regs . cs = GDT_SELECTOR_CODE0 ;
m_regs . ds = GDT_SELECTOR_DATA0 ;
m_regs . es = GDT_SELECTOR_DATA0 ;
2021-07-02 12:02:36 +00:00
m_regs . fs = 0 ;
2021-06-26 17:57:16 +00:00
m_regs . ss = GDT_SELECTOR_DATA0 ;
2021-07-02 12:02:36 +00:00
m_regs . gs = GDT_SELECTOR_PROC ;
2019-03-23 21:03:17 +00:00
} else {
2021-06-26 17:57:16 +00:00
m_regs . cs = GDT_SELECTOR_CODE3 | 3 ;
m_regs . ds = GDT_SELECTOR_DATA3 | 3 ;
m_regs . es = GDT_SELECTOR_DATA3 | 3 ;
m_regs . fs = GDT_SELECTOR_DATA3 | 3 ;
m_regs . ss = GDT_SELECTOR_DATA3 | 3 ;
m_regs . gs = GDT_SELECTOR_TLS | 3 ;
2019-03-23 21:03:17 +00:00
}
2021-06-23 19:54:41 +00:00
# else
2021-06-27 11:59:41 +00:00
if ( m_process - > is_kernel_process ( ) )
m_regs . cs = GDT_SELECTOR_CODE0 ;
else
m_regs . cs = GDT_SELECTOR_CODE3 | 3 ;
2021-06-23 19:54:41 +00:00
# endif
2019-03-23 21:03:17 +00:00
2021-08-06 11:59:22 +00:00
m_regs . cr3 = m_process - > address_space ( ) . page_directory ( ) . cr3 ( ) ;
2021-06-26 17:57:16 +00:00
2020-01-27 11:52:10 +00:00
m_kernel_stack_base = m_kernel_stack_region - > vaddr ( ) . get ( ) ;
2021-07-17 00:09:45 +00:00
m_kernel_stack_top = m_kernel_stack_region - > vaddr ( ) . offset ( default_kernel_stack_size ) . get ( ) & ~ ( FlatPtr ) 0x7u ;
2020-01-27 11:52:10 +00:00
2020-09-10 15:46:24 +00:00
if ( m_process - > is_kernel_process ( ) ) {
2021-08-19 19:53:53 +00:00
m_regs . set_sp ( m_kernel_stack_top ) ;
m_regs . set_sp0 ( m_kernel_stack_top ) ;
2019-03-23 21:03:17 +00:00
} else {
2020-01-27 11:52:10 +00:00
// Ring 3 processes get a separate stack for ring 0.
// The ring 3 stack will be assigned by exec().
2021-06-26 17:57:16 +00:00
# if ARCH(I386)
m_regs . ss0 = GDT_SELECTOR_DATA0 ;
2021-06-23 19:54:41 +00:00
# endif
2021-08-19 19:53:53 +00:00
m_regs . set_sp0 ( m_kernel_stack_top ) ;
2021-06-26 17:57:16 +00:00
}
2019-03-23 21:03:17 +00:00
2020-09-27 14:53:35 +00:00
// We need to add another reference if we could successfully create
// all the resources needed for this thread. The reason for this is that
// we don't want to delete this thread after dropping the reference,
// it may still be running or scheduled to be run.
// The finalizer is responsible for dropping this reference once this
// thread is ready to be cleaned up.
ref ( ) ;
2019-03-23 21:03:17 +00:00
}
Thread : : ~ Thread ( )
{
2020-11-11 23:05:00 +00:00
{
// We need to explicitly remove ourselves from the thread list
2021-08-22 08:44:43 +00:00
// here. We may get preempted in the middle of destructing this
2020-11-11 23:05:00 +00:00
// thread, which causes problems if the thread list is iterated.
// Specifically, if this is the last thread of a process, checking
// block conditions would access m_process, which would be in
// the middle of being destroyed.
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2021-02-23 19:42:32 +00:00
VERIFY ( ! m_process_thread_list_node . is_in_list ( ) ) ;
2021-01-22 23:56:08 +00:00
// We shouldn't be queued
2021-02-23 19:42:32 +00:00
VERIFY ( m_runnable_priority < 0 ) ;
2021-01-28 05:58:24 +00:00
}
2020-11-29 23:05:27 +00:00
}
2020-11-11 23:05:00 +00:00
2021-09-05 17:02:03 +00:00
void Thread : : block ( Kernel : : Mutex & lock , SpinlockLocker < Spinlock > & lock_lock , u32 lock_count )
2021-07-10 16:23:16 +00:00
{
2021-08-22 10:21:31 +00:00
VERIFY ( ! Processor : : current_in_irq ( ) ) ;
2021-07-10 16:23:16 +00:00
VERIFY ( this = = Thread : : current ( ) ) ;
ScopedCritical critical ;
2021-08-29 18:10:24 +00:00
VERIFY ( ! Memory : : s_mm_lock . is_locked_by_current_processor ( ) ) ;
2021-07-10 16:23:16 +00:00
2021-08-21 23:49:22 +00:00
SpinlockLocker block_lock ( m_block_lock ) ;
2021-07-10 16:23:16 +00:00
2021-08-21 23:49:22 +00:00
SpinlockLocker scheduler_lock ( g_scheduler_lock ) ;
2021-07-10 16:23:16 +00:00
switch ( state ( ) ) {
case Thread : : Stopped :
// It's possible that we were requested to be stopped!
break ;
case Thread : : Running :
VERIFY ( m_blocker = = nullptr ) ;
break ;
default :
VERIFY_NOT_REACHED ( ) ;
}
2021-07-16 21:48:22 +00:00
// If we're blocking on the big-lock we may actually be in the process
// of unblocking from another lock. If that's the case m_blocking_lock
// is already set
auto & big_lock = process ( ) . big_lock ( ) ;
VERIFY ( ( & lock = = & big_lock & & m_blocking_lock ! = & big_lock ) | | ! m_blocking_lock ) ;
2021-10-31 22:36:52 +00:00
auto * previous_blocking_lock = m_blocking_lock ;
2021-07-10 16:23:16 +00:00
m_blocking_lock = & lock ;
m_lock_requested_count = lock_count ;
set_state ( Thread : : Blocked ) ;
scheduler_lock . unlock ( ) ;
block_lock . unlock ( ) ;
lock_lock . unlock ( ) ;
2021-07-17 19:09:51 +00:00
dbgln_if ( THREAD_DEBUG , " Thread {} blocking on Mutex {} " , * this , & lock ) ;
2021-07-10 16:23:16 +00:00
for ( ; ; ) {
// Yield to the scheduler, and wait for us to resume unblocked.
2021-08-29 18:10:24 +00:00
VERIFY ( ! g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
2021-08-09 23:16:08 +00:00
VERIFY ( Processor : : in_critical ( ) ) ;
2021-08-29 10:48:43 +00:00
if ( & lock ! = & big_lock & & big_lock . is_locked_by_current_thread ( ) ) {
2021-07-16 01:38:07 +00:00
// We're locking another lock and already hold the big lock...
// We need to release the big lock
2021-07-16 01:45:22 +00:00
yield_and_release_relock_big_lock ( ) ;
2021-07-16 01:38:07 +00:00
} else {
2021-08-10 19:20:45 +00:00
// By the time we've reached this another thread might have
// marked us as holding the big lock, so this call must not
// verify that we're not holding it.
yield_without_releasing_big_lock ( VerifyLockNotHeld : : No ) ;
2021-07-16 01:38:07 +00:00
}
2021-08-09 23:16:08 +00:00
VERIFY ( Processor : : in_critical ( ) ) ;
2021-07-10 16:23:16 +00:00
2021-08-21 23:49:22 +00:00
SpinlockLocker block_lock2 ( m_block_lock ) ;
2021-07-10 16:23:16 +00:00
VERIFY ( ! m_blocking_lock ) ;
2021-07-16 21:48:22 +00:00
m_blocking_lock = previous_blocking_lock ;
2021-07-10 16:23:16 +00:00
break ;
}
lock_lock . lock ( ) ;
}
2021-07-17 19:09:51 +00:00
u32 Thread : : unblock_from_lock ( Kernel : : Mutex & lock )
2021-07-10 16:23:16 +00:00
{
2021-08-21 23:49:22 +00:00
SpinlockLocker block_lock ( m_block_lock ) ;
2021-07-10 16:23:16 +00:00
VERIFY ( m_blocking_lock = = & lock ) ;
auto requested_count = m_lock_requested_count ;
block_lock . unlock ( ) ;
auto do_unblock = [ & ] ( ) {
2021-08-21 23:49:22 +00:00
SpinlockLocker scheduler_lock ( g_scheduler_lock ) ;
SpinlockLocker block_lock ( m_block_lock ) ;
2021-07-10 16:23:16 +00:00
VERIFY ( m_blocking_lock = = & lock ) ;
2021-08-22 10:21:31 +00:00
VERIFY ( ! Processor : : current_in_irq ( ) ) ;
2021-08-29 18:10:24 +00:00
VERIFY ( g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
VERIFY ( m_block_lock . is_locked_by_current_processor ( ) ) ;
2021-07-10 16:23:16 +00:00
VERIFY ( m_blocking_lock = = & lock ) ;
2021-07-17 19:09:51 +00:00
dbgln_if ( THREAD_DEBUG , " Thread {} unblocked from Mutex {} " , * this , & lock ) ;
2021-07-10 16:23:16 +00:00
m_blocking_lock = nullptr ;
if ( Thread : : current ( ) = = this ) {
set_state ( Thread : : Running ) ;
return ;
}
VERIFY ( m_state ! = Thread : : Runnable & & m_state ! = Thread : : Running ) ;
set_state ( Thread : : Runnable ) ;
} ;
2021-11-06 21:06:08 +00:00
if ( Processor : : current_in_irq ( ) ! = 0 ) {
2021-08-22 08:44:43 +00:00
Processor : : deferred_call_queue ( [ do_unblock = move ( do_unblock ) , self = make_weak_ptr ( ) ] ( ) {
2021-07-10 16:23:16 +00:00
if ( auto this_thread = self . strong_ref ( ) )
do_unblock ( ) ;
} ) ;
} else {
do_unblock ( ) ;
}
return requested_count ;
}
2020-11-29 23:05:27 +00:00
void Thread : : unblock_from_blocker ( Blocker & blocker )
{
2020-12-09 04:18:45 +00:00
auto do_unblock = [ & ] ( ) {
2021-08-21 23:49:22 +00:00
SpinlockLocker scheduler_lock ( g_scheduler_lock ) ;
SpinlockLocker block_lock ( m_block_lock ) ;
2020-12-09 04:18:45 +00:00
if ( m_blocker ! = & blocker )
return ;
if ( ! should_be_stopped ( ) & & ! is_stopped ( ) )
unblock ( ) ;
} ;
2021-11-06 21:06:08 +00:00
if ( Processor : : current_in_irq ( ) ! = 0 ) {
2021-08-22 08:44:43 +00:00
Processor : : deferred_call_queue ( [ do_unblock = move ( do_unblock ) , self = make_weak_ptr ( ) ] ( ) {
2020-12-09 04:18:45 +00:00
if ( auto this_thread = self . strong_ref ( ) )
do_unblock ( ) ;
} ) ;
} else {
do_unblock ( ) ;
}
2019-03-23 21:03:17 +00:00
}
2020-11-29 23:05:27 +00:00
void Thread : : unblock ( u8 signal )
2019-03-23 21:03:17 +00:00
{
2021-08-22 10:21:31 +00:00
VERIFY ( ! Processor : : current_in_irq ( ) ) ;
2021-08-29 18:10:24 +00:00
VERIFY ( g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
VERIFY ( m_block_lock . is_locked_by_current_processor ( ) ) ;
2020-11-29 23:05:27 +00:00
if ( m_state ! = Thread : : Blocked )
return ;
2021-07-10 16:23:16 +00:00
if ( m_blocking_lock )
return ;
2021-02-23 19:42:32 +00:00
VERIFY ( m_blocker ) ;
2020-12-09 04:18:45 +00:00
if ( signal ! = 0 ) {
2021-01-20 23:06:19 +00:00
if ( is_handling_page_fault ( ) ) {
// Don't let signals unblock threads that are blocked inside a page fault handler.
// This prevents threads from EINTR'ing the inode read in an inode page fault.
// FIXME: There's probably a better way to solve this.
return ;
}
2020-12-09 04:18:45 +00:00
if ( ! m_blocker - > can_be_interrupted ( ) & & ! m_should_die )
return ;
2020-11-29 23:05:27 +00:00
m_blocker - > set_interrupted_by_signal ( signal ) ;
2020-12-09 04:18:45 +00:00
}
2020-04-06 12:38:33 +00:00
m_blocker = nullptr ;
2020-06-28 21:34:31 +00:00
if ( Thread : : current ( ) = = this ) {
2020-08-10 20:05:24 +00:00
set_state ( Thread : : Running ) ;
2019-03-23 21:03:17 +00:00
return ;
}
2021-02-23 19:42:32 +00:00
VERIFY ( m_state ! = Thread : : Runnable & & m_state ! = Thread : : Running ) ;
2020-08-10 20:05:24 +00:00
set_state ( Thread : : Runnable ) ;
2019-03-23 21:03:17 +00:00
}
Kernel: Unwind kernel stacks before dying
While executing in the kernel, a thread can acquire various resources
that need cleanup, such as locks and references to RefCounted objects.
This cleanup normally happens on the exit path, such as in destructors
for various RAII guards. But we weren't calling those exit paths when
killing threads that have been executing in the kernel, such as threads
blocked on reading or sleeping, thus causing leaks.
This commit changes how killing threads works. Now, instead of killing
a thread directly, one is supposed to call thread->set_should_die(),
which will unblock it and make it unwind the stack if it is blocked
in the kernel. Then, just before returning to the userspace, the thread
will automatically die.
2019-11-14 15:46:01 +00:00
void Thread : : set_should_die ( )
{
2019-12-22 10:35:02 +00:00
if ( m_should_die ) {
2021-01-12 21:30:52 +00:00
dbgln ( " {} Should already die " , * this ) ;
Kernel: Unwind kernel stacks before dying
While executing in the kernel, a thread can acquire various resources
that need cleanup, such as locks and references to RefCounted objects.
This cleanup normally happens on the exit path, such as in destructors
for various RAII guards. But we weren't calling those exit paths when
killing threads that have been executing in the kernel, such as threads
blocked on reading or sleeping, thus causing leaks.
This commit changes how killing threads works. Now, instead of killing
a thread directly, one is supposed to call thread->set_should_die(),
which will unblock it and make it unwind the stack if it is blocked
in the kernel. Then, just before returning to the userspace, the thread
will automatically die.
2019-11-14 15:46:01 +00:00
return ;
2019-12-22 10:35:02 +00:00
}
2020-07-05 20:32:07 +00:00
ScopedCritical critical ;
Kernel: Unwind kernel stacks before dying
While executing in the kernel, a thread can acquire various resources
that need cleanup, such as locks and references to RefCounted objects.
This cleanup normally happens on the exit path, such as in destructors
for various RAII guards. But we weren't calling those exit paths when
killing threads that have been executing in the kernel, such as threads
blocked on reading or sleeping, thus causing leaks.
This commit changes how killing threads works. Now, instead of killing
a thread directly, one is supposed to call thread->set_should_die(),
which will unblock it and make it unwind the stack if it is blocked
in the kernel. Then, just before returning to the userspace, the thread
will automatically die.
2019-11-14 15:46:01 +00:00
// Remember that we should die instead of returning to
// the userspace.
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2020-12-08 04:29:41 +00:00
m_should_die = true ;
// NOTE: Even the current thread can technically be in "Stopped"
// state! This is the case when another thread sent a SIGSTOP to
// it while it was running and it calls e.g. exit() before
// the scheduler gets involved again.
if ( is_stopped ( ) ) {
// If we were stopped, we need to briefly resume so that
// the kernel stacks can clean up. We won't ever return back
// to user mode, though
2021-02-23 19:42:32 +00:00
VERIFY ( ! process ( ) . is_stopped ( ) ) ;
2020-12-08 04:29:41 +00:00
resume_from_stopped ( ) ;
2020-08-14 16:24:31 +00:00
}
Kernel: Unwind kernel stacks before dying
While executing in the kernel, a thread can acquire various resources
that need cleanup, such as locks and references to RefCounted objects.
This cleanup normally happens on the exit path, such as in destructors
for various RAII guards. But we weren't calling those exit paths when
killing threads that have been executing in the kernel, such as threads
blocked on reading or sleeping, thus causing leaks.
This commit changes how killing threads works. Now, instead of killing
a thread directly, one is supposed to call thread->set_should_die(),
which will unblock it and make it unwind the stack if it is blocked
in the kernel. Then, just before returning to the userspace, the thread
will automatically die.
2019-11-14 15:46:01 +00:00
if ( is_blocked ( ) ) {
2021-08-21 23:49:22 +00:00
SpinlockLocker block_lock ( m_block_lock ) ;
2020-12-08 04:29:41 +00:00
if ( m_blocker ) {
// We're blocked in the kernel.
m_blocker - > set_interrupted_by_death ( ) ;
unblock ( ) ;
}
Kernel: Unwind kernel stacks before dying
While executing in the kernel, a thread can acquire various resources
that need cleanup, such as locks and references to RefCounted objects.
This cleanup normally happens on the exit path, such as in destructors
for various RAII guards. But we weren't calling those exit paths when
killing threads that have been executing in the kernel, such as threads
blocked on reading or sleeping, thus causing leaks.
This commit changes how killing threads works. Now, instead of killing
a thread directly, one is supposed to call thread->set_should_die(),
which will unblock it and make it unwind the stack if it is blocked
in the kernel. Then, just before returning to the userspace, the thread
will automatically die.
2019-11-14 15:46:01 +00:00
}
}
void Thread : : die_if_needed ( )
{
2021-02-23 19:42:32 +00:00
VERIFY ( Thread : : current ( ) = = this ) ;
Kernel: Unwind kernel stacks before dying
While executing in the kernel, a thread can acquire various resources
that need cleanup, such as locks and references to RefCounted objects.
This cleanup normally happens on the exit path, such as in destructors
for various RAII guards. But we weren't calling those exit paths when
killing threads that have been executing in the kernel, such as threads
blocked on reading or sleeping, thus causing leaks.
This commit changes how killing threads works. Now, instead of killing
a thread directly, one is supposed to call thread->set_should_die(),
which will unblock it and make it unwind the stack if it is blocked
in the kernel. Then, just before returning to the userspace, the thread
will automatically die.
2019-11-14 15:46:01 +00:00
if ( ! m_should_die )
return ;
2020-12-14 23:36:22 +00:00
u32 unlock_count ;
2020-12-20 23:09:48 +00:00
[[maybe_unused]] auto rc = unlock_process_if_locked ( unlock_count ) ;
2019-12-22 11:34:38 +00:00
2021-06-06 09:40:11 +00:00
dbgln_if ( THREAD_DEBUG , " Thread {} is dying " , * this ) ;
{
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2021-06-06 09:40:11 +00:00
// It's possible that we don't reach the code after this block if the
// scheduler is invoked and FinalizerTask cleans up this thread, however
// that doesn't matter because we're trying to invoke the scheduler anyway
set_state ( Thread : : Dying ) ;
}
2020-07-05 20:32:07 +00:00
ScopedCritical critical ;
2020-07-04 23:37:36 +00:00
2020-07-05 20:32:07 +00:00
// Flag a context switch. Because we're in a critical section,
2021-02-10 20:18:03 +00:00
// Scheduler::yield will actually only mark a pending context switch
2020-07-05 20:32:07 +00:00
// Simply leaving the critical section would not necessarily trigger
// a switch.
2020-06-27 19:42:28 +00:00
Scheduler : : yield ( ) ;
2020-07-04 23:37:36 +00:00
2020-07-05 20:32:07 +00:00
// Now leave the critical section so that we can also trigger the
// actual context switch
2021-08-09 23:56:21 +00:00
Processor : : clear_critical ( ) ;
2021-08-22 10:21:31 +00:00
dbgln ( " die_if_needed returned from clear_critical!!! in irq: {} " , Processor : : current_in_irq ( ) ) ;
2020-07-05 20:32:07 +00:00
// We should never get here, but the scoped scheduler lock
// will be released by Scheduler::context_switch again
2021-02-23 19:42:32 +00:00
VERIFY_NOT_REACHED ( ) ;
Kernel: Unwind kernel stacks before dying
While executing in the kernel, a thread can acquire various resources
that need cleanup, such as locks and references to RefCounted objects.
This cleanup normally happens on the exit path, such as in destructors
for various RAII guards. But we weren't calling those exit paths when
killing threads that have been executing in the kernel, such as threads
blocked on reading or sleeping, thus causing leaks.
This commit changes how killing threads works. Now, instead of killing
a thread directly, one is supposed to call thread->set_should_die(),
which will unblock it and make it unwind the stack if it is blocked
in the kernel. Then, just before returning to the userspace, the thread
will automatically die.
2019-11-14 15:46:01 +00:00
}
2020-11-17 03:51:34 +00:00
void Thread : : exit ( void * exit_value )
{
2021-02-23 19:42:32 +00:00
VERIFY ( Thread : : current ( ) = = this ) ;
2021-08-22 23:22:38 +00:00
m_join_blocker_set . thread_did_exit ( exit_value ) ;
2020-11-17 03:51:34 +00:00
set_should_die ( ) ;
2020-12-14 23:36:22 +00:00
u32 unlock_count ;
2020-12-20 23:09:48 +00:00
[[maybe_unused]] auto rc = unlock_process_if_locked ( unlock_count ) ;
2021-05-28 09:18:58 +00:00
if ( m_thread_specific_range . has_value ( ) ) {
2021-08-06 11:59:22 +00:00
auto * region = process ( ) . address_space ( ) . find_region_from_range ( m_thread_specific_range . value ( ) ) ;
process ( ) . address_space ( ) . deallocate_region ( * region ) ;
2021-05-28 09:18:58 +00:00
}
2021-06-06 23:15:07 +00:00
# ifdef ENABLE_KERNEL_COVERAGE_COLLECTION
KCOVDevice : : free_thread ( ) ;
# endif
2020-11-17 03:51:34 +00:00
die_if_needed ( ) ;
}
2021-08-10 19:20:45 +00:00
void Thread : : yield_without_releasing_big_lock ( VerifyLockNotHeld verify_lock_not_held )
2020-12-08 04:29:41 +00:00
{
2021-08-29 18:10:24 +00:00
VERIFY ( ! g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
2021-08-29 10:48:43 +00:00
VERIFY ( verify_lock_not_held = = VerifyLockNotHeld : : No | | ! process ( ) . big_lock ( ) . is_locked_by_current_thread ( ) ) ;
2021-07-10 16:23:16 +00:00
// Disable interrupts here. This ensures we don't accidentally switch contexts twice
InterruptDisabler disable ;
Scheduler : : yield ( ) ; // flag a switch
2021-08-09 23:56:21 +00:00
u32 prev_critical = Processor : : clear_critical ( ) ;
2020-12-08 04:29:41 +00:00
// NOTE: We may be on a different CPU now!
2021-08-09 23:56:21 +00:00
Processor : : restore_critical ( prev_critical ) ;
2020-12-08 04:29:41 +00:00
}
2021-07-16 01:45:22 +00:00
void Thread : : yield_and_release_relock_big_lock ( )
2019-03-23 21:03:17 +00:00
{
2021-08-29 18:10:24 +00:00
VERIFY ( ! g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
2021-07-10 16:23:16 +00:00
// Disable interrupts here. This ensures we don't accidentally switch contexts twice
InterruptDisabler disable ;
Scheduler : : yield ( ) ; // flag a switch
2020-12-14 23:36:22 +00:00
u32 lock_count_to_restore = 0 ;
auto previous_locked = unlock_process_if_locked ( lock_count_to_restore ) ;
2020-09-26 03:44:43 +00:00
// NOTE: Even though we call Scheduler::yield here, unless we happen
// to be outside of a critical section, the yield will be postponed
// until leaving it in relock_process.
2020-12-14 23:36:22 +00:00
relock_process ( previous_locked , lock_count_to_restore ) ;
2019-03-23 21:03:17 +00:00
}
2019-12-01 10:57:20 +00:00
2020-12-14 23:36:22 +00:00
LockMode Thread : : unlock_process_if_locked ( u32 & lock_count_to_restore )
2020-12-09 04:18:45 +00:00
{
2020-12-14 23:36:22 +00:00
return process ( ) . big_lock ( ) . force_unlock_if_locked ( lock_count_to_restore ) ;
2020-12-09 04:18:45 +00:00
}
2020-12-14 23:36:22 +00:00
void Thread : : relock_process ( LockMode previous_locked , u32 lock_count_to_restore )
2019-12-01 14:54:47 +00:00
{
2020-09-26 03:44:43 +00:00
// Clearing the critical section may trigger the context switch
2021-07-05 21:07:18 +00:00
// flagged by calling Scheduler::yield above.
// We have to do it this way because we intentionally
2020-09-26 03:44:43 +00:00
// leave the critical section here to be able to switch contexts.
2021-08-09 23:56:21 +00:00
u32 prev_critical = Processor : : clear_critical ( ) ;
2021-01-27 22:23:21 +00:00
// CONTEXT SWITCH HAPPENS HERE!
2020-09-26 03:44:43 +00:00
2021-01-27 22:23:21 +00:00
// NOTE: We may be on a different CPU now!
2021-08-09 23:56:21 +00:00
Processor : : restore_critical ( prev_critical ) ;
2020-12-14 23:36:22 +00:00
if ( previous_locked ! = LockMode : : Unlocked ) {
// We've unblocked, relock the process if needed and carry on.
2021-04-24 22:24:30 +00:00
process ( ) . big_lock ( ) . restore_lock ( previous_locked , lock_count_to_restore ) ;
2020-12-14 23:36:22 +00:00
}
2019-12-01 10:57:20 +00:00
}
2019-03-23 21:03:17 +00:00
2021-10-31 21:54:39 +00:00
// NOLINTNEXTLINE(readability-make-member-function-const) False positive; We call block<SleepBlocker> which is not const
2021-02-27 22:56:16 +00:00
auto Thread : : sleep ( clockid_t clock_id , const Time & duration , Time * remaining_time ) - > BlockResult
2019-03-23 21:03:17 +00:00
{
2021-02-23 19:42:32 +00:00
VERIFY ( state ( ) = = Thread : : Running ) ;
2021-01-10 23:29:28 +00:00
return Thread : : current ( ) - > block < Thread : : SleepBlocker > ( { } , Thread : : BlockTimeout ( false , & duration , nullptr , clock_id ) , remaining_time ) ;
2020-11-15 18:58:19 +00:00
}
2021-10-31 21:54:39 +00:00
// NOLINTNEXTLINE(readability-make-member-function-const) False positive; We call block<SleepBlocker> which is not const
2021-02-27 22:56:16 +00:00
auto Thread : : sleep_until ( clockid_t clock_id , const Time & deadline ) - > BlockResult
2020-11-15 18:58:19 +00:00
{
2021-02-23 19:42:32 +00:00
VERIFY ( state ( ) = = Thread : : Running ) ;
2021-01-10 23:29:28 +00:00
return Thread : : current ( ) - > block < Thread : : SleepBlocker > ( { } , Thread : : BlockTimeout ( true , & deadline , nullptr , clock_id ) ) ;
2019-03-23 21:03:17 +00:00
}
2021-08-05 18:48:14 +00:00
StringView Thread : : state_string ( ) const
2019-03-23 21:03:17 +00:00
{
2019-07-19 07:51:48 +00:00
switch ( state ( ) ) {
2019-06-07 09:43:58 +00:00
case Thread : : Invalid :
2021-08-05 18:48:14 +00:00
return " Invalid " sv ;
2019-06-07 09:43:58 +00:00
case Thread : : Runnable :
2021-08-05 18:48:14 +00:00
return " Runnable " sv ;
2019-06-07 09:43:58 +00:00
case Thread : : Running :
2021-08-05 18:48:14 +00:00
return " Running " sv ;
2019-06-07 09:43:58 +00:00
case Thread : : Dying :
2021-08-05 18:48:14 +00:00
return " Dying " sv ;
2019-06-07 09:43:58 +00:00
case Thread : : Dead :
2021-08-05 18:48:14 +00:00
return " Dead " sv ;
2019-06-07 09:43:58 +00:00
case Thread : : Stopped :
2021-08-05 18:48:14 +00:00
return " Stopped " sv ;
2020-09-27 14:53:35 +00:00
case Thread : : Blocked : {
2021-08-21 23:49:22 +00:00
SpinlockLocker block_lock ( m_block_lock ) ;
2021-07-10 16:23:16 +00:00
if ( m_blocking_lock )
2021-08-05 18:48:14 +00:00
return " Mutex " sv ;
2021-07-10 16:23:16 +00:00
if ( m_blocker )
return m_blocker - > state_string ( ) ;
VERIFY_NOT_REACHED ( ) ;
2019-03-23 21:03:17 +00:00
}
2020-09-27 14:53:35 +00:00
}
2021-03-09 21:35:13 +00:00
PANIC ( " Thread::state_string(): Invalid state: {} " , ( int ) state ( ) ) ;
2019-03-23 21:03:17 +00:00
}
void Thread : : finalize ( )
{
2021-02-23 19:42:32 +00:00
VERIFY ( Thread : : current ( ) = = g_finalizer ) ;
VERIFY ( Thread : : current ( ) ! = this ) ;
2019-08-01 18:01:23 +00:00
2021-01-23 22:29:11 +00:00
# if LOCK_DEBUG
2021-08-30 00:47:40 +00:00
VERIFY ( ! m_lock . is_locked_by_current_processor ( ) ) ;
2020-12-01 02:04:36 +00:00
if ( lock_count ( ) > 0 ) {
2021-01-18 16:25:44 +00:00
dbgln ( " Thread {} leaking {} Locks! " , * this , lock_count ( ) ) ;
2021-08-21 23:49:22 +00:00
SpinlockLocker list_lock ( m_holding_locks_lock ) ;
2021-04-24 22:17:02 +00:00
for ( auto & info : m_holding_locks_list ) {
2021-08-07 11:19:39 +00:00
const auto & location = info . lock_location ;
2021-07-17 19:09:51 +00:00
dbgln ( " - Mutex: \" {} \" @ {} locked in function \" {} \" at \" {}:{} \" with a count of: {} " , info . lock - > name ( ) , info . lock , location . function_name ( ) , location . filename ( ) , location . line_number ( ) , info . count ) ;
2021-04-24 22:17:02 +00:00
}
2021-02-23 19:42:32 +00:00
VERIFY_NOT_REACHED ( ) ;
2020-12-01 02:04:36 +00:00
}
# endif
2020-10-26 02:22:59 +00:00
{
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2021-02-07 12:03:24 +00:00
dbgln_if ( THREAD_DEBUG , " Finalizing thread {} " , * this ) ;
2020-10-26 02:22:59 +00:00
set_state ( Thread : : State : : Dead ) ;
2021-08-22 23:22:38 +00:00
m_join_blocker_set . thread_finalizing ( ) ;
2019-11-14 19:58:23 +00:00
}
2019-08-06 17:43:07 +00:00
if ( m_dump_backtrace_on_finalization )
2021-02-07 16:58:29 +00:00
dbgln ( " {} " , backtrace ( ) ) ;
2020-09-27 14:53:35 +00:00
2021-01-01 05:45:16 +00:00
drop_thread_count ( false ) ;
}
2020-09-27 14:53:35 +00:00
2021-01-01 05:45:16 +00:00
void Thread : : drop_thread_count ( bool initializing_first_thread )
{
2021-01-23 06:24:33 +00:00
bool is_last = process ( ) . remove_thread ( * this ) ;
2020-11-29 23:05:27 +00:00
2021-01-23 06:24:33 +00:00
if ( ! initializing_first_thread & & is_last )
2020-12-09 04:18:45 +00:00
process ( ) . finalize ( ) ;
2019-03-23 21:03:17 +00:00
}
void Thread : : finalize_dying_threads ( )
{
2021-02-23 19:42:32 +00:00
VERIFY ( Thread : : current ( ) = = g_finalizer ) ;
2019-04-20 12:02:19 +00:00
Vector < Thread * , 32 > dying_threads ;
2019-03-23 21:03:17 +00:00
{
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2019-06-07 09:43:58 +00:00
for_each_in_state ( Thread : : State : : Dying , [ & ] ( Thread & thread ) {
2020-07-05 20:32:07 +00:00
if ( thread . is_finalizable ( ) )
dying_threads . append ( & thread ) ;
2019-03-23 21:03:17 +00:00
} ) ;
}
2019-12-22 10:35:02 +00:00
for ( auto * thread : dying_threads ) {
2021-07-01 16:18:38 +00:00
RefPtr < Process > process = thread - > process ( ) ;
dbgln_if ( PROCESS_DEBUG , " Before finalization, {} has {} refs and its process has {} " ,
* thread , thread - > ref_count ( ) , thread - > process ( ) . ref_count ( ) ) ;
2019-03-23 21:03:17 +00:00
thread - > finalize ( ) ;
2021-07-01 16:18:38 +00:00
dbgln_if ( PROCESS_DEBUG , " After finalization, {} has {} refs and its process has {} " ,
* thread , thread - > ref_count ( ) , thread - > process ( ) . ref_count ( ) ) ;
2020-09-27 14:53:35 +00:00
// This thread will never execute again, drop the running reference
// NOTE: This may not necessarily drop the last reference if anything
// else is still holding onto this thread!
thread - > unref ( ) ;
2019-12-22 10:35:02 +00:00
}
2019-03-23 21:03:17 +00:00
}
2021-07-15 03:46:32 +00:00
void Thread : : update_time_scheduled ( u64 current_scheduler_time , bool is_kernel , bool no_longer_running )
{
if ( m_last_time_scheduled . has_value ( ) ) {
u64 delta ;
if ( current_scheduler_time > = m_last_time_scheduled . value ( ) )
delta = current_scheduler_time - m_last_time_scheduled . value ( ) ;
else
delta = m_last_time_scheduled . value ( ) - current_scheduler_time ; // the unlikely event that the clock wrapped
if ( delta ! = 0 ) {
// Add it to the global total *before* updating the thread's value!
Scheduler : : add_time_scheduled ( delta , is_kernel ) ;
auto & total_time = is_kernel ? m_total_time_scheduled_kernel : m_total_time_scheduled_user ;
2021-08-21 23:49:22 +00:00
SpinlockLocker scheduler_lock ( g_scheduler_lock ) ;
2021-07-15 03:46:32 +00:00
total_time + = delta ;
}
}
if ( no_longer_running )
m_last_time_scheduled = { } ;
else
m_last_time_scheduled = current_scheduler_time ;
}
2021-01-25 23:37:36 +00:00
bool Thread : : tick ( )
2019-03-23 21:03:17 +00:00
{
2021-01-25 23:37:36 +00:00
if ( previous_mode ( ) = = PreviousMode : : KernelMode ) {
2020-08-02 02:04:56 +00:00
+ + m_process - > m_ticks_in_kernel ;
2020-12-04 05:12:50 +00:00
+ + m_ticks_in_kernel ;
} else {
+ + m_process - > m_ticks_in_user ;
+ + m_ticks_in_user ;
}
2021-11-06 21:06:08 +00:00
- - m_ticks_left ;
return m_ticks_left ! = 0 ;
2019-03-23 21:03:17 +00:00
}
2020-12-08 04:29:41 +00:00
void Thread : : check_dispatch_pending_signal ( )
{
auto result = DispatchSignalResult : : Continue ;
{
2021-08-21 23:49:22 +00:00
SpinlockLocker scheduler_lock ( g_scheduler_lock ) ;
2021-11-06 21:06:08 +00:00
if ( pending_signals_for_state ( ) ! = 0 ) {
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( m_lock ) ;
2020-12-08 04:29:41 +00:00
result = dispatch_one_pending_signal ( ) ;
}
}
2021-08-22 08:44:43 +00:00
if ( result = = DispatchSignalResult : : Yield ) {
2021-08-10 19:20:45 +00:00
yield_without_releasing_big_lock ( ) ;
2020-12-08 04:29:41 +00:00
}
}
2020-09-09 02:37:15 +00:00
u32 Thread : : pending_signals ( ) const
{
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2020-11-29 23:05:27 +00:00
return pending_signals_for_state ( ) ;
}
u32 Thread : : pending_signals_for_state ( ) const
{
2021-08-29 18:10:24 +00:00
VERIFY ( g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
2020-11-29 23:05:27 +00:00
constexpr u32 stopped_signal_mask = ( 1 < < ( SIGCONT - 1 ) ) | ( 1 < < ( SIGKILL - 1 ) ) | ( 1 < < ( SIGTRAP - 1 ) ) ;
2021-01-20 23:06:19 +00:00
if ( is_handling_page_fault ( ) )
return 0 ;
2020-11-29 23:05:27 +00:00
return m_state ! = Stopped ? m_pending_signals : m_pending_signals & stopped_signal_mask ;
2020-09-09 02:37:15 +00:00
}
2020-02-01 09:27:25 +00:00
void Thread : : send_signal ( u8 signal , [[maybe_unused]] Process * sender )
2019-03-23 21:03:17 +00:00
{
2021-02-23 19:42:32 +00:00
VERIFY ( signal < 32 ) ;
2021-08-21 23:49:22 +00:00
SpinlockLocker scheduler_lock ( g_scheduler_lock ) ;
2019-07-08 16:59:48 +00:00
// FIXME: Figure out what to do for masked signals. Should we also ignore them here?
if ( should_ignore_signal ( signal ) ) {
2021-02-07 12:03:24 +00:00
dbgln_if ( SIGNAL_DEBUG , " Signal {} was ignored by {} " , signal , process ( ) ) ;
2019-07-08 16:59:48 +00:00
return ;
}
2019-03-23 21:03:17 +00:00
2021-01-23 22:59:27 +00:00
if constexpr ( SIGNAL_DEBUG ) {
2021-01-12 21:30:52 +00:00
if ( sender )
dbgln ( " Signal: {} sent {} to {} " , * sender , signal , process ( ) ) ;
else
dbgln ( " Signal: Kernel send {} to {} " , signal , process ( ) ) ;
}
2019-03-23 21:03:17 +00:00
2019-08-01 09:00:36 +00:00
m_pending_signals | = 1 < < ( signal - 1 ) ;
2021-11-06 21:06:08 +00:00
m_have_any_unmasked_pending_signals . store ( ( pending_signals_for_state ( ) & ~ m_signal_mask ) ! = 0 , AK : : memory_order_release ) ;
2021-12-11 23:01:42 +00:00
m_signal_blocker_set . unblock_all_blockers_whose_conditions_are_met ( ) ;
2020-11-29 23:05:27 +00:00
2021-12-11 20:37:56 +00:00
if ( ! has_unmasked_pending_signals ( ) )
return ;
2020-11-29 23:05:27 +00:00
if ( m_state = = Stopped ) {
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( m_lock ) ;
2021-11-06 21:06:08 +00:00
if ( pending_signals_for_state ( ) ! = 0 ) {
2021-02-07 12:03:24 +00:00
dbgln_if ( SIGNAL_DEBUG , " Signal: Resuming stopped {} to deliver signal {} " , * this , signal ) ;
2020-11-29 23:05:27 +00:00
resume_from_stopped ( ) ;
2020-12-08 04:29:41 +00:00
}
2020-11-29 23:05:27 +00:00
} else {
2021-08-21 23:49:22 +00:00
SpinlockLocker block_lock ( m_block_lock ) ;
2021-02-07 12:03:24 +00:00
dbgln_if ( SIGNAL_DEBUG , " Signal: Unblocking {} to deliver signal {} " , * this , signal ) ;
2020-11-29 23:05:27 +00:00
unblock ( signal ) ;
}
2019-03-23 21:03:17 +00:00
}
2020-09-09 02:37:15 +00:00
u32 Thread : : update_signal_mask ( u32 signal_mask )
{
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2020-09-09 02:37:15 +00:00
auto previous_signal_mask = m_signal_mask ;
m_signal_mask = signal_mask ;
2021-11-06 21:06:08 +00:00
m_have_any_unmasked_pending_signals . store ( ( pending_signals_for_state ( ) & ~ m_signal_mask ) ! = 0 , AK : : memory_order_release ) ;
2020-09-09 02:37:15 +00:00
return previous_signal_mask ;
}
u32 Thread : : signal_mask ( ) const
{
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2020-09-09 02:37:15 +00:00
return m_signal_mask ;
}
u32 Thread : : signal_mask_block ( sigset_t signal_set , bool block )
{
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2020-09-09 02:37:15 +00:00
auto previous_signal_mask = m_signal_mask ;
if ( block )
m_signal_mask | = signal_set ;
2021-12-11 22:08:57 +00:00
else
m_signal_mask & = ~ signal_set ;
2021-11-06 21:06:08 +00:00
m_have_any_unmasked_pending_signals . store ( ( pending_signals_for_state ( ) & ~ m_signal_mask ) ! = 0 , AK : : memory_order_release ) ;
2020-09-09 02:37:15 +00:00
return previous_signal_mask ;
}
2021-12-11 15:40:50 +00:00
void Thread : : reset_signals_for_exec ( )
2020-09-09 02:37:15 +00:00
{
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2021-12-11 15:18:39 +00:00
// The signal mask is preserved across execve(2).
2021-12-11 15:40:50 +00:00
// The pending signal set is preserved across an execve(2).
2020-09-09 02:37:15 +00:00
m_have_any_unmasked_pending_signals . store ( false , AK : : memory_order_release ) ;
2021-02-21 10:59:53 +00:00
m_signal_action_data . fill ( { } ) ;
2021-12-11 15:39:52 +00:00
// A successful call to execve(2) removes any existing alternate signal stack
m_alternative_signal_stack = 0 ;
m_alternative_signal_stack_size = 0 ;
2020-09-09 02:37:15 +00:00
}
2019-10-07 09:22:50 +00:00
// Certain exceptions, such as SIGSEGV and SIGILL, put a
// thread into a state where the signal handler must be
// invoked immediately, otherwise it will continue to fault.
// This function should be used in an exception handler to
// ensure that when the thread resumes, it's executing in
// the appropriate signal handler.
void Thread : : send_urgent_signal_to_self ( u8 signal )
{
2021-02-23 19:42:32 +00:00
VERIFY ( Thread : : current ( ) = = this ) ;
2020-11-29 23:05:27 +00:00
DispatchSignalResult result ;
{
2021-08-21 23:49:22 +00:00
SpinlockLocker lock ( g_scheduler_lock ) ;
2020-11-29 23:05:27 +00:00
result = dispatch_signal ( signal ) ;
}
2021-12-06 17:33:19 +00:00
if ( result = = DispatchSignalResult : : Terminate ) {
Thread : : current ( ) - > die_if_needed ( ) ;
VERIFY_NOT_REACHED ( ) ; // dispatch_signal will request termination of the thread, so the above call should never return
}
2020-11-29 23:05:27 +00:00
if ( result = = DispatchSignalResult : : Yield )
2021-07-16 01:45:22 +00:00
yield_and_release_relock_big_lock ( ) ;
2019-10-07 09:22:50 +00:00
}
2020-11-29 23:05:27 +00:00
DispatchSignalResult Thread : : dispatch_one_pending_signal ( )
2019-03-23 21:03:17 +00:00
{
2021-08-29 18:10:24 +00:00
VERIFY ( m_lock . is_locked_by_current_processor ( ) ) ;
2020-11-29 23:05:27 +00:00
u32 signal_candidates = pending_signals_for_state ( ) & ~ m_signal_mask ;
2020-12-01 15:05:49 +00:00
if ( signal_candidates = = 0 )
return DispatchSignalResult : : Continue ;
2019-03-23 21:03:17 +00:00
2019-08-01 09:00:36 +00:00
u8 signal = 1 ;
2019-03-23 21:03:17 +00:00
for ( ; signal < 32 ; + + signal ) {
2021-11-06 21:06:08 +00:00
if ( ( signal_candidates & ( 1 < < ( signal - 1 ) ) ) ! = 0 ) {
2019-03-23 21:03:17 +00:00
break ;
}
}
return dispatch_signal ( signal ) ;
}
2020-11-29 23:05:27 +00:00
DispatchSignalResult Thread : : try_dispatch_one_pending_signal ( u8 signal )
{
2021-02-23 19:42:32 +00:00
VERIFY ( signal ! = 0 ) ;
2021-08-21 23:49:22 +00:00
SpinlockLocker scheduler_lock ( g_scheduler_lock ) ;
SpinlockLocker lock ( m_lock ) ;
2020-11-29 23:05:27 +00:00
u32 signal_candidates = pending_signals_for_state ( ) & ~ m_signal_mask ;
2021-11-06 21:06:08 +00:00
if ( ( signal_candidates & ( 1 < < ( signal - 1 ) ) ) = = 0 )
2020-11-29 23:05:27 +00:00
return DispatchSignalResult : : Continue ;
return dispatch_signal ( signal ) ;
}
2019-06-07 15:13:23 +00:00
enum class DefaultSignalAction {
2019-03-23 21:03:17 +00:00
Terminate ,
Ignore ,
DumpCore ,
Stop ,
Continue ,
} ;
Kernel: Mark compilation-unit-only functions as static
This enables a nice warning in case a function becomes dead code. Also, in case
of signal_trampoline_dummy, marking it external (non-static) prevents it from
being 'optimized away', which would lead to surprising and weird linker errors.
I found these places by using -Wmissing-declarations.
The Kernel still shows these issues, which I think are false-positives,
but don't want to touch:
- Kernel/Arch/i386/CPU.cpp:1081:17: void Kernel::enter_thread_context(Kernel::Thread*, Kernel::Thread*)
- Kernel/Arch/i386/CPU.cpp:1170:17: void Kernel::context_first_init(Kernel::Thread*, Kernel::Thread*, Kernel::TrapFrame*)
- Kernel/Arch/i386/CPU.cpp:1304:16: u32 Kernel::do_init_context(Kernel::Thread*, u32)
- Kernel/Arch/i386/CPU.cpp:1347:17: void Kernel::pre_init_finished()
- Kernel/Arch/i386/CPU.cpp:1360:17: void Kernel::post_init_finished()
No idea, not gonna touch it.
- Kernel/init.cpp:104:30: void Kernel::init()
- Kernel/init.cpp:167:30: void Kernel::init_ap(u32, Kernel::Processor*)
- Kernel/init.cpp:184:17: void Kernel::init_finished(u32)
Called by boot.S.
- Kernel/init.cpp:383:16: int Kernel::__cxa_atexit(void (*)(void*), void*, void*)
- Kernel/StdLib.cpp:285:19: void __cxa_pure_virtual()
- Kernel/StdLib.cpp:300:19: void __stack_chk_fail()
- Kernel/StdLib.cpp:305:19: void __stack_chk_fail_local()
Not sure how to tell the compiler that the compiler is already using them.
Also, maybe __cxa_atexit should go into StdLib.cpp?
- Kernel/Modules/TestModule.cpp:31:17: void module_init()
- Kernel/Modules/TestModule.cpp:40:17: void module_fini()
Could maybe go into a new header. This would also provide type-checking for new modules.
2020-08-10 19:12:13 +00:00
static DefaultSignalAction default_signal_action ( u8 signal )
2019-03-23 21:03:17 +00:00
{
2021-02-23 19:42:32 +00:00
VERIFY ( signal & & signal < NSIG ) ;
2019-03-23 21:03:17 +00:00
switch ( signal ) {
case SIGHUP :
case SIGINT :
case SIGKILL :
case SIGPIPE :
case SIGALRM :
case SIGUSR1 :
case SIGUSR2 :
case SIGVTALRM :
case SIGSTKFLT :
case SIGIO :
case SIGPROF :
case SIGTERM :
return DefaultSignalAction : : Terminate ;
case SIGCHLD :
case SIGURG :
case SIGWINCH :
2020-09-08 16:07:25 +00:00
case SIGINFO :
2019-03-23 21:03:17 +00:00
return DefaultSignalAction : : Ignore ;
case SIGQUIT :
case SIGILL :
case SIGTRAP :
case SIGABRT :
case SIGBUS :
case SIGFPE :
case SIGSEGV :
case SIGXCPU :
case SIGXFSZ :
case SIGSYS :
return DefaultSignalAction : : DumpCore ;
case SIGCONT :
return DefaultSignalAction : : Continue ;
case SIGSTOP :
case SIGTSTP :
case SIGTTIN :
case SIGTTOU :
return DefaultSignalAction : : Stop ;
2021-08-22 08:44:43 +00:00
default :
VERIFY_NOT_REACHED ( ) ;
2019-03-23 21:03:17 +00:00
}
}
2019-07-08 16:59:48 +00:00
bool Thread : : should_ignore_signal ( u8 signal ) const
{
2021-02-23 19:42:32 +00:00
VERIFY ( signal < 32 ) ;
2021-10-31 22:36:52 +00:00
auto const & action = m_signal_action_data [ signal ] ;
2019-07-08 16:59:48 +00:00
if ( action . handler_or_sigaction . is_null ( ) )
return default_signal_action ( signal ) = = DefaultSignalAction : : Ignore ;
2021-10-31 22:52:43 +00:00
return ( ( sighandler_t ) action . handler_or_sigaction . get ( ) = = SIG_IGN ) ;
2019-07-08 16:59:48 +00:00
}
2019-10-07 09:22:50 +00:00
bool Thread : : has_signal_handler ( u8 signal ) const
{
2021-02-23 19:42:32 +00:00
VERIFY ( signal < 32 ) ;
2021-10-31 22:36:52 +00:00
auto const & action = m_signal_action_data [ signal ] ;
2019-10-07 09:22:50 +00:00
return ! action . handler_or_sigaction . is_null ( ) ;
}
2021-11-29 23:07:59 +00:00
bool Thread : : is_signal_masked ( u8 signal ) const
{
VERIFY ( signal < 32 ) ;
return ( 1 < < ( signal - 1 ) ) & m_signal_mask ;
}
2021-10-28 20:33:41 +00:00
bool Thread : : has_alternative_signal_stack ( ) const
{
return m_alternative_signal_stack_size ! = 0 ;
}
bool Thread : : is_in_alternative_signal_stack ( ) const
{
auto sp = get_register_dump_from_stack ( ) . userspace_sp ( ) ;
return sp > = m_alternative_signal_stack & & sp < m_alternative_signal_stack + m_alternative_signal_stack_size ;
}
2021-11-29 23:21:03 +00:00
static ErrorOr < void > push_value_on_user_stack ( FlatPtr & stack , FlatPtr data )
2019-11-04 08:29:47 +00:00
{
Kernel: Fix UB caused by taking a reference to a packed struct's member
Taking a reference or a pointer to a value that's not aligned properly
is undefined behavior. While `[[gnu::packed]]` ensures that reads from
and writes to fields of packed structs is a safe operation, the
information about the reduced alignment is lost when creating pointers
to these values.
Weirdly enough, GCC's undefined behavior sanitizer doesn't flag these,
even though the doc of `-Waddress-of-packed-member` says that it usually
leads to UB. In contrast, x86_64 Clang does flag these, which renders
the 64-bit kernel unable to boot.
For now, the `address-of-packed-member` warning will only be enabled in
the kernel, as it is absolutely crucial there because of KUBSAN, but
might get excessively noisy for the userland in the future.
Also note that we can't append to `CMAKE_CXX_FLAGS` like we do for other
flags in the kernel, because flags added via `add_compile_options` come
after these, so the `-Wno-address-of-packed-member` in the root would
cancel it out.
2021-08-01 18:30:43 +00:00
stack - = sizeof ( FlatPtr ) ;
2021-11-29 23:21:03 +00:00
return copy_to_user ( ( FlatPtr * ) stack , & data ) ;
2019-11-04 08:29:47 +00:00
}
2020-08-14 16:24:31 +00:00
void Thread : : resume_from_stopped ( )
{
2021-02-23 19:42:32 +00:00
VERIFY ( is_stopped ( ) ) ;
VERIFY ( m_stop_state ! = State : : Invalid ) ;
2021-08-29 18:10:24 +00:00
VERIFY ( g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
2020-12-09 04:18:45 +00:00
if ( m_stop_state = = Blocked ) {
2021-08-21 23:49:22 +00:00
SpinlockLocker block_lock ( m_block_lock ) ;
2021-07-10 16:23:16 +00:00
if ( m_blocker | | m_blocking_lock ) {
2020-12-09 04:18:45 +00:00
// Hasn't been unblocked yet
set_state ( Blocked , 0 ) ;
} else {
// Was unblocked while stopped
set_state ( Runnable ) ;
}
} else {
set_state ( m_stop_state , 0 ) ;
}
2020-08-14 16:24:31 +00:00
}
2020-11-29 23:05:27 +00:00
DispatchSignalResult Thread : : dispatch_signal ( u8 signal )
2019-03-23 21:03:17 +00:00
{
2021-02-23 19:42:32 +00:00
VERIFY_INTERRUPTS_DISABLED ( ) ;
2021-08-29 18:10:24 +00:00
VERIFY ( g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
2021-02-23 19:42:32 +00:00
VERIFY ( signal > 0 & & signal < = 32 ) ;
VERIFY ( process ( ) . is_user_process ( ) ) ;
VERIFY ( this = = Thread : : current ( ) ) ;
2019-03-23 21:03:17 +00:00
2021-03-09 21:35:13 +00:00
dbgln_if ( SIGNAL_DEBUG , " Dispatch signal {} to {}, state: {} " , signal , * this , state_string ( ) ) ;
2019-03-23 21:03:17 +00:00
2020-09-07 14:31:00 +00:00
if ( m_state = = Invalid | | ! is_initialized ( ) ) {
// Thread has barely been created, we need to wait until it is
// at least in Runnable state and is_initialized() returns true,
// which indicates that it is fully set up an we actually have
// a register state on the stack that we can modify
2020-11-29 23:05:27 +00:00
return DispatchSignalResult : : Deferred ;
}
2021-02-23 19:42:32 +00:00
VERIFY ( previous_mode ( ) = = PreviousMode : : UserMode ) ;
2021-01-25 20:19:34 +00:00
2019-03-23 21:03:17 +00:00
auto & action = m_signal_action_data [ signal ] ;
// FIXME: Implement SA_SIGINFO signal handlers.
2021-02-23 19:42:32 +00:00
VERIFY ( ! ( action . flags & SA_SIGINFO ) ) ;
2019-03-23 21:03:17 +00:00
// Mark this signal as handled.
2019-08-01 09:00:36 +00:00
m_pending_signals & = ~ ( 1 < < ( signal - 1 ) ) ;
2021-11-06 21:06:08 +00:00
m_have_any_unmasked_pending_signals . store ( ( m_pending_signals & ~ m_signal_mask ) ! = 0 , AK : : memory_order_release ) ;
2019-03-23 21:03:17 +00:00
2020-12-09 04:18:45 +00:00
auto & process = this - > process ( ) ;
2021-10-31 22:36:52 +00:00
auto * tracer = process . tracer ( ) ;
2020-12-09 04:18:45 +00:00
if ( signal = = SIGSTOP | | ( tracer & & default_signal_action ( signal ) = = DefaultSignalAction : : DumpCore ) ) {
2021-03-09 21:35:13 +00:00
dbgln_if ( SIGNAL_DEBUG , " Signal {} stopping this thread " , signal ) ;
2020-12-09 04:18:45 +00:00
set_state ( State : : Stopped , signal ) ;
2020-11-29 23:05:27 +00:00
return DispatchSignalResult : : Yield ;
2019-03-23 21:03:17 +00:00
}
2020-12-08 04:29:41 +00:00
if ( signal = = SIGCONT ) {
2021-01-12 21:30:52 +00:00
dbgln ( " signal: SIGCONT resuming {} " , * this ) ;
2020-08-14 16:24:31 +00:00
} else {
2020-12-09 04:18:45 +00:00
if ( tracer ) {
2020-03-28 08:47:16 +00:00
// when a thread is traced, it should be stopped whenever it receives a signal
// the tracer is notified of this by using waitpid()
// only "pending signals" from the tracer are sent to the tracee
2020-12-09 04:18:45 +00:00
if ( ! tracer - > has_pending_signal ( signal ) ) {
2021-01-12 21:30:52 +00:00
dbgln ( " signal: {} stopping {} for tracer " , signal , * this ) ;
2020-12-09 04:18:45 +00:00
set_state ( Stopped , signal ) ;
2020-11-29 23:05:27 +00:00
return DispatchSignalResult : : Yield ;
2020-03-28 08:47:16 +00:00
}
2020-12-09 04:18:45 +00:00
tracer - > unset_signal ( signal ) ;
2020-03-28 08:47:16 +00:00
}
2020-03-01 14:14:17 +00:00
}
2019-03-23 21:03:17 +00:00
2019-06-07 10:56:50 +00:00
auto handler_vaddr = action . handler_or_sigaction ;
if ( handler_vaddr . is_null ( ) ) {
2019-03-23 21:03:17 +00:00
switch ( default_signal_action ( signal ) ) {
case DefaultSignalAction : : Stop :
2020-12-09 04:18:45 +00:00
set_state ( Stopped , signal ) ;
2020-11-29 23:05:27 +00:00
return DispatchSignalResult : : Yield ;
2019-08-06 17:43:07 +00:00
case DefaultSignalAction : : DumpCore :
2021-08-22 12:51:04 +00:00
process . set_should_generate_coredump ( true ) ;
2020-12-09 04:18:45 +00:00
process . for_each_thread ( [ ] ( auto & thread ) {
2019-08-06 17:43:07 +00:00
thread . set_dump_backtrace_on_finalization ( ) ;
} ) ;
2019-07-25 19:02:19 +00:00
[[fallthrough]] ;
2019-03-23 21:03:17 +00:00
case DefaultSignalAction : : Terminate :
2020-08-02 02:04:56 +00:00
m_process - > terminate_due_to_signal ( signal ) ;
2020-11-29 23:05:27 +00:00
return DispatchSignalResult : : Terminate ;
2019-03-23 21:03:17 +00:00
case DefaultSignalAction : : Ignore :
2021-02-23 19:42:32 +00:00
VERIFY_NOT_REACHED ( ) ;
2019-03-23 21:03:17 +00:00
case DefaultSignalAction : : Continue :
2020-11-29 23:05:27 +00:00
return DispatchSignalResult : : Continue ;
2019-03-23 21:03:17 +00:00
}
2021-02-23 19:42:32 +00:00
VERIFY_NOT_REACHED ( ) ;
2019-03-23 21:03:17 +00:00
}
2021-08-14 15:05:53 +00:00
if ( ( sighandler_t ) handler_vaddr . as_ptr ( ) = = SIG_IGN ) {
2021-03-09 21:35:13 +00:00
dbgln_if ( SIGNAL_DEBUG , " Ignored signal {} " , signal ) ;
2020-11-29 23:05:27 +00:00
return DispatchSignalResult : : Continue ;
2019-03-23 21:03:17 +00:00
}
2021-02-23 19:42:32 +00:00
VERIFY ( previous_mode ( ) = = PreviousMode : : UserMode ) ;
VERIFY ( current_trap ( ) ) ;
2021-01-25 20:19:34 +00:00
2021-09-06 15:22:36 +00:00
ScopedAddressSpaceSwitcher switcher ( m_process ) ;
2019-09-04 13:14:54 +00:00
2019-07-03 19:17:35 +00:00
u32 old_signal_mask = m_signal_mask ;
u32 new_signal_mask = action . mask ;
2021-11-06 21:06:08 +00:00
if ( ( action . flags & SA_NODEFER ) = = SA_NODEFER )
2019-08-01 09:00:36 +00:00
new_signal_mask & = ~ ( 1 < < ( signal - 1 ) ) ;
2019-03-23 21:03:17 +00:00
else
2019-08-01 09:00:36 +00:00
new_signal_mask | = 1 < < ( signal - 1 ) ;
2019-03-23 21:03:17 +00:00
m_signal_mask | = new_signal_mask ;
2021-11-06 21:06:08 +00:00
m_have_any_unmasked_pending_signals . store ( ( m_pending_signals & ~ m_signal_mask ) ! = 0 , AK : : memory_order_release ) ;
2019-03-23 21:03:17 +00:00
2021-10-28 20:33:41 +00:00
bool use_alternative_stack = ( ( action . flags & SA_ONSTACK ) ! = 0 ) & & has_alternative_signal_stack ( ) & & ! is_in_alternative_signal_stack ( ) ;
2021-11-29 23:21:03 +00:00
auto setup_stack = [ & ] ( RegisterState & state ) - > ErrorOr < void > {
2021-10-28 20:33:41 +00:00
FlatPtr old_sp = state . userspace_sp ( ) ;
FlatPtr stack ;
if ( use_alternative_stack )
stack = m_alternative_signal_stack + m_alternative_signal_stack_size ;
else
stack = old_sp ;
2021-08-19 19:53:53 +00:00
FlatPtr ret_ip = state . ip ( ) ;
FlatPtr ret_flags = state . flags ( ) ;
dbgln_if ( SIGNAL_DEBUG , " Setting up user stack to return to IP {:p}, SP {:p} " , ret_ip , old_sp ) ;
2019-11-04 08:29:47 +00:00
2021-02-25 15:18:36 +00:00
# if ARCH(I386)
2019-11-04 08:29:47 +00:00
// Align the stack to 16 bytes.
Kernel: Properly align stack for signal handlers
The System V ABI requires that the stack is 16-byte aligned on function
call. Confusingly, however, they mean that the stack must be aligned
this way **before** the `CALL` instruction is executed. That instruction
pushes the return value onto the stack, so the callee will actually see
the stack pointer as a value `sizeof(FlatPtr)` smaller.
The signal trampoline was written with this in mind, but `setup_stack`
aligned the entire stack, *including the return address* to a 16-byte
boundary. Because of this, the trampoline subtracted too much from the
stack pointer, thus misaligning it.
This was not a problem on i686 because we didn't execute any
instructions from signal handlers that would require memory operands to
be aligned to more than 4 bytes. This is not the case, however, on
x86_64, where SSE instructions are enabled by default and they require
16-byte aligned operands. Running such instructions raised a GP fault,
immediately killing the offending program with a SIGSEGV signal.
This issue caused TestKernelAlarm to fail in LibC when ran locally, and
at one point, the zsh port was affected too.
Fixes #9291
2021-10-24 15:34:59 +00:00
// Note that we push 52 bytes (4 * 13) on to the stack
// before the return address, so we need to account for this here.
// 56 % 16 = 4, so we only need to take 4 bytes into consideration for
2021-07-01 22:57:48 +00:00
// the stack alignment.
Kernel: Properly align stack for signal handlers
The System V ABI requires that the stack is 16-byte aligned on function
call. Confusingly, however, they mean that the stack must be aligned
this way **before** the `CALL` instruction is executed. That instruction
pushes the return value onto the stack, so the callee will actually see
the stack pointer as a value `sizeof(FlatPtr)` smaller.
The signal trampoline was written with this in mind, but `setup_stack`
aligned the entire stack, *including the return address* to a 16-byte
boundary. Because of this, the trampoline subtracted too much from the
stack pointer, thus misaligning it.
This was not a problem on i686 because we didn't execute any
instructions from signal handlers that would require memory operands to
be aligned to more than 4 bytes. This is not the case, however, on
x86_64, where SSE instructions are enabled by default and they require
16-byte aligned operands. Running such instructions raised a GP fault,
immediately killing the offending program with a SIGSEGV signal.
This issue caused TestKernelAlarm to fail in LibC when ran locally, and
at one point, the zsh port was affected too.
Fixes #9291
2021-10-24 15:34:59 +00:00
FlatPtr stack_alignment = ( stack - 4 ) % 16 ;
Kernel: Fix UB caused by taking a reference to a packed struct's member
Taking a reference or a pointer to a value that's not aligned properly
is undefined behavior. While `[[gnu::packed]]` ensures that reads from
and writes to fields of packed structs is a safe operation, the
information about the reduced alignment is lost when creating pointers
to these values.
Weirdly enough, GCC's undefined behavior sanitizer doesn't flag these,
even though the doc of `-Waddress-of-packed-member` says that it usually
leads to UB. In contrast, x86_64 Clang does flag these, which renders
the 64-bit kernel unable to boot.
For now, the `address-of-packed-member` warning will only be enabled in
the kernel, as it is absolutely crucial there because of KUBSAN, but
might get excessively noisy for the userland in the future.
Also note that we can't append to `CMAKE_CXX_FLAGS` like we do for other
flags in the kernel, because flags added via `add_compile_options` come
after these, so the `-Wno-address-of-packed-member` in the root would
cancel it out.
2021-08-01 18:30:43 +00:00
stack - = stack_alignment ;
2019-11-04 08:29:47 +00:00
2021-11-29 23:21:03 +00:00
TRY ( push_value_on_user_stack ( stack , ret_flags ) ) ;
TRY ( push_value_on_user_stack ( stack , ret_ip ) ) ;
TRY ( push_value_on_user_stack ( stack , state . eax ) ) ;
TRY ( push_value_on_user_stack ( stack , state . ecx ) ) ;
TRY ( push_value_on_user_stack ( stack , state . edx ) ) ;
TRY ( push_value_on_user_stack ( stack , state . ebx ) ) ;
TRY ( push_value_on_user_stack ( stack , old_sp ) ) ;
TRY ( push_value_on_user_stack ( stack , state . ebp ) ) ;
TRY ( push_value_on_user_stack ( stack , state . esi ) ) ;
TRY ( push_value_on_user_stack ( stack , state . edi ) ) ;
2021-06-23 19:54:41 +00:00
# else
2021-06-29 08:31:25 +00:00
// Align the stack to 16 bytes.
Kernel: Properly align stack for signal handlers
The System V ABI requires that the stack is 16-byte aligned on function
call. Confusingly, however, they mean that the stack must be aligned
this way **before** the `CALL` instruction is executed. That instruction
pushes the return value onto the stack, so the callee will actually see
the stack pointer as a value `sizeof(FlatPtr)` smaller.
The signal trampoline was written with this in mind, but `setup_stack`
aligned the entire stack, *including the return address* to a 16-byte
boundary. Because of this, the trampoline subtracted too much from the
stack pointer, thus misaligning it.
This was not a problem on i686 because we didn't execute any
instructions from signal handlers that would require memory operands to
be aligned to more than 4 bytes. This is not the case, however, on
x86_64, where SSE instructions are enabled by default and they require
16-byte aligned operands. Running such instructions raised a GP fault,
immediately killing the offending program with a SIGSEGV signal.
This issue caused TestKernelAlarm to fail in LibC when ran locally, and
at one point, the zsh port was affected too.
Fixes #9291
2021-10-24 15:34:59 +00:00
// Note that we push 168 bytes (8 * 21) on to the stack
// before the return address, so we need to account for this here.
// 168 % 16 = 8, so we only need to take 8 bytes into consideration for
// the stack alignment.
2021-07-01 22:57:48 +00:00
// We also are not allowed to touch the thread's red-zone of 128 bytes
Kernel: Properly align stack for signal handlers
The System V ABI requires that the stack is 16-byte aligned on function
call. Confusingly, however, they mean that the stack must be aligned
this way **before** the `CALL` instruction is executed. That instruction
pushes the return value onto the stack, so the callee will actually see
the stack pointer as a value `sizeof(FlatPtr)` smaller.
The signal trampoline was written with this in mind, but `setup_stack`
aligned the entire stack, *including the return address* to a 16-byte
boundary. Because of this, the trampoline subtracted too much from the
stack pointer, thus misaligning it.
This was not a problem on i686 because we didn't execute any
instructions from signal handlers that would require memory operands to
be aligned to more than 4 bytes. This is not the case, however, on
x86_64, where SSE instructions are enabled by default and they require
16-byte aligned operands. Running such instructions raised a GP fault,
immediately killing the offending program with a SIGSEGV signal.
This issue caused TestKernelAlarm to fail in LibC when ran locally, and
at one point, the zsh port was affected too.
Fixes #9291
2021-10-24 15:34:59 +00:00
FlatPtr stack_alignment = ( stack - 8 ) % 16 ;
Kernel: Fix UB caused by taking a reference to a packed struct's member
Taking a reference or a pointer to a value that's not aligned properly
is undefined behavior. While `[[gnu::packed]]` ensures that reads from
and writes to fields of packed structs is a safe operation, the
information about the reduced alignment is lost when creating pointers
to these values.
Weirdly enough, GCC's undefined behavior sanitizer doesn't flag these,
even though the doc of `-Waddress-of-packed-member` says that it usually
leads to UB. In contrast, x86_64 Clang does flag these, which renders
the 64-bit kernel unable to boot.
For now, the `address-of-packed-member` warning will only be enabled in
the kernel, as it is absolutely crucial there because of KUBSAN, but
might get excessively noisy for the userland in the future.
Also note that we can't append to `CMAKE_CXX_FLAGS` like we do for other
flags in the kernel, because flags added via `add_compile_options` come
after these, so the `-Wno-address-of-packed-member` in the root would
cancel it out.
2021-08-01 18:30:43 +00:00
stack - = 128 + stack_alignment ;
2021-06-29 08:31:25 +00:00
2021-11-29 23:21:03 +00:00
TRY ( push_value_on_user_stack ( stack , ret_flags ) ) ;
TRY ( push_value_on_user_stack ( stack , ret_ip ) ) ;
TRY ( push_value_on_user_stack ( stack , state . r15 ) ) ;
TRY ( push_value_on_user_stack ( stack , state . r14 ) ) ;
TRY ( push_value_on_user_stack ( stack , state . r13 ) ) ;
TRY ( push_value_on_user_stack ( stack , state . r12 ) ) ;
TRY ( push_value_on_user_stack ( stack , state . r11 ) ) ;
TRY ( push_value_on_user_stack ( stack , state . r10 ) ) ;
TRY ( push_value_on_user_stack ( stack , state . r9 ) ) ;
TRY ( push_value_on_user_stack ( stack , state . r8 ) ) ;
TRY ( push_value_on_user_stack ( stack , state . rax ) ) ;
TRY ( push_value_on_user_stack ( stack , state . rcx ) ) ;
TRY ( push_value_on_user_stack ( stack , state . rdx ) ) ;
TRY ( push_value_on_user_stack ( stack , state . rbx ) ) ;
TRY ( push_value_on_user_stack ( stack , old_sp ) ) ;
TRY ( push_value_on_user_stack ( stack , state . rbp ) ) ;
TRY ( push_value_on_user_stack ( stack , state . rsi ) ) ;
TRY ( push_value_on_user_stack ( stack , state . rdi ) ) ;
2021-02-25 15:18:36 +00:00
# endif
2019-11-04 08:29:47 +00:00
// PUSH old_signal_mask
2021-11-29 23:21:03 +00:00
TRY ( push_value_on_user_stack ( stack , old_signal_mask ) ) ;
2019-11-04 08:29:47 +00:00
2021-11-29 23:21:03 +00:00
TRY ( push_value_on_user_stack ( stack , signal ) ) ;
TRY ( push_value_on_user_stack ( stack , handler_vaddr . get ( ) ) ) ;
Kernel: Properly align stack for signal handlers
The System V ABI requires that the stack is 16-byte aligned on function
call. Confusingly, however, they mean that the stack must be aligned
this way **before** the `CALL` instruction is executed. That instruction
pushes the return value onto the stack, so the callee will actually see
the stack pointer as a value `sizeof(FlatPtr)` smaller.
The signal trampoline was written with this in mind, but `setup_stack`
aligned the entire stack, *including the return address* to a 16-byte
boundary. Because of this, the trampoline subtracted too much from the
stack pointer, thus misaligning it.
This was not a problem on i686 because we didn't execute any
instructions from signal handlers that would require memory operands to
be aligned to more than 4 bytes. This is not the case, however, on
x86_64, where SSE instructions are enabled by default and they require
16-byte aligned operands. Running such instructions raised a GP fault,
immediately killing the offending program with a SIGSEGV signal.
This issue caused TestKernelAlarm to fail in LibC when ran locally, and
at one point, the zsh port was affected too.
Fixes #9291
2021-10-24 15:34:59 +00:00
VERIFY ( ( stack % 16 ) = = 0 ) ;
2021-11-29 23:21:03 +00:00
TRY ( push_value_on_user_stack ( stack , 0 ) ) ; // push fake return address
2019-11-04 08:29:47 +00:00
Kernel: Fix UB caused by taking a reference to a packed struct's member
Taking a reference or a pointer to a value that's not aligned properly
is undefined behavior. While `[[gnu::packed]]` ensures that reads from
and writes to fields of packed structs is a safe operation, the
information about the reduced alignment is lost when creating pointers
to these values.
Weirdly enough, GCC's undefined behavior sanitizer doesn't flag these,
even though the doc of `-Waddress-of-packed-member` says that it usually
leads to UB. In contrast, x86_64 Clang does flag these, which renders
the 64-bit kernel unable to boot.
For now, the `address-of-packed-member` warning will only be enabled in
the kernel, as it is absolutely crucial there because of KUBSAN, but
might get excessively noisy for the userland in the future.
Also note that we can't append to `CMAKE_CXX_FLAGS` like we do for other
flags in the kernel, because flags added via `add_compile_options` come
after these, so the `-Wno-address-of-packed-member` in the root would
cancel it out.
2021-08-01 18:30:43 +00:00
// We write back the adjusted stack value into the register state.
// We have to do this because we can't just pass around a reference to a packed field, as it's UB.
2021-08-19 19:53:53 +00:00
state . set_userspace_sp ( stack ) ;
2021-11-29 23:21:03 +00:00
return { } ;
2019-11-04 08:29:47 +00:00
} ;
// We now place the thread state on the userspace stack.
2020-08-02 18:08:22 +00:00
// Note that we use a RegisterState.
2020-02-15 23:15:37 +00:00
// Conversely, when the thread isn't blocking the RegisterState may not be
2019-11-04 08:29:47 +00:00
// valid (fork, exec etc) but the tss will, so we use that instead.
2020-08-02 18:08:22 +00:00
auto & regs = get_register_dump_from_stack ( ) ;
2021-11-29 23:21:03 +00:00
auto result = setup_stack ( regs ) ;
if ( result . is_error ( ) ) {
dbgln ( " Invalid stack pointer: {} " , regs . userspace_sp ( ) ) ;
process . set_should_generate_coredump ( true ) ;
process . for_each_thread ( [ ] ( auto & thread ) {
thread . set_dump_backtrace_on_finalization ( ) ;
} ) ;
m_process - > terminate_due_to_signal ( signal ) ;
return DispatchSignalResult : : Terminate ;
}
2021-06-26 12:56:28 +00:00
auto signal_trampoline_addr = process . signal_trampoline ( ) . get ( ) ;
2021-08-19 19:53:53 +00:00
regs . set_ip ( signal_trampoline_addr ) ;
2019-03-23 21:03:17 +00:00
2021-07-21 17:53:38 +00:00
dbgln_if ( SIGNAL_DEBUG , " Thread in state '{}' has been primed with signal handler {:#04x}:{:p} to deliver {} " , state_string ( ) , m_regs . cs , m_regs . ip ( ) , signal ) ;
2021-06-23 19:54:41 +00:00
2020-11-29 23:05:27 +00:00
return DispatchSignalResult : : Continue ;
2019-03-23 21:03:17 +00:00
}
2020-02-15 23:15:37 +00:00
RegisterState & Thread : : get_register_dump_from_stack ( )
2019-11-02 09:11:41 +00:00
{
2021-01-25 20:19:34 +00:00
auto * trap = current_trap ( ) ;
// We should *always* have a trap. If we don't we're probably a kernel
2021-08-22 08:44:43 +00:00
// thread that hasn't been preempted. If we want to support this, we
2021-06-29 08:31:25 +00:00
// need to capture the registers probably into m_regs and return it
2021-02-23 19:42:32 +00:00
VERIFY ( trap ) ;
2021-01-25 20:19:34 +00:00
while ( trap ) {
if ( ! trap - > next_trap )
break ;
trap = trap - > next_trap ;
}
return * trap - > regs ;
2019-11-02 09:11:41 +00:00
}
2021-11-07 23:51:39 +00:00
ErrorOr < NonnullRefPtr < Thread > > Thread : : try_clone ( Process & process )
2019-03-23 21:03:17 +00:00
{
2021-09-05 12:06:42 +00:00
auto clone = TRY ( Thread : : try_create ( process ) ) ;
2021-02-21 10:59:53 +00:00
auto signal_action_data_span = m_signal_action_data . span ( ) ;
signal_action_data_span . copy_to ( clone - > m_signal_action_data . span ( ) ) ;
2019-03-23 21:03:17 +00:00
clone - > m_signal_mask = m_signal_mask ;
2021-08-05 20:29:38 +00:00
clone - > m_fpu_state = m_fpu_state ;
2019-09-07 13:50:44 +00:00
clone - > m_thread_specific_data = m_thread_specific_data ;
2019-03-23 21:03:17 +00:00
return clone ;
}
2020-12-09 04:18:45 +00:00
void Thread : : set_state ( State new_state , u8 stop_signal )
2019-05-18 18:07:00 +00:00
{
2020-12-09 04:18:45 +00:00
State previous_state ;
2021-08-29 18:10:24 +00:00
VERIFY ( g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
2019-12-01 14:54:47 +00:00
if ( new_state = = m_state )
return ;
2020-12-09 04:18:45 +00:00
{
2021-08-21 23:49:22 +00:00
SpinlockLocker thread_lock ( m_lock ) ;
2020-12-09 04:18:45 +00:00
previous_state = m_state ;
if ( previous_state = = Invalid ) {
// If we were *just* created, we may have already pending signals
if ( has_unmasked_pending_signals ( ) ) {
2021-02-07 12:03:24 +00:00
dbgln_if ( THREAD_DEBUG , " Dispatch pending signals to new thread {} " , * this ) ;
2020-12-09 04:18:45 +00:00
dispatch_one_pending_signal ( ) ;
}
2020-09-07 14:31:00 +00:00
}
2020-12-09 04:18:45 +00:00
m_state = new_state ;
2021-02-07 12:03:24 +00:00
dbgln_if ( THREAD_DEBUG , " Set thread {} state to {} " , * this , state_string ( ) ) ;
2020-12-09 04:18:45 +00:00
}
2020-07-05 20:32:07 +00:00
2021-01-22 23:56:08 +00:00
if ( previous_state = = Runnable ) {
Scheduler : : dequeue_runnable_thread ( * this ) ;
} else if ( previous_state = = Stopped ) {
2020-11-29 23:05:27 +00:00
m_stop_state = State : : Invalid ;
2020-12-09 04:18:45 +00:00
auto & process = this - > process ( ) ;
2021-10-31 22:52:43 +00:00
if ( process . set_stopped ( false ) ) {
2020-12-09 04:18:45 +00:00
process . for_each_thread ( [ & ] ( auto & thread ) {
2021-05-16 09:36:52 +00:00
if ( & thread = = this )
return ;
if ( ! thread . is_stopped ( ) )
return ;
2021-02-07 12:03:24 +00:00
dbgln_if ( THREAD_DEBUG , " Resuming peer thread {} " , thread ) ;
2020-12-09 04:18:45 +00:00
thread . resume_from_stopped ( ) ;
} ) ;
process . unblock_waiters ( Thread : : WaitBlocker : : UnblockFlags : : Continued ) ;
2021-03-29 22:12:51 +00:00
// Tell the parent process (if any) about this change.
if ( auto parent = Process : : from_pid ( process . ppid ( ) ) ) {
[[maybe_unused]] auto result = parent - > send_signal ( SIGCHLD , & process ) ;
}
2020-12-09 04:18:45 +00:00
}
2020-11-29 23:05:27 +00:00
}
2020-10-28 22:06:16 +00:00
if ( m_state = = Runnable ) {
2021-08-08 12:19:55 +00:00
Scheduler : : enqueue_runnable_thread ( * this ) ;
2020-10-28 22:06:16 +00:00
Processor : : smp_wake_n_idle_processors ( 1 ) ;
} else if ( m_state = = Stopped ) {
2020-11-29 23:05:27 +00:00
// We don't want to restore to Running state, only Runnable!
2020-12-09 04:18:45 +00:00
m_stop_state = previous_state ! = Running ? previous_state : Runnable ;
auto & process = this - > process ( ) ;
2021-10-31 22:52:43 +00:00
if ( ! process . set_stopped ( true ) ) {
2020-12-09 04:18:45 +00:00
process . for_each_thread ( [ & ] ( auto & thread ) {
2021-05-16 09:36:52 +00:00
if ( & thread = = this )
return ;
if ( thread . is_stopped ( ) )
return ;
2021-02-07 12:03:24 +00:00
dbgln_if ( THREAD_DEBUG , " Stopping peer thread {} " , thread ) ;
2020-12-09 04:18:45 +00:00
thread . set_state ( Stopped , stop_signal ) ;
} ) ;
process . unblock_waiters ( Thread : : WaitBlocker : : UnblockFlags : : Stopped , stop_signal ) ;
2021-03-29 22:12:51 +00:00
// Tell the parent process (if any) about this change.
if ( auto parent = Process : : from_pid ( process . ppid ( ) ) ) {
[[maybe_unused]] auto result = parent - > send_signal ( SIGCHLD , & process ) ;
}
2020-12-09 04:18:45 +00:00
}
2020-11-29 23:05:27 +00:00
} else if ( m_state = = Dying ) {
2021-02-23 19:42:32 +00:00
VERIFY ( previous_state ! = Blocked ) ;
2020-08-06 01:13:28 +00:00
if ( this ! = Thread : : current ( ) & & is_finalizable ( ) ) {
// Some other thread set this thread to Dying, notify the
// finalizer right away as it can be cleaned up now
Scheduler : : notify_finalizer ( ) ;
}
2020-07-05 20:32:07 +00:00
}
2019-04-17 10:41:51 +00:00
}
2019-07-25 19:02:19 +00:00
2020-01-19 09:10:46 +00:00
struct RecognizedSymbol {
2021-02-25 15:18:36 +00:00
FlatPtr address ;
2020-04-08 11:30:50 +00:00
const KernelSymbol * symbol { nullptr } ;
2020-01-19 09:10:46 +00:00
} ;
2021-07-05 19:30:51 +00:00
static bool symbolicate ( RecognizedSymbol const & symbol , Process & process , StringBuilder & builder )
2020-01-19 09:10:46 +00:00
{
2021-11-06 21:06:08 +00:00
if ( symbol . address = = 0 )
2020-01-19 09:10:46 +00:00
return false ;
bool mask_kernel_addresses = ! process . is_superuser ( ) ;
2020-04-08 11:30:50 +00:00
if ( ! symbol . symbol ) {
2021-08-06 11:49:36 +00:00
if ( ! Memory : : is_user_address ( VirtualAddress ( symbol . address ) ) ) {
2020-01-19 09:10:46 +00:00
builder . append ( " 0xdeadc0de \n " ) ;
} else {
2021-08-06 11:59:22 +00:00
if ( auto * region = process . address_space ( ) . find_region_containing ( { VirtualAddress ( symbol . address ) , sizeof ( FlatPtr ) } ) ) {
2021-07-05 19:30:51 +00:00
size_t offset = symbol . address - region - > vaddr ( ) . get ( ) ;
if ( auto region_name = region - > name ( ) ; ! region_name . is_null ( ) & & ! region_name . is_empty ( ) )
2021-07-21 23:30:24 +00:00
builder . appendff ( " {:p} {} + {:#x} \n " , ( void * ) symbol . address , region_name , offset ) ;
2021-07-05 19:30:51 +00:00
else
2021-07-21 23:30:24 +00:00
builder . appendff ( " {:p} {:p} + {:#x} \n " , ( void * ) symbol . address , region - > vaddr ( ) . as_ptr ( ) , offset ) ;
2021-07-05 19:30:51 +00:00
} else {
builder . appendff ( " {:p} \n " , symbol . address ) ;
}
2020-01-19 09:10:46 +00:00
}
return true ;
}
2020-04-08 11:30:50 +00:00
unsigned offset = symbol . address - symbol . symbol - > address ;
if ( symbol . symbol - > address = = g_highest_kernel_symbol_address & & offset > 4096 ) {
2021-02-09 15:08:43 +00:00
builder . appendff ( " {:p} \n " , ( void * ) ( mask_kernel_addresses ? 0xdeadc0de : symbol . address ) ) ;
2020-01-19 09:10:46 +00:00
} else {
2021-07-21 23:30:24 +00:00
builder . appendff ( " {:p} {} + {:#x} \n " , ( void * ) ( mask_kernel_addresses ? 0xdeadc0de : symbol . address ) , symbol . symbol - > name , offset ) ;
2020-01-19 09:10:46 +00:00
}
return true ;
}
2021-02-07 16:58:29 +00:00
String Thread : : backtrace ( )
2019-07-25 19:02:19 +00:00
{
2020-01-19 09:10:46 +00:00
Vector < RecognizedSymbol , 128 > recognized_symbols ;
2019-07-25 19:02:19 +00:00
auto & process = const_cast < Process & > ( this - > process ( ) ) ;
2020-12-08 04:29:41 +00:00
auto stack_trace = Processor : : capture_stack_trace ( * this ) ;
2021-08-29 18:10:24 +00:00
VERIFY ( ! g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
2021-09-06 15:22:36 +00:00
ScopedAddressSpaceSwitcher switcher ( process ) ;
2020-12-08 04:29:41 +00:00
for ( auto & frame : stack_trace ) {
2021-08-06 11:49:36 +00:00
if ( Memory : : is_user_range ( VirtualAddress ( frame ) , sizeof ( FlatPtr ) * 2 ) ) {
2021-02-03 10:08:23 +00:00
recognized_symbols . append ( { frame } ) ;
2020-12-08 04:29:41 +00:00
} else {
recognized_symbols . append ( { frame , symbolicate_kernel_address ( frame ) } ) ;
2020-01-19 09:10:46 +00:00
}
2019-07-25 19:02:19 +00:00
}
2020-01-19 09:10:46 +00:00
StringBuilder builder ;
2019-07-25 19:02:19 +00:00
for ( auto & symbol : recognized_symbols ) {
2020-12-24 23:59:15 +00:00
if ( ! symbolicate ( symbol , process , builder ) )
2019-07-25 19:02:19 +00:00
break ;
}
return builder . to_string ( ) ;
}
2019-09-07 13:50:44 +00:00
2020-12-25 15:45:35 +00:00
size_t Thread : : thread_specific_region_alignment ( ) const
{
return max ( process ( ) . m_master_tls_alignment , alignof ( ThreadSpecificData ) ) ;
}
size_t Thread : : thread_specific_region_size ( ) const
{
return align_up_to ( process ( ) . m_master_tls_size , thread_specific_region_alignment ( ) ) + sizeof ( ThreadSpecificData ) ;
}
2021-11-07 23:51:39 +00:00
ErrorOr < void > Thread : : make_thread_specific_region ( Badge < Process > )
2019-09-07 13:50:44 +00:00
{
2021-03-15 19:56:13 +00:00
// The process may not require a TLS region, or allocate TLS later with sys$allocate_tls (which is what dynamically loaded programs do)
2020-10-10 09:13:21 +00:00
if ( ! process ( ) . m_master_tls_region )
2021-11-07 23:51:39 +00:00
return { } ;
2020-10-10 09:13:21 +00:00
2021-09-05 21:12:16 +00:00
auto range = TRY ( process ( ) . address_space ( ) . try_allocate_range ( { } , thread_specific_region_size ( ) ) ) ;
auto * region = TRY ( process ( ) . address_space ( ) . allocate_region ( range , " Thread-specific " , PROT_READ | PROT_WRITE ) ) ;
2020-12-25 15:45:35 +00:00
2021-09-05 21:12:16 +00:00
m_thread_specific_range = range ;
2021-05-28 09:18:58 +00:00
2020-01-05 17:00:15 +00:00
SmapDisabler disabler ;
2021-09-05 12:06:42 +00:00
auto * thread_specific_data = ( ThreadSpecificData * ) region - > vaddr ( ) . offset ( align_up_to ( process ( ) . m_master_tls_size , thread_specific_region_alignment ( ) ) ) . as_ptr ( ) ;
2019-09-07 13:50:44 +00:00
auto * thread_local_storage = ( u8 * ) ( ( u8 * ) thread_specific_data ) - align_up_to ( process ( ) . m_master_tls_size , process ( ) . m_master_tls_alignment ) ;
2020-01-20 12:06:41 +00:00
m_thread_specific_data = VirtualAddress ( thread_specific_data ) ;
2019-09-07 13:50:44 +00:00
thread_specific_data - > self = thread_specific_data ;
2021-03-15 19:56:13 +00:00
2021-11-06 21:06:08 +00:00
if ( process ( ) . m_master_tls_size ! = 0 )
AK: Make RefPtr, NonnullRefPtr, WeakPtr thread safe
This makes most operations thread safe, especially so that they
can safely be used in the Kernel. This includes obtaining a strong
reference from a weak reference, which now requires an explicit
call to WeakPtr::strong_ref(). Another major change is that
Weakable::make_weak_ref() may require the explicit target type.
Previously we used reinterpret_cast in WeakPtr, assuming that it
can be properly converted. But WeakPtr does not necessarily have
the knowledge to be able to do this. Instead, we now ask the class
itself to deliver a WeakPtr to the type that we want.
Also, WeakLink is no longer specific to a target type. The reason
for this is that we want to be able to safely convert e.g. WeakPtr<T>
to WeakPtr<U>, and before this we just reinterpret_cast the internal
WeakLink<T> to WeakLink<U>, which is a bold assumption that it would
actually produce the correct code. Instead, WeakLink now operates
on just a raw pointer and we only make those constructors/operators
available if we can verify that it can be safely cast.
In order to guarantee thread safety, we now use the least significant
bit in the pointer for locking purposes. This also means that only
properly aligned pointers can be used.
2020-09-29 22:26:13 +00:00
memcpy ( thread_local_storage , process ( ) . m_master_tls_region . unsafe_ptr ( ) - > vaddr ( ) . as_ptr ( ) , process ( ) . m_master_tls_size ) ;
2021-03-15 19:56:13 +00:00
2021-11-07 23:51:39 +00:00
return { } ;
2019-09-07 13:50:44 +00:00
}
2019-10-13 12:36:55 +00:00
2020-09-27 14:53:35 +00:00
RefPtr < Thread > Thread : : from_tid ( ThreadID tid )
2019-12-30 18:23:13 +00:00
{
2021-08-16 19:52:42 +00:00
return Thread : : all_instances ( ) . with ( [ & ] ( auto & list ) - > RefPtr < Thread > {
2021-08-15 10:38:02 +00:00
for ( Thread & thread : list ) {
if ( thread . tid ( ) = = tid )
return thread ;
2021-05-20 19:58:36 +00:00
}
2021-08-15 10:38:02 +00:00
return nullptr ;
} ) ;
2019-12-30 18:23:13 +00:00
}
2020-02-16 00:27:42 +00:00
2020-02-18 12:44:27 +00:00
void Thread : : reset_fpu_state ( )
{
2021-08-22 13:35:54 +00:00
memcpy ( & m_fpu_state , & Processor : : clean_fpu_state ( ) , sizeof ( FPUState ) ) ;
2020-02-18 12:44:27 +00:00
}
2020-12-09 04:18:45 +00:00
bool Thread : : should_be_stopped ( ) const
2020-04-07 15:23:37 +00:00
{
2020-12-09 04:18:45 +00:00
return process ( ) . is_stopped ( ) ;
2020-04-07 15:23:37 +00:00
}
2021-09-07 09:40:31 +00:00
void Thread : : track_lock_acquire ( LockRank rank )
{
// Nothing to do for locks without a rank.
if ( rank = = LockRank : : None )
return ;
if ( m_lock_rank_mask ! = LockRank : : None ) {
// Verify we are only attempting to take a lock of a higher rank.
VERIFY ( m_lock_rank_mask > rank ) ;
}
m_lock_rank_mask | = rank ;
}
void Thread : : track_lock_release ( LockRank rank )
{
// Nothing to do for locks without a rank.
if ( rank = = LockRank : : None )
return ;
// The rank value from the caller should only contain a single bit, otherwise
// we are disabling the tracking for multiple locks at once which will corrupt
// the lock tracking mask, and we will assert somewhere else.
auto rank_is_a_single_bit = [ ] ( auto rank_enum ) - > bool {
2021-09-12 15:17:31 +00:00
auto rank = to_underlying ( rank_enum ) ;
2021-09-07 09:40:31 +00:00
auto rank_without_least_significant_bit = rank - 1 ;
return ( rank & rank_without_least_significant_bit ) = = 0 ;
} ;
// We can't release locks out of order, as that would violate the ranking.
// This is validated by toggling the least significant bit of the mask, and
// then bit wise or-ing the rank we are trying to release with the resulting
// mask. If the rank we are releasing is truly the highest rank then the mask
// we get back will be equal to the current mask of stored on the thread.
auto rank_is_in_order = [ ] ( auto mask_enum , auto rank_enum ) - > bool {
2021-09-12 15:17:31 +00:00
auto mask = to_underlying ( mask_enum ) ;
auto rank = to_underlying ( rank_enum ) ;
2021-09-07 09:40:31 +00:00
auto mask_without_least_significant_bit = mask - 1 ;
return ( ( mask & mask_without_least_significant_bit ) | rank ) = = mask ;
} ;
VERIFY ( has_flag ( m_lock_rank_mask , rank ) ) ;
VERIFY ( rank_is_a_single_bit ( rank ) ) ;
VERIFY ( rank_is_in_order ( m_lock_rank_mask , rank ) ) ;
m_lock_rank_mask ^ = rank ;
}
2020-02-16 00:27:42 +00:00
}
2021-01-08 23:42:44 +00:00
2021-11-16 00:15:21 +00:00
ErrorOr < void > AK : : Formatter < Kernel : : Thread > : : format ( FormatBuilder & builder , Kernel : : Thread const & value )
2021-01-08 23:42:44 +00:00
{
return AK : : Formatter < FormatString > : : format (
builder ,
" {}({}:{}) " , value . process ( ) . name ( ) , value . pid ( ) . value ( ) , value . tid ( ) . value ( ) ) ;
}