blob: 67a9251e9ed444bb7c66f268665b1da155af629e [file]
// Copyright 2026 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/boot-options/boot-options.h>
#include <lib/counters.h>
#include <lib/object-constants.h>
#include <lib/user_copy/user_ptr.h>
#include <kernel/ffi.h>
#include <object/process_dispatcher.h>
#include <object/thread_dispatcher.h>
KCOUNTER(thread_legacy_yield, "thread.legacy_yield")
extern "C" {
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE bool cpp_thread_dispatcher_is_current(const ThreadDispatcher* thread) {
return thread == ThreadDispatcher::GetCurrent();
}
zx_status_t cpp_thread_dispatcher_create(
ProcessDispatcher* process, uint32_t flags, const char* name_ptr, size_t name_len,
ffi::Uninitialized<KernelHandle<ThreadDispatcher>>* out_handle,
ffi::Uninitialized<zx_rights_t>* out_rights) {
KernelHandle<ThreadDispatcher> handle;
zx_rights_t rights;
zx_status_t status =
ThreadDispatcher::Create(fbl::ImportFromRawPtr(process), flags,
ktl::string_view(name_ptr, name_len), &handle, &rights);
if (status == ZX_OK) {
out_handle->Initialize(ktl::move(handle));
out_rights->Initialize(rights);
}
return status;
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE zx_status_t cpp_thread_dispatcher_initialize(ThreadDispatcher* thread) {
return thread->Initialize();
}
zx_status_t cpp_thread_dispatcher_start(ThreadDispatcher* thread, zx_vaddr_t entry,
zx_vaddr_t stack, uint64_t arg1, uint64_t arg2, uint64_t tp,
uint64_t abi_reg, bool ensure_initial_thread) {
return thread->Start(
{
.pc = entry,
.sp = stack,
.arg1 = arg1,
.arg2 = arg2,
.tp = tp,
.abi_reg = abi_reg,
},
ensure_initial_thread);
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE void cpp_thread_dispatcher_exit_current() { ThreadDispatcher::ExitCurrent(); }
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE void cpp_thread_dispatcher_kill_current() { ThreadDispatcher::KillCurrent(); }
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE void cpp_thread_dispatcher_kill(ThreadDispatcher* thread) { thread->Kill(); }
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE zx_status_t cpp_thread_dispatcher_suspend(ThreadDispatcher* thread) {
return thread->Suspend();
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE void cpp_thread_dispatcher_resume(ThreadDispatcher* thread) { thread->Resume(); }
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE zx_status_t cpp_thread_dispatcher_restricted_kick(ThreadDispatcher* thread) {
return thread->RestrictedKick();
}
zx_status_t cpp_thread_dispatcher_read_state(ThreadDispatcher* thread, uint32_t state_kind,
void* buffer, size_t buffer_size) {
return thread->ReadState(static_cast<zx_thread_state_topic_t>(state_kind),
make_user_out_ptr(buffer), buffer_size);
}
zx_status_t cpp_thread_dispatcher_write_state(ThreadDispatcher* thread, uint32_t state_kind,
const void* buffer, size_t buffer_size) {
if ((state_kind & ZX_THREAD_STATE_DEBUG_REGS) && !BootOptions::Get()->enable_debugging_syscalls) {
return ZX_ERR_NOT_SUPPORTED;
}
return thread->WriteState(static_cast<zx_thread_state_topic_t>(state_kind),
make_user_in_ptr(buffer), buffer_size);
}
zx_status_t cpp_thread_dispatcher_set_base_profile(ThreadDispatcher* thread,
const SchedulerState::BaseProfile* profile) {
static_assert(sizeof(SchedulerState::BaseProfile) == kSchedulerStateBaseProfileSize,
"SchedulerState::BaseProfile size mismatch");
static_assert(alignof(SchedulerState::BaseProfile) == kSchedulerStateBaseProfileAlign,
"SchedulerState::BaseProfile align mismatch");
return thread->SetBaseProfile(*profile);
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE zx_status_t cpp_thread_dispatcher_set_soft_affinity(ThreadDispatcher* thread,
cpu_mask_t mask) {
return thread->SetSoftAffinity(mask);
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE void cpp_thread_dispatcher_get_info_for_userspace(
const ThreadDispatcher* thread, ffi::Uninitialized<zx_info_thread_t>* out_info) {
out_info->Initialize(thread->GetInfoForUserspace());
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE zx_status_t cpp_thread_dispatcher_get_stats_for_userspace(
ThreadDispatcher* thread, ffi::Uninitialized<zx_info_thread_stats_t>* out_info) {
return thread->GetStatsForUserspace(out_info->GetAddressUnchecked());
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE void cpp_thread_dispatcher_get_runtime_stats(
const ThreadDispatcher* thread, ffi::Uninitialized<zx_info_task_runtime_t>* out_info) {
out_info->Initialize(thread->GetRuntimeStats());
}
zx_status_t cpp_sys_thread_raise_exception(uint32_t options, zx_excp_type_t type,
const zx_exception_context_t* user_context) {
if (options != ZX_EXCEPTION_TARGET_JOB_DEBUGGER || type != ZX_EXCP_USER || !user_context) {
return ZX_ERR_INVALID_ARGS;
}
arch_exception_context_t context = {};
context.user_synth_code = user_context->synth_code;
context.user_synth_data = user_context->synth_data;
auto thread = ThreadDispatcher::GetCurrent();
thread->process()->OnUserExceptionForJobDebugger(thread, &context);
return ZX_OK;
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE zx_status_t cpp_sys_thread_legacy_yield(uint32_t options) {
if (options != 0) {
return ZX_ERR_INVALID_ARGS;
}
kcounter_add(thread_legacy_yield, 1);
Thread::Current::Yield();
return ZX_OK;
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE ThreadDispatcher::Blocked cpp_thread_dispatcher_set_blocked_reason(
ThreadDispatcher::Blocked reason) {
return ThreadDispatcher::SetBlockedReason(reason);
}
// TODO(https://fxbug.dev/537458631): Remove the annotations once cross-language inlining works.
FFI_ALWAYS_INLINE zx_status_t cpp_thread_dispatcher_get_exception_report(
const ThreadDispatcher* thread, ffi::Uninitialized<zx_exception_report_t>* out_report) {
return const_cast<ThreadDispatcher*>(thread)->GetExceptionReport(
out_report->GetAddressUnchecked());
}
} // extern "C"