2020-11-08 12:48:16 +00:00
/*
* Copyright ( c ) 2020 , the SerenityOS developers .
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-11-08 12:48:16 +00:00
*/
# include <AK/Assertions.h>
2021-09-12 16:06:33 +00:00
# include <AK/Platform.h>
2020-11-08 12:48:16 +00:00
# include <AK/StackInfo.h>
# include <stdio.h>
2021-01-12 18:21:59 +00:00
# include <string.h>
2020-11-08 12:48:16 +00:00
2022-10-09 21:23:23 +00:00
# ifdef AK_OS_SERENITY
2020-11-08 12:48:16 +00:00
# include <serenity.h>
2024-02-27 13:32:29 +00:00
# elif defined(AK_OS_LINUX) || defined(AK_LIBC_GLIBC) || defined(AK_OS_MACOS) || defined(AK_OS_IOS) || defined(AK_OS_NETBSD) || defined(AK_OS_SOLARIS) || defined(AK_OS_HAIKU)
2020-11-08 12:48:16 +00:00
# include <pthread.h>
2024-05-12 01:13:40 +00:00
# include <sys / resource.h>
2024-02-27 13:32:29 +00:00
# elif defined(AK_OS_FREEBSD) || defined(AK_OS_OPENBSD)
2022-07-10 13:19:55 +00:00
# include <pthread.h>
# include <pthread_np.h>
2023-03-04 12:53:51 +00:00
# elif defined(AK_OS_WINDOWS)
# include <Windows.h>
// NOTE: Prevent clang-format from re-ordering this header order
# include <Processthreadsapi.h>
2020-11-08 12:48:16 +00:00
# endif
namespace AK {
StackInfo : : StackInfo ( )
{
2022-10-09 21:23:23 +00:00
# ifdef AK_OS_SERENITY
2020-11-08 12:48:16 +00:00
if ( get_stack_bounds ( & m_base , & m_size ) < 0 ) {
perror ( " get_stack_bounds " ) ;
2021-02-23 19:42:32 +00:00
VERIFY_NOT_REACHED ( ) ;
2020-11-08 12:48:16 +00:00
}
2023-08-27 18:44:16 +00:00
# elif defined(AK_OS_LINUX) or defined(AK_LIBC_GLIBC) or defined(AK_OS_FREEBSD) or defined(AK_OS_NETBSD) or defined(AK_OS_SOLARIS) or defined(AK_OS_HAIKU)
2020-12-22 11:50:20 +00:00
int rc ;
2022-07-10 13:19:55 +00:00
pthread_attr_t attr ;
pthread_attr_init ( & attr ) ;
2023-08-27 18:44:16 +00:00
# if defined(AK_OS_LINUX) or defined(AK_LIBC_GLIBC) or defined(AK_OS_HAIKU)
2020-12-22 11:50:20 +00:00
if ( ( rc = pthread_getattr_np ( pthread_self ( ) , & attr ) ) ! = 0 ) {
2022-07-10 13:10:20 +00:00
fprintf ( stderr , " pthread_getattr_np: %s \n " , strerror ( rc ) ) ;
2021-02-23 19:42:32 +00:00
VERIFY_NOT_REACHED ( ) ;
2020-11-08 12:48:16 +00:00
}
2022-07-10 13:19:55 +00:00
# else
if ( ( rc = pthread_attr_get_np ( pthread_self ( ) , & attr ) ) ! = 0 ) {
fprintf ( stderr , " pthread_attr_get_np: %s \n " , strerror ( rc ) ) ;
VERIFY_NOT_REACHED ( ) ;
}
# endif
2020-12-22 11:50:20 +00:00
if ( ( rc = pthread_attr_getstack ( & attr , ( void * * ) & m_base , & m_size ) ) ! = 0 ) {
2022-07-10 13:10:20 +00:00
fprintf ( stderr , " pthread_attr_getstack: %s \n " , strerror ( rc ) ) ;
2021-02-23 19:42:32 +00:00
VERIFY_NOT_REACHED ( ) ;
2020-11-08 12:48:16 +00:00
}
pthread_attr_destroy ( & attr ) ;
2024-02-27 13:32:29 +00:00
# elif defined(AK_OS_MACOS) || defined(AK_OS_IOS)
2020-12-30 08:44:05 +00:00
// NOTE: !! On MacOS, pthread_get_stackaddr_np gives the TOP of the stack, not the bottom!
FlatPtr top_of_stack = ( FlatPtr ) pthread_get_stackaddr_np ( pthread_self ( ) ) ;
m_size = ( size_t ) pthread_get_stacksize_np ( pthread_self ( ) ) ;
// https://github.com/rust-lang/rust/issues/43347#issuecomment-316783599
// https://developer.apple.com/library/archive/qa/qa1419/_index.html
//
// MacOS seems inconsistent on what stack size is given for the main thread.
// According to the Apple docs, default for main thread is 8MB, and default for
// other threads is 512KB
2024-11-10 12:24:21 +00:00
if ( pthread_main_np ( ) = = 1 ) {
// Apparently the main thread's stack size is not reported correctly on macOS
// but we can use getrlimit to get the correct value.
rlimit limit { } ;
getrlimit ( RLIMIT_STACK , & limit ) ;
if ( limit . rlim_cur = = RLIM_INFINITY ) {
m_size = 8 * MiB ;
} else {
m_size = limit . rlim_cur ;
}
2020-11-08 12:48:16 +00:00
}
2020-12-30 08:44:05 +00:00
m_base = top_of_stack - m_size ;
2023-02-19 09:24:05 +00:00
# elif defined(AK_OS_OPENBSD)
int rc ;
stack_t thread_stack ;
if ( ( rc = pthread_stackseg_np ( pthread_self ( ) , & thread_stack ) ) ! = 0 ) {
fprintf ( stderr , " pthread_stackseg_np: %s \n " , strerror ( rc ) ) ;
VERIFY_NOT_REACHED ( ) ;
}
FlatPtr top_of_stack = ( FlatPtr ) thread_stack . ss_sp ;
m_size = ( size_t ) thread_stack . ss_size ;
m_base = top_of_stack - m_size ;
2023-03-04 12:53:51 +00:00
# elif defined(AK_OS_WINDOWS)
ULONG_PTR low_limit = 0 ;
ULONG_PTR high_limit = 0 ;
GetCurrentThreadStackLimits ( & low_limit , & high_limit ) ;
m_base = static_cast < FlatPtr > ( low_limit ) ;
m_size = static_cast < size_t > ( high_limit - low_limit ) ;
2020-11-08 12:48:16 +00:00
# else
2022-11-20 03:23:14 +00:00
# pragma message "StackInfo not supported on this platform! Recursion checks and stack scans may not work properly"
m_size = ( size_t ) ~ 0 ;
m_base = 0 ;
2020-11-08 12:48:16 +00:00
# endif
m_top = m_base + m_size ;
2024-05-12 01:13:40 +00:00
# if defined(AK_OS_LINUX) && !defined(AK_OS_ANDROID) && !defined(AK_LIBC_GLIBC)
// Note: musl libc always gives the initial size of the main thread's stack
if ( getpid ( ) = = static_cast < pid_t > ( gettid ( ) ) ) {
rlimit limit ;
getrlimit ( RLIMIT_STACK , & limit ) ;
rlim_t size = limit . rlim_cur ;
if ( size = = RLIM_INFINITY )
size = 8 * 0x10000 ;
// account for a guard page
size - = static_cast < rlim_t > ( sysconf ( _SC_PAGESIZE ) ) ;
m_size = static_cast < size_t > ( size ) ;
m_base = m_top - m_size ;
}
# endif
2020-11-08 12:48:16 +00:00
}
}