2021-07-02 15:06:48 +03:00
/*
* Copyright ( c ) 2021 , Spencer Dixon < spencercdixon @ gmail . com >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2023-05-23 19:31:13 +03:00
# include <AK/Time.h>
2021-07-02 15:06:48 +03:00
# include <LibTest/TestCase.h>
# include <LibThreading/Thread.h>
# include <unistd.h>
2023-05-23 19:31:13 +03:00
using namespace AK : : TimeLiterals ;
static void sleep_until_thread_exits ( Threading : : Thread const & thread )
{
static constexpr auto delay = 20 _ms ;
for ( auto i = 0 ; i < 100 ; + + i ) {
if ( thread . has_exited ( ) )
return ;
usleep ( delay . to_microseconds ( ) ) ;
}
FAIL ( " Timed out waiting for thread to exit " ) ;
}
2021-07-02 15:06:48 +03:00
TEST_CASE ( threads_can_detach )
{
2024-05-18 03:14:06 +03:00
IGNORE_USE_IN_ESCAPING_LAMBDA Atomic < int > should_be_42 = 0 ;
2021-07-02 15:06:48 +03:00
auto thread = Threading : : Thread : : construct ( [ & should_be_42 ] ( ) {
usleep ( 10 * 1000 ) ;
should_be_42 = 42 ;
return 0 ;
} ) ;
thread - > start ( ) ;
thread - > detach ( ) ;
2023-05-23 19:31:13 +03:00
sleep_until_thread_exits ( * thread ) ;
2021-07-02 15:06:48 +03:00
EXPECT ( should_be_42 = = 42 ) ;
}
2023-05-23 19:31:13 +03:00
TEST_CASE ( detached_threads_do_not_need_to_be_joined )
2021-07-02 15:06:48 +03:00
{
2024-05-18 03:14:06 +03:00
IGNORE_USE_IN_ESCAPING_LAMBDA Atomic < bool > should_exit { false } ;
2022-11-12 16:24:26 +03:00
auto thread = Threading : : Thread : : construct ( [ & ] ( ) {
while ( ! should_exit . load ( ) )
usleep ( 10 * 1000 ) ;
return 0 ;
} ) ;
2021-07-02 15:06:48 +03:00
thread - > start ( ) ;
thread - > detach ( ) ;
2022-11-12 16:24:26 +03:00
// Because of how the crash test forks and removes the thread, we can't use that to verify that join() crashes. Instead, we check the join crash condition ourselves.
EXPECT ( ! thread - > needs_to_be_joined ( ) ) ;
// FIXME: Dropping a running thread crashes because of the Function destructor. For now, force the detached thread to exit.
should_exit . store ( true ) ;
2023-05-23 19:31:13 +03:00
sleep_until_thread_exits ( * thread ) ;
2022-11-12 16:24:26 +03:00
}
TEST_CASE ( join_dead_thread )
{
auto thread = Threading : : Thread : : construct ( [ & ] ( ) { return 0 /*nullptr*/ ; } ) ;
thread - > start ( ) ;
2023-05-23 19:31:13 +03:00
2022-11-12 16:24:26 +03:00
// The thread should have exited by then.
2023-05-23 19:31:13 +03:00
sleep_until_thread_exits ( * thread ) ;
2022-11-12 16:24:26 +03:00
2023-05-07 21:14:06 +03:00
auto join_result = TRY_OR_FAIL ( thread - > join < int * > ( ) ) ;
EXPECT_EQ ( join_result , static_cast < int * > ( 0 ) ) ;
2021-07-02 15:06:48 +03:00
}