ThreadBlockers.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Debug.h>
  7. #include <Kernel/FileSystem/FileDescription.h>
  8. #include <Kernel/Net/Socket.h>
  9. #include <Kernel/Process.h>
  10. #include <Kernel/Scheduler.h>
  11. #include <Kernel/Thread.h>
  12. namespace Kernel {
  13. Thread::BlockTimeout::BlockTimeout(bool is_absolute, const Time* time, const Time* start_time, clockid_t clock_id)
  14. : m_clock_id(clock_id)
  15. , m_infinite(!time)
  16. {
  17. if (m_infinite)
  18. return;
  19. if (*time > Time::zero())
  20. m_time = *time;
  21. m_start_time = start_time ? *start_time : TimeManagement::the().current_time(clock_id);
  22. if (!is_absolute)
  23. m_time += m_start_time;
  24. }
  25. bool Thread::Blocker::add_to_blocker_set(Thread::BlockerSet& blocker_set, void* data)
  26. {
  27. VERIFY(!m_blocker_set);
  28. if (blocker_set.add_blocker(*this, data)) {
  29. m_blocker_set = &blocker_set;
  30. return true;
  31. }
  32. return false;
  33. }
  34. Thread::Blocker::~Blocker()
  35. {
  36. VERIFY(!m_lock.is_locked());
  37. if (m_blocker_set)
  38. m_blocker_set->remove_blocker(*this);
  39. }
  40. bool Thread::Blocker::setup_blocker()
  41. {
  42. return true;
  43. }
  44. void Thread::Blocker::begin_blocking(Badge<Thread>)
  45. {
  46. SpinlockLocker lock(m_lock);
  47. VERIFY(!m_is_blocking);
  48. m_is_blocking = true;
  49. }
  50. auto Thread::Blocker::end_blocking(Badge<Thread>, bool did_timeout) -> BlockResult
  51. {
  52. SpinlockLocker lock(m_lock);
  53. // if m_is_blocking is false here, some thread forced to
  54. // unblock us when we get here. This is only called from the
  55. // thread that was blocked.
  56. VERIFY(Thread::current() == m_thread);
  57. m_is_blocking = false;
  58. was_unblocked(did_timeout);
  59. return block_result();
  60. }
  61. Thread::JoinBlocker::JoinBlocker(Thread& joinee, KResult& try_join_result, void*& joinee_exit_value)
  62. : m_joinee(joinee)
  63. , m_joinee_exit_value(joinee_exit_value)
  64. , m_try_join_result(try_join_result)
  65. {
  66. }
  67. bool Thread::JoinBlocker::setup_blocker()
  68. {
  69. // We need to hold our lock to avoid a race where try_join succeeds
  70. // but the joinee is joining immediately
  71. SpinlockLocker lock(m_lock);
  72. bool should_block = true;
  73. m_try_join_result = m_joinee->try_join([&]() {
  74. if (!add_to_blocker_set(m_joinee->m_join_blocker_set))
  75. should_block = false;
  76. });
  77. if (m_try_join_result.is_error())
  78. return false;
  79. return should_block;
  80. }
  81. void Thread::JoinBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
  82. {
  83. // If we should have blocked but got here it must have been that the
  84. // timeout was already in the past. So we need to ask the BlockerSet
  85. // to supply us the information. We cannot hold the lock as unblock
  86. // could be called by the BlockerSet at any time!
  87. if (reason == UnblockImmediatelyReason::TimeoutInThePast) {
  88. m_joinee->m_join_blocker_set.try_unblock(*this);
  89. }
  90. }
  91. bool Thread::JoinBlocker::unblock(void* value, bool from_add_blocker)
  92. {
  93. {
  94. SpinlockLocker lock(m_lock);
  95. if (m_did_unblock)
  96. return false;
  97. m_did_unblock = true;
  98. m_joinee_exit_value = value;
  99. do_set_interrupted_by_death();
  100. }
  101. if (!from_add_blocker)
  102. unblock_from_blocker();
  103. return true;
  104. }
  105. Thread::WaitQueueBlocker::WaitQueueBlocker(WaitQueue& wait_queue, StringView block_reason)
  106. : m_wait_queue(wait_queue)
  107. , m_block_reason(block_reason)
  108. {
  109. }
  110. bool Thread::WaitQueueBlocker::setup_blocker()
  111. {
  112. return add_to_blocker_set(m_wait_queue);
  113. }
  114. Thread::WaitQueueBlocker::~WaitQueueBlocker()
  115. {
  116. }
  117. bool Thread::WaitQueueBlocker::unblock()
  118. {
  119. {
  120. SpinlockLocker lock(m_lock);
  121. if (m_did_unblock)
  122. return false;
  123. m_did_unblock = true;
  124. }
  125. unblock_from_blocker();
  126. return true;
  127. }
  128. Thread::FutexBlocker::FutexBlocker(FutexQueue& futex_queue, u32 bitset)
  129. : m_futex_queue(futex_queue)
  130. , m_bitset(bitset)
  131. {
  132. }
  133. bool Thread::FutexBlocker::setup_blocker()
  134. {
  135. return add_to_blocker_set(m_futex_queue);
  136. }
  137. Thread::FutexBlocker::~FutexBlocker()
  138. {
  139. }
  140. void Thread::FutexBlocker::finish_requeue(FutexQueue& futex_queue)
  141. {
  142. VERIFY(m_lock.is_locked_by_current_processor());
  143. set_blocker_set_raw_locked(&futex_queue);
  144. // We can now release the lock
  145. m_lock.unlock(m_relock_flags);
  146. }
  147. bool Thread::FutexBlocker::unblock_bitset(u32 bitset)
  148. {
  149. {
  150. SpinlockLocker lock(m_lock);
  151. if (m_did_unblock || (bitset != FUTEX_BITSET_MATCH_ANY && (m_bitset & bitset) == 0))
  152. return false;
  153. m_did_unblock = true;
  154. }
  155. unblock_from_blocker();
  156. return true;
  157. }
  158. bool Thread::FutexBlocker::unblock(bool force)
  159. {
  160. {
  161. SpinlockLocker lock(m_lock);
  162. if (m_did_unblock)
  163. return force;
  164. m_did_unblock = true;
  165. }
  166. unblock_from_blocker();
  167. return true;
  168. }
  169. Thread::FileDescriptionBlocker::FileDescriptionBlocker(FileDescription& description, BlockFlags flags, BlockFlags& unblocked_flags)
  170. : m_blocked_description(description)
  171. , m_flags(flags)
  172. , m_unblocked_flags(unblocked_flags)
  173. {
  174. }
  175. bool Thread::FileDescriptionBlocker::setup_blocker()
  176. {
  177. m_unblocked_flags = BlockFlags::None;
  178. return add_to_blocker_set(m_blocked_description->blocker_set());
  179. }
  180. bool Thread::FileDescriptionBlocker::unblock_if_conditions_are_met(bool from_add_blocker, void*)
  181. {
  182. auto unblock_flags = m_blocked_description->should_unblock(m_flags);
  183. if (unblock_flags == BlockFlags::None)
  184. return false;
  185. {
  186. SpinlockLocker lock(m_lock);
  187. if (m_did_unblock)
  188. return false;
  189. m_did_unblock = true;
  190. m_unblocked_flags = unblock_flags;
  191. }
  192. if (!from_add_blocker)
  193. unblock_from_blocker();
  194. return true;
  195. }
  196. void Thread::FileDescriptionBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
  197. {
  198. if (reason == UnblockImmediatelyReason::UnblockConditionAlreadyMet)
  199. return;
  200. // If we should have blocked but got here it must have been that the
  201. // timeout was already in the past. So we need to ask the BlockerSet
  202. // to supply us the information. We cannot hold the lock as unblock
  203. // could be called by the BlockerSet at any time!
  204. VERIFY(reason == UnblockImmediatelyReason::TimeoutInThePast);
  205. // Just call unblock_if_conditions_are_met here because we will query the file description
  206. // for the data and don't need any input from the FileBlockerSet.
  207. // However, it's possible that if timeout_in_past is true then FileBlockerSet
  208. // may call us at any given time, so our call to unblock here may fail.
  209. // Either way, unblock will be called at least once, which provides
  210. // all the data we need.
  211. unblock_if_conditions_are_met(false, nullptr);
  212. }
  213. const FileDescription& Thread::FileDescriptionBlocker::blocked_description() const
  214. {
  215. return m_blocked_description;
  216. }
  217. Thread::AcceptBlocker::AcceptBlocker(FileDescription& description, BlockFlags& unblocked_flags)
  218. : FileDescriptionBlocker(description, BlockFlags::Accept | BlockFlags::Exception, unblocked_flags)
  219. {
  220. }
  221. Thread::ConnectBlocker::ConnectBlocker(FileDescription& description, BlockFlags& unblocked_flags)
  222. : FileDescriptionBlocker(description, BlockFlags::Connect | BlockFlags::Exception, unblocked_flags)
  223. {
  224. }
  225. Thread::WriteBlocker::WriteBlocker(FileDescription& description, BlockFlags& unblocked_flags)
  226. : FileDescriptionBlocker(description, BlockFlags::Write | BlockFlags::Exception, unblocked_flags)
  227. {
  228. }
  229. auto Thread::WriteBlocker::override_timeout(const BlockTimeout& timeout) -> const BlockTimeout&
  230. {
  231. auto& description = blocked_description();
  232. if (description.is_socket()) {
  233. auto& socket = *description.socket();
  234. if (socket.has_send_timeout()) {
  235. Time send_timeout = socket.send_timeout();
  236. m_timeout = BlockTimeout(false, &send_timeout, timeout.start_time(), timeout.clock_id());
  237. if (timeout.is_infinite() || (!m_timeout.is_infinite() && m_timeout.absolute_time() < timeout.absolute_time()))
  238. return m_timeout;
  239. }
  240. }
  241. return timeout;
  242. }
  243. Thread::ReadBlocker::ReadBlocker(FileDescription& description, BlockFlags& unblocked_flags)
  244. : FileDescriptionBlocker(description, BlockFlags::Read | BlockFlags::Exception, unblocked_flags)
  245. {
  246. }
  247. auto Thread::ReadBlocker::override_timeout(const BlockTimeout& timeout) -> const BlockTimeout&
  248. {
  249. auto& description = blocked_description();
  250. if (description.is_socket()) {
  251. auto& socket = *description.socket();
  252. if (socket.has_receive_timeout()) {
  253. Time receive_timeout = socket.receive_timeout();
  254. m_timeout = BlockTimeout(false, &receive_timeout, timeout.start_time(), timeout.clock_id());
  255. if (timeout.is_infinite() || (!m_timeout.is_infinite() && m_timeout.absolute_time() < timeout.absolute_time()))
  256. return m_timeout;
  257. }
  258. }
  259. return timeout;
  260. }
  261. Thread::SleepBlocker::SleepBlocker(const BlockTimeout& deadline, Time* remaining)
  262. : m_deadline(deadline)
  263. , m_remaining(remaining)
  264. {
  265. }
  266. auto Thread::SleepBlocker::override_timeout(const BlockTimeout& timeout) -> const BlockTimeout&
  267. {
  268. VERIFY(timeout.is_infinite()); // A timeout should not be provided
  269. // To simplify things only use the sleep deadline.
  270. return m_deadline;
  271. }
  272. void Thread::SleepBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
  273. {
  274. // SleepBlocker::should_block should always return true, so timeout
  275. // in the past is the only valid case when this function is called
  276. VERIFY(reason == UnblockImmediatelyReason::TimeoutInThePast);
  277. calculate_remaining();
  278. }
  279. void Thread::SleepBlocker::was_unblocked(bool did_timeout)
  280. {
  281. Blocker::was_unblocked(did_timeout);
  282. calculate_remaining();
  283. }
  284. void Thread::SleepBlocker::calculate_remaining()
  285. {
  286. if (!m_remaining)
  287. return;
  288. auto time_now = TimeManagement::the().current_time(m_deadline.clock_id());
  289. if (time_now < m_deadline.absolute_time())
  290. *m_remaining = m_deadline.absolute_time() - time_now;
  291. else
  292. *m_remaining = {};
  293. }
  294. Thread::BlockResult Thread::SleepBlocker::block_result()
  295. {
  296. auto result = Blocker::block_result();
  297. if (result == Thread::BlockResult::InterruptedByTimeout)
  298. return Thread::BlockResult::WokeNormally;
  299. return result;
  300. }
  301. Thread::SelectBlocker::SelectBlocker(FDVector& fds)
  302. : m_fds(fds)
  303. {
  304. }
  305. bool Thread::SelectBlocker::setup_blocker()
  306. {
  307. bool should_block = true;
  308. for (auto& fd_entry : m_fds) {
  309. fd_entry.unblocked_flags = FileBlocker::BlockFlags::None;
  310. if (!should_block)
  311. continue;
  312. if (!fd_entry.description->blocker_set().add_blocker(*this, &fd_entry))
  313. should_block = false;
  314. }
  315. return should_block;
  316. }
  317. Thread::SelectBlocker::~SelectBlocker()
  318. {
  319. for (auto& fd_entry : m_fds)
  320. fd_entry.description->blocker_set().remove_blocker(*this);
  321. }
  322. void Thread::SelectBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
  323. {
  324. SpinlockLocker lock(m_lock);
  325. if (m_did_unblock)
  326. return;
  327. m_did_unblock = true;
  328. if (reason == UnblockImmediatelyReason::UnblockConditionAlreadyMet) {
  329. auto count = collect_unblocked_flags();
  330. VERIFY(count > 0);
  331. }
  332. }
  333. bool Thread::SelectBlocker::unblock_if_conditions_are_met(bool from_add_blocker, void* data)
  334. {
  335. VERIFY(data); // data is a pointer to an entry in the m_fds vector
  336. auto& fd_info = *static_cast<FDInfo*>(data);
  337. {
  338. SpinlockLocker lock(m_lock);
  339. if (m_did_unblock)
  340. return false;
  341. auto unblock_flags = fd_info.description->should_unblock(fd_info.block_flags);
  342. if (unblock_flags == BlockFlags::None)
  343. return false;
  344. m_did_unblock = true;
  345. // We need to store unblock_flags here, otherwise someone else
  346. // affecting this file descriptor could change the information
  347. // between now and when was_unblocked is called!
  348. fd_info.unblocked_flags = unblock_flags;
  349. }
  350. // Only do this once for the first one
  351. if (!from_add_blocker)
  352. unblock_from_blocker();
  353. return true;
  354. }
  355. size_t Thread::SelectBlocker::collect_unblocked_flags()
  356. {
  357. size_t count = 0;
  358. for (auto& fd_entry : m_fds) {
  359. VERIFY(fd_entry.block_flags != FileBlocker::BlockFlags::None);
  360. // unblock will have set at least the first descriptor's unblock
  361. // flags that triggered the unblock. Make sure we don't discard that
  362. // information as it may have changed by now!
  363. if (fd_entry.unblocked_flags == FileBlocker::BlockFlags::None)
  364. fd_entry.unblocked_flags = fd_entry.description->should_unblock(fd_entry.block_flags);
  365. if (fd_entry.unblocked_flags != FileBlocker::BlockFlags::None)
  366. count++;
  367. }
  368. return count;
  369. }
  370. void Thread::SelectBlocker::was_unblocked(bool did_timeout)
  371. {
  372. Blocker::was_unblocked(did_timeout);
  373. if (!did_timeout && !was_interrupted()) {
  374. {
  375. SpinlockLocker lock(m_lock);
  376. VERIFY(m_did_unblock);
  377. }
  378. size_t count = collect_unblocked_flags();
  379. // If we were blocked and didn't time out, we should have at least one unblocked fd!
  380. VERIFY(count > 0);
  381. }
  382. }
  383. Thread::WaitBlockerSet::ProcessBlockInfo::ProcessBlockInfo(NonnullRefPtr<Process>&& process, WaitBlocker::UnblockFlags flags, u8 signal)
  384. : process(move(process))
  385. , flags(flags)
  386. , signal(signal)
  387. {
  388. }
  389. Thread::WaitBlockerSet::ProcessBlockInfo::~ProcessBlockInfo()
  390. {
  391. }
  392. void Thread::WaitBlockerSet::try_unblock(Thread::WaitBlocker& blocker)
  393. {
  394. SpinlockLocker lock(m_lock);
  395. // We if we have any processes pending
  396. for (size_t i = 0; i < m_processes.size(); i++) {
  397. auto& info = m_processes[i];
  398. // We need to call unblock as if we were called from add_blocker
  399. // so that we don't trigger a context switch by yielding!
  400. if (info.was_waited && blocker.is_wait())
  401. continue; // This state was already waited on, do not unblock
  402. if (blocker.unblock(info.process, info.flags, info.signal, true)) {
  403. if (blocker.is_wait()) {
  404. if (info.flags == Thread::WaitBlocker::UnblockFlags::Terminated) {
  405. m_processes.remove(i);
  406. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] terminated, remove {}", m_process, *info.process);
  407. } else {
  408. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] terminated, mark as waited {}", m_process, *info.process);
  409. info.was_waited = true;
  410. }
  411. }
  412. break;
  413. }
  414. }
  415. }
  416. void Thread::WaitBlockerSet::disowned_by_waiter(Process& process)
  417. {
  418. SpinlockLocker lock(m_lock);
  419. if (m_finalized)
  420. return;
  421. for (size_t i = 0; i < m_processes.size();) {
  422. auto& info = m_processes[i];
  423. if (info.process == &process) {
  424. unblock_all_blockers_whose_conditions_are_met_locked([&](Blocker& b, void*, bool&) {
  425. VERIFY(b.blocker_type() == Blocker::Type::Wait);
  426. auto& blocker = static_cast<WaitBlocker&>(b);
  427. bool did_unblock = blocker.unblock(info.process, WaitBlocker::UnblockFlags::Disowned, 0, false);
  428. VERIFY(did_unblock); // disowning must unblock everyone
  429. return true;
  430. });
  431. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] disowned {}", m_process, *info.process);
  432. m_processes.remove(i);
  433. continue;
  434. }
  435. i++;
  436. }
  437. }
  438. bool Thread::WaitBlockerSet::unblock(Process& process, WaitBlocker::UnblockFlags flags, u8 signal)
  439. {
  440. VERIFY(flags != WaitBlocker::UnblockFlags::Disowned);
  441. bool did_unblock_any = false;
  442. bool did_wait = false;
  443. bool was_waited_already = false;
  444. SpinlockLocker lock(m_lock);
  445. if (m_finalized)
  446. return false;
  447. if (flags != WaitBlocker::UnblockFlags::Terminated) {
  448. // First check if this state was already waited on
  449. for (auto& info : m_processes) {
  450. if (info.process == &process) {
  451. was_waited_already = info.was_waited;
  452. break;
  453. }
  454. }
  455. }
  456. unblock_all_blockers_whose_conditions_are_met_locked([&](Blocker& b, void*, bool&) {
  457. VERIFY(b.blocker_type() == Blocker::Type::Wait);
  458. auto& blocker = static_cast<WaitBlocker&>(b);
  459. if (was_waited_already && blocker.is_wait())
  460. return false; // This state was already waited on, do not unblock
  461. if (blocker.unblock(process, flags, signal, false)) {
  462. did_wait |= blocker.is_wait(); // anyone requesting a wait
  463. did_unblock_any = true;
  464. return true;
  465. }
  466. return false;
  467. });
  468. // If no one has waited (yet), or this wasn't a wait, or if it's anything other than
  469. // UnblockFlags::Terminated then add it to your list
  470. if (!did_unblock_any || !did_wait || flags != WaitBlocker::UnblockFlags::Terminated) {
  471. bool updated_existing = false;
  472. for (auto& info : m_processes) {
  473. if (info.process == &process) {
  474. VERIFY(info.flags != WaitBlocker::UnblockFlags::Terminated);
  475. info.flags = flags;
  476. info.signal = signal;
  477. info.was_waited = did_wait;
  478. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] update {} flags={}, waited={}", m_process, process, (int)flags, info.was_waited);
  479. updated_existing = true;
  480. break;
  481. }
  482. }
  483. if (!updated_existing) {
  484. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] add {} flags: {}", m_process, process, (int)flags);
  485. m_processes.append(ProcessBlockInfo(process, flags, signal));
  486. }
  487. }
  488. return did_unblock_any;
  489. }
  490. bool Thread::WaitBlockerSet::should_add_blocker(Blocker& b, void*)
  491. {
  492. // NOTE: m_lock is held already!
  493. if (m_finalized)
  494. return false;
  495. VERIFY(b.blocker_type() == Blocker::Type::Wait);
  496. auto& blocker = static_cast<WaitBlocker&>(b);
  497. // See if we can match any process immediately
  498. for (size_t i = 0; i < m_processes.size(); i++) {
  499. auto& info = m_processes[i];
  500. if (blocker.unblock(info.process, info.flags, info.signal, true)) {
  501. // Only remove the entry if UnblockFlags::Terminated
  502. if (info.flags == Thread::WaitBlocker::UnblockFlags::Terminated && blocker.is_wait())
  503. m_processes.remove(i);
  504. return false;
  505. }
  506. }
  507. return true;
  508. }
  509. void Thread::WaitBlockerSet::finalize()
  510. {
  511. SpinlockLocker lock(m_lock);
  512. VERIFY(!m_finalized);
  513. m_finalized = true;
  514. // Clear the list of threads here so we can drop the references to them
  515. m_processes.clear();
  516. // NOTE: Kernel processes don't have a leaked ref on them.
  517. if (!m_process.is_kernel_process()) {
  518. // No more waiters, drop the last reference immediately. This may
  519. // cause us to be destructed ourselves!
  520. VERIFY(m_process.ref_count() > 0);
  521. m_process.unref();
  522. }
  523. }
  524. Thread::WaitBlocker::WaitBlocker(int wait_options, Variant<Empty, NonnullRefPtr<Process>, NonnullRefPtr<ProcessGroup>> waitee, KResultOr<siginfo_t>& result)
  525. : m_wait_options(wait_options)
  526. , m_result(result)
  527. , m_waitee(move(waitee))
  528. {
  529. }
  530. bool Thread::WaitBlocker::setup_blocker()
  531. {
  532. if (m_wait_options & WNOHANG)
  533. return false;
  534. return add_to_blocker_set(Process::current().wait_blocker_set());
  535. }
  536. void Thread::WaitBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason)
  537. {
  538. Process::current().wait_blocker_set().try_unblock(*this);
  539. }
  540. void Thread::WaitBlocker::was_unblocked(bool)
  541. {
  542. bool got_sigchld, try_unblock;
  543. {
  544. SpinlockLocker lock(m_lock);
  545. try_unblock = !m_did_unblock;
  546. got_sigchld = m_got_sigchild;
  547. }
  548. if (try_unblock)
  549. Process::current().wait_blocker_set().try_unblock(*this);
  550. // If we were interrupted by SIGCHLD (which gets special handling
  551. // here) we're not going to return with EINTR. But we're going to
  552. // deliver SIGCHLD (only) here.
  553. auto* current_thread = Thread::current();
  554. if (got_sigchld && current_thread->state() != State::Stopped)
  555. current_thread->try_dispatch_one_pending_signal(SIGCHLD);
  556. }
  557. void Thread::WaitBlocker::do_was_disowned()
  558. {
  559. VERIFY(!m_did_unblock);
  560. m_did_unblock = true;
  561. m_result = ECHILD;
  562. }
  563. void Thread::WaitBlocker::do_set_result(const siginfo_t& result)
  564. {
  565. VERIFY(!m_did_unblock);
  566. m_did_unblock = true;
  567. m_result = result;
  568. if (do_get_interrupted_by_signal() == SIGCHLD) {
  569. // This makes it so that wait() will return normally despite the
  570. // fact that SIGCHLD was delivered. Calling do_clear_interrupted_by_signal
  571. // will disable dispatching signals in Thread::block and prevent
  572. // it from returning with EINTR. We will then manually dispatch
  573. // SIGCHLD (and only SIGCHLD) in was_unblocked.
  574. m_got_sigchild = true;
  575. do_clear_interrupted_by_signal();
  576. }
  577. }
  578. bool Thread::WaitBlocker::unblock(Process& process, UnblockFlags flags, u8 signal, bool from_add_blocker)
  579. {
  580. VERIFY(flags != UnblockFlags::Terminated || signal == 0); // signal argument should be ignored for Terminated
  581. bool do_not_unblock = m_waitee.visit(
  582. [&](NonnullRefPtr<Process> const& waitee_process) {
  583. return &process != waitee_process;
  584. },
  585. [&](NonnullRefPtr<ProcessGroup> const& waitee_process_group) {
  586. return waitee_process_group->pgid() != process.pgid();
  587. },
  588. [&](Empty const&) {
  589. // Generic waiter won't be unblocked by disown
  590. return flags == UnblockFlags::Disowned;
  591. });
  592. if (do_not_unblock)
  593. return false;
  594. switch (flags) {
  595. case UnblockFlags::Terminated:
  596. if (!(m_wait_options & WEXITED))
  597. return false;
  598. break;
  599. case UnblockFlags::Stopped:
  600. if (!(m_wait_options & WSTOPPED))
  601. return false;
  602. if (!(m_wait_options & WUNTRACED) && !process.is_traced())
  603. return false;
  604. break;
  605. case UnblockFlags::Continued:
  606. if (!(m_wait_options & WCONTINUED))
  607. return false;
  608. if (!(m_wait_options & WUNTRACED) && !process.is_traced())
  609. return false;
  610. break;
  611. case UnblockFlags::Disowned:
  612. SpinlockLocker lock(m_lock);
  613. // Disowning must unblock anyone waiting for this process explicitly
  614. if (!m_did_unblock)
  615. do_was_disowned();
  616. return true;
  617. }
  618. if (flags == UnblockFlags::Terminated) {
  619. VERIFY(process.is_dead());
  620. SpinlockLocker lock(m_lock);
  621. if (m_did_unblock)
  622. return false;
  623. // Up until this point, this function may have been called
  624. // more than once!
  625. do_set_result(process.wait_info());
  626. } else {
  627. siginfo_t siginfo {};
  628. {
  629. SpinlockLocker lock(g_scheduler_lock);
  630. // We need to gather the information before we release the scheduler lock!
  631. siginfo.si_signo = SIGCHLD;
  632. siginfo.si_pid = process.pid().value();
  633. siginfo.si_uid = process.uid().value();
  634. siginfo.si_status = signal;
  635. switch (flags) {
  636. case UnblockFlags::Terminated:
  637. case UnblockFlags::Disowned:
  638. VERIFY_NOT_REACHED();
  639. case UnblockFlags::Stopped:
  640. siginfo.si_code = CLD_STOPPED;
  641. break;
  642. case UnblockFlags::Continued:
  643. siginfo.si_code = CLD_CONTINUED;
  644. break;
  645. }
  646. }
  647. SpinlockLocker lock(m_lock);
  648. if (m_did_unblock)
  649. return false;
  650. // Up until this point, this function may have been called
  651. // more than once!
  652. do_set_result(siginfo);
  653. }
  654. if (!from_add_blocker) {
  655. // Only call unblock if we weren't called from within add_to_blocker_set!
  656. VERIFY(flags != UnblockFlags::Disowned);
  657. unblock_from_blocker();
  658. }
  659. // Because this may be called from add_blocker, in which case we should
  660. // not be actually trying to unblock the thread (because it hasn't actually
  661. // been blocked yet), we need to return true anyway
  662. return true;
  663. }
  664. }