MachPortServer.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "MachPortServer.h"
  7. #include <AK/Debug.h>
  8. #include <LibCore/Platform/MachMessageTypes.h>
  9. #include <LibCore/Platform/ProcessStatisticsMach.h>
  10. namespace Ladybird {
  11. MachPortServer::MachPortServer()
  12. : m_thread(Threading::Thread::construct([this]() -> intptr_t { thread_loop(); return 0; }, "MachPortServer"sv))
  13. , m_server_port_name(ByteString::formatted("org.ladybird.Ladybird.helper.{}", getpid()))
  14. {
  15. if (auto err = allocate_server_port(); err.is_error())
  16. dbgln("Failed to allocate server port: {}", err.error());
  17. else
  18. start();
  19. }
  20. MachPortServer::~MachPortServer()
  21. {
  22. stop();
  23. }
  24. void MachPortServer::start()
  25. {
  26. m_thread->start();
  27. }
  28. void MachPortServer::stop()
  29. {
  30. // FIXME: We should join instead (after storing should_stop = false) when we have a way to interrupt the thread's mach_msg call
  31. m_thread->detach();
  32. m_should_stop.store(true, MemoryOrder::memory_order_release);
  33. }
  34. bool MachPortServer::is_initialized()
  35. {
  36. return MACH_PORT_VALID(m_server_port_recv_right.port()) && MACH_PORT_VALID(m_server_port_send_right.port());
  37. }
  38. ErrorOr<void> MachPortServer::allocate_server_port()
  39. {
  40. m_server_port_recv_right = TRY(Core::MachPort::create_with_right(Core::MachPort::PortRight::Receive));
  41. m_server_port_send_right = TRY(m_server_port_recv_right.insert_right(Core::MachPort::MessageRight::MakeSend));
  42. TRY(m_server_port_recv_right.register_with_bootstrap_server(m_server_port_name));
  43. dbgln_if(MACH_PORT_DEBUG, "Success! we created and attached mach port {:x} to bootstrap server with name {}", m_server_port_recv_right.port(), m_server_port_name);
  44. return {};
  45. }
  46. void MachPortServer::thread_loop()
  47. {
  48. while (!m_should_stop.load(MemoryOrder::memory_order_acquire)) {
  49. Core::Platform::ReceivedMachMessage message {};
  50. // Get the pid of the child from the audit trailer so we can associate the port w/it
  51. mach_msg_options_t const options = MACH_RCV_MSG | MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
  52. // FIXME: How can we interrupt this call during application shutdown?
  53. auto const ret = mach_msg(&message.header, options, 0, sizeof(message), m_server_port_recv_right.port(), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  54. if (ret != KERN_SUCCESS) {
  55. dbgln("mach_msg failed: {}", mach_error_string(ret));
  56. break;
  57. }
  58. if (message.header.msgh_id == Core::Platform::BACKING_STORE_IOSURFACES_MESSAGE_ID) {
  59. auto pid = static_cast<pid_t>(message.body.parent_iosurface.trailer.msgh_audit.val[5]);
  60. auto const& backing_stores_message = message.body.parent_iosurface;
  61. auto front_child_port = Core::MachPort::adopt_right(backing_stores_message.front_descriptor.name, Core::MachPort::PortRight::Send);
  62. auto back_child_port = Core::MachPort::adopt_right(backing_stores_message.back_descriptor.name, Core::MachPort::PortRight::Send);
  63. auto const& metadata = backing_stores_message.metadata;
  64. if (on_receive_backing_stores)
  65. on_receive_backing_stores({ .pid = pid,
  66. .page_id = metadata.page_id,
  67. .front_backing_store_id = metadata.front_backing_store_id,
  68. .back_backing_store_id = metadata.back_backing_store_id,
  69. .front_backing_store_port = move(front_child_port),
  70. .back_backing_store_port = move(back_child_port) });
  71. continue;
  72. }
  73. if (message.header.msgh_id == Core::Platform::SELF_TASK_PORT_MESSAGE_ID) {
  74. if (MACH_MSGH_BITS_LOCAL(message.header.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND) {
  75. dbgln("Received message with invalid local port rights {}, ignoring", MACH_MSGH_BITS_LOCAL(message.header.msgh_bits));
  76. continue;
  77. }
  78. auto const& task_port_message = message.body.parent;
  79. auto pid = static_cast<pid_t>(task_port_message.trailer.msgh_audit.val[5]);
  80. auto child_port = Core::MachPort::adopt_right(task_port_message.port_descriptor.name, Core::MachPort::PortRight::Send);
  81. dbgln_if(MACH_PORT_DEBUG, "Received child port {:x} from pid {}", child_port.port(), pid);
  82. if (on_receive_child_mach_port)
  83. on_receive_child_mach_port(pid, move(child_port));
  84. continue;
  85. }
  86. dbgln("Received message with id {}, ignoring", message.header.msgh_id);
  87. }
  88. }
  89. }