ThreadBlockers.cpp 26 KB

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