[Kernel] ReleaseSemaphore for Posix to match Windows semantics

This commit is contained in:
Herman S.
2025-10-12 20:30:29 +09:00
parent 28e48410c5
commit 32b8c341ee
4 changed files with 32 additions and 13 deletions

View File

@@ -320,14 +320,15 @@ class PosixCondition<Semaphore> final : public PosixConditionBase {
bool Signal() override { return Release(1, nullptr); } bool Signal() override { return Release(1, nullptr); }
bool Release(uint32_t release_count, int* out_previous_count) { bool Release(uint32_t release_count, int* out_previous_count) {
if (maximum_count_ - count_ >= release_count) { auto lock = std::unique_lock(mutex_);
auto lock = std::unique_lock(mutex_); // Validate that releasing would not exceed the maximum count
if (out_previous_count) *out_previous_count = count_; if (count_ + release_count > maximum_count_) {
count_ += release_count; return false;
cond_.notify_all();
return true;
} }
return false; if (out_previous_count) *out_previous_count = count_;
count_ += release_count;
cond_.notify_all();
return true;
} }
private: private:

View File

@@ -718,7 +718,10 @@ uint32_t xeKeReleaseSemaphore(X_KSEMAPHORE* semaphore_ptr, uint32_t increment,
// TODO(benvanik): increment thread priority? // TODO(benvanik): increment thread priority?
// TODO(benvanik): wait? // TODO(benvanik): wait?
return sem->ReleaseSemaphore(adjustment); int32_t previous_count = 0;
[[maybe_unused]] bool success =
sem->ReleaseSemaphore(adjustment, &previous_count);
return static_cast<uint32_t>(previous_count);
} }
dword_result_t KeReleaseSemaphore_entry(pointer_t<X_KSEMAPHORE> semaphore_ptr, dword_result_t KeReleaseSemaphore_entry(pointer_t<X_KSEMAPHORE> semaphore_ptr,
@@ -777,7 +780,17 @@ dword_result_t NtReleaseSemaphore_entry(dword_t sem_handle,
auto sem = auto sem =
kernel_state()->object_table()->LookupObject<XSemaphore>(sem_handle); kernel_state()->object_table()->LookupObject<XSemaphore>(sem_handle);
if (sem) { if (sem) {
previous_count = sem->ReleaseSemaphore((int32_t)release_count); bool success =
sem->ReleaseSemaphore((int32_t)release_count, &previous_count);
if (!success) {
// Releasing would exceed the semaphore's maximum count
// Windows returns STATUS_SEMAPHORE_LIMIT_EXCEEDED (0x0000012B)
XELOGW(
"NtReleaseSemaphore: release_count={} would exceed maximum (current "
"count={})",
uint32_t(release_count), previous_count);
result = 0x0000012B;
}
} else { } else {
result = X_STATUS_INVALID_HANDLE; result = X_STATUS_INVALID_HANDLE;
} }

View File

@@ -40,10 +40,14 @@ bool XSemaphore::InitializeNative(void* native_ptr, X_DISPATCH_HEADER* header) {
return !!semaphore_; return !!semaphore_;
} }
int32_t XSemaphore::ReleaseSemaphore(int32_t release_count) { bool XSemaphore::ReleaseSemaphore(int32_t release_count,
int32_t* out_previous_count) {
int32_t previous_count = 0; int32_t previous_count = 0;
semaphore_->Release(release_count, &previous_count); bool success = semaphore_->Release(release_count, &previous_count);
return previous_count; if (out_previous_count) {
*out_previous_count = previous_count;
}
return success;
} }
bool XSemaphore::Save(ByteStream* stream) { bool XSemaphore::Save(ByteStream* stream) {

View File

@@ -29,7 +29,8 @@ class XSemaphore : public XObject {
[[nodiscard]] bool InitializeNative(void* native_ptr, [[nodiscard]] bool InitializeNative(void* native_ptr,
X_DISPATCH_HEADER* header); X_DISPATCH_HEADER* header);
int32_t ReleaseSemaphore(int32_t release_count); [[nodiscard]] bool ReleaseSemaphore(int32_t release_count,
int32_t* out_previous_count);
bool Save(ByteStream* stream) override; bool Save(ByteStream* stream) override;
static object_ref<XSemaphore> Restore(KernelState* kernel_state, static object_ref<XSemaphore> Restore(KernelState* kernel_state,