ThreadBlockers.cpp 25 KB

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