ThreadBlockers.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. * Copyright (c) 2022, Idan Horowitz <idan.horowitz@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/BuiltinWrappers.h>
  8. #include <Kernel/Debug.h>
  9. #include <Kernel/FileSystem/OpenFileDescription.h>
  10. #include <Kernel/Net/Socket.h>
  11. #include <Kernel/Process.h>
  12. #include <Kernel/Scheduler.h>
  13. #include <Kernel/Thread.h>
  14. namespace Kernel {
  15. Thread::BlockTimeout::BlockTimeout(bool is_absolute, Time const* time, Time const* start_time, clockid_t clock_id)
  16. : m_clock_id(clock_id)
  17. , m_infinite(!time)
  18. {
  19. if (m_infinite)
  20. return;
  21. if (*time > Time::zero())
  22. m_time = *time;
  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() = default;
  37. void Thread::Blocker::finalize()
  38. {
  39. if (m_blocker_set)
  40. m_blocker_set->remove_blocker(*this);
  41. }
  42. bool Thread::Blocker::setup_blocker()
  43. {
  44. return true;
  45. }
  46. void Thread::Blocker::begin_blocking(Badge<Thread>)
  47. {
  48. SpinlockLocker lock(m_lock);
  49. VERIFY(!m_is_blocking);
  50. m_is_blocking = true;
  51. }
  52. auto Thread::Blocker::end_blocking(Badge<Thread>, bool did_timeout) -> BlockResult
  53. {
  54. SpinlockLocker lock(m_lock);
  55. // if m_is_blocking is false here, some thread forced to
  56. // unblock us when we get here. This is only called from the
  57. // thread that was blocked.
  58. VERIFY(Thread::current() == m_thread);
  59. m_is_blocking = false;
  60. was_unblocked(did_timeout);
  61. return block_result();
  62. }
  63. Thread::JoinBlocker::JoinBlocker(Thread& joinee, ErrorOr<void>& try_join_result, void*& joinee_exit_value)
  64. : m_joinee(joinee)
  65. , m_joinee_exit_value(joinee_exit_value)
  66. , m_try_join_result(try_join_result)
  67. {
  68. }
  69. bool Thread::JoinBlocker::setup_blocker()
  70. {
  71. // We need to hold our lock to avoid a race where try_join succeeds
  72. // but the joinee is joining immediately
  73. SpinlockLocker lock(m_lock);
  74. bool should_block = true;
  75. m_try_join_result = m_joinee->try_join([&]() {
  76. if (!add_to_blocker_set(m_joinee->m_join_blocker_set))
  77. should_block = false;
  78. });
  79. if (m_try_join_result.is_error())
  80. return false;
  81. return should_block;
  82. }
  83. void Thread::JoinBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
  84. {
  85. // If we should have blocked but got here it must have been that the
  86. // timeout was already in the past. So we need to ask the BlockerSet
  87. // to supply us the information. We cannot hold the lock as unblock
  88. // could be called by the BlockerSet at any time!
  89. if (reason == UnblockImmediatelyReason::TimeoutInThePast) {
  90. m_joinee->m_join_blocker_set.try_unblock(*this);
  91. }
  92. }
  93. bool Thread::JoinBlocker::unblock(void* value, bool from_add_blocker)
  94. {
  95. {
  96. SpinlockLocker lock(m_lock);
  97. if (m_did_unblock)
  98. return false;
  99. m_did_unblock = true;
  100. m_joinee_exit_value = value;
  101. do_set_interrupted_by_death();
  102. }
  103. if (!from_add_blocker)
  104. unblock_from_blocker();
  105. return true;
  106. }
  107. Thread::WaitQueueBlocker::WaitQueueBlocker(WaitQueue& wait_queue, StringView block_reason)
  108. : m_wait_queue(wait_queue)
  109. , m_block_reason(block_reason)
  110. {
  111. }
  112. bool Thread::WaitQueueBlocker::setup_blocker()
  113. {
  114. return add_to_blocker_set(m_wait_queue);
  115. }
  116. Thread::WaitQueueBlocker::~WaitQueueBlocker() = default;
  117. bool Thread::WaitQueueBlocker::unblock()
  118. {
  119. {
  120. SpinlockLocker 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_futex_queue(futex_queue)
  130. , m_bitset(bitset)
  131. {
  132. }
  133. bool Thread::FutexBlocker::setup_blocker()
  134. {
  135. return add_to_blocker_set(m_futex_queue);
  136. }
  137. Thread::FutexBlocker::~FutexBlocker() = default;
  138. void Thread::FutexBlocker::finish_requeue(FutexQueue& futex_queue)
  139. {
  140. VERIFY(m_lock.is_locked_by_current_processor());
  141. set_blocker_set_raw_locked(&futex_queue);
  142. // We can now release the lock
  143. m_lock.unlock(m_relock_flags);
  144. }
  145. bool Thread::FutexBlocker::unblock_bitset(u32 bitset)
  146. {
  147. {
  148. SpinlockLocker lock(m_lock);
  149. if (m_did_unblock || (bitset != FUTEX_BITSET_MATCH_ANY && (m_bitset & bitset) == 0))
  150. return false;
  151. m_did_unblock = true;
  152. }
  153. unblock_from_blocker();
  154. return true;
  155. }
  156. bool Thread::FutexBlocker::unblock(bool force)
  157. {
  158. {
  159. SpinlockLocker lock(m_lock);
  160. if (m_did_unblock)
  161. return force;
  162. m_did_unblock = true;
  163. }
  164. unblock_from_blocker();
  165. return true;
  166. }
  167. Thread::OpenFileDescriptionBlocker::OpenFileDescriptionBlocker(OpenFileDescription& description, BlockFlags flags, BlockFlags& unblocked_flags)
  168. : m_blocked_description(description)
  169. , m_flags(flags)
  170. , m_unblocked_flags(unblocked_flags)
  171. {
  172. }
  173. bool Thread::OpenFileDescriptionBlocker::setup_blocker()
  174. {
  175. m_unblocked_flags = BlockFlags::None;
  176. return add_to_blocker_set(m_blocked_description->blocker_set());
  177. }
  178. bool Thread::OpenFileDescriptionBlocker::unblock_if_conditions_are_met(bool from_add_blocker, void*)
  179. {
  180. auto unblock_flags = m_blocked_description->should_unblock(m_flags);
  181. if (unblock_flags == BlockFlags::None)
  182. return false;
  183. {
  184. SpinlockLocker lock(m_lock);
  185. if (m_did_unblock)
  186. return false;
  187. m_did_unblock = true;
  188. m_unblocked_flags = unblock_flags;
  189. }
  190. if (!from_add_blocker)
  191. unblock_from_blocker();
  192. return true;
  193. }
  194. void Thread::OpenFileDescriptionBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
  195. {
  196. if (reason == UnblockImmediatelyReason::UnblockConditionAlreadyMet)
  197. return;
  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 BlockerSet
  200. // to supply us the information. We cannot hold the lock as unblock
  201. // could be called by the BlockerSet at any time!
  202. VERIFY(reason == UnblockImmediatelyReason::TimeoutInThePast);
  203. // Just call unblock_if_conditions_are_met here because we will query the file description
  204. // for the data and don't need any input from the FileBlockerSet.
  205. // However, it's possible that if timeout_in_past is true then FileBlockerSet
  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_if_conditions_are_met(false, nullptr);
  210. }
  211. OpenFileDescription const& Thread::OpenFileDescriptionBlocker::blocked_description() const
  212. {
  213. return m_blocked_description;
  214. }
  215. Thread::AcceptBlocker::AcceptBlocker(OpenFileDescription& description, BlockFlags& unblocked_flags)
  216. : OpenFileDescriptionBlocker(description, BlockFlags::Accept | BlockFlags::Exception, unblocked_flags)
  217. {
  218. }
  219. Thread::ConnectBlocker::ConnectBlocker(OpenFileDescription& description, BlockFlags& unblocked_flags)
  220. : OpenFileDescriptionBlocker(description, BlockFlags::Connect | BlockFlags::Exception, unblocked_flags)
  221. {
  222. }
  223. Thread::WriteBlocker::WriteBlocker(OpenFileDescription& description, BlockFlags& unblocked_flags)
  224. : OpenFileDescriptionBlocker(description, BlockFlags::Write | BlockFlags::Exception, unblocked_flags)
  225. {
  226. }
  227. auto Thread::WriteBlocker::override_timeout(BlockTimeout const& timeout) -> BlockTimeout const&
  228. {
  229. auto const& description = blocked_description();
  230. if (description.is_socket()) {
  231. auto const& 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(OpenFileDescription& description, BlockFlags& unblocked_flags)
  242. : OpenFileDescriptionBlocker(description, BlockFlags::Read | BlockFlags::Exception, unblocked_flags)
  243. {
  244. }
  245. auto Thread::ReadBlocker::override_timeout(BlockTimeout const& timeout) -> BlockTimeout const&
  246. {
  247. auto const& description = blocked_description();
  248. if (description.is_socket()) {
  249. auto const& 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(BlockTimeout const& deadline, Time* remaining)
  260. : m_deadline(deadline)
  261. , m_remaining(remaining)
  262. {
  263. }
  264. auto Thread::SleepBlocker::override_timeout(BlockTimeout const& timeout) -> BlockTimeout const&
  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::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
  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(reason == UnblockImmediatelyReason::TimeoutInThePast);
  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());
  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. }
  303. bool Thread::SelectBlocker::setup_blocker()
  304. {
  305. bool should_block = true;
  306. for (auto& fd_entry : m_fds) {
  307. fd_entry.unblocked_flags = FileBlocker::BlockFlags::None;
  308. if (!should_block)
  309. continue;
  310. if (!fd_entry.description) {
  311. should_block = false;
  312. continue;
  313. }
  314. if (!fd_entry.description->blocker_set().add_blocker(*this, &fd_entry))
  315. should_block = false;
  316. }
  317. return should_block;
  318. }
  319. Thread::SelectBlocker::~SelectBlocker() = default;
  320. void Thread::SelectBlocker::finalize()
  321. {
  322. Thread::FileBlocker::finalize();
  323. for (auto& fd_entry : m_fds) {
  324. if (fd_entry.description)
  325. fd_entry.description->blocker_set().remove_blocker(*this);
  326. }
  327. }
  328. void Thread::SelectBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
  329. {
  330. SpinlockLocker lock(m_lock);
  331. if (m_did_unblock)
  332. return;
  333. m_did_unblock = true;
  334. if (reason == UnblockImmediatelyReason::UnblockConditionAlreadyMet) {
  335. auto count = collect_unblocked_flags();
  336. VERIFY(count > 0);
  337. }
  338. }
  339. bool Thread::SelectBlocker::unblock_if_conditions_are_met(bool from_add_blocker, void* data)
  340. {
  341. VERIFY(data); // data is a pointer to an entry in the m_fds vector
  342. auto& fd_info = *static_cast<FDInfo*>(data);
  343. {
  344. SpinlockLocker lock(m_lock);
  345. if (m_did_unblock)
  346. return false;
  347. VERIFY(fd_info.description);
  348. auto unblock_flags = fd_info.description->should_unblock(fd_info.block_flags);
  349. if (unblock_flags == BlockFlags::None)
  350. return false;
  351. m_did_unblock = true;
  352. // We need to store unblock_flags here, otherwise someone else
  353. // affecting this file descriptor could change the information
  354. // between now and when was_unblocked is called!
  355. fd_info.unblocked_flags = unblock_flags;
  356. }
  357. // Only do this once for the first one
  358. if (!from_add_blocker)
  359. unblock_from_blocker();
  360. return true;
  361. }
  362. size_t Thread::SelectBlocker::collect_unblocked_flags()
  363. {
  364. size_t count = 0;
  365. for (auto& fd_entry : m_fds) {
  366. VERIFY(fd_entry.block_flags != FileBlocker::BlockFlags::None);
  367. if (!fd_entry.description) {
  368. count++;
  369. continue;
  370. }
  371. // unblock will have set at least the first descriptor's unblock
  372. // flags that triggered the unblock. Make sure we don't discard that
  373. // information as it may have changed by now!
  374. if (fd_entry.unblocked_flags == FileBlocker::BlockFlags::None)
  375. fd_entry.unblocked_flags = fd_entry.description->should_unblock(fd_entry.block_flags);
  376. if (fd_entry.unblocked_flags != FileBlocker::BlockFlags::None)
  377. count++;
  378. }
  379. return count;
  380. }
  381. void Thread::SelectBlocker::was_unblocked(bool did_timeout)
  382. {
  383. Blocker::was_unblocked(did_timeout);
  384. if (!did_timeout && !was_interrupted()) {
  385. {
  386. SpinlockLocker lock(m_lock);
  387. VERIFY(m_did_unblock);
  388. }
  389. size_t count = collect_unblocked_flags();
  390. // If we were blocked and didn't time out, we should have at least one unblocked fd!
  391. VERIFY(count > 0);
  392. }
  393. }
  394. Thread::SignalBlocker::SignalBlocker(sigset_t pending_set, siginfo_t& result)
  395. : m_pending_set(pending_set)
  396. , m_result(result)
  397. {
  398. }
  399. void Thread::SignalBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason unblock_immediately_reason)
  400. {
  401. if (unblock_immediately_reason != UnblockImmediatelyReason::TimeoutInThePast)
  402. return;
  403. // If the specified timeout is 0 the caller is simply trying to poll once for pending signals,
  404. // so simply calling check_pending_signals should populate the requested information.
  405. check_pending_signals(false);
  406. }
  407. bool Thread::SignalBlocker::setup_blocker()
  408. {
  409. return add_to_blocker_set(thread().m_signal_blocker_set);
  410. }
  411. bool Thread::SignalBlocker::check_pending_signals(bool from_add_blocker)
  412. {
  413. {
  414. SpinlockLocker lock(m_lock);
  415. if (m_did_unblock)
  416. return false;
  417. auto pending_signals = thread().pending_signals() & m_pending_set;
  418. // Also unblock if we have just "handled" that signal and are in the procecss
  419. // of running their signal handler (i.e. we just unmarked the signal as pending).
  420. if (thread().m_currently_handled_signal)
  421. pending_signals |= (1 << (thread().m_currently_handled_signal - 1)) & m_pending_set;
  422. auto matching_pending_signal = bit_scan_forward(pending_signals);
  423. if (matching_pending_signal == 0)
  424. return false;
  425. m_did_unblock = true;
  426. m_result = {};
  427. m_result.si_signo = matching_pending_signal;
  428. m_result.si_code = 0; // FIXME: How can we determine this?
  429. }
  430. if (!from_add_blocker)
  431. unblock_from_blocker();
  432. return true;
  433. }
  434. Thread::WaitBlockerSet::ProcessBlockInfo::ProcessBlockInfo(NonnullRefPtr<Process>&& process, WaitBlocker::UnblockFlags flags, u8 signal)
  435. : process(move(process))
  436. , flags(flags)
  437. , signal(signal)
  438. {
  439. }
  440. Thread::WaitBlockerSet::ProcessBlockInfo::~ProcessBlockInfo() = default;
  441. void Thread::WaitBlockerSet::try_unblock(Thread::WaitBlocker& blocker)
  442. {
  443. SpinlockLocker lock(m_lock);
  444. // We if we have any processes pending
  445. for (size_t i = 0; i < m_processes.size(); i++) {
  446. auto& info = m_processes[i];
  447. // We need to call unblock as if we were called from add_blocker
  448. // so that we don't trigger a context switch by yielding!
  449. if (info.was_waited && blocker.is_wait())
  450. continue; // This state was already waited on, do not unblock
  451. if (blocker.unblock(info.process, info.flags, info.signal, true)) {
  452. if (blocker.is_wait()) {
  453. if (info.flags == Thread::WaitBlocker::UnblockFlags::Terminated) {
  454. m_processes.remove(i);
  455. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] terminated, remove {}", m_process, *info.process);
  456. } else {
  457. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] terminated, mark as waited {}", m_process, *info.process);
  458. info.was_waited = true;
  459. }
  460. }
  461. break;
  462. }
  463. }
  464. }
  465. void Thread::WaitBlockerSet::disowned_by_waiter(Process& process)
  466. {
  467. SpinlockLocker lock(m_lock);
  468. if (m_finalized)
  469. return;
  470. for (size_t i = 0; i < m_processes.size();) {
  471. auto& info = m_processes[i];
  472. if (info.process == &process) {
  473. unblock_all_blockers_whose_conditions_are_met_locked([&](Blocker& b, void*, bool&) {
  474. VERIFY(b.blocker_type() == Blocker::Type::Wait);
  475. auto& blocker = static_cast<WaitBlocker&>(b);
  476. bool did_unblock = blocker.unblock(info.process, WaitBlocker::UnblockFlags::Disowned, 0, false);
  477. VERIFY(did_unblock); // disowning must unblock everyone
  478. return true;
  479. });
  480. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] disowned {}", m_process, *info.process);
  481. m_processes.remove(i);
  482. continue;
  483. }
  484. i++;
  485. }
  486. }
  487. bool Thread::WaitBlockerSet::unblock(Process& process, WaitBlocker::UnblockFlags flags, u8 signal)
  488. {
  489. VERIFY(flags != WaitBlocker::UnblockFlags::Disowned);
  490. bool did_unblock_any = false;
  491. bool did_wait = false;
  492. bool was_waited_already = false;
  493. SpinlockLocker lock(m_lock);
  494. if (m_finalized)
  495. return false;
  496. if (flags != WaitBlocker::UnblockFlags::Terminated) {
  497. // First check if this state was already waited on
  498. for (auto& info : m_processes) {
  499. if (info.process == &process) {
  500. was_waited_already = info.was_waited;
  501. break;
  502. }
  503. }
  504. }
  505. unblock_all_blockers_whose_conditions_are_met_locked([&](Blocker& b, void*, bool&) {
  506. VERIFY(b.blocker_type() == Blocker::Type::Wait);
  507. auto& blocker = static_cast<WaitBlocker&>(b);
  508. if (was_waited_already && blocker.is_wait())
  509. return false; // This state was already waited on, do not unblock
  510. if (blocker.unblock(process, flags, signal, false)) {
  511. did_wait |= blocker.is_wait(); // anyone requesting a wait
  512. did_unblock_any = true;
  513. return true;
  514. }
  515. return false;
  516. });
  517. // If no one has waited (yet), or this wasn't a wait, or if it's anything other than
  518. // UnblockFlags::Terminated then add it to your list
  519. if (!did_unblock_any || !did_wait || flags != WaitBlocker::UnblockFlags::Terminated) {
  520. bool updated_existing = false;
  521. for (auto& info : m_processes) {
  522. if (info.process == &process) {
  523. VERIFY(info.flags != WaitBlocker::UnblockFlags::Terminated);
  524. info.flags = flags;
  525. info.signal = signal;
  526. info.was_waited = did_wait;
  527. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] update {} flags={}, waited={}", m_process, process, (int)flags, info.was_waited);
  528. updated_existing = true;
  529. break;
  530. }
  531. }
  532. if (!updated_existing) {
  533. dbgln_if(WAITBLOCK_DEBUG, "WaitBlockerSet[{}] add {} flags: {}", m_process, process, (int)flags);
  534. m_processes.append(ProcessBlockInfo(process, flags, signal));
  535. }
  536. }
  537. return did_unblock_any;
  538. }
  539. bool Thread::WaitBlockerSet::should_add_blocker(Blocker& b, void*)
  540. {
  541. // NOTE: m_lock is held already!
  542. if (m_finalized)
  543. return false;
  544. VERIFY(b.blocker_type() == Blocker::Type::Wait);
  545. auto& blocker = static_cast<WaitBlocker&>(b);
  546. // See if we can match any process immediately
  547. for (size_t i = 0; i < m_processes.size(); i++) {
  548. auto& info = m_processes[i];
  549. if (blocker.unblock(info.process, info.flags, info.signal, true)) {
  550. // Only remove the entry if UnblockFlags::Terminated
  551. if (info.flags == Thread::WaitBlocker::UnblockFlags::Terminated && blocker.is_wait())
  552. m_processes.remove(i);
  553. return false;
  554. }
  555. }
  556. return true;
  557. }
  558. void Thread::WaitBlockerSet::finalize()
  559. {
  560. SpinlockLocker lock(m_lock);
  561. VERIFY(!m_finalized);
  562. m_finalized = true;
  563. // Clear the list of threads here so we can drop the references to them
  564. m_processes.clear();
  565. // NOTE: Kernel processes don't have a leaked ref on them.
  566. if (!m_process.is_kernel_process()) {
  567. // No more waiters, drop the last reference immediately. This may
  568. // cause us to be destructed ourselves!
  569. VERIFY(m_process.ref_count() > 0);
  570. m_process.unref();
  571. }
  572. }
  573. Thread::WaitBlocker::WaitBlocker(int wait_options, Variant<Empty, NonnullRefPtr<Process>, NonnullRefPtr<ProcessGroup>> waitee, ErrorOr<siginfo_t>& result)
  574. : m_wait_options(wait_options)
  575. , m_result(result)
  576. , m_waitee(move(waitee))
  577. {
  578. }
  579. bool Thread::WaitBlocker::setup_blocker()
  580. {
  581. if (m_wait_options & WNOHANG)
  582. return false;
  583. return add_to_blocker_set(Process::current().wait_blocker_set());
  584. }
  585. void Thread::WaitBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason)
  586. {
  587. Process::current().wait_blocker_set().try_unblock(*this);
  588. }
  589. void Thread::WaitBlocker::was_unblocked(bool)
  590. {
  591. bool got_sigchld, try_unblock;
  592. {
  593. SpinlockLocker lock(m_lock);
  594. try_unblock = !m_did_unblock;
  595. got_sigchld = m_got_sigchild;
  596. }
  597. if (try_unblock)
  598. Process::current().wait_blocker_set().try_unblock(*this);
  599. // If we were interrupted by SIGCHLD (which gets special handling
  600. // here) we're not going to return with EINTR. But we're going to
  601. // deliver SIGCHLD (only) here.
  602. auto* current_thread = Thread::current();
  603. if (got_sigchld && current_thread->state() != State::Stopped)
  604. current_thread->try_dispatch_one_pending_signal(SIGCHLD);
  605. }
  606. void Thread::WaitBlocker::do_was_disowned()
  607. {
  608. VERIFY(!m_did_unblock);
  609. m_did_unblock = true;
  610. m_result = ECHILD;
  611. }
  612. void Thread::WaitBlocker::do_set_result(siginfo_t const& result)
  613. {
  614. VERIFY(!m_did_unblock);
  615. m_did_unblock = true;
  616. m_result = result;
  617. if (do_get_interrupted_by_signal() == SIGCHLD) {
  618. // This makes it so that wait() will return normally despite the
  619. // fact that SIGCHLD was delivered. Calling do_clear_interrupted_by_signal
  620. // will disable dispatching signals in Thread::block and prevent
  621. // it from returning with EINTR. We will then manually dispatch
  622. // SIGCHLD (and only SIGCHLD) in was_unblocked.
  623. m_got_sigchild = true;
  624. do_clear_interrupted_by_signal();
  625. }
  626. }
  627. bool Thread::WaitBlocker::unblock(Process& process, UnblockFlags flags, u8 signal, bool from_add_blocker)
  628. {
  629. VERIFY(flags != UnblockFlags::Terminated || signal == 0); // signal argument should be ignored for Terminated
  630. bool do_not_unblock = m_waitee.visit(
  631. [&](NonnullRefPtr<Process> const& waitee_process) {
  632. return &process != waitee_process;
  633. },
  634. [&](NonnullRefPtr<ProcessGroup> const& waitee_process_group) {
  635. return waitee_process_group->pgid() != process.pgid();
  636. },
  637. [&](Empty const&) {
  638. // Generic waiter won't be unblocked by disown
  639. return flags == UnblockFlags::Disowned;
  640. });
  641. if (do_not_unblock)
  642. return false;
  643. switch (flags) {
  644. case UnblockFlags::Terminated:
  645. if (!(m_wait_options & WEXITED))
  646. return false;
  647. break;
  648. case UnblockFlags::Stopped:
  649. if (!(m_wait_options & WSTOPPED))
  650. return false;
  651. if (!(m_wait_options & WUNTRACED) && !process.is_traced())
  652. return false;
  653. break;
  654. case UnblockFlags::Continued:
  655. if (!(m_wait_options & WCONTINUED))
  656. return false;
  657. if (!(m_wait_options & WUNTRACED) && !process.is_traced())
  658. return false;
  659. break;
  660. case UnblockFlags::Disowned:
  661. SpinlockLocker lock(m_lock);
  662. // Disowning must unblock anyone waiting for this process explicitly
  663. if (!m_did_unblock)
  664. do_was_disowned();
  665. return true;
  666. }
  667. if (flags == UnblockFlags::Terminated) {
  668. VERIFY(process.is_dead());
  669. SpinlockLocker lock(m_lock);
  670. if (m_did_unblock)
  671. return false;
  672. // Up until this point, this function may have been called
  673. // more than once!
  674. do_set_result(process.wait_info());
  675. } else {
  676. siginfo_t siginfo {};
  677. {
  678. SpinlockLocker lock(g_scheduler_lock);
  679. // We need to gather the information before we release the scheduler lock!
  680. siginfo.si_signo = SIGCHLD;
  681. siginfo.si_pid = process.pid().value();
  682. siginfo.si_uid = process.uid().value();
  683. siginfo.si_status = signal;
  684. switch (flags) {
  685. case UnblockFlags::Terminated:
  686. case UnblockFlags::Disowned:
  687. VERIFY_NOT_REACHED();
  688. case UnblockFlags::Stopped:
  689. siginfo.si_code = CLD_STOPPED;
  690. break;
  691. case UnblockFlags::Continued:
  692. siginfo.si_code = CLD_CONTINUED;
  693. break;
  694. }
  695. }
  696. SpinlockLocker lock(m_lock);
  697. if (m_did_unblock)
  698. return false;
  699. // Up until this point, this function may have been called
  700. // more than once!
  701. do_set_result(siginfo);
  702. }
  703. if (!from_add_blocker) {
  704. // Only call unblock if we weren't called from within add_to_blocker_set!
  705. VERIFY(flags != UnblockFlags::Disowned);
  706. unblock_from_blocker();
  707. }
  708. // Because this may be called from add_blocker, in which case we should
  709. // not be actually trying to unblock the thread (because it hasn't actually
  710. // been blocked yet), we need to return true anyway
  711. return true;
  712. }
  713. Thread::FlockBlocker::FlockBlocker(NonnullRefPtr<Inode> inode, flock const& flock)
  714. : m_inode(move(inode))
  715. , m_flock(flock)
  716. {
  717. }
  718. void Thread::FlockBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason)
  719. {
  720. VERIFY(reason == UnblockImmediatelyReason::UnblockConditionAlreadyMet);
  721. }
  722. bool Thread::FlockBlocker::setup_blocker()
  723. {
  724. return add_to_blocker_set(m_inode->flock_blocker_set());
  725. }
  726. bool Thread::FlockBlocker::try_unblock(bool from_add_blocker)
  727. {
  728. if (!m_inode->can_apply_flock(m_flock))
  729. return false;
  730. {
  731. SpinlockLocker lock(m_lock);
  732. if (m_did_unblock)
  733. return false;
  734. m_did_unblock = true;
  735. }
  736. if (!from_add_blocker)
  737. unblock_from_blocker();
  738. return true;
  739. }
  740. }