mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Support recursive mutants
This commit is contained in:
@@ -86,12 +86,45 @@ struct event : ref_counted_object
|
||||
|
||||
struct mutant : ref_counted_object
|
||||
{
|
||||
bool locked{false};
|
||||
uint32_t locked_count{0};
|
||||
uint32_t owning_thread_id{};
|
||||
std::wstring name{};
|
||||
|
||||
bool try_lock(const uint32_t thread_id)
|
||||
{
|
||||
if (this->locked_count == 0)
|
||||
{
|
||||
++this->locked_count;
|
||||
this->owning_thread_id = thread_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this->owning_thread_id != thread_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
++this->locked_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t release()
|
||||
{
|
||||
const auto old_count = this->locked_count;
|
||||
|
||||
if (this->locked_count <= 0)
|
||||
{
|
||||
return old_count;
|
||||
}
|
||||
|
||||
--this->locked_count;
|
||||
return old_count;
|
||||
}
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->locked);
|
||||
buffer.write(this->locked_count);
|
||||
buffer.write(this->owning_thread_id);
|
||||
buffer.write(this->name);
|
||||
|
||||
ref_counted_object::serialize(buffer);
|
||||
@@ -99,7 +132,8 @@ struct mutant : ref_counted_object
|
||||
|
||||
void deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read(this->locked);
|
||||
buffer.read(this->locked_count);
|
||||
buffer.read(this->owning_thread_id);
|
||||
buffer.read(this->name);
|
||||
|
||||
ref_counted_object::deserialize(buffer);
|
||||
@@ -156,7 +190,7 @@ struct section
|
||||
}
|
||||
};
|
||||
|
||||
struct semaphore
|
||||
struct semaphore : ref_counted_object
|
||||
{
|
||||
std::wstring name{};
|
||||
volatile uint32_t current_count{};
|
||||
@@ -167,6 +201,8 @@ struct semaphore
|
||||
buffer.write(this->name);
|
||||
buffer.write(this->current_count);
|
||||
buffer.write(this->max_count);
|
||||
|
||||
ref_counted_object::serialize(buffer);
|
||||
}
|
||||
|
||||
void deserialize(utils::buffer_deserializer& buffer)
|
||||
@@ -174,6 +210,8 @@ struct semaphore
|
||||
buffer.read(this->name);
|
||||
buffer.read(this->current_count);
|
||||
buffer.read(this->max_count);
|
||||
|
||||
ref_counted_object::deserialize(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -399,6 +399,32 @@ namespace
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtReleaseMutant(const syscall_context& c, const handle mutant_handle,
|
||||
const emulator_object<LONG> previous_count)
|
||||
{
|
||||
if (mutant_handle.value.type != handle_types::mutant)
|
||||
{
|
||||
c.win_emu.logger.error("Bad handle type for NtReleaseMutant\n");
|
||||
c.emu.stop();
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
auto* mutant = c.proc.mutants.get(mutant_handle);
|
||||
if (!mutant)
|
||||
{
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
const auto old_count = mutant->release();
|
||||
|
||||
if (previous_count)
|
||||
{
|
||||
previous_count.write(old_count);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtCreateMutant(const syscall_context& c, const emulator_object<handle> mutant_handle,
|
||||
const ACCESS_MASK /*desired_access*/,
|
||||
const emulator_object<OBJECT_ATTRIBUTES> object_attributes,
|
||||
@@ -426,9 +452,13 @@ namespace
|
||||
}
|
||||
|
||||
mutant e{};
|
||||
e.locked = initial_owner != FALSE;
|
||||
e.name = std::move(name);
|
||||
|
||||
if (initial_owner)
|
||||
{
|
||||
e.try_lock(c.win_emu.current_thread().id);
|
||||
}
|
||||
|
||||
const auto handle = c.proc.mutants.store(std::move(e));
|
||||
mutant_handle.write(handle);
|
||||
|
||||
@@ -2632,6 +2662,39 @@ namespace
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtOpenSemaphore(const syscall_context& c, const emulator_object<handle> semaphore_handle,
|
||||
const ACCESS_MASK /*desired_access*/,
|
||||
const emulator_object<OBJECT_ATTRIBUTES> object_attributes)
|
||||
{
|
||||
if (!object_attributes)
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const auto attributes = object_attributes.read();
|
||||
if (!attributes.ObjectName)
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const auto name = read_unicode_string(c.emu, attributes.ObjectName);
|
||||
if (name.empty())
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
for (const auto& semaphore : c.proc.semaphores)
|
||||
{
|
||||
if (semaphore.second.name == name)
|
||||
{
|
||||
semaphore_handle.write(c.proc.semaphores.make_handle(semaphore.first));
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, const emulator_object<handle> semaphore_handle,
|
||||
const ACCESS_MASK /*desired_access*/,
|
||||
const emulator_object<OBJECT_ATTRIBUTES> object_attributes,
|
||||
@@ -2650,6 +2713,17 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
if (!s.name.empty())
|
||||
{
|
||||
for (const auto& semaphore : c.proc.semaphores)
|
||||
{
|
||||
if (semaphore.second.name == s.name)
|
||||
{
|
||||
return STATUS_OBJECT_NAME_EXISTS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto handle = c.proc.semaphores.store(std::move(s));
|
||||
semaphore_handle.write(handle);
|
||||
|
||||
@@ -3014,6 +3088,7 @@ void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& ha
|
||||
add_handler(NtWriteFile);
|
||||
add_handler(NtRaiseHardError);
|
||||
add_handler(NtCreateSemaphore);
|
||||
add_handler(NtOpenSemaphore);
|
||||
add_handler(NtReadVirtualMemory);
|
||||
add_handler(NtQueryInformationToken);
|
||||
add_handler(NtDxgkIsFeatureEnabled);
|
||||
@@ -3059,6 +3134,7 @@ void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& ha
|
||||
add_handler(NtQueryAttributesFile);
|
||||
add_handler(NtWaitForMultipleObjects);
|
||||
add_handler(NtCreateMutant);
|
||||
add_handler(NtReleaseMutant);
|
||||
|
||||
#undef add_handler
|
||||
}
|
||||
|
||||
@@ -519,7 +519,7 @@ namespace
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_object_signaled(process_context& c, const handle h)
|
||||
bool is_object_signaled(process_context& c, const handle h, uint32_t current_thread_id)
|
||||
{
|
||||
const auto type = h.value.type;
|
||||
|
||||
@@ -544,13 +544,7 @@ namespace
|
||||
auto* e = c.mutants.get(h);
|
||||
if (e)
|
||||
{
|
||||
if (e->locked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
e->locked = true;
|
||||
return true;
|
||||
return e->try_lock(current_thread_id);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -649,7 +643,7 @@ bool emulator_thread::is_thread_ready(windows_emulator& win_emu)
|
||||
{
|
||||
const auto& obj = this->await_objects[i];
|
||||
|
||||
const auto signaled = is_object_signaled(win_emu.process(), obj);
|
||||
const auto signaled = is_object_signaled(win_emu.process(), obj, this->id);
|
||||
all_signaled &= signaled;
|
||||
|
||||
if (signaled && this->await_any)
|
||||
|
||||
Reference in New Issue
Block a user