ThreadBlockers.cpp 25 KB

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