Thread.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/Assertions.h>
  9. #include <AK/AtomicRefCounted.h>
  10. #include <AK/ByteString.h>
  11. #include <AK/DistinctNumeric.h>
  12. #include <AK/Function.h>
  13. #include <AK/Result.h>
  14. #include <LibCore/EventReceiver.h>
  15. #include <pthread.h>
  16. namespace Threading {
  17. AK_TYPEDEF_DISTINCT_ORDERED_ID(intptr_t, ThreadError);
  18. // States of userspace threads are simplified over actual kernel states (and possibly POSIX states).
  19. // 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.
  20. enum class ThreadState : u8 {
  21. // Thread has been constructed but not started.
  22. // Transitions to Running via start().
  23. Startable,
  24. // Thread has been started, might be running, and can be joined.
  25. // 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.
  26. // Transitions to Detached via detach(), transitions to Exited when the thread finishes its action function.
  27. Running,
  28. // Thread has not been detached and exited, and has to still be joined.
  29. // Transitions to Joined via join().
  30. Exited,
  31. // Thread has been started but also detached, meaning it cannot be joined.
  32. // Transitions to DetachedExited when the thread finishes its action function.
  33. Detached,
  34. // Thread has exited but was detached, meaning it cannot be joined.
  35. DetachedExited,
  36. // Thread has exited and been joined.
  37. Joined,
  38. };
  39. class Thread final
  40. : public AtomicRefCounted<Thread>
  41. , public Weakable<Thread> {
  42. public:
  43. static NonnullRefPtr<Thread> construct(Function<intptr_t()> action, StringView thread_name = {})
  44. {
  45. return adopt_ref(*new Thread(move(action), thread_name));
  46. }
  47. static ErrorOr<NonnullRefPtr<Thread>> try_create(Function<intptr_t()> action, StringView thread_name = {})
  48. {
  49. return adopt_nonnull_ref_or_enomem(new (nothrow) Thread(move(action), thread_name));
  50. }
  51. virtual ~Thread();
  52. ErrorOr<void> set_priority(int priority);
  53. ErrorOr<int> get_priority() const;
  54. // Only callable in the Startable state.
  55. void start();
  56. // Only callable in the Running state.
  57. void detach();
  58. // Only callable in the Running or Exited states.
  59. template<typename T = void>
  60. Result<T, ThreadError> join();
  61. ByteString thread_name() const;
  62. pthread_t tid() const;
  63. ThreadState state() const;
  64. bool is_started() const;
  65. bool needs_to_be_joined() const;
  66. bool has_exited() const;
  67. private:
  68. explicit Thread(Function<intptr_t()> action, StringView thread_name = {});
  69. Function<intptr_t()> m_action;
  70. pthread_t m_tid { 0 };
  71. ByteString m_thread_name;
  72. Atomic<ThreadState> m_state { ThreadState::Startable };
  73. };
  74. template<typename T>
  75. Result<T, ThreadError> Thread::join()
  76. {
  77. VERIFY(needs_to_be_joined());
  78. void* thread_return = nullptr;
  79. int rc = pthread_join(m_tid, &thread_return);
  80. if (rc != 0) {
  81. return ThreadError { rc };
  82. }
  83. // The other thread has now stopped running, so a TOCTOU bug is not possible.
  84. // (If you call join from two different threads, you're doing something *very* wrong anyways.)
  85. VERIFY(m_state == ThreadState::Exited);
  86. m_state = ThreadState::Joined;
  87. if constexpr (IsVoid<T>)
  88. return {};
  89. else
  90. return { static_cast<T>(thread_return) };
  91. }
  92. }
  93. template<>
  94. struct AK::Formatter<Threading::Thread> : AK::Formatter<FormatString> {
  95. ErrorOr<void> format(FormatBuilder& builder, Threading::Thread const& thread)
  96. {
  97. return Formatter<FormatString>::format(builder, "Thread \"{}\"({})"sv, thread.thread_name(), thread.tid());
  98. }
  99. };
  100. template<>
  101. struct AK::Formatter<Threading::ThreadState> : AK::Formatter<FormatString> {
  102. ErrorOr<void> format(FormatBuilder& builder, Threading::ThreadState state)
  103. {
  104. ByteString name = "";
  105. switch (state) {
  106. case Threading::ThreadState::Detached:
  107. name = "Detached";
  108. break;
  109. case Threading::ThreadState::DetachedExited:
  110. name = "DetachedExited";
  111. break;
  112. case Threading::ThreadState::Exited:
  113. name = "Exited";
  114. break;
  115. case Threading::ThreadState::Joined:
  116. name = "Joined";
  117. break;
  118. case Threading::ThreadState::Running:
  119. name = "Running";
  120. break;
  121. case Threading::ThreadState::Startable:
  122. name = "Startable";
  123. break;
  124. default:
  125. VERIFY_NOT_REACHED();
  126. }
  127. return Formatter<FormatString>::format(builder, "{}"sv, name);
  128. }
  129. };