Previously, a `Thread` could be deleted while its action was running,
even if it was running detached.
By changing it to be atomically reference counted, and incrementing the
count when starting the action, we can keep the Thread and its running
action `Function` alive until it exits. Thus, detached `Thread` objects
can be deleted by the thread creating them and allowed to die
naturally.
Inheritance from `EventReceiver` on the `Thread` class was only used in
the `BackgroundAction` class, where the children vector was keeping the
action alive until the work was completed. However, this can be
accomplished by instead capturing a `NonnullRefPtr` of `this`. The work
function can then avoid having to remove the `BackgroundAction` from
its parent `Thread` when the work completes.
This replaces all state-related variables with a single ThreadState.
These are simplified over what the Kernel has, but capture all
userspace-available thread state.
Locking the state behind an atomic and using proper atomic operations
also gets rid of quite some deadlocks and race conditions that have
existed around m_tid and others beforehand.
In terms of behavior, this introduces the following changes:
- All thread state mishandling (e.g. joining a detached thread) crashes
the program. Mishandling thread state is a severe kind of concurrency
bug that might also be indeterministic, so letting it silently
disappear with the return value of pthread_ APIs is a bad idea. The
thread state can always be checked beforehand to ensure that no crash
happens.
- Destructing a still-running thread will crash in AK/Function, so the
Thread destructor issues its own warning for debugging purposes.
- Thread issues warnings before crashes in many places to aid
concurrency debugging (the most difficult kind of debugging).
- Joining dead but not detached threads is legal, as per POSIX APIs.
- The thread ID is never reset to 0 after the thread has been started
and subsequently been assigned a valid thread ID. The thread's exit
state is still obtainable.
- Detaching threads that are about to exit is considered a programming
bug and will often (not always, as we can't catch all execution
sequences involved in such a situation) crash the program on purpose.
If you want to detach a thread that will definitely exit on its own,
you have to prevent it from exiting before detach() was called (e.g.
with an "exit requested" flag).
We have a new, improved string type coming up in AK (OOM aware, no null
state), and while it's going to use UTF-8, the name UTF8String is a
mouthful - so let's free up the String name by renaming the existing
class.
Making the old one have an annoying name will hopefully also help with
quick adoption :^)
Users can now determine whether a thread has been started or not. A
started thread might also have already terminated.
Implementation note: We *could* detect this with pthread APIs maybe, but
this is much simpler.
While null StringViews are just as bad, these prevent the removal of
StringView(char const*) as that constructor accepts a nullptr.
No functional changes.
Sometimes you don't care about `joining()` the result of a thread. The
underlying pthread implementation already existed for detaching and
now we expose it to the higher level API.