Thread.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibThreading/Thread.h>
  7. #include <pthread.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. namespace Threading {
  11. Thread::Thread(Function<intptr_t()> action, StringView thread_name)
  12. : Core::EventReceiver(nullptr)
  13. , m_action(move(action))
  14. , m_thread_name(thread_name.is_null() ? ""sv : thread_name)
  15. {
  16. }
  17. Thread::~Thread()
  18. {
  19. if (needs_to_be_joined()) {
  20. dbgln("Destroying {} while it is still running undetached!", *this);
  21. [[maybe_unused]] auto res = join();
  22. }
  23. if (m_state == ThreadState::Detached)
  24. dbgln("Bug! {} in state {} is being destroyed; AK/Function will crash shortly!", *this, m_state.load());
  25. }
  26. ErrorOr<void> Thread::set_priority(int priority)
  27. {
  28. // MacOS has an extra __opaque field, so list initialization will not compile on MacOS Lagom.
  29. sched_param scheduling_parameters {};
  30. scheduling_parameters.sched_priority = priority;
  31. int result = pthread_setschedparam(m_tid, 0, &scheduling_parameters);
  32. if (result != 0)
  33. return Error::from_errno(result);
  34. return {};
  35. }
  36. ErrorOr<int> Thread::get_priority() const
  37. {
  38. sched_param scheduling_parameters {};
  39. int policy;
  40. int result = pthread_getschedparam(m_tid, &policy, &scheduling_parameters);
  41. if (result != 0)
  42. return Error::from_errno(result);
  43. return scheduling_parameters.sched_priority;
  44. }
  45. DeprecatedString Thread::thread_name() const { return m_thread_name; }
  46. pthread_t Thread::tid() const { return m_tid; }
  47. ThreadState Thread::state() const { return m_state; }
  48. bool Thread::is_started() const { return m_state != ThreadState::Startable; }
  49. bool Threading::Thread::needs_to_be_joined() const
  50. {
  51. auto state = m_state.load();
  52. return state == ThreadState::Running || state == ThreadState::Exited;
  53. }
  54. bool Threading::Thread::has_exited() const
  55. {
  56. auto state = m_state.load();
  57. return state == ThreadState::Joined || state == ThreadState::Exited || state == ThreadState::DetachedExited;
  58. }
  59. void Thread::start()
  60. {
  61. VERIFY(!is_started());
  62. // Set this first so that the other thread starts out seeing m_state == Running.
  63. m_state = Threading::ThreadState::Running;
  64. int rc = pthread_create(
  65. &m_tid,
  66. // FIXME: Use pthread_attr_t to start a thread detached if that was requested by the user before the call to start().
  67. nullptr,
  68. [](void* arg) -> void* {
  69. Thread* self = static_cast<Thread*>(arg);
  70. auto exit_code = self->m_action();
  71. auto expected = Threading::ThreadState::Running;
  72. // This code might race with a call to detach().
  73. if (!self->m_state.compare_exchange_strong(expected, Threading::ThreadState::Exited)) {
  74. // If the original state was Detached, we need to set to DetachedExited instead.
  75. if (expected == Threading::ThreadState::Detached) {
  76. if (!self->m_state.compare_exchange_strong(expected, Threading::ThreadState::DetachedExited)) {
  77. dbgln("Thread logic bug: Found thread state {} while trying to set ExitedDetached state!", expected);
  78. VERIFY_NOT_REACHED();
  79. }
  80. } else {
  81. dbgln("Thread logic bug: Found thread state {} while trying to set Exited state!", expected);
  82. VERIFY_NOT_REACHED();
  83. }
  84. }
  85. return reinterpret_cast<void*>(exit_code);
  86. },
  87. static_cast<void*>(this));
  88. VERIFY(rc == 0);
  89. #ifdef AK_OS_SERENITY
  90. if (!m_thread_name.is_empty()) {
  91. rc = pthread_setname_np(m_tid, m_thread_name.characters());
  92. VERIFY(rc == 0);
  93. }
  94. #endif
  95. dbgln("Started {}", *this);
  96. }
  97. void Thread::detach()
  98. {
  99. auto expected = Threading::ThreadState::Running;
  100. // This code might race with the other thread exiting.
  101. if (!m_state.compare_exchange_strong(expected, Threading::ThreadState::Detached)) {
  102. if (expected == Threading::ThreadState::Exited)
  103. return;
  104. // Always report a precise error before crashing. These kinds of bugs are hard to reproduce.
  105. dbgln("Thread logic bug: trying to detach {} in state {}, which is neither Started nor Exited", this, expected);
  106. VERIFY_NOT_REACHED();
  107. }
  108. int rc = pthread_detach(m_tid);
  109. VERIFY(rc == 0);
  110. }
  111. }