2024-04-04 20:10:08 +00:00
/*
* Copyright ( c ) 2024 , Andrew Kaster < akaster @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "MachPortServer.h"
# include <AK/Debug.h>
2024-06-20 18:34:51 +00:00
# include <LibCore/Platform/MachMessageTypes.h>
2024-04-21 03:35:17 +00:00
# include <LibCore/Platform/ProcessStatisticsMach.h>
2024-04-04 20:10:08 +00:00
namespace Ladybird {
MachPortServer : : MachPortServer ( )
: m_thread ( Threading : : Thread : : construct ( [ this ] ( ) - > intptr_t { thread_loop ( ) ; return 0 ; } , " MachPortServer " sv ) )
2024-07-20 14:43:15 +00:00
, m_server_port_name ( ByteString : : formatted ( " org.ladybird.Ladybird.helper.{} " , getpid ( ) ) )
2024-04-04 20:10:08 +00:00
{
if ( auto err = allocate_server_port ( ) ; err . is_error ( ) )
dbgln ( " Failed to allocate server port: {} " , err . error ( ) ) ;
else
start ( ) ;
}
MachPortServer : : ~ MachPortServer ( )
{
stop ( ) ;
}
void MachPortServer : : start ( )
{
m_thread - > start ( ) ;
}
void MachPortServer : : stop ( )
{
// FIXME: We should join instead (after storing should_stop = false) when we have a way to interrupt the thread's mach_msg call
m_thread - > detach ( ) ;
m_should_stop . store ( true , MemoryOrder : : memory_order_release ) ;
}
bool MachPortServer : : is_initialized ( )
{
return MACH_PORT_VALID ( m_server_port_recv_right . port ( ) ) & & MACH_PORT_VALID ( m_server_port_send_right . port ( ) ) ;
}
ErrorOr < void > MachPortServer : : allocate_server_port ( )
{
m_server_port_recv_right = TRY ( Core : : MachPort : : create_with_right ( Core : : MachPort : : PortRight : : Receive ) ) ;
m_server_port_send_right = TRY ( m_server_port_recv_right . insert_right ( Core : : MachPort : : MessageRight : : MakeSend ) ) ;
TRY ( m_server_port_recv_right . register_with_bootstrap_server ( m_server_port_name ) ) ;
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 ) ;
return { } ;
}
void MachPortServer : : thread_loop ( )
{
while ( ! m_should_stop . load ( MemoryOrder : : memory_order_acquire ) ) {
2024-06-20 18:34:51 +00:00
Core : : Platform : : ReceivedMachMessage message { } ;
2024-04-04 20:10:08 +00:00
// Get the pid of the child from the audit trailer so we can associate the port w/it
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 ) ;
// FIXME: How can we interrupt this call during application shutdown?
auto const ret = mach_msg ( & message . header , options , 0 , sizeof ( message ) , m_server_port_recv_right . port ( ) , MACH_MSG_TIMEOUT_NONE , MACH_PORT_NULL ) ;
if ( ret ! = KERN_SUCCESS ) {
dbgln ( " mach_msg failed: {} " , mach_error_string ( ret ) ) ;
break ;
}
2024-06-20 18:34:51 +00:00
if ( message . header . msgh_id = = Core : : Platform : : BACKING_STORE_IOSURFACES_MESSAGE_ID ) {
auto pid = static_cast < pid_t > ( message . body . parent_iosurface . trailer . msgh_audit . val [ 5 ] ) ;
auto const & backing_stores_message = message . body . parent_iosurface ;
auto front_child_port = Core : : MachPort : : adopt_right ( backing_stores_message . front_descriptor . name , Core : : MachPort : : PortRight : : Send ) ;
auto back_child_port = Core : : MachPort : : adopt_right ( backing_stores_message . back_descriptor . name , Core : : MachPort : : PortRight : : Send ) ;
auto const & metadata = backing_stores_message . metadata ;
if ( on_receive_backing_stores )
on_receive_backing_stores ( { . pid = pid ,
. page_id = metadata . page_id ,
. front_backing_store_id = metadata . front_backing_store_id ,
. back_backing_store_id = metadata . back_backing_store_id ,
. front_backing_store_port = move ( front_child_port ) ,
. back_backing_store_port = move ( back_child_port ) } ) ;
2024-04-04 20:10:08 +00:00
continue ;
}
2024-06-20 18:34:51 +00:00
if ( message . header . msgh_id = = Core : : Platform : : SELF_TASK_PORT_MESSAGE_ID ) {
if ( MACH_MSGH_BITS_LOCAL ( message . header . msgh_bits ) ! = MACH_MSG_TYPE_MOVE_SEND ) {
dbgln ( " Received message with invalid local port rights {}, ignoring " , MACH_MSGH_BITS_LOCAL ( message . header . msgh_bits ) ) ;
continue ;
}
auto const & task_port_message = message . body . parent ;
auto pid = static_cast < pid_t > ( task_port_message . trailer . msgh_audit . val [ 5 ] ) ;
auto child_port = Core : : MachPort : : adopt_right ( task_port_message . port_descriptor . name , Core : : MachPort : : PortRight : : Send ) ;
dbgln_if ( MACH_PORT_DEBUG , " Received child port {:x} from pid {} " , child_port . port ( ) , pid ) ;
if ( on_receive_child_mach_port )
on_receive_child_mach_port ( pid , move ( child_port ) ) ;
2024-04-04 20:10:08 +00:00
continue ;
}
2024-06-20 18:34:51 +00:00
dbgln ( " Received message with id {}, ignoring " , message . header . msgh_id ) ;
2024-04-04 20:10:08 +00:00
}
}
}