ThreadBlockers.cpp 24 KB

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