2020-01-18 08:38:21 +00:00
/*
2020-01-24 13:45:29 +00:00
* Copyright ( c ) 2019 - 2020 , Sergey Bugaev < bugaevc @ serenityos . org >
2021-07-02 12:05:07 +00:00
* Copyright ( c ) 2021 , Spencer Dixon < spencercdixon @ gmail . com >
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
*/
2019-08-25 15:55:56 +00:00
# pragma once
2022-11-12 13:13:40 +00:00
# include <AK/Assertions.h>
2023-08-06 06:31:42 +00:00
# include <AK/AtomicRefCounted.h>
2023-12-16 14:19:34 +00:00
# include <AK/ByteString.h>
LibThread: Improve semantics of Thread::join, and remove Thread::quit.
Thread::quit was created before the pthread_create_helper in pthread.cpp
that automagically calls pthread_exit from all pthreads after the user's
thread function exits. It is unused, and unecessary now.
Cleanup some logging, and make join return a Result<T, ThreadError>.
This also adds a new type, LibThread::ThreadError as an
AK::DistinctNumeric. Hopefully, this will make it possible to have a
Result<int, ThreadError> and have it compile? It also makes it clear
that the int there is an error at the call site.
By default, the T on join is void, meaning the caller doesn't care about
the return value from the thread.
As Result is a [[nodiscard]] type, also change the current caller of
join to explicitly ignore it.
Move the logging out of join as well, as it's the user's
responsibility whether to log or not.
2021-01-01 03:56:04 +00:00
# include <AK/DistinctNumeric.h>
2019-08-25 15:55:56 +00:00
# include <AK/Function.h>
LibThread: Improve semantics of Thread::join, and remove Thread::quit.
Thread::quit was created before the pthread_create_helper in pthread.cpp
that automagically calls pthread_exit from all pthreads after the user's
thread function exits. It is unused, and unecessary now.
Cleanup some logging, and make join return a Result<T, ThreadError>.
This also adds a new type, LibThread::ThreadError as an
AK::DistinctNumeric. Hopefully, this will make it possible to have a
Result<int, ThreadError> and have it compile? It also makes it clear
that the int there is an error at the call site.
By default, the T on join is void, meaning the caller doesn't care about
the return value from the thread.
As Result is a [[nodiscard]] type, also change the current caller of
join to explicitly ignore it.
Move the logging out of join as well, as it's the user's
responsibility whether to log or not.
2021-01-01 03:56:04 +00:00
# include <AK/Result.h>
2023-08-06 16:09:39 +00:00
# include <LibCore/EventReceiver.h>
2020-01-30 23:46:13 +00:00
# include <pthread.h>
2019-08-25 15:55:56 +00:00
2021-05-22 16:47:42 +00:00
namespace Threading {
2019-08-25 15:55:56 +00:00
2022-07-22 18:43:50 +00:00
AK_TYPEDEF_DISTINCT_ORDERED_ID ( intptr_t , ThreadError ) ;
LibThread: Improve semantics of Thread::join, and remove Thread::quit.
Thread::quit was created before the pthread_create_helper in pthread.cpp
that automagically calls pthread_exit from all pthreads after the user's
thread function exits. It is unused, and unecessary now.
Cleanup some logging, and make join return a Result<T, ThreadError>.
This also adds a new type, LibThread::ThreadError as an
AK::DistinctNumeric. Hopefully, this will make it possible to have a
Result<int, ThreadError> and have it compile? It also makes it clear
that the int there is an error at the call site.
By default, the T on join is void, meaning the caller doesn't care about
the return value from the thread.
As Result is a [[nodiscard]] type, also change the current caller of
join to explicitly ignore it.
Move the logging out of join as well, as it's the user's
responsibility whether to log or not.
2021-01-01 03:56:04 +00:00
2022-11-12 13:12:25 +00:00
// States of userspace threads are simplified over actual kernel states (and possibly POSIX states).
// There are only a couple of well-defined transitions between these states, and any attempt to call a function in a state where this is not allowed will crash the program.
enum class ThreadState : u8 {
// Thread has been constructed but not started.
// Transitions to Running via start().
Startable ,
// Thread has been started, might be running, and can be joined.
// Note that join() (valid to call in this state) only changes the thread state after the thread has exited, so it only ever transitions from Exited to Joined.
// Transitions to Detached via detach(), transitions to Exited when the thread finishes its action function.
Running ,
// Thread has not been detached and exited, and has to still be joined.
// Transitions to Joined via join().
Exited ,
// Thread has been started but also detached, meaning it cannot be joined.
// Transitions to DetachedExited when the thread finishes its action function.
Detached ,
// Thread has exited but was detached, meaning it cannot be joined.
DetachedExited ,
// Thread has exited and been joined.
Joined ,
} ;
2023-08-06 06:21:49 +00:00
class Thread final
2023-08-06 06:31:42 +00:00
: public AtomicRefCounted < Thread >
2023-08-06 06:21:49 +00:00
, public Weakable < Thread > {
2019-08-25 15:55:56 +00:00
public :
2024-05-18 00:14:06 +00:00
static NonnullRefPtr < Thread > construct ( ESCAPING Function < intptr_t ( ) > action , StringView thread_name = { } )
2023-08-06 06:21:49 +00:00
{
return adopt_ref ( * new Thread ( move ( action ) , thread_name ) ) ;
}
2024-05-18 00:14:06 +00:00
static ErrorOr < NonnullRefPtr < Thread > > try_create ( ESCAPING Function < intptr_t ( ) > action , StringView thread_name = { } )
2023-08-06 06:21:49 +00:00
{
return adopt_nonnull_ref_or_enomem ( new ( nothrow ) Thread ( move ( action ) , thread_name ) ) ;
}
2019-08-25 15:55:56 +00:00
virtual ~ Thread ( ) ;
2022-11-13 09:23:24 +00:00
ErrorOr < void > set_priority ( int priority ) ;
ErrorOr < int > get_priority ( ) const ;
2022-11-12 13:13:40 +00:00
// Only callable in the Startable state.
2019-08-25 15:55:56 +00:00
void start ( ) ;
2022-11-12 13:13:40 +00:00
// Only callable in the Running state.
2021-07-02 12:05:07 +00:00
void detach ( ) ;
LibThread: Improve semantics of Thread::join, and remove Thread::quit.
Thread::quit was created before the pthread_create_helper in pthread.cpp
that automagically calls pthread_exit from all pthreads after the user's
thread function exits. It is unused, and unecessary now.
Cleanup some logging, and make join return a Result<T, ThreadError>.
This also adds a new type, LibThread::ThreadError as an
AK::DistinctNumeric. Hopefully, this will make it possible to have a
Result<int, ThreadError> and have it compile? It also makes it clear
that the int there is an error at the call site.
By default, the T on join is void, meaning the caller doesn't care about
the return value from the thread.
As Result is a [[nodiscard]] type, also change the current caller of
join to explicitly ignore it.
Move the logging out of join as well, as it's the user's
responsibility whether to log or not.
2021-01-01 03:56:04 +00:00
2022-11-12 13:13:40 +00:00
// Only callable in the Running or Exited states.
LibThread: Improve semantics of Thread::join, and remove Thread::quit.
Thread::quit was created before the pthread_create_helper in pthread.cpp
that automagically calls pthread_exit from all pthreads after the user's
thread function exits. It is unused, and unecessary now.
Cleanup some logging, and make join return a Result<T, ThreadError>.
This also adds a new type, LibThread::ThreadError as an
AK::DistinctNumeric. Hopefully, this will make it possible to have a
Result<int, ThreadError> and have it compile? It also makes it clear
that the int there is an error at the call site.
By default, the T on join is void, meaning the caller doesn't care about
the return value from the thread.
As Result is a [[nodiscard]] type, also change the current caller of
join to explicitly ignore it.
Move the logging out of join as well, as it's the user's
responsibility whether to log or not.
2021-01-01 03:56:04 +00:00
template < typename T = void >
Result < T , ThreadError > join ( ) ;
2023-12-16 14:19:34 +00:00
ByteString thread_name ( ) const ;
2022-11-12 11:57:21 +00:00
pthread_t tid ( ) const ;
2022-11-12 13:13:40 +00:00
ThreadState state ( ) const ;
2022-11-12 11:57:21 +00:00
bool is_started ( ) const ;
2022-11-12 13:13:40 +00:00
bool needs_to_be_joined ( ) const ;
bool has_exited ( ) const ;
2019-08-25 15:55:56 +00:00
private :
2024-05-18 00:14:06 +00:00
explicit Thread ( ESCAPING Function < intptr_t ( ) > action , StringView thread_name = { } ) ;
2021-04-26 17:09:04 +00:00
Function < intptr_t ( ) > m_action ;
2020-08-16 22:28:56 +00:00
pthread_t m_tid { 0 } ;
2023-12-16 14:19:34 +00:00
ByteString m_thread_name ;
2022-11-12 13:13:40 +00:00
Atomic < ThreadState > m_state { ThreadState : : Startable } ;
2019-08-25 15:55:56 +00:00
} ;
LibThread: Improve semantics of Thread::join, and remove Thread::quit.
Thread::quit was created before the pthread_create_helper in pthread.cpp
that automagically calls pthread_exit from all pthreads after the user's
thread function exits. It is unused, and unecessary now.
Cleanup some logging, and make join return a Result<T, ThreadError>.
This also adds a new type, LibThread::ThreadError as an
AK::DistinctNumeric. Hopefully, this will make it possible to have a
Result<int, ThreadError> and have it compile? It also makes it clear
that the int there is an error at the call site.
By default, the T on join is void, meaning the caller doesn't care about
the return value from the thread.
As Result is a [[nodiscard]] type, also change the current caller of
join to explicitly ignore it.
Move the logging out of join as well, as it's the user's
responsibility whether to log or not.
2021-01-01 03:56:04 +00:00
template < typename T >
Result < T , ThreadError > Thread : : join ( )
{
2022-11-12 13:13:40 +00:00
VERIFY ( needs_to_be_joined ( ) ) ;
LibThread: Improve semantics of Thread::join, and remove Thread::quit.
Thread::quit was created before the pthread_create_helper in pthread.cpp
that automagically calls pthread_exit from all pthreads after the user's
thread function exits. It is unused, and unecessary now.
Cleanup some logging, and make join return a Result<T, ThreadError>.
This also adds a new type, LibThread::ThreadError as an
AK::DistinctNumeric. Hopefully, this will make it possible to have a
Result<int, ThreadError> and have it compile? It also makes it clear
that the int there is an error at the call site.
By default, the T on join is void, meaning the caller doesn't care about
the return value from the thread.
As Result is a [[nodiscard]] type, also change the current caller of
join to explicitly ignore it.
Move the logging out of join as well, as it's the user's
responsibility whether to log or not.
2021-01-01 03:56:04 +00:00
void * thread_return = nullptr ;
int rc = pthread_join ( m_tid , & thread_return ) ;
if ( rc ! = 0 ) {
return ThreadError { rc } ;
}
2022-11-12 13:13:40 +00:00
// The other thread has now stopped running, so a TOCTOU bug is not possible.
// (If you call join from two different threads, you're doing something *very* wrong anyways.)
VERIFY ( m_state = = ThreadState : : Exited ) ;
m_state = ThreadState : : Joined ;
2021-04-10 13:59:06 +00:00
if constexpr ( IsVoid < T > )
LibThread: Improve semantics of Thread::join, and remove Thread::quit.
Thread::quit was created before the pthread_create_helper in pthread.cpp
that automagically calls pthread_exit from all pthreads after the user's
thread function exits. It is unused, and unecessary now.
Cleanup some logging, and make join return a Result<T, ThreadError>.
This also adds a new type, LibThread::ThreadError as an
AK::DistinctNumeric. Hopefully, this will make it possible to have a
Result<int, ThreadError> and have it compile? It also makes it clear
that the int there is an error at the call site.
By default, the T on join is void, meaning the caller doesn't care about
the return value from the thread.
As Result is a [[nodiscard]] type, also change the current caller of
join to explicitly ignore it.
Move the logging out of join as well, as it's the user's
responsibility whether to log or not.
2021-01-01 03:56:04 +00:00
return { } ;
else
return { static_cast < T > ( thread_return ) } ;
}
2019-08-25 15:55:56 +00:00
}
2022-11-12 12:58:18 +00:00
template < >
struct AK : : Formatter < Threading : : Thread > : AK : : Formatter < FormatString > {
ErrorOr < void > format ( FormatBuilder & builder , Threading : : Thread const & thread )
{
return Formatter < FormatString > : : format ( builder , " Thread \" {} \" ({}) " sv , thread . thread_name ( ) , thread . tid ( ) ) ;
}
} ;
2022-11-12 13:12:25 +00:00
template < >
struct AK : : Formatter < Threading : : ThreadState > : AK : : Formatter < FormatString > {
ErrorOr < void > format ( FormatBuilder & builder , Threading : : ThreadState state )
{
2023-12-16 14:19:34 +00:00
ByteString name = " " ;
2022-11-12 13:12:25 +00:00
switch ( state ) {
case Threading : : ThreadState : : Detached :
name = " Detached " ;
break ;
case Threading : : ThreadState : : DetachedExited :
name = " DetachedExited " ;
break ;
case Threading : : ThreadState : : Exited :
name = " Exited " ;
break ;
case Threading : : ThreadState : : Joined :
name = " Joined " ;
break ;
case Threading : : ThreadState : : Running :
name = " Running " ;
break ;
case Threading : : ThreadState : : Startable :
name = " Startable " ;
break ;
default :
VERIFY_NOT_REACHED ( ) ;
}
return Formatter < FormatString > : : format ( builder , " {} " sv , name ) ;
}
} ;