ThreadBlockers.cpp 25 KB

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