Add a ton of RPC calls

This commit adds a bunch of RPC calls, mostly XNU trap calls (calls that go directly to duct-taped XNU Mach trap calls).

The wrapper generator can now automatically generate server-side wrapper/boilerplate code  these XNU trap calls.

These calls have not yet been tested and some (most of the non-IPC calls) probably require functions that haven't been implemented yet.
This commit is contained in:
Ariel Abreu 2022-01-28 00:07:03 -05:00
parent a5627fddf1
commit 89e7afe22e
No known key found for this signature in database
GPG Key ID: D67AE16CCEA85B70
11 changed files with 531 additions and 64 deletions

View File

@ -322,6 +322,7 @@ add_library(darlingserver_duct_tape
target_include_directories(darlingserver_duct_tape PRIVATE
internal-include
${CMAKE_CURRENT_BINARY_DIR}/../internal-include
)
target_include_directories(darlingserver_duct_tape PUBLIC
@ -330,6 +331,7 @@ target_include_directories(darlingserver_duct_tape PUBLIC
add_dependencies(darlingserver_duct_tape
kernel_mig_generate
generate_dserver_rpc_wrappers
)
target_link_libraries(darlingserver_duct_tape PUBLIC

View File

@ -6,6 +6,7 @@
#include <stdbool.h>
#include <libsimple/lock.h>
#include <darlingserver/rpc.internal.h>
#ifdef __cplusplus
extern "C" {
@ -70,8 +71,10 @@ uint32_t dtape_task_self_trap(void);
uint32_t dtape_host_self_trap(void);
uint32_t dtape_thread_self_trap(void);
uint32_t dtape_mach_reply_port(void);
int dtape_mach_msg_overwrite(uintptr_t msg, int32_t option, uint32_t send_size, uint32_t rcv_size, uint32_t rcv_name, uint32_t timeout, uint32_t notify, uintptr_t rcv_msg, uint32_t rcv_limit);
int dtape_mach_port_deallocate(uint32_t task_name_right, uint32_t port_name_right);
uint32_t dtape_thread_get_special_reply_port(void);
uint32_t dtape_mk_timer_create(void);
DSERVER_DTAPE_DECLS;
/**
* The threshold beyond which thread IDs are considered IDs for kernel threads.
@ -106,6 +109,14 @@ void dtape_thread_destroy(dtape_thread_handle_t thread);
void dtape_thread_entering(dtape_thread_handle_t thread);
void dtape_thread_exiting(dtape_thread_handle_t thread);
void dtape_thread_set_handles(dtape_thread_handle_t thread, uintptr_t pthread_handle, uintptr_t dispatch_qaddr);
/**
* Returns the thread corresponding to the given thread port.
*
* @warning It is VERY important that the caller ensures the thread cannot die while we're looking it up.
* This can be accomplished, for example, by locking the global thread list before the call.
*/
dtape_thread_handle_t dtape_thread_for_port(uint32_t thread_port);
void* dtape_thread_context(dtape_thread_handle_t thread);
void dtape_task_uidgid(dtape_task_handle_t task, int new_uid, int new_gid, int* old_uid, int* old_gid);

View File

@ -9,6 +9,7 @@
#include <ipc/ipc_importance.h>
#include <kern/restartable.h>
#include <kern/sync_sema.h>
#include <mach/mach_traps.h>
#include <stdlib.h>
@ -333,6 +334,18 @@ kern_return_t task_unregister_dyld_image_infos(task_t task, dyld_kernel_image_in
dtape_stub_unsafe();
};
kern_return_t task_for_pid(struct task_for_pid_args* args) {
dtape_stub_unsafe();
};
kern_return_t task_name_for_pid(struct task_name_for_pid_args* args) {
dtape_stub_unsafe();
};
kern_return_t pid_for_task(struct pid_for_task_args* args) {
dtape_stub_unsafe();
};
// <copied from="xnu://7195.141.2/osfmk/kern/task_policy.c">
/*

View File

@ -112,6 +112,24 @@ void dtape_thread_set_handles(dtape_thread_handle_t thread_handle, uintptr_t pth
thread->dispatch_qaddr = dispatch_qaddr;
};
dtape_thread_handle_t dtape_thread_for_port(uint32_t thread_port) {
thread_t xnu_thread = port_name_to_thread(thread_port, PORT_TO_THREAD_NONE);
if (!xnu_thread) {
return xnu_thread;
}
// port_name_to_thread returns a reference on the thread upon success.
// because we cannot take a reference on the duct-taped thread owner,
// this reference is meaningless. therefore, we drop it.
// we entrust our caller with the responsibility of ensuring it remains alive.
thread_deallocate(xnu_thread);
return dtape_thread_for_xnu_thread(xnu_thread);
};
void* dtape_thread_context(dtape_thread_handle_t thread_handle) {
dtape_thread_t* thread = thread_handle;
return thread->context;
};
thread_t current_thread(void) {
dtape_thread_t* thread = dtape_hooks->current_thread();
return &thread->xnu_thread;
@ -352,6 +370,14 @@ kern_return_t thread_wire(host_priv_t host_priv, thread_t thread, boolean_t wire
dtape_stub_unsafe();
};
void thread_handoff_parameter(thread_t thread, thread_continue_t continuation, void *parameter, thread_handoff_option_t option) {
dtape_stub_unsafe();
};
wait_result_t thread_handoff_deallocate(thread_t thread, thread_handoff_option_t option) {
dtape_stub_unsafe();
};
// ignore the lock timeout
#define LockTimeOutUsec UINT32_MAX

View File

@ -18,25 +18,12 @@ uint32_t dtape_mach_reply_port(void) {
return mach_reply_port(NULL);
};
int dtape_mach_msg_overwrite(uintptr_t msg, int32_t option, uint32_t send_size, uint32_t rcv_size, uint32_t rcv_name, uint32_t timeout, uint32_t notify, uintptr_t rcv_msg, uint32_t rcv_limit) {
struct mach_msg_overwrite_trap_args args = {
.msg = msg,
.option = option,
.send_size = send_size,
.rcv_size = rcv_size,
.rcv_name = rcv_name,
.timeout = timeout,
.priority = notify,
.rcv_msg = rcv_msg,
// no rcv_limit
};
return mach_msg_overwrite_trap(&args);
uint32_t dtape_thread_get_special_reply_port(void) {
return thread_get_special_reply_port(NULL);
};
int dtape_mach_port_deallocate(uint32_t task_name_right, uint32_t port_name_right) {
struct _kernelrpc_mach_port_deallocate_args args = {
.target = task_name_right,
.name = port_name_right,
};
return _kernelrpc_mach_port_deallocate_trap(&args);
uint32_t dtape_mk_timer_create(void) {
return mk_timer_create_trap(NULL);
};
DSERVER_DTAPE_DEFS;

View File

@ -40,7 +40,7 @@ namespace DarlingServer {
private:
std::unordered_map<typename Entry::ID, std::shared_ptr<Entry>> _map;
std::unordered_map<typename Entry::NSID, std::shared_ptr<Entry>> _nsmap;
std::shared_mutex _rwlock;
mutable std::shared_mutex _rwlock;
// sometimes, the factory used with registerIfAbsent needs to be able to look up other entries
// (and the factory is called with the lock held, so trying to acquire the lock again would be a deadlock)
@ -176,6 +176,34 @@ namespace DarlingServer {
return (*it2).second;
};
/**
* Locks the registry, preventing new entries from being added and old ones from being removed.
*
* This should be used very sparingly; you almost certainly don't want to use this.
* The primary use case for this is preventing an entry from being removed while it is being used
* in a situation where taking its shared_ptr is not possible.
*
* Every call to this method MUST be balanced with a call to unlock().
*/
void lock() const {
_rwlock.lock();
};
void unlock() const {
_rwlock.unlock();
};
using ScopedLock = std::unique_lock<std::shared_mutex>;
/**
* Locks the registry like lock(), but employs the RAII idiom to automatically unlock it at the end of the scope.
*
* Scoped locks can also be manually unlocked earlier.
*/
ScopedLock scopedLock() const {
return ScopedLock(_rwlock);
};
};
Registry<Process>& processRegistry();

View File

@ -118,6 +118,13 @@ namespace DarlingServer {
void setThreadHandles(uintptr_t pthreadHandle, uintptr_t dispatchQueueAddress);
static std::shared_ptr<Thread> currentThread();
/**
* Returns the Thread that corresponds to the given thread port in the current port space.
*
* @note This function may only be called from a microthread context.
*/
static std::shared_ptr<Thread> threadForPort(uint32_t thread_port);
};
};

View File

@ -6,22 +6,31 @@ from collections import OrderedDict
import textwrap
from datetime import datetime
XNU_TRAP_CALL = 1 << 0
XNU_TRAP_NOPREFIX = 1 << 1
XNU_TRAP_NOSUFFIX = 1 << 2
XNU_TRAP_NOSUFFIX_ARGS = 1 << 3
# NOTE: in Python 3.7+, we can rely on dictionaries having their items in insertion order.
# unfortunately, we can't expect everyone building Darling to have Python 3.7+ installed.
calls = [
#
# FORMAT:
# tuple with 3 members:
# tuple with either 3 or 4 members:
# 1. call name: the name of the remote procedure
# 2. call parameters: the set of parameters callers are expected to provide arguments for.
# 3. return parameters: the set of parameters the procedure is expected to return values for.
# 4. flags: an optional set of flags that modify how this call is processed and wrapped.
# if the set of flags (4) is omitted, it defaults to 0.
#
# PARAMETERS:
# each parameter (both for calls and returns) is a tuple with either 2 or 3 members:
# 1. parameter name: the name of the parameter (duh)
# 2. public type: the type used in the public RPC wrappers
# 3. (optional) private type: the type used internally for serialization and for the server implementation.
# if the private type (3) is omitted, it is the same as the public type.
#
# TYPES:
# the types that can be used are normal C types. however, to be more architecture-agnostic,
# it is recommended to use `stdint.h` types whenever possible (e.g. `int32_t` instead of `int`,
# `uint64_t` instead of `unsigned long`, etc.).
@ -30,11 +39,16 @@ calls = [
# that is wide enough to accommodate pointers for all architectures. a good choice is `uint64_t`;
# NOT `uintptr_t`, as its size varies according to the architecture.
#
# SPECIAL TYPES:
# one special type that is supported is `@fd`. this type indicates that the parameter specifies a file descriptor.
# it will be treated as an `int` type-wise, but the RPC wrappers will perform some additional work on it
# to serialize it across the connection. this works bi-directionally (i.e. both the client and server can send and receive FDs).
# the resulting descriptor received on the other end (in either client or server) will behave like a `dup()`ed descriptor.
#
# FLAGS:
# currently, the only flag that can be passed is XNU_TRAP_CALL. this indicates that the given call is actually an XNU trap.
# this enables more advanced wrappers to be generated for that call and avoid unnecessary boilerplate code on the server side.
#
# TODO: we should probably add a class for these calls (so it's more readable).
# we could even create a DSL (à-la-MIG), but that's probably overkill since
# we only use our RPC for darlingserver calls.
@ -56,22 +70,6 @@ calls = [
('length', 'uint64_t'),
]),
('task_self_trap', [], [
('port_name', 'uint32_t'),
]),
('host_self_trap', [], [
('port_name', 'uint32_t'),
]),
('thread_self_trap', [], [
('port_name', 'uint32_t'),
]),
('mach_reply_port', [], [
('port_name', 'uint32_t'),
]),
('kprintf', [
('string', 'const char*', 'uint64_t'),
('string_length', 'uint64_t'),
@ -85,23 +83,6 @@ calls = [
('tracer', 'uint32_t'),
]),
('mach_msg_overwrite', [
('msg', 'void*', 'uint64_t'),
('option', 'int32_t'),
('send_size', 'uint32_t'),
('rcv_size', 'uint32_t'),
('rcv_name', 'uint32_t'),
('timeout', 'uint32_t'),
('notify', 'uint32_t'),
('rcv_msg', 'void*', 'uint64_t'),
('rcv_limit', 'uint32_t'),
], []),
('mach_port_deallocate', [
('task_right_name', 'uint32_t'),
('port_right_name', 'uint32_t'),
], []),
('uidgid', [
('new_uid', 'int32_t'),
('new_gid', 'int32_t'),
@ -125,6 +106,246 @@ calls = [
], [
('length', 'uint64_t'),
]),
#
# pthread cancelation
#
('pthread_kill', [
('thread_port', 'uint32_t'),
('signal', 'int32_t'),
], []),
('pthread_canceled', [
('action', 'int32_t'),
], []),
('pthread_markcancel', [
('thread_port', 'uint32_t'),
], []),
#
# Mach IPC traps
#
('task_self_trap', [], [
('port_name', 'uint32_t'),
]),
('host_self_trap', [], [
('port_name', 'uint32_t'),
]),
('thread_self_trap', [], [
('port_name', 'uint32_t'),
]),
('mach_reply_port', [], [
('port_name', 'uint32_t'),
]),
('thread_get_special_reply_port', [], [
('port_name', 'uint32_t'),
]),
('mach_msg_overwrite', [
('msg', 'void*', 'uint64_t'),
('option', 'int32_t'),
('send_size', 'uint32_t'),
('rcv_size', 'uint32_t'),
('rcv_name', 'uint32_t'),
('timeout', 'uint32_t'),
('priority', 'uint32_t'),
('rcv_msg', 'void*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
('mach_port_deallocate', [
('target', 'uint32_t'),
('name', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_allocate', [
('target', 'uint32_t'),
('right', 'int32_t'),
# this would be better as a return parameter,
# but due to the way darlingserver handles Mach IPC calls,
# we need a pointer into the calling process's memory
('name', 'uint32_t*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_mod_refs', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('right', 'int32_t'),
('delta', 'int32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_move_member', [
('target', 'uint32_t'),
('member', 'uint32_t'),
('after', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_insert_right', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('poly', 'uint32_t'),
('polyPoly', 'int32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_insert_member', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('pset', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_extract_member', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('pset', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_construct', [
('target', 'uint32_t'),
('options', 'void*', 'uint64_t'),
('context', 'uint64_t'),
('name', 'uint32_t*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_destruct', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('srdelta', 'int32_t'),
('guard', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_guard', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('guard', 'uint64_t'),
('strict', 'bool'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_unguard', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('guard', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_request_notification', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('msgid', 'int32_t'),
('sync', 'uint32_t'),
('notify', 'uint32_t'),
('notifyPoly', 'uint32_t'),
('previous', 'uint32_t*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_get_attributes', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('flavor', 'int32_t'),
('info', 'void*', 'uint64_t'),
('count', 'uint32_t*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('mach_port_type', [
('target', 'uint32_t'),
('name', 'uint32_t'),
('ptype', 'uint32_t*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
('task_for_pid', [
('target_tport', 'uint32_t'),
('pid', 'int32_t'),
('t', 'uint32_t*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX | XNU_TRAP_NOSUFFIX),
('task_name_for_pid', [
('target_tport', 'uint32_t'),
('pid', 'int32_t'),
('t', 'uint32_t*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX | XNU_TRAP_NOSUFFIX),
('pid_for_task', [
('t', 'uint32_t'),
('pid', 'int32_t*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX | XNU_TRAP_NOSUFFIX),
#
# Mach VM traps
#
('mach_vm_allocate', [
('target', 'uint32_t'),
('addr', 'uint64_t*', 'uint64_t'),
('size', 'uint64_t'),
('flags', 'int32_t'),
], [], XNU_TRAP_CALL),
('mach_vm_deallocate', [
('target', 'uint32_t'),
('address', 'uint64_t'),
('size', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
#
# Mach semaphore traps
#
('semaphore_signal', [
('signal_name', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
('semaphore_signal_all', [
('signal_name', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
('semaphore_wait', [
('wait_name', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
('semaphore_wait_signal', [
('wait_name', 'uint32_t'),
('signal_name', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
('semaphore_timedwait', [
('wait_name', 'uint32_t'),
('sec', 'uint32_t'),
('nsec', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
('semaphore_timedwait_signal', [
('wait_name', 'uint32_t'),
('signal_name', 'uint32_t'),
('sec', 'uint32_t'),
('nsec', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
#
# mk_timer traps
#
('mk_timer_create', [], [
('port_name', 'uint32_t'),
]),
('mk_timer_destroy', [
('name', 'uint32_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
('mk_timer_arm', [
('name', 'uint32_t'),
('expire_time', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
('mk_timer_cancel', [
('name', 'uint32_t'),
('result_time', 'uint64_t*', 'uint64_t'),
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
]
def parse_type(param_tuple, is_public):
@ -411,6 +632,112 @@ for call in calls:
internal_header.write("\t}; \\\n")
internal_header.write("\n")
internal_header.write("#define DSERVER_CLASS_SOURCE_DEFS \\\n")
for call in calls:
call_name = call[0]
call_parameters = call[1]
reply_parameters = call[2]
flags = call[3] if len(call) >= 4 else 0
camel_name = to_camel_case(call_name)
if (flags & XNU_TRAP_CALL) == 0:
continue
# XNU traps return values by writing directly to the calling process's memory at the addresses given as regular call parameters
if len(reply_parameters) > 0:
raise RuntimeError("Call marked as an XNU trap has reply parameters")
internal_header.write("\tvoid DarlingServer::Call::{0}::processCall() {{ \\\n".format(camel_name))
internal_header.write("\t\t_sendReply(dtape_{0}(".format(call_name))
is_first = True
for param in call_parameters:
param_name = param[0]
if is_first:
is_first = False
else:
internal_header.write(", ")
internal_header.write("_body.{0}".format(param_name))
internal_header.write(")); \\\n")
internal_header.write("\t}; \\\n")
internal_header.write("\n")
internal_header.write("#define DSERVER_DTAPE_DECLS \\\n")
for call in calls:
call_name = call[0]
call_parameters = call[1]
flags = call[3] if len(call) >= 4 else 0
camel_name = to_camel_case(call_name)
if (flags & XNU_TRAP_CALL) == 0:
continue
internal_header.write("\tint dtape_{0}(".format(call_name))
is_first = True
for param in call_parameters:
param_name = param[0]
if is_first:
is_first = False
else:
internal_header.write(", ")
internal_header.write("{0} {1}".format(parse_type(param, False), param_name))
internal_header.write("); \\\n")
internal_header.write("\n")
internal_header.write("#define DSERVER_DTAPE_DEFS \\\n")
for call in calls:
call_name = call[0]
call_parameters = call[1]
flags = call[3] if len(call) >= 4 else 0
camel_name = to_camel_case(call_name)
if (flags & XNU_TRAP_CALL) == 0:
continue
trap_name = call_name
if (flags & XNU_TRAP_NOPREFIX) == 0:
trap_name = "_kernelrpc_" + trap_name
if (flags & XNU_TRAP_NOSUFFIX) == 0:
trap_name = trap_name + "_trap"
trap_args_name = call_name
if (flags & XNU_TRAP_NOPREFIX) == 0:
trap_args_name = "_kernelrpc_" + trap_args_name
if (flags & (XNU_TRAP_NOSUFFIX | XNU_TRAP_NOSUFFIX_ARGS)) == 0:
trap_args_name = trap_args_name + "_trap"
internal_header.write("\tint dtape_{0}(".format(call_name))
is_first = True
for param in call_parameters:
param_name = param[0]
if is_first:
is_first = False
else:
internal_header.write(", ")
internal_header.write("{0} {1}".format(parse_type(param, False), param_name))
internal_header.write(") { \\\n")
internal_header.write("\t\tstruct {0}_args args = {{ \\\n".format(trap_args_name))
for param in call_parameters:
param_name = param[0]
internal_header.write("\t\t\t.{0} = {0}, \\\n".format(param_name))
internal_header.write("\t\t}; \\\n")
internal_header.write("\t\treturn {0}(&args); \\\n".format(trap_name))
internal_header.write("\t}; \\\n")
internal_header.write("\n")
for call in calls:
call_name = call[0]
call_parameters = call[1]

View File

@ -26,6 +26,7 @@
#include <darlingserver/duct-tape.h>
#include <darlingserver/config.hpp>
#include <sys/fcntl.h>
#include <sys/syscall.h>
static DarlingServer::Log callLog("calls");
@ -373,14 +374,6 @@ void DarlingServer::Call::GetTracer::processCall() {
_sendReply(code, tracer);
};
void DarlingServer::Call::MachMsgOverwrite::processCall() {
_sendReply(dtape_mach_msg_overwrite(_body.msg, _body.option, _body.send_size, _body.rcv_size, _body.rcv_name, _body.timeout, _body.notify, _body.rcv_msg, _body.rcv_limit));
};
void DarlingServer::Call::MachPortDeallocate::processCall() {
_sendReply(dtape_mach_port_deallocate(_body.task_right_name, _body.port_right_name));
};
void DarlingServer::Call::Uidgid::processCall() {
int code = 0;
int uid = -1;
@ -461,3 +454,53 @@ void DarlingServer::Call::MldrPath::processCall() {
_sendReply(code, fullLength);
};
void DarlingServer::Call::ThreadGetSpecialReplyPort::processCall() {
_sendReply(0, dtape_thread_get_special_reply_port());
};
void DarlingServer::Call::MkTimerCreate::processCall() {
_sendReply(0, dtape_mk_timer_create());
};
void DarlingServer::Call::PthreadKill::processCall() {
int code = 0;
if (auto targetThread = Thread::threadForPort(_body.thread_port)) {
if (auto targetProcess = targetThread->process()) {
if (syscall(SYS_tgkill, targetProcess->id(), targetThread->id(), _body.signal) < 0) {
code = -errno;
}
} else {
code = -ESRCH;
}
} else {
code = -ESRCH;
}
_sendReply(code);
};
void DarlingServer::Call::PthreadCanceled::processCall() {
int code = 0;
callLog.error() << "TODO: " << __PRETTY_FUNCTION__ << callLog.endLog;
code = -ENOSYS;
_sendReply(code);
};
void DarlingServer::Call::PthreadMarkcancel::processCall() {
int code = 0;
if (auto targetThread = Thread::threadForPort(_body.thread_port)) {
callLog.error() << "TODO: " << __PRETTY_FUNCTION__ << callLog.endLog;
code = -ENOSYS;
} else {
code = -ESRCH;
}
_sendReply(code);
};
DSERVER_CLASS_SOURCE_DEFS;

View File

@ -77,6 +77,8 @@ DarlingServer::Process::Process(ID id, NSID nsid):
// NOTE: see thread.cpp for why it's okay to use `this` here
_dtapeTask = dtape_task_create(parentProcess ? parentProcess->_dtapeTask : nullptr, _nspid, this);
processLog.info() << "New process created with ID " << _pid << " and NSID " << _nspid;
};
DarlingServer::Process::Process(KernelProcessConstructorTag tag):

View File

@ -49,6 +49,8 @@ static thread_local libsimple_lock_t* unlockMeWhenSuspending = nullptr;
*/
static thread_local uint64_t interruptDisableCount = 0;
static DarlingServer::Log threadLog("thread");
DarlingServer::Thread::Thread(std::shared_ptr<Process> process, NSID nsid):
_nstid(nsid),
_process(process)
@ -96,6 +98,8 @@ DarlingServer::Thread::Thread(std::shared_ptr<Process> process, NSID nsid):
// NOTE: it's okay to use raw `this` without a shared pointer because the duct-taped thread will always live for less time than this Thread instance
_dtapeThread = dtape_thread_create(process->_dtapeTask, _nstid, this);
threadLog.info() << "New thread created with ID " << _tid << " and NSID " << _nstid << " for process with ID " << (process ? process->id() : -1) << " and NSID " << (process ? process->nsid() : -1);
};
DarlingServer::Thread::Thread(KernelThreadConstructorTag tag):
@ -448,3 +452,20 @@ void DarlingServer::Thread::_kernelAsync(std::function<void()> fn) {
runnerThread->resume(); // resume the runner (it's most likely suspended waiting for work)
libsimple_lock_unlock(&kernelAsyncRunnerQueueLock);
};
std::shared_ptr<DarlingServer::Thread> DarlingServer::Thread::threadForPort(uint32_t thread_port) {
// prevent the target thread from dying by taking the global thread registry lock
auto registryLock = threadRegistry().scopedLock();
dtape_thread_handle_t thread_handle = dtape_thread_for_port(thread_port);
if (!thread_handle) {
return nullptr;
}
Thread* thread = static_cast<Thread*>(dtape_thread_context(thread_handle));
if (!thread) {
return nullptr;
}
return thread->shared_from_this();
};