13 #ifndef __STOUT_WINDOWS_OS_HPP__ 14 #define __STOUT_WINDOWS_OS_HPP__ 16 #include <sys/utime.h> 65 COMPUTER_NAME_FORMAT
format = ComputerNamePhysicalDnsHostname;
67 if (::GetComputerNameExW(format,
nullptr, &size) == 0) {
68 if (::GetLastError() != ERROR_MORE_DATA) {
73 std::vector<wchar_t> buffer;
76 if (::GetComputerNameExW(format, buffer.data(), &
size) == 0) {
80 return stringify(std::wstring(buffer.data()));
92 time.HighPart = filetime.dwHighDateTime;
93 time.LowPart = filetime.dwLowDateTime;
98 constexpr uint64_t epoch_offset = 116444736000000000ULL;
103 std::is_same<decltype(time.QuadPart), uint64_t>::value,
104 "Expected `ULARGE_INTEGER.QuadPart` to be of type `uint64_t`");
106 CHECK_GE(time.QuadPart, epoch_offset)
107 <<
"windows_to_unix_epoch: Given time was before UNIX epoch: " 110 return static_cast<double>(time.QuadPart - epoch_offset) / 10000000;
122 DWORD max_items = 4096;
123 DWORD bytes_returned;
125 size_t size_in_bytes;
135 processes.resize(max_items);
136 size_in_bytes = processes.size() *
sizeof(
pid_t);
137 CHECK_LE(size_in_bytes, MAXDWORD);
139 BOOL result = ::EnumProcesses(
141 static_cast<DWORD
>(size_in_bytes),
145 return WindowsError(
"os::pids: Call to `EnumProcesses` failed");
149 }
while (bytes_returned >= size_in_bytes);
151 std::set<pid_t> pids_set(processes.begin(), processes.end());
173 const std::string& key,
174 const std::string& value,
175 bool overwrite =
true)
184 ::GetEnvironmentVariableW(wide_stringify(key).data(),
nullptr, 0) != 0 &&
185 ::GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
190 ::SetEnvironmentVariableW(
191 wide_stringify(key).data(), wide_stringify(value).data());
197 inline void unsetenv(
const std::string& key)
201 ::SetEnvironmentVariableW(wide_stringify(key).data(),
nullptr);
209 inline void eraseenv(
const std::string& key)
252 const bool wait_for_child = (options &
WNOHANG) == 0;
258 "os::waitpid: Value of pid is '" +
stringify(pid) +
259 "'; the Windows implementation currently does not allow values <= 0");
260 }
else if (options != 0 && options !=
WNOHANG) {
265 "os::waitpid: Only flag `WNOHANG` is implemented on Windows");
273 PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
275 static_cast<DWORD>(pid));
277 if (process ==
nullptr) {
278 return WindowsError(
"os::waitpid: Failed to open process for pid '" +
286 const DWORD wait_time = wait_for_child ? INFINITE : 0;
287 const DWORD wait_results = ::WaitForSingleObject(
288 scoped_process.get(),
292 const bool state_signaled = wait_results == WAIT_OBJECT_0;
293 if (options == 0 && !state_signaled) {
298 "os::waitpid: Failed to wait for pid '" +
stringify(pid) +
299 "'. `::WaitForSingleObject` should have waited for child process to " +
300 "exit, but returned code '" +
stringify(wait_results) +
302 }
else if (wait_for_child && !state_signaled &&
303 wait_results != WAIT_TIMEOUT) {
309 "os::waitpid: Failed to wait for pid '" +
stringify(pid) +
310 "'. `ENOHANG` flag was passed in, so `::WaitForSingleObject` should " +
311 "have either returned `WAIT_OBJECT_0` or `WAIT_TIMEOUT` (the " +
312 "timeout was set to 0, because we are not waiting for the child), " +
313 "but instead returned code '" +
stringify(wait_results) +
"'");
316 if (!wait_for_child && wait_results == WAIT_TIMEOUT) {
324 DWORD child_exit_code = 0;
325 if (!::GetExitCodeProcess(scoped_process.get(), &child_exit_code)) {
328 "os::waitpid: Successfully waited on child process with pid '" +
329 std::to_string(pid) +
"', but could not retrieve exit code");
332 if (status !=
nullptr) {
333 *status = child_exit_code;
341 inline std::string
hstrerror(
int err) =
delete;
347 const std::string&
path,
348 bool recursive) =
delete;
355 const std::string& path,
366 if (duration.
ms() < 0) {
370 ::Sleep(static_cast<DWORD>(duration.
ms()));
385 SYSTEM_INFO sys_info;
386 ::GetSystemInfo(&sys_info);
387 return static_cast<long>(sys_info.dwNumberOfProcessors);
400 "Failed to determine system load averages");
409 MEMORYSTATUSEX memory_status;
410 memory_status.dwLength =
sizeof(MEMORYSTATUSEX);
411 if (!::GlobalMemoryStatusEx(&memory_status)) {
412 return WindowsError(
"os::memory: Call to `GlobalMemoryStatusEx` failed");
415 memory.
total =
Bytes(memory_status.ullTotalPhys);
416 memory.
free =
Bytes(memory_status.ullAvailPhys);
431 inline tm*
gmtime_r(
const time_t* timep, tm* result)
433 return ::gmtime_s(result, timep) == ERROR_SUCCESS ? result :
nullptr;
442 HANDLE snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid);
443 if (snapshot_handle == INVALID_HANDLE_VALUE) {
445 "os::process_entry: Call to `CreateToolhelp32Snapshot` failed");
448 SharedHandle safe_snapshot_handle(snapshot_handle, ::CloseHandle);
452 memset(&process_entry, 0,
sizeof(process_entry));
457 SetLastError(ERROR_SUCCESS);
458 BOOL has_next = Process32First(safe_snapshot_handle.get(), &
process_entry);
459 if (has_next == FALSE) {
464 if (::GetLastError() != ERROR_SUCCESS) {
465 return WindowsError(
"os::process_entry: Call to `Process32First` failed");
467 return Error(
"os::process_entry: Call to `Process32First` failed");
472 while (has_next == TRUE) {
473 if (process_entry.th32ProcessID == pid) {
478 has_next = Process32Next(safe_snapshot_handle.get(), &
process_entry);
479 if (has_next == FALSE) {
480 DWORD last_error = ::GetLastError();
481 if (last_error != ERROR_NO_MORE_FILES && last_error != ERROR_SUCCESS) {
483 "os::process_entry: Call to `Process32Next` failed");
501 return Error(
"os::process: Invalid parameter: pid == 0");
509 }
else if (entry.
isNone()) {
513 HANDLE process_handle = ::OpenProcess(
514 PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,
519 if (process_handle ==
nullptr) {
520 return WindowsError(
"os::process: Call to `OpenProcess` failed");
523 SharedHandle safe_process_handle(process_handle, ::CloseHandle);
526 PROCESS_MEMORY_COUNTERS proc_mem_counters;
527 BOOL get_process_memory_info = ::GetProcessMemoryInfo(
530 sizeof(proc_mem_counters));
532 if (!get_process_memory_info) {
533 return WindowsError(
"os::process: Call to `GetProcessMemoryInfo` failed");
538 BOOL process_id_to_session_id = ::ProcessIdToSessionId(pid, &session_id);
540 if (!process_id_to_session_id) {
541 return WindowsError(
"os::process: Call to `ProcessIdToSessionId` failed");
545 FILETIME create_filetime, exit_filetime, kernel_filetime, user_filetime;
546 BOOL get_process_times = ::GetProcessTimes(
553 if (!get_process_times) {
554 return WindowsError(
"os::process: Call to `GetProcessTimes` failed");
558 ULARGE_INTEGER lKernelTime, lUserTime;
559 lKernelTime.HighPart = kernel_filetime.dwHighDateTime;
560 lKernelTime.LowPart = kernel_filetime.dwLowDateTime;
561 lUserTime.HighPart = user_filetime.dwHighDateTime;
562 lUserTime.LowPart = user_filetime.dwLowDateTime;
569 entry.
get().th32ParentProcessID,
572 Bytes(proc_mem_counters.WorkingSetSize),
591 if (::GetAllUsersProfileDirectoryW(
nullptr, &size)) {
595 "os::var: `GetAllUsersProfileDirectoryW` succeeded unexpectedly");
598 std::vector<wchar_t> buffer;
599 buffer.reserve(static_cast<size_t>(size));
600 if (!::GetAllUsersProfileDirectoryW(buffer.data(), &
size)) {
601 return WindowsError(
"os::var: `GetAllUsersProfileDirectoryW` failed");
604 return stringify(std::wstring(buffer.data()));
616 const std::string system_root = system_root_env.
isSome()
617 ? system_root_env.
get()
624 path::join(system_root,
"System32",
"WindowsPowerShell",
"v1.0"));
629 #endif // __STOUT_WINDOWS_OS_HPP__
bool isNone() const
Definition: result.hpp:113
Try< uid_t > uid(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:224
Definition: nothing.hpp:16
Definition: errorbase.hpp:36
Try< Bytes > size(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:130
UINT uid_t
Definition: windows.hpp:183
T & get()&
Definition: try.hpp:80
HANDLE get_handle() const
Definition: windows.hpp:90
Definition: windows.hpp:72
std::stringstream & join(std::stringstream &stream, const std::string &separator, T &&...args)
Definition: strings.hpp:307
Try< Nothing > chmod(const std::string &path, int mode)
Definition: os.hpp:195
Try< Nothing > sleep(const Duration &duration)
Definition: os.hpp:219
static Result< T > error(const std::string &message)
Definition: result.hpp:54
Try< std::list< Process > > processes()
Definition: os.hpp:184
Try< Nothing > mknod(const std::string &path, mode_t mode, dev_t dev)
Definition: os.hpp:205
Result< ProcessStatus > status(pid_t pid)
Definition: proc.hpp:166
Definition: error.hpp:108
#define WNOHANG
Definition: windows.hpp:382
double ms() const
Definition: duration.hpp:48
Definition: errorbase.hpp:50
Definition: posix_signalhandler.hpp:23
std::string join(const std::string &path1, const std::string &path2, const char _separator=os::PATH_SEPARATOR)
Definition: path.hpp:116
void setenv(const std::string &key, const std::string &value, bool overwrite=true)
Definition: os.hpp:157
void unsetenv(const std::string &key)
Definition: os.hpp:167
Definition: duration.hpp:32
Bytes freeSwap
Definition: os.hpp:39
std::string host_default_path()
Definition: os.hpp:474
bool isSome() const
Definition: option.hpp:116
Try< Load > loadavg()
Definition: os.hpp:280
Try< std::string > nodename()
Definition: os.hpp:56
DWORD pid_t
Definition: windows.hpp:181
Definition: process.hpp:32
int mode_t
Definition: windows.hpp:177
Bytes totalSwap
Definition: os.hpp:38
Try< dev_t > dev(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:181
double windows_to_unix_epoch(const FILETIME &filetime)
Definition: os.hpp:87
constexpr Handle HANDLE
Definition: ingress.hpp:37
Try< Nothing > utime(const std::string &path)
Definition: utime.hpp:32
Try< long > cpus()
Definition: os.hpp:265
std::string hstrerror(int err)=delete
static Option< T > none()
Definition: option.hpp:32
bool isSome() const
Definition: try.hpp:77
const T & get() const &
Definition: option.hpp:119
Option< std::string > getenv(const std::string &key)
Definition: getenv.hpp:29
int random()
Definition: os.hpp:580
Try< Version > release()
Definition: os.hpp:378
Result< pid_t > waitpid(pid_t pid, int *status, int options)
Definition: os.hpp:141
Try< UTSInfo > uname()
Definition: os.hpp:297
Result< Process > process(pid_t pid)
Definition: freebsd.hpp:30
Definition: attributes.hpp:24
Bytes total
Definition: os.hpp:36
T & get()&
Definition: result.hpp:116
Definition: executor.hpp:48
void eraseenv(const std::string &key)
Definition: os.hpp:181
Try< Nothing > chown(uid_t uid, gid_t gid, const std::string &path, bool recursive)
Definition: chown.hpp:29
Try< mode_t > mode(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:168
bool isError() const
Definition: result.hpp:114
Try< std::string > format(const std::string &fmt, va_list args)
Definition: format.hpp:68
Result< PROCESSENTRY32W > process_entry(pid_t pid)
Definition: os.hpp:437
Definition: duration.hpp:165
Try< std::string > var()
Definition: os.hpp:407
std::string stringify(int flags)
Try< Memory > memory()
Definition: freebsd.hpp:78
Try< std::list< std::string > > glob(const std::string &pattern)
Definition: os.hpp:239
Bytes free
Definition: os.hpp:37
Try< std::set< pid_t > > pids()
Definition: freebsd.hpp:62
Try< std::vector< Value > > time(const std::string &hierarchy, const std::string &cgroup)
UINT gid_t
Definition: windows.hpp:184
tm * gmtime_r(const time_t *timep, tm *result)
Definition: os.hpp:431