ThreadBlockers.cpp 25 KB

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