mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 11:13:57 +00:00
Fix semaphores and mutexes
This commit is contained in:
@@ -31,6 +31,8 @@ using NTSTATUS = std::uint32_t;
|
||||
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
|
||||
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
|
||||
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
|
||||
#define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L)
|
||||
#define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L)
|
||||
#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL)
|
||||
#define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L)
|
||||
#define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L)
|
||||
|
||||
@@ -354,6 +354,8 @@ constexpr auto BASE_NAMED_OBJECTS_DIRECTORY = make_pseudo_handle(0x2, handle_typ
|
||||
constexpr auto KNOWN_DLLS_SYMLINK = make_pseudo_handle(0x1, handle_types::symlink);
|
||||
constexpr auto SHARED_SECTION = make_pseudo_handle(0x1, handle_types::section);
|
||||
|
||||
constexpr auto WER_PORT_READY = make_pseudo_handle(0x1, handle_types::event);
|
||||
|
||||
constexpr auto CONSOLE_HANDLE = make_pseudo_handle(0x1, handle_types::file);
|
||||
constexpr auto STDOUT_HANDLE = make_pseudo_handle(0x2, handle_types::file);
|
||||
constexpr auto STDIN_HANDLE = make_pseudo_handle(0x3, handle_types::file);
|
||||
|
||||
@@ -108,17 +108,17 @@ struct mutant : ref_counted_object
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t release()
|
||||
std::pair<uint32_t, bool> release(const uint32_t thread_id)
|
||||
{
|
||||
const auto old_count = this->locked_count;
|
||||
|
||||
if (this->locked_count <= 0)
|
||||
if (this->locked_count <= 0 || this->owning_thread_id != thread_id)
|
||||
{
|
||||
return old_count;
|
||||
return {old_count, false};
|
||||
}
|
||||
|
||||
--this->locked_count;
|
||||
return old_count;
|
||||
return {old_count, true};
|
||||
}
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
@@ -239,9 +239,34 @@ struct section
|
||||
struct semaphore : ref_counted_object
|
||||
{
|
||||
std::u16string name{};
|
||||
volatile uint32_t current_count{};
|
||||
uint32_t current_count{};
|
||||
uint32_t max_count{};
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
if (this->current_count > 0)
|
||||
{
|
||||
--this->current_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<uint32_t, bool> release(const uint32_t release_count)
|
||||
{
|
||||
const auto old_count = this->current_count;
|
||||
|
||||
if (this->current_count + release_count > this->max_count)
|
||||
{
|
||||
return {old_count, false};
|
||||
}
|
||||
|
||||
this->current_count += release_count;
|
||||
|
||||
return {old_count, true};
|
||||
}
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->name);
|
||||
|
||||
@@ -449,14 +449,14 @@ namespace
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
const auto old_count = mutant->release();
|
||||
const auto [old_count, succeeded] = mutant->release(c.proc.current_thread_id);
|
||||
|
||||
if (previous_count)
|
||||
{
|
||||
previous_count.write(static_cast<LONG>(old_count));
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return succeeded ? STATUS_SUCCESS : STATUS_MUTANT_NOT_OWNED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtCreateMutant(const syscall_context& c, const emulator_object<handle> mutant_handle,
|
||||
@@ -553,6 +553,12 @@ namespace
|
||||
const auto name =
|
||||
read_unicode_string(c.emu, reinterpret_cast<UNICODE_STRING<EmulatorTraits<Emu64>>*>(attributes.ObjectName));
|
||||
|
||||
if (name == u"\\KernelObjects\\SystemErrorPortReady")
|
||||
{
|
||||
event_handle.write(WER_PORT_READY.bits);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
for (auto& entry : c.proc.events)
|
||||
{
|
||||
if (entry.second.name == name)
|
||||
@@ -3020,6 +3026,32 @@ namespace
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtReleaseSemaphore(const syscall_context& c, const handle semaphore_handle,
|
||||
const ULONG release_count, const emulator_object<LONG> previous_count)
|
||||
{
|
||||
if (semaphore_handle.value.type != handle_types::semaphore)
|
||||
{
|
||||
c.win_emu.log.error("Bad handle type for NtReleaseSemaphore\n");
|
||||
c.emu.stop();
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
auto* mutant = c.proc.semaphores.get(semaphore_handle);
|
||||
if (!mutant)
|
||||
{
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
const auto [old_count, succeeded] = mutant->release(release_count);
|
||||
|
||||
if (previous_count)
|
||||
{
|
||||
previous_count.write(static_cast<LONG>(old_count));
|
||||
}
|
||||
|
||||
return succeeded ? STATUS_SUCCESS : STATUS_SEMAPHORE_LIMIT_EXCEEDED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, const emulator_object<handle> semaphore_handle,
|
||||
const ACCESS_MASK /*desired_access*/,
|
||||
const emulator_object<OBJECT_ATTRIBUTES<EmulatorTraits<Emu64>>> object_attributes,
|
||||
@@ -3222,8 +3254,9 @@ namespace
|
||||
|
||||
bool is_awaitable_object_type(const handle h)
|
||||
{
|
||||
return h.value.type == handle_types::thread //
|
||||
|| h.value.type == handle_types::mutant //
|
||||
return h.value.type == handle_types::thread //
|
||||
|| h.value.type == handle_types::mutant //
|
||||
|| h.value.type == handle_types::semaphore //
|
||||
|| h.value.type == handle_types::event;
|
||||
}
|
||||
|
||||
@@ -3537,6 +3570,7 @@ void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& ha
|
||||
add_handler(NtUserModifyUserStartupInfoFlags);
|
||||
add_handler(NtUserGetDCEx);
|
||||
add_handler(NtUserGetDpiForCurrentProcess);
|
||||
add_handler(NtReleaseSemaphore);
|
||||
|
||||
#undef add_handler
|
||||
}
|
||||
|
||||
@@ -634,6 +634,11 @@ namespace
|
||||
break;
|
||||
|
||||
case handle_types::event: {
|
||||
if (h.value.is_pseudo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
auto* e = c.events.get(h);
|
||||
if (e)
|
||||
{
|
||||
@@ -653,6 +658,16 @@ namespace
|
||||
break;
|
||||
}
|
||||
|
||||
case handle_types::semaphore: {
|
||||
auto* s = c.semaphores.get(h);
|
||||
if (s)
|
||||
{
|
||||
return s->try_lock();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case handle_types::thread: {
|
||||
const auto* t = c.threads.get(h);
|
||||
if (t)
|
||||
|
||||
Reference in New Issue
Block a user