aboutsummaryrefslogtreecommitdiff
path: root/zencore/thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zencore/thread.cpp')
-rw-r--r--zencore/thread.cpp599
1 files changed, 559 insertions, 40 deletions
diff --git a/zencore/thread.cpp b/zencore/thread.cpp
index da711fe89..14fb0ed65 100644
--- a/zencore/thread.cpp
+++ b/zencore/thread.cpp
@@ -3,11 +3,25 @@
#include <zencore/thread.h>
#include <zencore/except.h>
+#include <zencore/scopeguard.h>
#include <zencore/string.h>
+#include <zencore/testing.h>
#if ZEN_PLATFORM_WINDOWS
+# include <shellapi.h>
+# include <Shlobj.h>
# include <zencore/windows.h>
#elif ZEN_PLATFORM_LINUX
+# include <chrono>
+# include <condition_variable>
+# include <mutex>
+
+# include <poll.h>
+# include <pthread.h>
+# include <signal.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# include <time.h>
# include <unistd.h>
#endif
@@ -69,6 +83,8 @@ SetCurrentThreadName([[maybe_unused]] std::string_view ThreadName)
std::string ThreadNameZ{ThreadName};
SetNameInternal(GetCurrentThreadId(), ThreadNameZ.c_str());
#else
+ std::string ThreadNameZ{ThreadName};
+ pthread_setname_np(pthread_self(), ThreadNameZ.c_str());
#endif
} // namespace zen
@@ -98,40 +114,80 @@ RwLock::ReleaseExclusive()
//////////////////////////////////////////////////////////////////////////
-#if ZEN_PLATFORM_WINDOWS
+#if !ZEN_PLATFORM_WINDOWS
+struct EventInner
+{
+ std::mutex Mutex;
+ std::condition_variable CondVar;
+ bool volatile bSet = false;
+};
+#endif // !ZEN_PLATFORM_WINDOWS
Event::Event()
{
- m_EventHandle = CreateEvent(nullptr, true, false, nullptr);
+ bool bManualReset = true;
+ bool bInitialState = false;
+
+#if ZEN_PLATFORM_WINDOWS
+ m_EventHandle = CreateEvent(nullptr, bManualReset, bInitialState, nullptr);
+#else
+ ZEN_UNUSED(bManualReset);
+ auto* Inner = new EventInner();
+ Inner->bSet = bInitialState;
+ m_EventHandle = Inner;
+#endif
}
Event::~Event()
{
- CloseHandle(m_EventHandle);
+ Close();
}
void
Event::Set()
{
+#if ZEN_PLATFORM_WINDOWS
SetEvent(m_EventHandle);
+#else
+ auto* Inner = (EventInner*)m_EventHandle;
+ {
+ std::unique_lock Lock(Inner->Mutex);
+ Inner->bSet = true;
+ }
+ Inner->CondVar.notify_all();
+#endif
}
void
Event::Reset()
{
+#if ZEN_PLATFORM_WINDOWS
ResetEvent(m_EventHandle);
+#else
+ auto* Inner = (EventInner*)m_EventHandle;
+ {
+ std::unique_lock Lock(Inner->Mutex);
+ Inner->bSet = false;
+ }
+#endif
}
void
Event::Close()
{
+#if ZEN_PLATFORM_WINDOWS
CloseHandle(m_EventHandle);
+#else
+ auto* Inner = (EventInner*)m_EventHandle;
+ delete Inner;
+#endif
m_EventHandle = nullptr;
}
bool
Event::Wait(int TimeoutMs)
{
+#if ZEN_PLATFORM_WINDOWS
using namespace std::literals;
const DWORD Timeout = (TimeoutMs < 0) ? INFINITE : TimeoutMs;
@@ -144,12 +200,50 @@ Event::Wait(int TimeoutMs)
}
return (Result == WAIT_OBJECT_0);
+#else
+ auto* Inner = (EventInner*)m_EventHandle;
+
+ if (TimeoutMs >= 0)
+ {
+ std::unique_lock Lock(Inner->Mutex);
+
+ if (Inner->bSet)
+ {
+ return true;
+ }
+
+ return Inner->CondVar.wait_for(
+ Lock,
+ std::chrono::milliseconds(TimeoutMs),
+ [&] { return Inner->bSet; }
+ );
+ }
+
+ std::unique_lock Lock(Inner->Mutex);
+
+ if (!Inner->bSet)
+ {
+ Inner->CondVar.wait(Lock, [&] { return Inner->bSet; });
+ }
+
+ return true;
+#endif
}
//////////////////////////////////////////////////////////////////////////
-NamedEvent::NamedEvent(std::u8string_view EventName) : Event(nullptr)
+#if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MACOS
+struct NamedEventPosix
{
+ int SocketFd = 0;
+ sockaddr_un SocketAddr = {};
+ bool bBound = false;
+};
+#endif
+
+NamedEvent::NamedEvent(std::string_view EventName)
+{
+#if ZEN_PLATFORM_WINDOWS
using namespace std::literals;
ExtendableStringBuilder<64> Name;
@@ -157,30 +251,131 @@ NamedEvent::NamedEvent(std::u8string_view EventName) : Event(nullptr)
Name << EventName;
m_EventHandle = CreateEventA(nullptr, true, false, Name.c_str());
+#else
+ int SocketFd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (SocketFd < 0)
+ {
+ ThrowLastError("Failed to create IPC socket");
+ }
+
+ auto* Inner = new NamedEventPosix();
+ Inner->SocketFd = SocketFd;
+
+ char* PathPtr = Inner->SocketAddr.sun_path;
+ size_t PathLen = sizeof(Inner->SocketAddr.sun_path) - 1; // -1 for null-term
+# if ZEN_PLATFORM_LINUX
+ PathPtr[0] = '\0'; // make the domain socket...
+ PathPtr += 1; // ...use the abstract namespace
+ PathLen -= 1;
+# endif
+ EventName.copy(PathPtr, PathLen);
+
+ m_EventHandle = Inner;
+#endif
}
-NamedEvent::NamedEvent(std::string_view EventName) : Event(nullptr)
+NamedEvent::~NamedEvent()
{
- using namespace std::literals;
+ Close();
+}
- ExtendableStringBuilder<64> Name;
- Name << "Local\\"sv;
- Name << EventName;
+void NamedEvent::Close()
+{
+ if (m_EventHandle == nullptr)
+ {
+ return;
+ }
- m_EventHandle = CreateEventA(nullptr, true, false, Name.c_str());
+#if ZEN_PLATFORM_WINDOWS
+ CloseHandle(m_EventHandle);
+#else
+ auto* Inner = (NamedEventPosix*)m_EventHandle;
+ close(Inner->SocketFd);
+ delete Inner;
+#endif
+
+ m_EventHandle = nullptr;
}
+
+void NamedEvent::Set()
+{
+#if ZEN_PLATFORM_WINDOWS
+ SetEvent(m_EventHandle);
+#else
+ auto* Inner = (NamedEventPosix*)m_EventHandle;
+
+ uint8_t OneByte = 0x49;
+ sendto(
+ Inner->SocketFd,
+ &OneByte, sizeof(OneByte),
+ 0, (sockaddr*)&Inner->SocketAddr, sizeof(Inner->SocketAddr)
+ );
+#endif
+}
+
+bool NamedEvent::Wait(int TimeoutMs)
+{
+#if ZEN_PLATFORM_WINDOWS
+ const DWORD Timeout = (TimeoutMs < 0) ? INFINITE : TimeoutMs;
+
+ DWORD Result = WaitForSingleObject(m_EventHandle, Timeout);
+
+ if (Result == WAIT_FAILED)
+ {
+ using namespace std::literals;
+ zen::ThrowLastError("Event wait failed"sv);
+ }
+
+ return (Result == WAIT_OBJECT_0);
+#else
+ auto* Inner = (NamedEventPosix*)m_EventHandle;
+ int SocketFd = Inner->SocketFd;
+
+ int Result;
+
+ if (!Inner->bBound)
+ {
+ Result = bind(SocketFd, (sockaddr*)&(Inner->SocketAddr), sizeof(Inner->SocketAddr));
+ if (!Result)
+ {
+ zen::ThrowLastError("Bind IPC socket failed");
+ }
+ Inner->bBound = true;
+ }
+
+ pollfd PollFd = { SocketFd, POLLIN };
+ Result = poll(&PollFd, 1, TimeoutMs);
+ if (Result > 0)
+ {
+ uint8_t OneByte;
+ Result = recv(SocketFd, &OneByte, sizeof(OneByte), 0);
+
+ return true;
+ }
+
+ return false;
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////
+
NamedMutex::~NamedMutex()
{
+#if ZEN_PLATFORM_WINDOWS
if (m_MutexHandle)
{
CloseHandle(m_MutexHandle);
}
+#else
+ /* ZEN_TODO_MR: NamedMutex */
+#endif
}
bool
NamedMutex::Create(std::string_view MutexName)
{
+#if ZEN_PLATFORM_WINDOWS
ZEN_ASSERT(m_MutexHandle == nullptr);
using namespace std::literals;
@@ -192,11 +387,17 @@ NamedMutex::Create(std::string_view MutexName)
m_MutexHandle = CreateMutexA(nullptr, /* InitialOwner */ TRUE, Name.c_str());
return !!m_MutexHandle;
+#else
+ ZEN_UNUSED(MutexName);
+ /* ZEN_TODO_MR: NamedMutex */
+ return true;
+#endif // ZEN_PLATFORM_WINDOWS
}
bool
NamedMutex::Exists(std::string_view MutexName)
{
+#if ZEN_PLATFORM_WINDOWS
using namespace std::literals;
ExtendableStringBuilder<64> Name;
@@ -213,24 +414,33 @@ NamedMutex::Exists(std::string_view MutexName)
CloseHandle(MutexHandle);
return true;
+#else
+ ZEN_UNUSED(MutexName);
+ /* ZEN_TODO_MR: NamedMutex */
+ return false;
+#endif // ZEN_PLATFORM_WINDOWS
}
-#endif // ZEN_PLATFORM_WINDOWS
-
-#if ZEN_PLATFORM_WINDOWS
-
//////////////////////////////////////////////////////////////////////////
ProcessHandle::ProcessHandle() = default;
+#if ZEN_PLATFORM_WINDOWS
void
ProcessHandle::Initialize(void* ProcessHandle)
{
ZEN_ASSERT(m_ProcessHandle == nullptr);
+
+ if (ProcessHandle == INVALID_HANDLE_VALUE)
+ {
+ ProcessHandle = nullptr;
+ }
+
// TODO: perform some debug verification here to verify it's a valid handle?
m_ProcessHandle = ProcessHandle;
m_Pid = GetProcessId(m_ProcessHandle);
}
+#endif // ZEN_PLATFORM_WINDOWS
ProcessHandle::~ProcessHandle()
{
@@ -241,12 +451,21 @@ void
ProcessHandle::Initialize(int Pid)
{
ZEN_ASSERT(m_ProcessHandle == nullptr);
- m_ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, Pid);
- using namespace fmt::literals;
+#if ZEN_PLATFORM_WINDOWS
+ m_ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, Pid);
+#elif ZEN_PLATFORM_LINUX
+ if (Pid > 0)
+ {
+ m_ProcessHandle = (void*)(intptr_t(Pid));
+ }
+#else
+# error Check process control on this platform
+#endif
if (!m_ProcessHandle)
{
+ using namespace fmt::literals;
ThrowLastError("ProcessHandle::Initialize(pid: {}) failed"_format(Pid));
}
@@ -256,29 +475,51 @@ ProcessHandle::Initialize(int Pid)
bool
ProcessHandle::IsRunning() const
{
+ bool bActive = false;
+
+#if ZEN_PLATFORM_WINDOWS
DWORD ExitCode = 0;
GetExitCodeProcess(m_ProcessHandle, &ExitCode);
+ bActive = (ExitCode == STILL_ACTIVE);
+#elif ZEN_PLATFORM_LINUX
+ StringBuilder<64> ProcPath;
+ ProcPath << "/proc/" << m_Pid;
+ bActive = (access(ProcPath.c_str(), F_OK) != 0);
+#else
+# error Check process control on this platform
+#endif
- return ExitCode == STILL_ACTIVE;
+ return bActive;
}
bool
ProcessHandle::IsValid() const
{
- return (m_ProcessHandle != nullptr) && (m_ProcessHandle != INVALID_HANDLE_VALUE);
+ return (m_ProcessHandle != nullptr);
}
void
ProcessHandle::Terminate(int ExitCode)
{
- if (IsRunning())
+ if (!IsRunning())
{
- TerminateProcess(m_ProcessHandle, ExitCode);
+ return;
}
+ bool bSuccess = false;
+
+#if ZEN_PLATFORM_WINDOWS
+ TerminateProcess(m_ProcessHandle, ExitCode);
DWORD WaitResult = WaitForSingleObject(m_ProcessHandle, INFINITE);
+ bSuccess = (WaitResult != WAIT_OBJECT_0);
+#elif ZEN_PLATFORM_LINUX
+ ZEN_UNUSED(ExitCode);
+ bSuccess = (kill(m_Pid, SIGKILL) == 0);
+#else
+# error Check kill() on this platform
+#endif
- if (WaitResult != WAIT_OBJECT_0)
+ if (!bSuccess)
{
// What might go wrong here, and what is meaningful to act on?
}
@@ -289,14 +530,20 @@ ProcessHandle::Reset()
{
if (IsValid())
{
+#if ZEN_PLATFORM_WINDOWS
CloseHandle(m_ProcessHandle);
+#endif
m_ProcessHandle = nullptr;
+ m_Pid = 0;
}
}
bool
ProcessHandle::Wait(int TimeoutMs)
{
+ using namespace std::literals;
+
+#if ZEN_PLATFORM_WINDOWS
const DWORD Timeout = (TimeoutMs < 0) ? INFINITE : TimeoutMs;
const DWORD WaitResult = WaitForSingleObject(m_ProcessHandle, Timeout);
@@ -310,19 +557,252 @@ ProcessHandle::Wait(int TimeoutMs)
return false;
case WAIT_FAILED:
- // What might go wrong here, and what is meaningful to act on?
- using namespace std::literals;
- ThrowLastError("Process::Wait failed"sv);
+ break;
}
+#elif ZEN_PLATFORM_LINUX
+ const int SleepMs = 20;
+ timespec SleepTime = { 0, SleepMs * 1000 * 1000 };
+ for (int i = 0; ; i += SleepMs)
+ {
+ if (i >= TimeoutMs)
+ {
+ return false;
+ }
- return false;
-}
+ if (kill(m_Pid, 0) < 0)
+ {
+ if (zen::GetLastError() == ESRCH)
+ {
+ return true;
+ }
+ break;
+ }
-#endif // ZEN_PLATFORM_WINDOWS
+ nanosleep(&SleepTime, nullptr);
+ }
+#else
+# error Check kill() on this platform
+#endif
+
+ // What might go wrong here, and what is meaningful to act on?
+ ThrowLastError("Process::Wait failed"sv);
+}
//////////////////////////////////////////////////////////////////////////
#if ZEN_PLATFORM_WINDOWS
+static CreateProcResult CreateProcNormal(
+ const std::filesystem::path& Executable,
+ std::string_view CommandLine,
+ const CreateProcOptions& Options)
+{
+ PROCESS_INFORMATION ProcessInfo{};
+ STARTUPINFO StartupInfo{.cb = sizeof(STARTUPINFO)};
+
+ const bool InheritHandles = false;
+ void* Environment = nullptr;
+ LPSECURITY_ATTRIBUTES ProcessAttributes = nullptr;
+ LPSECURITY_ATTRIBUTES ThreadAttributes = nullptr;
+
+ DWORD CreationFlags = 0;
+ if (Options.Flags & CreateProcOptions::Flag_NewConsole)
+ {
+ CreationFlags |= CREATE_NEW_CONSOLE;
+ }
+
+ const wchar_t* WorkingDir = nullptr;
+ if (Options.WorkingDirectory != nullptr)
+ {
+ WorkingDir = Options.WorkingDirectory->c_str();
+ }
+
+ ExtendableWideStringBuilder<256> CommandLineZ;
+ CommandLineZ << CommandLine;
+
+ BOOL Success = CreateProcessW(Executable.c_str(),
+ CommandLineZ.Data(),
+ ProcessAttributes,
+ ThreadAttributes,
+ InheritHandles,
+ CreationFlags,
+ Environment,
+ WorkingDir,
+ &StartupInfo,
+ &ProcessInfo);
+
+ if (!Success)
+ {
+ return nullptr;
+ }
+
+ CloseHandle(ProcessInfo.hThread);
+ return ProcessInfo.hProcess;
+}
+
+static CreateProcResult CreateProcUnelevated(
+ const std::filesystem::path& Executable,
+ std::string_view CommandLine,
+ const CreateProcOptions& Options)
+{
+ /* Launches a binary with the shell as its parent. The shell (such as
+ Explorer) should be an unelevated process. */
+
+ // No sense in using this route if we are not elevated in the first place
+ if (IsUserAnAdmin() == FALSE)
+ {
+ return CreateProcNormal(Executable, CommandLine, Options);
+ }
+
+ // Get the users' shell process and open it for process creation
+ HWND ShellWnd = GetShellWindow();
+ if (ShellWnd == nullptr)
+ {
+ return nullptr;
+ }
+
+ DWORD ShellPid;
+ GetWindowThreadProcessId(ShellWnd, &ShellPid);
+
+ HANDLE Process = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, ShellPid);
+ if (Process == nullptr)
+ {
+ return nullptr;
+ }
+ auto $0 = MakeGuard([&] { CloseHandle(Process); });
+
+ // Creating a process as a child of another process is done by setting a
+ // thread-attribute list on the startup info passed to CreateProcess()
+ SIZE_T AttrListSize;
+ InitializeProcThreadAttributeList(nullptr, 1, 0, &AttrListSize);
+
+ auto AttrList = (PPROC_THREAD_ATTRIBUTE_LIST)malloc(AttrListSize);
+ auto $1 = MakeGuard([&] { free(AttrList); });
+
+ if (!InitializeProcThreadAttributeList(AttrList, 1, 0, &AttrListSize))
+ {
+ return nullptr;
+ }
+
+ BOOL bOk = UpdateProcThreadAttribute(AttrList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
+ (HANDLE*)&Process, sizeof(Process), nullptr, nullptr);
+ if (!bOk)
+ {
+ return nullptr;
+ }
+
+ // By this point we know we are an elevated process. It is not allowed to
+ // create a process as a child of another unelevated process that share our
+ // elevated console window if we have one. So we'll need to create a new one.
+ uint32_t CreateProcFlags = EXTENDED_STARTUPINFO_PRESENT;
+ if (GetConsoleWindow() != nullptr)
+ {
+ CreateProcFlags |= CREATE_NEW_CONSOLE;
+ }
+ else
+ {
+ CreateProcFlags |= DETACHED_PROCESS;
+ }
+
+ // Everything is set up now so we can proceed and launch the process
+ STARTUPINFOEXW StartupInfo = {
+ .StartupInfo = { .cb = sizeof(STARTUPINFOEXW) },
+ .lpAttributeList = AttrList,
+ };
+ PROCESS_INFORMATION ProcessInfo = {};
+
+ if (Options.Flags & CreateProcOptions::Flag_NewConsole)
+ {
+ CreateProcFlags |= CREATE_NEW_CONSOLE;
+ }
+
+ ExtendableWideStringBuilder<256> CommandLineZ;
+ CommandLineZ << CommandLine;
+
+ bOk = CreateProcessW(Executable.c_str(), CommandLineZ.Data(), nullptr, nullptr,
+ FALSE, CreateProcFlags, nullptr, nullptr, &StartupInfo.StartupInfo,
+ &ProcessInfo);
+ if (bOk == FALSE)
+ {
+ return nullptr;
+ }
+
+ CloseHandle(ProcessInfo.hThread);
+ return ProcessInfo.hProcess;
+}
+
+static CreateProcResult CreateProcElevated(
+ const std::filesystem::path& Executable,
+ std::string_view CommandLine,
+ const CreateProcOptions& Options)
+{
+ ExtendableWideStringBuilder<256> CommandLineZ;
+ CommandLineZ << CommandLine;
+
+ SHELLEXECUTEINFO ShellExecuteInfo;
+ ZeroMemory(&ShellExecuteInfo, sizeof(ShellExecuteInfo));
+ ShellExecuteInfo.cbSize = sizeof(ShellExecuteInfo);
+ ShellExecuteInfo.fMask = SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS;
+ ShellExecuteInfo.lpFile = Executable.c_str();
+ ShellExecuteInfo.lpVerb = TEXT("runas");
+ ShellExecuteInfo.nShow = SW_SHOW;
+ ShellExecuteInfo.lpParameters = CommandLineZ.c_str();
+
+ if (Options.WorkingDirectory != nullptr)
+ {
+ ShellExecuteInfo.lpDirectory = Options.WorkingDirectory->c_str();
+ }
+
+ if (::ShellExecuteEx(&ShellExecuteInfo))
+ {
+ return ShellExecuteInfo.hProcess;
+ }
+
+ return nullptr;
+}
+#endif // ZEN_PLATFORM_WINDOWS
+
+CreateProcResult CreateProc(
+ const std::filesystem::path& Executable,
+ std::string_view CommandLine,
+ const CreateProcOptions& Options)
+{
+#if ZEN_PLATFORM_WINDOWS
+ if (Options.Flags & CreateProcOptions::Flag_Unelevated)
+ {
+ return CreateProcUnelevated(Executable, CommandLine, Options);
+ }
+
+ if (Options.Flags & CreateProcOptions::Flag_Elevated)
+ {
+ return CreateProcElevated(Executable, CommandLine, Options);
+ }
+
+ return CreateProcNormal(Executable, CommandLine, Options);
+#else
+ int ChildPid = fork();
+ if (ChildPid < 0)
+ {
+ ThrowLastError("Failed to fork a new child process");
+ }
+ else if (ChildPid == 0)
+ {
+ if (Options.WorkingDirectory != nullptr)
+ {
+ chdir(Options.WorkingDirectory->c_str());
+ }
+
+ std::string CommandLineZ(CommandLine);
+ if (execl(Executable.c_str(), CommandLineZ.c_str(), nullptr) < 0)
+ {
+ ThrowLastError("Failed to exec() a new process image");
+ }
+ }
+
+ return ChildPid;
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////
ProcessMonitor::ProcessMonitor()
{
@@ -332,9 +812,11 @@ ProcessMonitor::~ProcessMonitor()
{
RwLock::ExclusiveLockScope _(m_Lock);
- for (HANDLE& Proc : m_ProcessHandles)
+ for (HandleType& Proc : m_ProcessHandles)
{
+#if ZEN_PLATFORM_WINDOWS
CloseHandle(Proc);
+#endif
Proc = 0;
}
}
@@ -346,24 +828,34 @@ ProcessMonitor::IsRunning()
bool FoundOne = false;
- for (HANDLE& Proc : m_ProcessHandles)
+ for (HandleType& Proc : m_ProcessHandles)
{
+ bool ProcIsActive;
+
+#if ZEN_PLATFORM_WINDOWS
DWORD ExitCode = 0;
GetExitCodeProcess(Proc, &ExitCode);
- if (ExitCode != STILL_ACTIVE)
+ ProcIsActive = (ExitCode != STILL_ACTIVE);
+ if (!ProcIsActive)
{
CloseHandle(Proc);
- Proc = 0;
}
- else
+#else
+ int Pid = int(intptr_t(Proc));
+ ProcIsActive = IsProcessRunning(Pid);
+#endif
+
+ if (!ProcIsActive)
{
- // Still alive
- FoundOne = true;
+ Proc = 0;
}
+
+ // Still alive
+ FoundOne |= ProcIsActive;
}
- std::erase_if(m_ProcessHandles, [](HANDLE Handle) { return Handle == 0; });
+ std::erase_if(m_ProcessHandles, [](HandleType Handle) { return Handle == 0; });
return FoundOne;
}
@@ -371,7 +863,13 @@ ProcessMonitor::IsRunning()
void
ProcessMonitor::AddPid(int Pid)
{
- HANDLE ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, Pid);
+ HandleType ProcessHandle;
+
+#if ZEN_PLATFORM_WINDOWS
+ ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, Pid);
+#else
+ ProcessHandle = HandleType(intptr_t(Pid));
+#endif
if (ProcessHandle)
{
@@ -387,8 +885,6 @@ ProcessMonitor::IsActive() const
return m_ProcessHandles.empty() == false;
}
-#endif // ZEN_PLATFORM_WINDOWS
-
//////////////////////////////////////////////////////////////////////////
bool
@@ -418,7 +914,9 @@ IsProcessRunning(int pid)
return true;
#else
- ZEN_NOT_IMPLEMENTED();
+ char Buffer[64];
+ sprintf(Buffer, "/proc/%d", pid);
+ return access(Buffer, F_OK) == 0;
#endif
}
@@ -428,7 +926,17 @@ GetCurrentProcessId()
#if ZEN_PLATFORM_WINDOWS
return ::GetCurrentProcessId();
#else
- return getpid();
+ return int(getpid());
+#endif
+}
+
+int
+GetCurrentThreadId()
+{
+#if ZEN_PLATFORM_WINDOWS
+ return ::GetCurrentThreadId();
+#else
+ return int(gettid());
#endif
}
@@ -447,9 +955,20 @@ Sleep(int ms)
// Testing related code follows...
//
+#if ZEN_WITH_TESTS
+
void
thread_forcelink()
{
}
+TEST_CASE("Thread")
+{
+ int Pid = GetCurrentProcessId();
+ CHECK(Pid > 0);
+ CHECK(IsProcessRunning(Pid));
+}
+
+#endif // ZEN_WITH_TESTS
+
} // namespace zen