#include "common.h" #include "errors.h" #include "handles.h" #include "internal.h" #include "kernel32.h" #include "processes.h" #include "strutil.h" #include #include #include #include #include #include #include #include namespace { std::u16string makeMutexName(LPCWSTR name) { if (!name) { return {}; } size_t len = wstrlen(reinterpret_cast(name)); return {reinterpret_cast(name), len}; } void makeWideNameFromAnsi(LPCSTR ansiName, std::vector &outWide) { outWide.clear(); if (!ansiName) { return; } outWide = stringToWideString(ansiName); } } // namespace namespace kernel32 { namespace { std::mutex mutexRegistryLock; std::unordered_map namedMutexes; std::mutex eventRegistryLock; std::unordered_map namedEvents; std::mutex semaphoreRegistryLock; std::unordered_map namedSemaphores; EventObject *eventObjectFromHandle(HANDLE hEvent) { auto data = handles::dataFromHandle(hEvent, false); if (data.type != handles::TYPE_EVENT || data.ptr == nullptr) { return nullptr; } return reinterpret_cast(data.ptr); } SemaphoreObject *semaphoreObjectFromHandle(HANDLE hSemaphore) { auto data = handles::dataFromHandle(hSemaphore, false); if (data.type != handles::TYPE_SEMAPHORE || data.ptr == nullptr) { return nullptr; } return reinterpret_cast(data.ptr); } MutexObject *mutexObjectFromHandle(HANDLE hMutex) { auto data = handles::dataFromHandle(hMutex, false); if (data.type != handles::TYPE_MUTEX || data.ptr == nullptr) { return nullptr; } return reinterpret_cast(data.ptr); } bool setEventSignaledState(HANDLE hEvent, bool signaled) { EventObject *obj = eventObjectFromHandle(hEvent); if (!obj) { return false; } pthread_mutex_lock(&obj->mutex); obj->signaled = signaled; if (signaled) { if (obj->manualReset) { pthread_cond_broadcast(&obj->cond); } else { pthread_cond_signal(&obj->cond); } } pthread_mutex_unlock(&obj->mutex); return true; } } // namespace void releaseMutexObject(MutexObject *obj) { if (!obj) { return; } std::lock_guard lock(mutexRegistryLock); obj->refCount--; if (obj->refCount == 0) { if (!obj->name.empty()) { namedMutexes.erase(obj->name); } pthread_mutex_destroy(&obj->mutex); delete obj; } } void releaseEventObject(EventObject *obj) { if (!obj) { return; } std::lock_guard lock(eventRegistryLock); obj->refCount--; if (obj->refCount == 0) { if (!obj->name.empty()) { namedEvents.erase(obj->name); } pthread_cond_destroy(&obj->cond); pthread_mutex_destroy(&obj->mutex); delete obj; } } void releaseSemaphoreObject(SemaphoreObject *obj) { if (!obj) { return; } std::lock_guard lock(semaphoreRegistryLock); obj->refCount--; if (obj->refCount == 0) { if (!obj->name.empty()) { namedSemaphores.erase(obj->name); } pthread_cond_destroy(&obj->cond); pthread_mutex_destroy(&obj->mutex); delete obj; } } HANDLE WIN_FUNC CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName) { std::string nameLog; if (lpName) { nameLog = wideStringToString(reinterpret_cast(lpName)); } else { nameLog = ""; } DEBUG_LOG("CreateMutexW(%p, %d, %s)\n", lpMutexAttributes, bInitialOwner, nameLog.c_str()); (void)lpMutexAttributes; std::u16string name = makeMutexName(lpName); MutexObject *obj = nullptr; bool alreadyExists = false; { std::lock_guard lock(mutexRegistryLock); if (!name.empty()) { auto it = namedMutexes.find(name); if (it != namedMutexes.end()) { obj = it->second; obj->refCount++; alreadyExists = true; } } if (!obj) { obj = new MutexObject(); pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&obj->mutex, &attr); pthread_mutexattr_destroy(&attr); obj->name = name; if (!name.empty()) { namedMutexes[name] = obj; } } } if (!alreadyExists && bInitialOwner) { pthread_mutex_lock(&obj->mutex); obj->owner = pthread_self(); obj->ownerValid = true; obj->recursionCount = 1; } HANDLE handle = handles::allocDataHandle({handles::TYPE_MUTEX, obj, 0}); wibo::lastError = alreadyExists ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS; return handle; } HANDLE WIN_FUNC CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName) { DEBUG_LOG("CreateMutexA -> "); std::vector wideName; makeWideNameFromAnsi(lpName, wideName); return CreateMutexW(lpMutexAttributes, bInitialOwner, lpName ? reinterpret_cast(wideName.data()) : nullptr); } BOOL WIN_FUNC ReleaseMutex(HANDLE hMutex) { DEBUG_LOG("ReleaseMutex(%p)\n", hMutex); MutexObject *obj = mutexObjectFromHandle(hMutex); if (!obj) { wibo::lastError = ERROR_INVALID_HANDLE; return FALSE; } pthread_t self = pthread_self(); pthread_mutex_lock(&obj->mutex); if (!obj->ownerValid || !pthread_equal(obj->owner, self) || obj->recursionCount == 0) { pthread_mutex_unlock(&obj->mutex); wibo::lastError = ERROR_NOT_OWNER; return FALSE; } obj->recursionCount--; if (obj->recursionCount == 0) { obj->ownerValid = false; } pthread_mutex_unlock(&obj->mutex); wibo::lastError = ERROR_SUCCESS; return TRUE; } HANDLE WIN_FUNC CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName) { std::string nameLog; if (lpName) { nameLog = wideStringToString(reinterpret_cast(lpName)); } else { nameLog = ""; } DEBUG_LOG("CreateEventW(name=%s, manualReset=%d, initialState=%d)\n", nameLog.c_str(), bManualReset, bInitialState); (void)lpEventAttributes; std::u16string name = makeMutexName(lpName); EventObject *obj = nullptr; bool alreadyExists = false; { std::lock_guard lock(eventRegistryLock); if (!name.empty()) { auto it = namedEvents.find(name); if (it != namedEvents.end()) { obj = it->second; obj->refCount++; alreadyExists = true; } } if (!obj) { obj = new EventObject(); pthread_mutex_init(&obj->mutex, nullptr); pthread_cond_init(&obj->cond, nullptr); obj->manualReset = bManualReset; obj->signaled = bInitialState; obj->name = name; if (!name.empty()) { namedEvents[name] = obj; } } } HANDLE handle = handles::allocDataHandle({handles::TYPE_EVENT, obj, 0}); wibo::lastError = alreadyExists ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS; return handle; } HANDLE WIN_FUNC CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName) { DEBUG_LOG("CreateEventA -> "); std::vector wideName; makeWideNameFromAnsi(lpName, wideName); return CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName ? reinterpret_cast(wideName.data()) : nullptr); } HANDLE WIN_FUNC CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName) { DEBUG_LOG("CreateSemaphoreW(%p, %ld, %ld, %ls)\n", lpSemaphoreAttributes, static_cast(lInitialCount), static_cast(lMaximumCount), lpName ? reinterpret_cast(lpName) : L""); (void)lpSemaphoreAttributes; std::u16string name = makeMutexName(lpName); SemaphoreObject *obj = nullptr; bool alreadyExists = false; { std::lock_guard lock(semaphoreRegistryLock); if (!name.empty()) { auto it = namedSemaphores.find(name); if (it != namedSemaphores.end()) { obj = it->second; obj->refCount++; alreadyExists = true; } } if (!obj) { if (lMaximumCount <= 0 || lInitialCount < 0 || lInitialCount > lMaximumCount) { wibo::lastError = ERROR_INVALID_PARAMETER; return nullptr; } obj = new SemaphoreObject(); pthread_mutex_init(&obj->mutex, nullptr); pthread_cond_init(&obj->cond, nullptr); obj->count = lInitialCount; obj->maxCount = lMaximumCount; obj->name = name; if (!name.empty()) { namedSemaphores[name] = obj; } } } HANDLE handle = handles::allocDataHandle({handles::TYPE_SEMAPHORE, obj, 0}); wibo::lastError = alreadyExists ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS; return handle; } HANDLE WIN_FUNC CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCSTR lpName) { DEBUG_LOG("CreateSemaphoreA -> "); std::vector wideName; makeWideNameFromAnsi(lpName, wideName); return CreateSemaphoreW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName ? reinterpret_cast(wideName.data()) : nullptr); } BOOL WIN_FUNC ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, PLONG lpPreviousCount) { DEBUG_LOG("ReleaseSemaphore(%p, %ld, %p)\n", hSemaphore, static_cast(lReleaseCount), lpPreviousCount); if (lReleaseCount <= 0) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } SemaphoreObject *obj = semaphoreObjectFromHandle(hSemaphore); if (!obj) { wibo::lastError = ERROR_INVALID_HANDLE; return FALSE; } pthread_mutex_lock(&obj->mutex); if (lpPreviousCount) { *lpPreviousCount = obj->count; } if (lReleaseCount > obj->maxCount - obj->count) { pthread_mutex_unlock(&obj->mutex); wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } obj->count += lReleaseCount; pthread_mutex_unlock(&obj->mutex); pthread_cond_broadcast(&obj->cond); wibo::lastError = ERROR_SUCCESS; return TRUE; } BOOL WIN_FUNC SetEvent(HANDLE hEvent) { DEBUG_LOG("SetEvent(%p)\n", hEvent); if (!setEventSignaledState(hEvent, true)) { wibo::lastError = ERROR_INVALID_HANDLE; return FALSE; } wibo::lastError = ERROR_SUCCESS; return TRUE; } BOOL WIN_FUNC ResetEvent(HANDLE hEvent) { DEBUG_LOG("ResetEvent(%p)\n", hEvent); if (!setEventSignaledState(hEvent, false)) { wibo::lastError = ERROR_INVALID_HANDLE; return FALSE; } wibo::lastError = ERROR_SUCCESS; return TRUE; } DWORD WIN_FUNC WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { DEBUG_LOG("WaitForSingleObject(%p, %u)\n", hHandle, dwMilliseconds); handles::Data data = handles::dataFromHandle(hHandle, false); switch (data.type) { case handles::TYPE_PROCESS: { if (dwMilliseconds != INFINITE) { DEBUG_LOG("WaitForSingleObject: timeout for process not supported\n"); wibo::lastError = ERROR_NOT_SUPPORTED; return WAIT_FAILED; } auto *process = reinterpret_cast(data.ptr); int status = 0; for (;;) { if (waitpid(process->pid, &status, 0) == -1) { if (errno == EINTR) { continue; } if (errno == ECHILD && process->terminationRequested) { process->exitCode = process->forcedExitCode; break; } DEBUG_LOG("WaitForSingleObject: waitpid(%d) failed: %s\n", process->pid, strerror(errno)); wibo::lastError = ERROR_INVALID_HANDLE; return WAIT_FAILED; } break; } if (process->terminationRequested) { process->exitCode = process->forcedExitCode; } else if (WIFEXITED(status)) { process->exitCode = static_cast(WEXITSTATUS(status)); } else { DEBUG_LOG("WaitForSingleObject: child process exited abnormally - returning exit code 1\n"); process->exitCode = 1; } process->terminationRequested = false; wibo::lastError = ERROR_SUCCESS; return WAIT_OBJECT_0; } case handles::TYPE_EVENT: { EventObject *obj = reinterpret_cast(data.ptr); if (dwMilliseconds != INFINITE) { DEBUG_LOG("WaitForSingleObject: timeout for event not supported\n"); wibo::lastError = ERROR_NOT_SUPPORTED; return WAIT_FAILED; } pthread_mutex_lock(&obj->mutex); while (!obj->signaled) { pthread_cond_wait(&obj->cond, &obj->mutex); } if (!obj->manualReset) { obj->signaled = false; } pthread_mutex_unlock(&obj->mutex); wibo::lastError = ERROR_SUCCESS; return WAIT_OBJECT_0; } case handles::TYPE_THREAD: { ThreadObject *obj = reinterpret_cast(data.ptr); if (dwMilliseconds != INFINITE) { DEBUG_LOG("WaitForSingleObject: timeout for thread not supported\n"); wibo::lastError = ERROR_NOT_SUPPORTED; return WAIT_FAILED; } pthread_mutex_lock(&obj->mutex); while (!obj->finished) { pthread_cond_wait(&obj->cond, &obj->mutex); } bool needJoin = !obj->joined && !obj->detached; pthread_t thread = obj->thread; if (needJoin) { obj->joined = true; } pthread_mutex_unlock(&obj->mutex); if (needJoin) { pthread_join(thread, nullptr); } wibo::lastError = ERROR_SUCCESS; return WAIT_OBJECT_0; } case handles::TYPE_SEMAPHORE: { SemaphoreObject *obj = reinterpret_cast(data.ptr); if (dwMilliseconds != INFINITE) { DEBUG_LOG("WaitForSingleObject: timeout for semaphore not supported\n"); wibo::lastError = ERROR_NOT_SUPPORTED; return WAIT_FAILED; } pthread_mutex_lock(&obj->mutex); while (obj->count == 0) { pthread_cond_wait(&obj->cond, &obj->mutex); } obj->count--; pthread_mutex_unlock(&obj->mutex); wibo::lastError = ERROR_SUCCESS; return WAIT_OBJECT_0; } case handles::TYPE_MUTEX: { MutexObject *obj = reinterpret_cast(data.ptr); if (dwMilliseconds != INFINITE) { DEBUG_LOG("WaitForSingleObject: timeout for mutex not supported\n"); wibo::lastError = ERROR_NOT_SUPPORTED; return WAIT_FAILED; } pthread_mutex_lock(&obj->mutex); pthread_t self = pthread_self(); if (obj->ownerValid && pthread_equal(obj->owner, self)) { obj->recursionCount++; } else { obj->owner = self; obj->ownerValid = true; obj->recursionCount = 1; } wibo::lastError = ERROR_SUCCESS; return WAIT_OBJECT_0; } default: DEBUG_LOG("WaitForSingleObject: unsupported handle type %d\n", data.type); wibo::lastError = ERROR_INVALID_HANDLE; return WAIT_FAILED; } } void resetOverlappedEvent(OVERLAPPED *ov) { if (!ov || !ov->hEvent) { return; } setEventSignaledState(ov->hEvent, false); } void signalOverlappedEvent(OVERLAPPED *ov) { if (!ov || !ov->hEvent) { return; } setEventSignaledState(ov->hEvent, true); } } // namespace kernel32