int ty_thread_create(ty_thread *thread, ty_thread_func *f, void *udata) { struct thread_context ctx; int r; ctx.thread = thread; ctx.f = f; ctx.udata = udata; ctx.ev = CreateEvent(NULL, TRUE, FALSE, NULL); if (!ctx.ev) { r = ty_error(TY_ERROR_SYSTEM, "CreateEvent() failed: %s", ty_win32_strerror(0)); goto cleanup; } thread->h = (HANDLE)_beginthreadex(NULL, 0, thread_proc, &ctx, 0, (unsigned int *)&thread->thread_id); if (!thread->h) { r = ty_error(TY_ERROR_SYSTEM, "_beginthreadex() failed: %s", ty_win32_strerror(0)); goto cleanup; } WaitForSingleObject(ctx.ev, INFINITE); r = 0; cleanup: if (ctx.ev) CloseHandle(ctx.ev); return r; }
static int start_stdin_thread(void) { input_available = CreateEvent(NULL, TRUE, FALSE, NULL); if (!input_available) return ty_error(TY_ERROR_SYSTEM, "CreateEvent() failed: %s", ty_win32_strerror(0)); input_processed = CreateEvent(NULL, TRUE, TRUE, NULL); if (!input_processed) return ty_error(TY_ERROR_SYSTEM, "CreateEvent() failed: %s", ty_win32_strerror(0)); input_thread = (HANDLE)_beginthreadex(NULL, 0, stdin_thread, NULL, 0, NULL); if (!input_thread) return ty_error(TY_ERROR_SYSTEM, "_beginthreadex() failed: %s", ty_win32_strerror(0)); return 0; }
int ty_terminal_setup(int flags) { HANDLE handle; DWORD mode; BOOL r; handle = GetStdHandle(STD_INPUT_HANDLE); if (handle == INVALID_HANDLE_VALUE) return ty_error(TY_ERROR_SYSTEM, "GetStdHandle(STD_INPUT_HANDLE) failed"); r = GetConsoleMode(handle, &mode); if (!r) { if (GetLastError() == ERROR_INVALID_HANDLE) return ty_error(TY_ERROR_UNSUPPORTED, "Not a terminal"); return ty_error(TY_ERROR_SYSTEM, "GetConsoleMode(STD_INPUT_HANDLE) failed: %s", ty_win32_strerror(0)); } if (!saved_console_mode) { orig_console_mode = mode; saved_console_mode = true; atexit(ty_terminal_restore); } mode |= ENABLE_PROCESSED_INPUT; mode &= (DWORD)~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); if (!(flags & TY_TERMINAL_RAW)) mode |= ENABLE_LINE_INPUT; if (!(flags & TY_TERMINAL_SILENT)) mode |= ENABLE_ECHO_INPUT; r = SetConsoleMode(handle, mode); if (!r) return ty_error(TY_ERROR_SYSTEM, "SetConsoleMode(STD_INPUT_HANDLE) failed: %s", ty_win32_strerror(0)); return 0; }
int ty_poll(const ty_descriptor_set *set, int timeout) { assert(set); assert(set->count); assert(set->count <= 64); DWORD ret = WaitForMultipleObjects((DWORD)set->count, set->desc, FALSE, timeout < 0 ? INFINITE : (DWORD)timeout); switch (ret) { case WAIT_FAILED: return ty_error(TY_ERROR_SYSTEM, "WaitForMultipleObjects() failed: %s", ty_win32_strerror(0)); case WAIT_TIMEOUT: return 0; } return set->id[ret - WAIT_OBJECT_0]; }
int ty_cond_init(ty_cond *cond) { static bool init; static InitializeConditionVariable_func *InitializeConditionVariable_; if (!init) { HANDLE kernel32 = GetModuleHandle("kernel32.dll"); // Condition Variables appeared on Vista, emulate them on Windows XP InitializeConditionVariable_ = (InitializeConditionVariable_func *)GetProcAddress(kernel32, "InitializeConditionVariable"); if (InitializeConditionVariable_) { WakeConditionVariable_ = (WakeConditionVariable_func *)GetProcAddress(kernel32, "WakeConditionVariable"); WakeAllConditionVariable_ = (WakeAllConditionVariable_func *)GetProcAddress(kernel32, "WakeAllConditionVariable"); SleepConditionVariableCS_ = (SleepConditionVariableCS_func *)GetProcAddress(kernel32, "SleepConditionVariableCS"); } else { WakeConditionVariable_ = WakeConditionVariable_fallback; WakeAllConditionVariable_ = WakeAllConditionVariable_fallback; SleepConditionVariableCS_ = SleepConditionVariableCS_fallback; } init = true; } if (InitializeConditionVariable_) { InitializeConditionVariable_((CONDITION_VARIABLE *)&cond->cv); } else { memset(cond, 0, sizeof(*cond)); cond->xp.ev = CreateEvent(NULL, TRUE, FALSE, NULL); if (!cond->xp.ev) return ty_error(TY_ERROR_SYSTEM, "CreateEvent() failed: %s", ty_win32_strerror(0)); InitializeCriticalSection((CRITICAL_SECTION *)&cond->xp.mutex); } cond->init = true; return 0; }
int ty_stat(const char *path, ty_file_info *info, bool follow) { TY_UNUSED(follow); assert(path && path[0]); assert(info); HANDLE h; BY_HANDLE_FILE_INFORMATION attr; int r; // FIXME: check error handling h = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (h == INVALID_HANDLE_VALUE) { switch (GetLastError()) { case ERROR_ACCESS_DENIED: return ty_error(TY_ERROR_ACCESS, "Permission denied for '%s'", path); case ERROR_NOT_READY: return ty_error(TY_ERROR_IO, "I/O error while stating '%s'", path); case ERROR_FILE_NOT_FOUND: return ty_error(TY_ERROR_NOT_FOUND, "Path '%s' does not exist", path); case ERROR_PATH_NOT_FOUND: return ty_error(TY_ERROR_NOT_FOUND, "Part of '%s' is not a directory", path); } // Let's lie a little, error will be clearer this way return ty_error(TY_ERROR_SYSTEM, "GetFileAttributesEx('%s') failed: %s", path, ty_win32_strerror(0)); } r = GetFileInformationByHandle(h, &attr); if (!r) return ty_error(TY_ERROR_SYSTEM, "GetFileInformationByHandle('%s') failed: %s", path, ty_win32_strerror(0)); if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { info->type = TY_FILE_DIRECTORY; } else if (attr.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) { info->type = TY_FILE_SPECIAL; } else { info->type = TY_FILE_REGULAR; } info->size = ((uint64_t)attr.nFileSizeHigh << 32) | attr.nFileSizeLow; info->mtime = filetime_to_unix_time(&attr.ftLastWriteTime); return 0; }