mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
LibCore: Add a rough abstraction class around Mach port rights
This commit is contained in:
parent
4a9546a7c8
commit
77f18cf062
Notes:
sideshowbarker
2024-07-17 06:29:49 +09:00
Author: https://github.com/ADKaster Commit: https://github.com/SerenityOS/serenity/commit/77f18cf062 Pull-request: https://github.com/SerenityOS/serenity/pull/23841 Reviewed-by: https://github.com/bugaevc Reviewed-by: https://github.com/nico ✅ Reviewed-by: https://github.com/trflynn89 ✅
4 changed files with 255 additions and 0 deletions
|
@ -116,6 +116,9 @@ source_set("sources") {
|
||||||
"LocalServer.h",
|
"LocalServer.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
if (current_os == "mac") {
|
||||||
|
sources += [ "MachPort.cpp" ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
source_set("filewatcher") {
|
source_set("filewatcher") {
|
||||||
|
|
|
@ -69,6 +69,10 @@ else()
|
||||||
list(APPEND SOURCES FileWatcherUnimplemented.cpp)
|
list(APPEND SOURCES FileWatcherUnimplemented.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE OR CMAKE_SYSTEM_NAME STREQUAL "GNU")
|
||||||
|
list(APPEND SOURCES MachPort.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
serenity_lib(LibCore core)
|
serenity_lib(LibCore core)
|
||||||
target_link_libraries(LibCore PRIVATE LibCrypt LibSystem LibTimeZone LibURL)
|
target_link_libraries(LibCore PRIVATE LibCrypt LibSystem LibTimeZone LibURL)
|
||||||
target_link_libraries(LibCore PUBLIC LibCoreMinimal)
|
target_link_libraries(LibCore PUBLIC LibCoreMinimal)
|
||||||
|
|
166
Userland/Libraries/LibCore/MachPort.cpp
Normal file
166
Userland/Libraries/LibCore/MachPort.cpp
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/ByteString.h>
|
||||||
|
#include <AK/Format.h>
|
||||||
|
#include <LibCore/MachPort.h>
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACOS)
|
||||||
|
# include <bootstrap.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
static constexpr MachPort::PortRight associated_port_right(MachPort::MessageRight right)
|
||||||
|
{
|
||||||
|
switch (right) {
|
||||||
|
case MachPort::MessageRight::MoveReceive:
|
||||||
|
case MachPort::MessageRight::CopyReceive:
|
||||||
|
case MachPort::MessageRight::DisposeReceive:
|
||||||
|
return MachPort::PortRight::Receive;
|
||||||
|
case MachPort::MessageRight::MoveSend:
|
||||||
|
case MachPort::MessageRight::CopySend:
|
||||||
|
case MachPort::MessageRight::MakeSend:
|
||||||
|
case MachPort::MessageRight::DisposeSend:
|
||||||
|
return MachPort::PortRight::Send;
|
||||||
|
case MachPort::MessageRight::MoveSendOnce:
|
||||||
|
case MachPort::MessageRight::MakeSendOnce:
|
||||||
|
case MachPort::MessageRight::DisposeSendOnce:
|
||||||
|
return MachPort::PortRight::SendOnce;
|
||||||
|
}
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Error mach_error_to_error(kern_return_t error)
|
||||||
|
{
|
||||||
|
char const* err_string = mach_error_string(error);
|
||||||
|
StringView const err_view(err_string, strlen(err_string));
|
||||||
|
return Error::from_string_view(err_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Error bootstrap_error_to_error(kern_return_t error)
|
||||||
|
{
|
||||||
|
char const* err_string = bootstrap_strerror(error);
|
||||||
|
StringView const err_view(err_string, strlen(err_string));
|
||||||
|
return Error::from_string_view(err_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
MachPort::MachPort(PortRight right, mach_port_t port)
|
||||||
|
: m_right(right)
|
||||||
|
, m_port(port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MachPort::~MachPort()
|
||||||
|
{
|
||||||
|
unref_port();
|
||||||
|
}
|
||||||
|
|
||||||
|
MachPort::MachPort(MachPort&& other)
|
||||||
|
: m_right(other.m_right)
|
||||||
|
, m_port(other.release())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MachPort& MachPort::operator=(MachPort&& other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
unref_port();
|
||||||
|
m_right = other.m_right;
|
||||||
|
m_port = other.release();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MachPort::unref_port()
|
||||||
|
{
|
||||||
|
if (!MACH_PORT_VALID(m_port))
|
||||||
|
return;
|
||||||
|
|
||||||
|
kern_return_t res = KERN_FAILURE;
|
||||||
|
switch (m_right) {
|
||||||
|
case PortRight::Send:
|
||||||
|
case PortRight::SendOnce:
|
||||||
|
case PortRight::DeadName:
|
||||||
|
res = mach_port_deallocate(mach_task_self(), m_port);
|
||||||
|
break;
|
||||||
|
case PortRight::Receive:
|
||||||
|
case PortRight::PortSet:
|
||||||
|
res = mach_port_mod_refs(mach_task_self(), m_port, to_underlying(m_right), -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
VERIFY(res == KERN_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<MachPort> MachPort::create_with_right(PortRight right)
|
||||||
|
{
|
||||||
|
mach_port_t port = MACH_PORT_NULL;
|
||||||
|
auto const ret = mach_port_allocate(mach_task_self(), to_underlying(right), &port);
|
||||||
|
if (ret != KERN_SUCCESS) {
|
||||||
|
dbgln("Unable to allocate port with right: {}", to_underlying(right));
|
||||||
|
return mach_error_to_error(ret);
|
||||||
|
}
|
||||||
|
return MachPort(right, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
MachPort MachPort::adopt_right(mach_port_t port, PortRight right)
|
||||||
|
{
|
||||||
|
return MachPort(right, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
mach_port_t MachPort::release()
|
||||||
|
{
|
||||||
|
return exchange(m_port, MACH_PORT_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<MachPort> MachPort::insert_right(MessageRight right)
|
||||||
|
{
|
||||||
|
auto const ret = mach_port_insert_right(mach_task_self(), m_port, m_port, to_underlying(right));
|
||||||
|
if (ret != KERN_SUCCESS) {
|
||||||
|
dbgln("Unable to insert message right: {}", to_underlying(right));
|
||||||
|
return mach_error_to_error(ret);
|
||||||
|
}
|
||||||
|
return MachPort(associated_port_right(right), m_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACOS)
|
||||||
|
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
// bootstrap_register has been deprecated since macOS 10.5, but rules are more 'guidelines' than actual rules
|
||||||
|
|
||||||
|
ErrorOr<void> MachPort::register_with_bootstrap_server(ByteString const& service_name)
|
||||||
|
{
|
||||||
|
if (service_name.length() > sizeof(name_t) - 1)
|
||||||
|
return Error::from_errno(E2BIG);
|
||||||
|
|
||||||
|
auto const ret = bootstrap_register(bootstrap_port, const_cast<char*>(service_name.characters()), m_port);
|
||||||
|
if (ret != KERN_SUCCESS) {
|
||||||
|
dbgln("Unable to register {} with bootstrap on port {:p}", service_name, m_port);
|
||||||
|
return bootstrap_error_to_error(ret);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
ErrorOr<MachPort> MachPort::look_up_from_bootstrap_server(ByteString const& service_name)
|
||||||
|
{
|
||||||
|
if (service_name.length() > sizeof(name_t) - 1)
|
||||||
|
return Error::from_errno(E2BIG);
|
||||||
|
|
||||||
|
mach_port_t port = MACH_PORT_NULL;
|
||||||
|
auto const ret = bootstrap_look_up(bootstrap_port, service_name.characters(), &port);
|
||||||
|
if (ret != KERN_SUCCESS) {
|
||||||
|
dbgln("Unable to look up service {} in bootstrap", service_name);
|
||||||
|
return bootstrap_error_to_error(ret);
|
||||||
|
}
|
||||||
|
return MachPort(PortRight::Send, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
82
Userland/Libraries/LibCore/MachPort.h
Normal file
82
Userland/Libraries/LibCore/MachPort.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Platform.h>
|
||||||
|
|
||||||
|
#ifndef AK_OS_MACH
|
||||||
|
# error "MachPort is only available on Mach platforms"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <AK/Error.h>
|
||||||
|
#include <AK/Noncopyable.h>
|
||||||
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
// https://www.gnu.org/software/hurd/gnumach-doc/Major-Concepts.html#Major-Concepts
|
||||||
|
class MachPort {
|
||||||
|
AK_MAKE_NONCOPYABLE(MachPort);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// https://www.gnu.org/software/hurd/gnumach-doc/Exchanging-Port-Rights.html#Exchanging-Port-Rights
|
||||||
|
enum class PortRight : mach_port_right_t {
|
||||||
|
Send = MACH_PORT_RIGHT_SEND,
|
||||||
|
Receive = MACH_PORT_RIGHT_RECEIVE,
|
||||||
|
SendOnce = MACH_PORT_RIGHT_SEND_ONCE,
|
||||||
|
PortSet = MACH_PORT_RIGHT_PORT_SET,
|
||||||
|
DeadName = MACH_PORT_RIGHT_DEAD_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MessageRight : mach_msg_type_name_t {
|
||||||
|
MoveReceive = MACH_MSG_TYPE_MOVE_RECEIVE,
|
||||||
|
MoveSend = MACH_MSG_TYPE_MOVE_SEND,
|
||||||
|
MoveSendOnce = MACH_MSG_TYPE_MOVE_SEND_ONCE,
|
||||||
|
CopySend = MACH_MSG_TYPE_COPY_SEND,
|
||||||
|
MakeSend = MACH_MSG_TYPE_MAKE_SEND,
|
||||||
|
MakeSendOnce = MACH_MSG_TYPE_MAKE_SEND_ONCE,
|
||||||
|
#if defined(AK_OS_MACOS)
|
||||||
|
CopyReceive = MACH_MSG_TYPE_COPY_RECEIVE,
|
||||||
|
DisposeReceive = MACH_MSG_TYPE_DISPOSE_RECEIVE,
|
||||||
|
DisposeSend = MACH_MSG_TYPE_DISPOSE_SEND,
|
||||||
|
DisposeSendOnce = MACH_MSG_TYPE_DISPOSE_SEND_ONCE,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
MachPort() = default;
|
||||||
|
MachPort(MachPort&& other);
|
||||||
|
MachPort& operator=(MachPort&& other);
|
||||||
|
~MachPort();
|
||||||
|
|
||||||
|
mach_port_t release();
|
||||||
|
|
||||||
|
static ErrorOr<MachPort> create_with_right(PortRight);
|
||||||
|
static MachPort adopt_right(mach_port_t, PortRight);
|
||||||
|
|
||||||
|
ErrorOr<MachPort> insert_right(MessageRight);
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACOS)
|
||||||
|
// https://opensource.apple.com/source/launchd/launchd-842.92.1/liblaunch/bootstrap.h.auto.html
|
||||||
|
static ErrorOr<MachPort> look_up_from_bootstrap_server(ByteString const& service_name);
|
||||||
|
ErrorOr<void> register_with_bootstrap_server(ByteString const& service_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// FIXME: mach_msg wrapper? For now just let the owner poke into the internals
|
||||||
|
mach_port_t port() { return m_port; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
MachPort(PortRight, mach_port_t);
|
||||||
|
|
||||||
|
void unref_port();
|
||||||
|
|
||||||
|
PortRight m_right { PortRight::DeadName };
|
||||||
|
mach_port_t m_port { MACH_PORT_NULL };
|
||||||
|
};
|
||||||
|
|
||||||
|
Error mach_error_to_error(kern_return_t error);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue