kernel: Rename thread functions and move thread runner out from thread.cpp

kernel: Fill init cpu context from kernel
kernel: Various style nits
This commit is contained in:
sunho 2021-05-26 11:13:35 +09:00 committed by Nicolas Jallamion
parent 141eceebc4
commit dcfdb2a01b
14 changed files with 212 additions and 210 deletions

View File

@ -184,7 +184,7 @@ void draw_app_close(GuiState &gui, HostState &host) {
if (ImGui::Button("OK", BUTTON_SIZE) || ImGui::IsKeyPressed(host.cfg.keyboard_button_cross)) {
const auto app_path = gui.apps_list_opened[gui.current_app_selected];
update_last_loaded_apps(host, app_path);
host.kernel.stop_all_threads();
host.kernel.exit_delete_all_threads();
host.load_app_path = app_path;
host.load_exec = true;
}

View File

@ -1307,7 +1307,7 @@ void draw_live_area_screen(GuiState &gui, HostState &host) {
ImGui::SetCursorPos(ImVec2(display_size.x - (60.0f * SCALE.x) - BUTTON_SIZE.x, 44.0f * SCALE.y));
if (ImGui::Button("Esc", BUTTON_SIZE) || ImGui::IsKeyPressed(host.cfg.keyboard_button_circle)) {
if (app_path == host.io.app_path) {
host.kernel.stop_all_threads();
host.kernel.exit_delete_all_threads();
host.load_exec = true;
} else {
gui.apps_list_opened.erase(get_app_open_list_index(gui, app_path));

View File

@ -411,7 +411,7 @@ bool handle_events(HostState &host, GuiState &gui) {
ImGui_ImplSdl_ProcessEvent(gui.imgui_state.get(), &event);
switch (event.type) {
case SDL_QUIT:
host.kernel.stop_all_threads();
host.kernel.exit_delete_all_threads();
host.gxm.display_queue.abort();
host.display.abort.exchange(true);
host.display.condvar.notify_all();
@ -527,12 +527,12 @@ ExitCode run_app(HostState &host, Ptr<const void> &entry_point) {
return ::resolve_nid_name(host.kernel, addr);
};
const SceUID main_thread_id = ThreadState::create(entry_point, host.kernel, host.mem, host.io.title_id.c_str(), SCE_KERNEL_DEFAULT_PRIORITY_USER, static_cast<int>(SCE_KERNEL_STACK_SIZE_USER_MAIN), nullptr);
if (main_thread_id < 0) {
const ThreadStatePtr thread = host.kernel.create_thread(host.mem, host.io.title_id.c_str(), entry_point, SCE_KERNEL_DEFAULT_PRIORITY_USER, static_cast<int>(SCE_KERNEL_STACK_SIZE_USER_MAIN), nullptr);
if (!thread) {
app::error_dialog("Failed to init main thread.", host.window.get());
return InitThreadFailed;
}
const SceUID main_thread_id = thread->id;
const ThreadStatePtr main_thread = util::find(main_thread_id, host.kernel.threads);
@ -550,7 +550,7 @@ ExitCode run_app(HostState &host, Ptr<const void> &entry_point) {
// TODO: why does fios need separate thread its stack freed anyways?
const ThreadStatePtr module_thread = host.kernel.create_thread(host.mem, module_name);
const auto ret = module_thread->run_guest_function(module_start.address(), { 0, 0 });
module_thread->exit();
host.kernel.exit_delete_thread(module_thread);
LOG_INFO("Module {} (at \"{}\") module_start returned {}", module_name, module->path, log_hex(ret));
}
@ -570,7 +570,7 @@ ExitCode run_app(HostState &host, Ptr<const void> &entry_point) {
param.size = SceSize(buf.size());
param.attr = arr.address();
}
if (main_thread->start(host.kernel, param.size, Ptr<void>(param.attr)) < 0) {
if (main_thread->start(host.kernel, host.mem, param.size, Ptr<void>(param.attr)) < 0) {
app::error_dialog("Failed to run main thread.", host.window.get());
return RunThreadFailed;
}

View File

@ -163,9 +163,13 @@ struct KernelState {
bool init(MemState &mem, CallImportFunc call_import, CPUBackend cpu_backend, bool cpu_opt);
ThreadStatePtr create_thread(MemState &mem, const char *name);
ThreadStatePtr create_thread(MemState &mem, const char *name, Ptr<const void> entry_point, int init_priority, int stack_size, const SceKernelThreadOptParam *option);
void exit_thread(ThreadStatePtr thread);
void exit_delete_thread(ThreadStatePtr thread);
ThreadStatePtr get_thread(SceUID thread_id);
Ptr<Ptr<void>> get_thread_tls_addr(MemState &mem, SceUID thread_id, int key);
void stop_all_threads();
void exit_delete_all_threads();
int run_guest_function(Address callback_address, const std::vector<uint32_t> &args);

View File

@ -53,8 +53,6 @@ enum class ThreadStatus {
wait, // Waiting to be awaken by sync object or operation
};
constexpr auto kernel_tls_size = 0x800;
struct ThreadSignal {
ThreadSignal() = default;
~ThreadSignal() = default;
@ -82,9 +80,11 @@ struct ThreadState {
std::string name;
SceUID id;
Address entry_point;
Block stack;
int stack_size;
Block tls;
int priority;
uint64_t start_tick;
@ -97,27 +97,28 @@ struct ThreadState {
std::vector<std::shared_ptr<ThreadState>> waiting_threads;
int returned_value;
static SceUID create(Ptr<const void> entry_point, KernelState &kernel, MemState &mem, const char *name, int init_priority, int stack_size, const SceKernelThreadOptParam *option);
int start(KernelState &kernel, SceSize arglen, const Ptr<void> &argp);
int init(KernelState &kernel, MemState &mem, const char *name, Ptr<const void> entry_point, int init_priority, int stack_size, const SceKernelThreadOptParam *option);
int start(KernelState &kernel, MemState &mem, SceSize arglen, const Ptr<void> &argp);
void update_status(ThreadStatus status, std::optional<ThreadStatus> expected = std::nullopt);
Address stack_top() const;
bool run_loop();
void clear_run_queue();
void stop_loop();
void flush_callback_requests();
void halt();
void exit();
void raise_waiting_threads();
Ptr<void> copy_block_to_stack(MemState &mem, const Ptr<void> &data, const int size);
int run_guest_function(Address callback_address, const std::vector<uint32_t> &args);
void request_callback(Address callback_address, const std::vector<uint32_t> &args, const std::function<void(int res)> notify = nullptr);
void suspend();
void resume(bool step = false);
std::string log_stack_traceback(KernelState &kernel, MemState &mem);
std::string log_stack_traceback(KernelState &kernel, MemState &mem) const;
private:
void clear_run_queue();
CPUContext init_cpu_ctx;
RunQueue jobs_to_add;
RunQueue callback_requests;
ThreadToDo to_do = ThreadToDo::wait;
std::condition_variable something_to_do;
};

View File

@ -26,6 +26,7 @@
#include <util/find.h>
#include <util/log.h>
#include <SDL_thread.h>
#include <spdlog/fmt/fmt.h>
#include <util/lock_and_find.h>
@ -46,6 +47,29 @@ void CorenumAllocator::set_max_core_count(const std::size_t max) {
alloc.set_maximum(max);
}
// TODO implement cross platform debug thread name setter and eliminate SDL thread
struct ThreadParams {
KernelState *kernel = nullptr;
SceUID thid = SCE_KERNEL_ERROR_ILLEGAL_THREAD_ID;
std::shared_ptr<SDL_semaphore> host_may_destroy_params = std::shared_ptr<SDL_semaphore>(SDL_CreateSemaphore(0), SDL_DestroySemaphore);
};
static int SDLCALL thread_function(void *data) {
assert(data != nullptr);
const ThreadParams params = *static_cast<const ThreadParams *>(data);
SDL_SemPost(params.host_may_destroy_params.get());
const ThreadStatePtr thread = lock_and_find(params.thid, params.kernel->threads, params.kernel->mutex);
thread->run_loop();
const uint32_t r0 = read_reg(*thread->cpu, 0);
thread->returned_value = r0;
std::lock_guard<std::mutex> lock(params.kernel->mutex);
params.kernel->threads.erase(thread->id);
params.kernel->corenum_allocator.free_corenum(get_processor_id(*thread->cpu));
return r0;
}
bool KernelState::init(MemState &mem, CallImportFunc call_import, CPUBackend cpu_backend, bool cpu_opt) {
constexpr std::size_t MAX_CORE_COUNT = 150;
@ -91,6 +115,38 @@ ThreadStatePtr KernelState::get_thread(SceUID thread_id) {
return it->second;
}
ThreadStatePtr KernelState::create_thread(MemState &mem, const char *name) {
constexpr size_t DEFAULT_STACK_SIZE = 0x1000;
return create_thread(mem, name, Ptr<void>(0), SCE_KERNEL_DEFAULT_PRIORITY, DEFAULT_STACK_SIZE, nullptr);
}
ThreadStatePtr KernelState::create_thread(MemState &mem, const char *name, Ptr<const void> entry_point, int init_priority, int stack_size, const SceKernelThreadOptParam *option) {
ThreadStatePtr thread = std::make_shared<ThreadState>();
thread->id = get_next_uid();
if (thread->init(*this, mem, name, entry_point, init_priority, stack_size, option) < 0)
return nullptr;
const auto lock = std::lock_guard(mutex);
threads.emplace(thread->id, thread);
ThreadParams params;
params.kernel = this;
params.thid = thread->id;
SDL_CreateThread(&thread_function, thread->name.c_str(), &params);
SDL_SemWait(params.host_may_destroy_params.get());
return thread;
}
void KernelState::exit_thread(ThreadStatePtr thread) {
thread->clear_run_queue();
stop(*thread->cpu);
}
void KernelState::exit_delete_thread(ThreadStatePtr thread) {
thread->clear_run_queue();
thread->stop_loop();
}
Ptr<Ptr<void>> KernelState::get_thread_tls_addr(MemState &mem, SceUID thread_id, int key) {
Ptr<Ptr<void>> address(0);
//magic numbers taken from decompiled source. There is 0x400 unused bytes of unknown usage
@ -103,19 +159,13 @@ Ptr<Ptr<void>> KernelState::get_thread_tls_addr(MemState &mem, SceUID thread_id,
return address;
}
void KernelState::stop_all_threads() {
void KernelState::exit_delete_all_threads() {
const std::lock_guard<std::mutex> lock(mutex);
for (ThreadStatePtrs::iterator thread = threads.begin(); thread != threads.end(); ++thread) {
thread->second->exit();
for (auto [_, thread] : threads) {
exit_delete_thread(thread);
}
}
ThreadStatePtr KernelState::create_thread(MemState &mem, const char *name) {
constexpr size_t DEFAULT_STACK_SIZE = 0x1000;
const SceUID id = ThreadState::create(Ptr<void>(0), *this, mem, name, SCE_KERNEL_DEFAULT_PRIORITY, DEFAULT_STACK_SIZE, nullptr);
return lock_and_find(id, threads, mutex);
}
int KernelState::run_guest_function(Address callback_address, const std::vector<uint32_t> &args) {
return this->guest_func_runner->run_guest_function(callback_address, args);
}

View File

@ -29,43 +29,32 @@
#include <spdlog/fmt/fmt.h>
#include <util/log.h>
#include <SDL_thread.h>
#include <cassert>
#include <cstring>
#include <memory>
#include <sstream>
struct ThreadParams {
KernelState *kernel = nullptr;
SceUID thid = SCE_KERNEL_ERROR_ILLEGAL_THREAD_ID;
std::shared_ptr<SDL_semaphore> host_may_destroy_params = std::shared_ptr<SDL_semaphore>(SDL_CreateSemaphore(0), SDL_DestroySemaphore);
};
static int SDLCALL thread_function(void *data) {
assert(data != nullptr);
const ThreadParams params = *static_cast<const ThreadParams *>(data);
SDL_SemPost(params.host_may_destroy_params.get());
const ThreadStatePtr thread = lock_and_find(params.thid, params.kernel->threads, params.kernel->mutex);
thread->run_loop();
const uint32_t r0 = read_reg(*thread->cpu, 0);
thread->returned_value = r0;
std::lock_guard<std::mutex> lock(params.kernel->mutex);
thread->raise_waiting_threads();
params.kernel->threads.erase(thread->id);
params.kernel->corenum_allocator.free_corenum(get_processor_id(*thread->cpu));
return r0;
void ThreadSignal::wait() {
std::unique_lock<std::mutex> lock(mutex);
recv_cond.wait(lock, [&]() { return signaled; });
signaled = false;
}
SceUID ThreadState::create(Ptr<const void> entry_point, KernelState &kernel, MemState &mem, const char *name, int init_priority, int stack_size, const SceKernelThreadOptParam *option = nullptr) {
SceUID thid = kernel.get_next_uid();
bool ThreadSignal::send() {
std::unique_lock<std::mutex> lock(mutex);
if (signaled) {
return false;
}
signaled = true;
recv_cond.notify_one();
return true;
}
const ThreadStatePtr thread = std::make_shared<ThreadState>();
thread->name = name;
thread->entry_point = entry_point.address();
thread->id = thid;
int ThreadState::init(KernelState &kernel, MemState &mem, const char *name, Ptr<const void> entry_point, int init_priority, int stack_size, const SceKernelThreadOptParam *option = nullptr) {
constexpr size_t KERNEL_TLS_SIZE = 0x800;
this->name = name;
this->entry_point = entry_point.address();
int core_num = kernel.corenum_allocator.new_corenum();
if (core_num < 0) {
@ -75,66 +64,57 @@ SceUID ThreadState::create(Ptr<const void> entry_point, KernelState &kernel, Mem
if (init_priority > SCE_KERNEL_LOWEST_PRIORITY_USER) {
assert(SCE_KERNEL_HIGHEST_DEFAULT_PRIORITY <= init_priority && init_priority <= SCE_KERNEL_LOWEST_DEFAULT_PRIORITY);
thread->priority = init_priority - SCE_KERNEL_DEFAULT_PRIORITY + SCE_KERNEL_GAME_DEFAULT_PRIORITY_ACTUAL;
priority = init_priority - SCE_KERNEL_DEFAULT_PRIORITY + SCE_KERNEL_GAME_DEFAULT_PRIORITY_ACTUAL;
} else {
thread->priority = init_priority;
priority = init_priority;
}
thread->stack_size = stack_size;
thread->start_tick = rtc_get_ticks(kernel.base_tick.tick);
this->stack_size = stack_size;
start_tick = rtc_get_ticks(kernel.base_tick.tick);
auto alloc_name = fmt::format("Stack for thread {} (#{})", name, thid);
thread->stack = alloc_block(mem, stack_size, alloc_name.c_str());
const Address stack_top = thread->stack.get() + stack_size;
memset(thread->stack.get_ptr<void>().get(mem), 0xcc, stack_size);
thread->cpu = init_cpu(kernel.cpu_backend, kernel.cpu_opt, thid, static_cast<std::size_t>(core_num), entry_point.address(), stack_top, mem, kernel.cpu_protocol.get());
if (!thread->cpu) {
cpu = init_cpu(kernel.cpu_backend, kernel.cpu_opt, id, static_cast<std::size_t>(core_num), mem, kernel.cpu_protocol.get());
if (!cpu) {
return SCE_KERNEL_ERROR_ERROR;
}
if (kernel.debugger.watch_code) {
set_log_code(*thread->cpu, true);
set_log_code(*cpu, true);
}
if (kernel.debugger.watch_memory) {
set_log_mem(*thread->cpu, true);
set_log_mem(*cpu, true);
}
if (option) {
write_reg(*thread->cpu, 0, option->attr);
write_reg(*thread->cpu, 1, option->size);
}
std::string alloc_name = fmt::format("Stack for thread {} (#{})", name, id);
stack = alloc_block(mem, stack_size, alloc_name.c_str());
memset(stack.get_ptr<void>().get(mem), 0xcc, stack_size);
alloc_name = fmt::format("TLS for thread {} (#{})", name, thid);
auto tls_size = kernel_tls_size + kernel.tls_msize;
thread->tls = alloc_block(mem, tls_size, alloc_name.c_str());
auto base_tls_address_ptr = thread->tls.get_ptr<uint8_t>();
memset(base_tls_address_ptr.get(mem), 0, tls_size);
alloc_name = fmt::format("TLS for thread {} (#{})", name, id);
const size_t tls_size = KERNEL_TLS_SIZE + kernel.tls_msize;
tls = alloc_block(mem, tls_size, alloc_name.c_str());
const Ptr<uint8_t> base_tls_ptr = tls.get_ptr<uint8_t>();
memset(base_tls_ptr.get(mem), 0, tls_size);
if (kernel.tls_address) {
auto user_tls_address_ptr = base_tls_address_ptr + kernel_tls_size;
write_tpidruro(*thread->cpu, user_tls_address_ptr.address());
const Ptr<uint8_t> user_tls_ptr = base_tls_ptr + KERNEL_TLS_SIZE;
write_tpidruro(*cpu, user_tls_ptr.address());
assert(kernel.tls_psize <= kernel.tls_msize);
memcpy(user_tls_address_ptr.get(mem), kernel.tls_address.get(mem), kernel.tls_psize);
memcpy(user_tls_ptr.get(mem), kernel.tls_address.get(mem), kernel.tls_psize);
} else {
write_tpidruro(*thread->cpu, 0);
write_tpidruro(*cpu, 0);
}
thread->init_cpu_ctx = save_context(*thread->cpu);
CPUContext ctx;
ctx.set_sp(stack_top());
ctx.cpsr = 0x400001D3;
if (option) {
ctx.cpu_registers[0] = option->attr;
ctx.cpu_registers[1] = option->size;
}
this->init_cpu_ctx = ctx;
const std::unique_lock<std::mutex> lock(kernel.mutex);
kernel.threads.emplace(thid, thread);
ThreadParams params;
params.kernel = &kernel;
params.thid = thid;
SDL_CreateThread(&thread_function, thread->name.c_str(), &params);
SDL_SemWait(params.host_may_destroy_params.get());
return thid;
return 0;
}
void ThreadState::flush_callback_requests() {
if (!jobs_to_add.empty()) {
if (!callback_requests.empty()) {
const auto current = run_queue.begin();
// Add resuming job
ThreadJob job;
@ -144,10 +124,10 @@ void ThreadState::flush_callback_requests() {
run_queue.push_front(job);
// Add requested callback jobs
for (auto it = jobs_to_add.rbegin(); it != jobs_to_add.rend(); ++it) {
for (auto it = callback_requests.rbegin(); it != callback_requests.rend(); ++it) {
run_queue.push_front(*it);
}
jobs_to_add.clear();
callback_requests.clear();
stop(*cpu);
}
}
@ -162,17 +142,27 @@ void ThreadState::raise_waiting_threads() {
waiting_threads.clear();
}
int ThreadState::start(KernelState &kernel, SceSize arglen, const Ptr<void> &argp) {
int ThreadState::start(KernelState &kernel, MemState &mem, SceSize arglen, const Ptr<void> &argp) {
if (status == ThreadStatus::run)
return SCE_KERNEL_ERROR_RUNNING;
std::unique_lock<std::mutex> thread_lock(mutex);
CPUContext ctx = save_context(*cpu);
CPUContext ctx = init_cpu_ctx;
ctx.cpu_registers[0] = arglen;
ctx.cpu_registers[1] = argp.address();
ctx.set_pc(entry_point);
ctx.set_lr(cpu->halt_instruction_pc);
// Copy data to stack
if (argp && arglen > 0) {
const Address stack_top = stack.get() + stack_size;
const int aligned_size = align(arglen, 8);
const Address data_addr = stack_top - aligned_size;
memcpy(Ptr<uint8_t>(data_addr).get(mem), argp.get(mem), arglen);
ctx.cpu_registers[1] = data_addr;
ctx.set_sp(data_addr);
}
ThreadJob job;
job.ctx = ctx;
@ -190,21 +180,6 @@ int ThreadState::start(KernelState &kernel, SceSize arglen, const Ptr<void> &arg
return SCE_KERNEL_OK;
}
Ptr<void> ThreadState::copy_block_to_stack(MemState &mem, const Ptr<void> &data, const int size) {
std::unique_lock<std::mutex> thread_lock(mutex);
const Address stack_top = stack.get() + stack_size;
const Address sp = read_sp(*cpu);
assert(sp <= stack_top && sp >= stack.get());
assert(sp - stack.get() >= size);
const int aligned_size = align(size, 8);
const Address data_addr = sp - aligned_size;
memcpy(Ptr<uint8_t>(data_addr).get(mem), data.get(mem), size);
write_sp(*cpu, data_addr);
return Ptr<void>(data_addr);
}
bool ThreadState::run_loop() {
int res = 0;
RunQueue::iterator current_job;
@ -212,6 +187,7 @@ bool ThreadState::run_loop() {
while (true) {
switch (to_do) {
case ThreadToDo::exit:
raise_waiting_threads();
return true;
case ThreadToDo::run:
case ThreadToDo::step:
@ -252,27 +228,23 @@ bool ThreadState::run_loop() {
break;
}
if (hit_breakpoint(*cpu)) {
to_do = ThreadToDo::suspend;
}
if (to_do == ThreadToDo::suspend) {
if (hit_breakpoint(*cpu) || to_do == ThreadToDo::suspend) {
ThreadJob job;
job.ctx = save_context(*cpu);
job.notify = current_job->notify;
run_queue.erase(current_job);
run_queue.push_front(job);
update_status(ThreadStatus::suspend);
to_do = ThreadToDo::wait;
}
if (res == 1) {
if (res) {
if (current_job->notify) {
current_job->notify(read_reg(*cpu, 0));
}
run_queue.erase(current_job);
}
break;
case ThreadToDo::suspend:
case ThreadToDo::wait:
something_to_do.wait(lock);
break;
@ -281,48 +253,58 @@ bool ThreadState::run_loop() {
}
int ThreadState::run_guest_function(Address callback_address, const std::vector<uint32_t> &args) {
std::unique_lock<std::mutex> thread_lock(mutex);
std::mutex notify_mutex;
std::condition_variable notify_cond;
bool done = false;
int res = 0;
ThreadJob job;
job.notify = [&](int res2) {
std::lock_guard<std::mutex> lock(notify_mutex);
done = true;
res = res2;
notify_cond.notify_one();
};
CPUContext ctx = init_cpu_ctx;
assert(args.size() <= 4);
std::unique_lock<std::mutex> thread_lock(mutex);
ThreadJob job;
CPUContext ctx = init_cpu_ctx;
for (int i = 0; i < args.size(); i++) {
ctx.cpu_registers[i] = args[i];
}
ctx.set_pc(callback_address);
ctx.set_lr(cpu->halt_instruction_pc);
job.ctx = ctx;
// TODO: remaining arguments should be pushed into stack
std::mutex notify_mutex;
std::condition_variable notify_cond;
bool notify_done = false;
int notify_res = 0;
job.notify = [&](int res) {
std::lock_guard<std::mutex> lock(notify_mutex);
notify_done = true;
notify_res = res;
notify_cond.notify_one();
};
// Push a job
to_do = ThreadToDo::run;
run_queue.push_back(job);
something_to_do.notify_one();
// Wait until job finishes
thread_lock.unlock();
std::unique_lock<std::mutex> lock(notify_mutex);
notify_cond.wait(lock, [&]() { return done; });
notify_cond.wait(lock, [&]() { return notify_done; });
return res;
return notify_res;
}
void ThreadState::stop_loop() {
std::lock_guard<std::mutex> lock(mutex);
const auto last_to_do = to_do;
to_do = ThreadToDo::exit;
if (last_to_do == ThreadToDo::wait) {
something_to_do.notify_one();
} else {
stop(*cpu);
}
}
void ThreadState::update_status(ThreadStatus status, std::optional<ThreadStatus> expected) {
if (expected) {
if (expected)
assert(expected.value() == this->status);
}
this->status = status;
status_cond.notify_all();
@ -331,7 +313,12 @@ void ThreadState::update_status(ThreadStatus status, std::optional<ThreadStatus>
}
}
Address ThreadState::stack_top() const {
return stack.get() + stack_size;
}
void ThreadState::clear_run_queue() {
const auto lock = std::lock_guard(mutex);
if (!run_queue.empty()) {
const auto top = run_queue.begin();
if (top->notify) {
@ -342,11 +329,12 @@ void ThreadState::clear_run_queue() {
}
void ThreadState::request_callback(Address callback_address, const std::vector<uint32_t> &args, const std::function<void(int res)> notify) {
std::unique_lock<std::mutex> thread_lock(mutex);
assert(args.size() <= 4);
const auto thread_lock = std::lock_guard(mutex);
ThreadJob job;
CPUContext ctx = save_context(*cpu);
job.notify = notify;
assert(args.size() <= 4);
for (int i = 0; i < args.size(); i++) {
ctx.cpu_registers[i] = args[i];
}
@ -354,27 +342,8 @@ void ThreadState::request_callback(Address callback_address, const std::vector<u
ctx.set_pc(callback_address);
ctx.set_lr(cpu->halt_instruction_pc);
job.ctx = ctx;
// TODO: remaining arguments should be pushed into stack
jobs_to_add.push_back(job);
}
void ThreadState::halt() {
std::lock_guard<std::mutex> lock(mutex);
clear_run_queue();
stop(*cpu);
}
void ThreadState::exit() {
std::lock_guard<std::mutex> lock(mutex);
const auto last_to_do = to_do;
to_do = ThreadToDo::exit;
clear_run_queue();
if (last_to_do == ThreadToDo::wait) {
something_to_do.notify_one();
} else {
stop(*cpu);
}
callback_requests.push_back(job);
}
void ThreadState::suspend() {
@ -384,12 +353,12 @@ void ThreadState::suspend() {
}
void ThreadState::resume(bool step) {
assert(to_do == ThreadToDo::suspend);
assert(to_do == ThreadToDo::wait);
to_do = step ? ThreadToDo::step : ThreadToDo::run;
something_to_do.notify_one();
}
std::string ThreadState::log_stack_traceback(KernelState &kernel, MemState &mem) {
std::string ThreadState::log_stack_traceback(KernelState &kernel, MemState &mem) const {
constexpr Address START_OFFSET = 0;
constexpr Address END_OFFSET = 1024;
std::stringstream ss;
@ -401,20 +370,4 @@ std::string ThreadState::log_stack_traceback(KernelState &kernel, MemState &mem)
ss << fmt::format("{} (module: {})\n", log_hex(value), mod->module_name);
}
return ss.str();
}
void ThreadSignal::wait() {
std::unique_lock<std::mutex> lock(mutex);
recv_cond.wait(lock, [&]() { return signaled; });
signaled = false;
}
bool ThreadSignal::send() {
std::unique_lock<std::mutex> lock(mutex);
if (signaled) {
return false;
}
signaled = true;
recv_cond.notify_one();
return true;
}
}

View File

@ -343,7 +343,7 @@ EXPORT(SceInt32, _sceAppMgrLoadExec, const char *appPath, Ptr<char> const argv[]
return RET_ERROR(SCE_APPMGR_ERROR_TOO_LONG_ARGV);
}
host.kernel.stop_all_threads();
host.kernel.exit_delete_all_threads();
host.load_app_path = host.io.app_path;
host.load_exec_path = exec_path;

View File

@ -1623,14 +1623,11 @@ EXPORT(int, sceGxmInitialize, const SceGxmInitializeParams *params) {
host.gxm.display_queue.maxPendingCount_ = params->displayQueueMaxPendingCount;
const ThreadStatePtr main_thread = util::find(thread_id, host.kernel.threads);
const auto stack_size = SCE_KERNEL_STACK_SIZE_USER_DEFAULT; // TODO: Verify this is the correct stack size
host.gxm.display_queue_thread = ThreadState::create(Ptr<void>(read_pc(*main_thread->cpu)), host.kernel, host.mem, "SceGxmDisplayQueue", SCE_KERNEL_HIGHEST_PRIORITY_USER, stack_size, nullptr);
if (host.gxm.display_queue_thread < 0) {
const ThreadStatePtr display_queue_thread = host.kernel.create_thread(host.mem, "SceGxmDisplayQueue", Ptr<void>(0), SCE_KERNEL_HIGHEST_PRIORITY_USER, SCE_KERNEL_STACK_SIZE_USER_DEFAULT, nullptr);
if (!display_queue_thread) {
return RET_ERROR(SCE_GXM_ERROR_DRIVER);
}
host.gxm.display_queue_thread = display_queue_thread->id;
GxmThreadParams gxm_params;
gxm_params.mem = &host.mem;
@ -3216,7 +3213,7 @@ EXPORT(int, sceGxmSyncObjectDestroy, Ptr<SceGxmSyncObject> syncObject) {
EXPORT(int, sceGxmTerminate) {
const ThreadStatePtr thread = lock_and_find(host.gxm.display_queue_thread, host.kernel.threads, host.kernel.mutex);
thread->exit();
host.kernel.exit_delete_thread(thread);
return 0;
}

View File

@ -104,7 +104,7 @@ EXPORT(SceUID, _sceKernelLoadStartModule, const char *moduleFileName, SceSize ar
auto module_thread = host.kernel.create_thread(host.mem, moduleFileName);
uint32_t result = module_thread->run_guest_function(entry_point.address(), { args, argp.address() });
module_thread->exit();
host.kernel.exit_delete_thread(module_thread);
LOG_INFO("Module {} (at \"{}\") module_start returned {}", module->module_name, module->path, log_hex(result));

View File

@ -406,10 +406,7 @@ EXPORT(int, _sceKernelStartThread, SceUID thid, SceSize arglen, Ptr<void> argp)
return SCE_KERNEL_ERROR_RUNNING;
}
if (argp && arglen > 0) {
new_argp = thread->copy_block_to_stack(host.mem, argp, arglen);
}
const int res = thread->start(host.kernel, arglen, new_argp);
const int res = thread->start(host.kernel, host.mem, arglen, argp);
if (res < 0) {
return RET_ERROR(res);
}
@ -629,10 +626,10 @@ EXPORT(int, sceKernelCreateThreadForUser, const char *name, SceKernelThreadEntry
return RET_ERROR(SCE_KERNEL_ERROR_INVALID_CPU_AFFINITY);
}
const SceUID thid = ThreadState::create(entry.cast<const void>(), host.kernel, host.mem, name, init_priority, options->stack_size, options->option.get(host.mem));
if (thid < 0)
return RET_ERROR(thid);
return thid;
const ThreadStatePtr thread = host.kernel.create_thread(host.mem, name, entry.cast<void>(), init_priority, options->stack_size, options->option.get(host.mem));
if (!thread)
return RET_ERROR(SCE_KERNEL_ERROR_ERROR);
return thread->id;
}
int delay_thread(SceUInt delay_us) {
@ -700,7 +697,7 @@ EXPORT(int, sceKernelDeleteThread, SceUID thid) {
if (!thread || thread->status != ThreadStatus::dormant) {
return SCE_KERNEL_ERROR_NOT_DORMANT;
}
thread->exit();
host.kernel.exit_delete_thread(thread);
return 0;
}
@ -712,7 +709,7 @@ EXPORT(int, sceKernelDeleteTimer, SceUID timer_handle) {
EXPORT(int, sceKernelExitDeleteThread, int status) {
const ThreadStatePtr thread = lock_and_find(thread_id, host.kernel.threads, host.kernel.mutex);
thread->exit();
host.kernel.exit_delete_thread(thread);
return status;
}

View File

@ -20,8 +20,8 @@
#include <util/lock_and_find.h>
EXPORT(int, sceKernelExitThread, int status) {
const ThreadStatePtr thread = lock_and_find(thread_id, host.kernel.threads, host.kernel.mutex);
thread->halt();
const ThreadStatePtr thread = host.kernel.get_thread(thread_id);
host.kernel.exit_thread(thread);
return status;
}

View File

@ -35,7 +35,7 @@ EXPORT(int, sceDbgAssertionHandler, const char *filename, int line, bool do_stop
LOG_INFO("file {}, line {}, {}", filename, line, buffer.data());
if (do_stop)
host.kernel.stop_all_threads();
host.kernel.exit_delete_all_threads();
if (!result) {
return SCE_KERNEL_ERROR_INVALID_ARGUMENT;

View File

@ -997,7 +997,7 @@ EXPORT(int, sceKernelDeleteLwMutex, Ptr<SceKernelLwMutexWork> workarea) {
EXPORT(int, sceKernelExitProcess, int res) {
// TODO Handle exit code?
host.kernel.stop_all_threads();
host.kernel.exit_delete_all_threads();
return SCE_KERNEL_OK;
}