diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin index cabd4b4cc..a0d91f4c0 100644 --- a/core/dynlib/lib_windows.odin +++ b/core/dynlib/lib_windows.odin @@ -1,25 +1,25 @@ // +build windows package dynlib -import "core:sys/win32" +import win32 "core:sys/windows" import "core:strings" load_library :: proc(path: string, global_symbols := false) -> (Library, bool) { // NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL wide_path := win32.utf8_to_wstring(path, context.temp_allocator); - handle := cast(Library)win32.load_library_w(wide_path); + handle := cast(Library)win32.LoadLibraryW(wide_path); return handle, handle != nil; } unload_library :: proc(library: Library) -> bool { - ok := win32.free_library(cast(win32.Hmodule)library); + ok := win32.FreeLibrary(cast(win32.HMODULE)library); return bool(ok); } symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) { c_str := strings.clone_to_cstring(symbol, context.temp_allocator); - ptr = win32.get_proc_address(cast(win32.Hmodule)library, c_str); + ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str); found = ptr != nil; return; } diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index ceb9f3ef8..aa2ae88b4 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -1,7 +1,7 @@ // +build windows package os -import "core:sys/win32" +import win32 "core:sys/windows" import "core:intrinsics" OS :: "windows"; @@ -85,8 +85,8 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn } share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE); - sa: ^win32.Security_Attributes = nil; - sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = true}; + sa: ^win32.SECURITY_ATTRIBUTES = nil; + sa_inherit := win32.SECURITY_ATTRIBUTES{nLength = size_of(win32.SECURITY_ATTRIBUTES), bInheritHandle = true}; if mode&O_CLOEXEC == 0 { sa = &sa_inherit; } @@ -105,16 +105,16 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn create_mode = win32.OPEN_EXISTING; } wide_path := win32.utf8_to_wstring(path); - handle := Handle(win32.create_file_w(wide_path, access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil)); + handle := Handle(win32.CreateFileW(auto_cast wide_path, access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil)); if handle != INVALID_HANDLE do return handle, ERROR_NONE; - err := Errno(win32.get_last_error()); + err := Errno(win32.GetLastError()); return INVALID_HANDLE, err; } close :: proc(fd: Handle) -> Errno { - if win32.close_handle(win32.Handle(fd)) == 0 { - return Errno(win32.get_last_error()); + if !win32.CloseHandle(win32.HANDLE(fd)) { + return Errno(win32.GetLastError()); } return ERROR_NONE; } @@ -123,18 +123,18 @@ close :: proc(fd: Handle) -> Errno { write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 do return 0, ERROR_NONE; - single_write_length: i32; + single_write_length: win32.DWORD; total_write: i64; length := i64(len(data)); for total_write < length { remaining := length - total_write; MAX :: 1<<31-1; - to_write: i32 = min(i32(remaining), MAX); + to_write := win32.DWORD(min(i32(remaining), MAX)); - e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil); + e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil); if single_write_length <= 0 || !e { - err := Errno(win32.get_last_error()); + err := Errno(win32.GetLastError()); return int(total_write), err; } total_write += i64(single_write_length); @@ -145,18 +145,18 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { read :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 do return 0, ERROR_NONE; - single_read_length: i32; + single_read_length: win32.DWORD; total_read: i64; length := i64(len(data)); for total_read < length { remaining := length - total_read; MAX :: 1<<32-1; - to_read: u32 = min(u32(remaining), MAX); + to_read := win32.DWORD(min(u32(remaining), MAX)); - e := win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil); + e := win32.ReadFile(win32.HANDLE(fd), &data[total_read], to_read, &single_read_length, nil); if single_read_length <= 0 || !e { - err := Errno(win32.get_last_error()); + err := Errno(win32.GetLastError()); return int(total_read), err; } total_read += i64(single_read_length); @@ -173,37 +173,37 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { } hi := i32(offset>>32); lo := i32(offset); - ft := win32.get_file_type(win32.Handle(fd)); + ft := win32.GetFileType(win32.HANDLE(fd)); if ft == win32.FILE_TYPE_PIPE do return 0, ERROR_FILE_IS_PIPE; - dw_ptr := win32.set_file_pointer(win32.Handle(fd), lo, &hi, w); + dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w); if dw_ptr == win32.INVALID_SET_FILE_POINTER { - err := Errno(win32.get_last_error()); + err := Errno(win32.GetLastError()); return 0, err; } return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE; } file_size :: proc(fd: Handle) -> (i64, Errno) { - length: i64; + length: win32.LARGE_INTEGER; err: Errno; - if !win32.get_file_size_ex(win32.Handle(fd), &length) { - err = Errno(win32.get_last_error()); + if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) { + err = Errno(win32.GetLastError()); } - return length, err; + return i64(length), err; } // NOTE(bill): Uses startup to initialize it -stdin := get_std_handle(win32.STD_INPUT_HANDLE); -stdout := get_std_handle(win32.STD_OUTPUT_HANDLE); -stderr := get_std_handle(win32.STD_ERROR_HANDLE); +stdin := get_std_handle(int(win32.STD_INPUT_HANDLE)); +stdout := get_std_handle(int(win32.STD_OUTPUT_HANDLE)); +stderr := get_std_handle(int(win32.STD_ERROR_HANDLE)); get_std_handle :: proc "contextless" (h: int) -> Handle { - fd := win32.get_std_handle(i32(h)); - win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0); + fd := win32.GetStdHandle(win32.DWORD(h)); + win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0); return Handle(fd); } @@ -212,32 +212,32 @@ get_std_handle :: proc "contextless" (h: int) -> Handle { last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { - file_info: win32.By_Handle_File_Information; - if !win32.get_file_information_by_handle(win32.Handle(fd), &file_info) { - return 0, Errno(win32.get_last_error()); + file_info: win32.BY_HANDLE_FILE_INFORMATION; + if !win32.GetFileInformationByHandle(win32.HANDLE(fd), &file_info) { + return 0, Errno(win32.GetLastError()); } - lo := File_Time(file_info.last_write_time.lo); - hi := File_Time(file_info.last_write_time.hi); + lo := File_Time(file_info.ftLastWriteTime.dwLowDateTime); + hi := File_Time(file_info.ftLastWriteTime.dwHighDateTime); return lo | hi << 32, ERROR_NONE; } last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { - data: win32.File_Attribute_Data; + data: win32.WIN32_FILE_ATTRIBUTE_DATA; wide_path := win32.utf8_to_wstring(name); - if !win32.get_file_attributes_ex_w(wide_path, win32.GetFileExInfoStandard, &data) { - return 0, Errno(win32.get_last_error()); + if !win32.GetFileAttributesExW(auto_cast wide_path, win32.GetFileExInfoStandard, &data) { + return 0, Errno(win32.GetLastError()); } - l := File_Time(data.last_write_time.lo); - h := File_Time(data.last_write_time.hi); + l := File_Time(data.ftLastWriteTime.dwLowDateTime); + h := File_Time(data.ftLastWriteTime.dwHighDateTime); return l | h << 32, ERROR_NONE; } heap_alloc :: proc(size: int) -> rawptr { - return win32.heap_alloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, size); + return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, uint(size)); } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { if new_size == 0 { @@ -246,11 +246,11 @@ heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { } if ptr == nil do return heap_alloc(new_size); - return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size); + return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, uint(new_size)); } heap_free :: proc(ptr: rawptr) { if ptr == nil do return; - win32.heap_free(win32.get_process_heap(), 0, ptr); + win32.HeapFree(win32.GetProcessHeap(), 0, ptr); } get_page_size :: proc() -> int { @@ -259,9 +259,9 @@ get_page_size :: proc() -> int { @static page_size := -1; if page_size != -1 do return page_size; - info: win32.System_Info; - win32.get_system_info(&info); - page_size = int(info.page_size); + info: win32.SYSTEM_INFO; + win32.GetSystemInfo(&info); + page_size = int(info.dwPageSize); return page_size; } @@ -274,10 +274,10 @@ get_page_size :: proc() -> int { get_current_directory :: proc() -> string { for intrinsics.atomic_xchg(&cwd_gate, true) {} - sz_utf16 := win32.get_current_directory_w(0, nil); + sz_utf16 := win32.GetCurrentDirectoryW(0, nil); dir_buf_wstr := make([]u16, sz_utf16, context.temp_allocator); // the first time, it _includes_ the NUL. - sz_utf16 = win32.get_current_directory_w(u32(len(dir_buf_wstr)), cast(win32.Wstring) &dir_buf_wstr[0]); + sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), auto_cast &dir_buf_wstr[0]); assert(int(sz_utf16)+1 == len(dir_buf_wstr)); // the second time, it _excludes_ the NUL. intrinsics.atomic_store(&cwd_gate, false); @@ -291,8 +291,8 @@ set_current_directory :: proc(path: string) -> (err: Errno) { for intrinsics.atomic_xchg(&cwd_gate, true) {} defer intrinsics.atomic_store(&cwd_gate, false); - res := win32.set_current_directory_w(wstr); - if res == 0 do return Errno(win32.get_last_error()); + res := win32.SetCurrentDirectoryW(auto_cast wstr); + if !res do return Errno(win32.GetLastError()); return; } @@ -300,29 +300,29 @@ set_current_directory :: proc(path: string) -> (err: Errno) { exit :: proc(code: int) -> ! { - win32.exit_process(u32(code)); + win32.ExitProcess(win32.DWORD(code)); } current_thread_id :: proc "contextless" () -> int { - return int(win32.get_current_thread_id()); + return int(win32.GetCurrentThreadId()); } _alloc_command_line_arguments :: proc() -> []string { arg_count: i32; - arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count); + arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count); arg_list := make([]string, int(arg_count)); for _, i in arg_list { - wc_str := (^win32.Wstring)(uintptr(arg_list_ptr) + size_of(win32.Wstring)*uintptr(i))^; - olen := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1, - nil, 0, nil, nil); + wc_str := (^win32.wstring)(uintptr(arg_list_ptr) + size_of(win32.wstring)*uintptr(i))^; + olen := win32.WideCharToMultiByte(win32.CP_UTF8, 0, wc_str, -1, + nil, 0, nil, nil); buf := make([]byte, int(olen)); - n := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1, - cstring(&buf[0]), olen, nil, nil); + n := win32.WideCharToMultiByte(win32.CP_UTF8, 0, wc_str, -1, + &buf[0], olen, nil, nil); if n > 0 { n -= 1; } @@ -332,10 +332,10 @@ _alloc_command_line_arguments :: proc() -> []string { return arg_list; } -get_windows_version_ansi :: proc() -> win32.OS_Version_Info_Ex_A { - osvi : win32.OS_Version_Info_Ex_A; - osvi.os_version_info_size = size_of(win32.OS_Version_Info_Ex_A); - win32.get_version(&osvi); +get_windows_version_ansi :: proc() -> win32.OSVERSIONINFOEXW { + osvi : win32.OSVERSIONINFOEXW; + osvi.os_version_info_size = size_of(win32.OSVERSIONINFOEXW); + win32.GetVersionExW(&osvi); return osvi; } diff --git a/core/sync/channel.odin b/core/sync/channel.odin index ae9a196c5..809f1bf39 100644 --- a/core/sync/channel.odin +++ b/core/sync/channel.odin @@ -2,6 +2,7 @@ package sync import "core:mem" import "core:time" +import "core:fmt" import "core:math/rand" _, _ :: time, rand; @@ -17,13 +18,16 @@ _Channel_Internal :: struct(T: typeid) { unbuffered_msg: T, // Will be used as the backing to the queue if no `cap` is given - mutex: Mutex, - r_cond: Condition, - w_cond: Condition, + mutex: Mutex, + r_mutex: Mutex, + w_mutex: Mutex, + r_cond: Condition, + w_cond: Condition, - closed: bool, - r_waiting: int, - w_waiting: int, + is_buffered: bool, + is_closed: bool, + r_waiting: int, + w_waiting: int, } channel_init :: proc(c: ^$C/Channel($T), cap: int = 0, allocator := context.allocator) { @@ -38,16 +42,20 @@ channel_make :: proc($T: typeid, cap: int = 0, allocator := context.allocator) - ch.allocator = allocator; mutex_init(&ch.mutex); + mutex_init(&ch.r_mutex); + mutex_init(&ch.w_mutex); condition_init(&ch.r_cond, &ch.mutex); condition_init(&ch.w_cond, &ch.mutex); - ch.closed = false; + ch.is_closed = false; ch.r_waiting = 0; ch.w_waiting = 0; ch.unbuffered_msg = T{}; if cap > 0 { + ch.is_buffered = true; ch.queue = make([dynamic]T, 0, cap, ch.allocator); } else { + ch.is_buffered = false; d := mem.Raw_Dynamic_Array{ data = &ch.unbuffered_msg, len = 0, @@ -67,6 +75,8 @@ channel_destroy :: proc(ch: $C/Channel($T)) { } mutex_destroy(&ch.mutex); + mutex_destroy(&ch.r_mutex); + mutex_destroy(&ch.w_mutex); condition_destroy(&ch.r_cond); condition_destroy(&ch.w_cond); free(ch.internal, ch.allocator); @@ -75,8 +85,8 @@ channel_destroy :: proc(ch: $C/Channel($T)) { channel_close :: proc(ch: $C/Channel($T)) -> (ok: bool) { mutex_lock(&ch.mutex); - if !ch.closed { - ch.closed = true; + if !ch.is_closed { + ch.is_closed = true; condition_broadcast(&ch.r_cond); condition_broadcast(&ch.w_cond); ok = true; @@ -89,25 +99,45 @@ channel_close :: proc(ch: $C/Channel($T)) -> (ok: bool) { channel_write :: proc(ch: $C/Channel($T), msg: T) -> (ok: bool) { mutex_lock(&ch.mutex); defer mutex_unlock(&ch.mutex); + // fmt.println("channel_write"); + // defer fmt.println("channel_write done"); - if ch.closed { + if ch.is_closed { return; } - - for len(ch.queue) == cap(ch.queue) { + for !channel_can_write(ch) { ch.w_waiting += 1; condition_wait_for(&ch.w_cond); ch.w_waiting -= 1; } - if len(ch.queue) < cap(ch.queue) { + if ch.is_buffered { + if len(ch.queue) < cap(ch.queue) { + append(&ch.queue, msg); + ok = true; + } + + if ch.r_waiting > 0 { + condition_signal(&ch.r_cond); + } + } else { + for len(ch.queue) == cap(ch.queue) { + ch.w_waiting += 1; + condition_wait_for(&ch.w_cond); + ch.w_waiting -= 1; + } + assert(len(ch.queue) < cap(ch.queue)); append(&ch.queue, msg); ok = true; - } + assert(ch.w_waiting >= 0); + ch.w_waiting += 1; - if ch.r_waiting > 0 { - condition_signal(&ch.r_cond); + if ch.r_waiting > 0 { + condition_signal(&ch.r_cond); + } + + condition_wait_for(&ch.w_cond); } return; @@ -116,27 +146,41 @@ channel_write :: proc(ch: $C/Channel($T), msg: T) -> (ok: bool) { channel_read :: proc(ch: $C/Channel($T)) -> (msg: T, ok: bool) #optional_ok { mutex_lock(&ch.mutex); defer mutex_unlock(&ch.mutex); + // fmt.println("channel_read"); + // defer fmt.println("channel_read done"); - for len(ch.queue) == 0 { - if ch.closed { - return; - } - + if ch.is_closed { + return; + } + for !channel_can_read(ch) { ch.r_waiting += 1; condition_wait_for(&ch.r_cond); ch.r_waiting -= 1; } + if ch.is_closed { + return; + } - msg, ok = pop_front(&ch.queue); + if ch.is_buffered { + assert(len(ch.queue) > 0); + msg, ok = pop_front_safe(&ch.queue); - if ch.w_waiting > 0 { + if ch.w_waiting > 0 { + condition_signal(&ch.w_cond); + } + } else { + assert(ch.w_waiting > 0); + assert(len(ch.queue) > 0); + msg, ok = pop_front_safe(&ch.queue); + + ch.w_waiting -= 1; condition_signal(&ch.w_cond); } return; } -channel_size :: proc(ch: $C/Channel($T)) -> (size: int) { +channel_len :: proc(ch: $C/Channel($T)) -> (size: int) { if channel_is_buffered(ch) { mutex_lock(&ch.mutex); size = len(ch.queue); @@ -147,111 +191,56 @@ channel_size :: proc(ch: $C/Channel($T)) -> (size: int) { channel_is_closed :: proc(ch: $C/Channel($T)) -> bool { mutex_lock(&ch.mutex); - closed := ch.closed; + closed := ch.is_closed; mutex_unlock(&ch.mutex); return closed; } channel_is_buffered :: proc(ch: $C/Channel($T)) -> bool { - q := transmute(mem.Raw_Dynamic_Array)ch.queue; - return q.cap != 0 && (q.data != &ch.unbuffered_msg); + return ch.is_buffered; } channel_can_write :: proc(ch: $C/Channel($T)) -> bool { mutex_lock(&ch.mutex); defer mutex_unlock(&ch.mutex); - return len(ch.queue) < cap(ch.queue); + if ch.is_closed { + return false; + } + if ch.is_buffered { + return len(ch.queue) < cap(ch.queue); + } + return ch.r_waiting > 0; } channel_can_read :: proc(ch: $C/Channel($T)) -> bool { mutex_lock(&ch.mutex); defer mutex_unlock(&ch.mutex); - return len(ch.queue) > 0; + if ch.is_buffered { + return len(ch.queue) > 0; + } + return ch.w_waiting > 0; } channel_can_read_write :: proc(ch: $C/Channel($T)) -> bool { mutex_lock(&ch.mutex); defer mutex_unlock(&ch.mutex); - return 0 < len(ch.queue) && len(ch.queue) < cap(ch.queue); + if ch.is_buffered { + return 0 < len(ch.queue) && len(ch.queue) < cap(ch.queue); + } + return ch.r_waiting > 0 && ch.w_waiting > 0; } channel_iterator :: proc(ch: $C/Channel($T)) -> (elem: T, ok: bool) { mutex_lock(&ch.mutex); defer mutex_unlock(&ch.mutex); - if len(ch.queue) > 0 { + if ch.is_buffered { + if len(ch.queue) > 0 { + return channel_read(ch); + } + } else if ch.w_waiting > 0 { return channel_read(ch); } return T{}, false; } - - - -channel_select :: proc(readers, writers: []$C/Channel($T), write_msgs: []T) -> (read_msg: T, index: int) { - Candidate :: struct { - ch: C, - msg: T, - index: int, - read: bool, - }; - - count := 0; - candidates := make([]Candidate, len(readers) + len(writers)); - defer delete(candidates); - - for c, i in readers { - if channel_can_read(c) { - candidates[count] = { - ch = c, - index = i, - read = true, - }; - count += 1; - } - } - - for c, i in writers { - if channel_can_write(c) { - candidates[count] = { - ch = c, - index = count, - read = false, - msg = write_msgs[i], - }; - count += 1; - } - } - - if count == 0 { - return T{}, -1; - } - - // Randomize the input - r := rand.create(time.read_cycle_counter()); - s := candidates[rand.int_max(count, &r)]; - if s.read { - ok: bool; - if read_msg, ok = channel_read(s.ch); !ok { - index = -1; - return; - } - } else { - if !channel_write(s.ch, s.msg) { - index = -1; - return; - } - } - - index = s.index; - return; -} - - -channel_select_write :: proc(writers: []$C/Channel($T), write_msgs: []T) -> (read_msg: T, index: int) { - return channel_select([]C{}, writers, msg); -} -channel_select_read :: proc(readers: []$C/Channel($T)) -> (index: int) { - _, index = channel_select(readers, []C{}, nil); - return; -} diff --git a/core/sync/sync_windows.odin b/core/sync/sync_windows.odin index 311c2fdcb..a4e1ec129 100644 --- a/core/sync/sync_windows.odin +++ b/core/sync/sync_windows.odin @@ -1,20 +1,23 @@ // +build windows package sync -import "core:sys/win32" +import win32 "core:sys/windows" -foreign import kernel32 "system:kernel32.lib" -// A lock that can only be held by one thread at once. Mutex :: struct { - _critical_section: win32.Critical_Section, + _handle: win32.SRWLOCK, + +} + +Recursive_Mutex :: struct { + _handle: win32.CRITICAL_SECTION, } // Blocks until signalled. // When signalled, awakens exactly one waiting thread. Condition :: struct { - _handle: WIN32_CONDITION_VARIABLE, + _handle: win32.CONDITION_VARIABLE, mutex: ^Mutex, } @@ -22,87 +25,98 @@ Condition :: struct { // When waited upon, blocks until the internal count is greater than zero, then subtracts one. // Posting to the semaphore increases the count by one, or the provided amount. Semaphore :: struct { - _handle: win32.Handle, + _handle: win32.HANDLE, } semaphore_init :: proc(s: ^Semaphore, initial_count := 0) { - s._handle = win32.create_semaphore_w(nil, i32(initial_count), 1<<31-1, nil); + s._handle = win32.CreateSemaphoreW(nil, win32.LONG(initial_count), 1<<31-1, nil); } semaphore_destroy :: proc(s: ^Semaphore) { - win32.close_handle(s._handle); + win32.CloseHandle(s._handle); } semaphore_post :: proc(s: ^Semaphore, count := 1) { - win32.release_semaphore(s._handle, i32(count), nil); + win32.ReleaseSemaphore(s._handle, win32.LONG(count), nil); } semaphore_wait_for :: proc(s: ^Semaphore) { - // NOTE(tetra, 2019-10-30): wait_for_single_object decrements the count before it returns. - result := win32.wait_for_single_object(s._handle, win32.INFINITE); + // NOTE(tetra, 2019-10-30): WaitForSingleObject decrements the count before it returns. + result := win32.WaitForSingleObject(s._handle, win32.INFINITE); assert(result != win32.WAIT_FAILED); } mutex_init :: proc(m: ^Mutex, spin_count := 0) { - win32.initialize_critical_section_and_spin_count(&m._critical_section, u32(spin_count)); + win32.InitializeSRWLock(&m._handle); } mutex_destroy :: proc(m: ^Mutex) { - win32.delete_critical_section(&m._critical_section); + win32.ReleaseSRWLockExclusive(&m._handle); } mutex_lock :: proc(m: ^Mutex) { - win32.enter_critical_section(&m._critical_section); + win32.AcquireSRWLockExclusive(&m._handle); } mutex_try_lock :: proc(m: ^Mutex) -> bool { - return bool(win32.try_enter_critical_section(&m._critical_section)); + return bool(win32.TryAcquireSRWLockExclusive(&m._handle)); } mutex_unlock :: proc(m: ^Mutex) { - win32.leave_critical_section(&m._critical_section); + win32.ReleaseSRWLockExclusive(&m._handle); } -@private WIN32_CONDITION_VARIABLE :: distinct rawptr; -@private -foreign kernel32 { - InitializeConditionVariable :: proc(ConditionVariable: ^WIN32_CONDITION_VARIABLE) --- - WakeConditionVariable :: proc(ConditionVariable: ^WIN32_CONDITION_VARIABLE) --- - WakeAllConditionVariable :: proc(ConditionVariable: ^WIN32_CONDITION_VARIABLE) --- - SleepConditionVariableCS :: proc(ConditionVariable: ^WIN32_CONDITION_VARIABLE, CriticalSection: ^win32.Critical_Section, dwMilliseconds: u32) -> b32 --- + +recursive_mutex_init :: proc(m: ^Recursive_Mutex, spin_count := 0) { + win32.InitializeCriticalSectionAndSpinCount(&m._handle, u32(spin_count)); +} + +recursive_mutex_destroy :: proc(m: ^Recursive_Mutex) { + win32.DeleteCriticalSection(&m._handle); +} + +recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { + win32.EnterCriticalSection(&m._handle); +} + +recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool { + return bool(win32.TryEnterCriticalSection(&m._handle)); +} + +recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) { + win32.LeaveCriticalSection(&m._handle); } condition_init :: proc(c: ^Condition, mutex: ^Mutex) -> bool { assert(mutex != nil); - InitializeConditionVariable(&c._handle); + win32.InitializeConditionVariable(&c._handle); c.mutex = mutex; - return c._handle != nil; + return true; } condition_destroy :: proc(c: ^Condition) { - if c._handle != nil { - WakeAllConditionVariable(&c._handle); - } + // Does nothing } condition_signal :: proc(c: ^Condition) -> bool { - if c._handle == nil { + if c._handle.ptr == nil { return false; } - WakeConditionVariable(&c._handle); + win32.WakeConditionVariable(&c._handle); return true; } condition_broadcast :: proc(c: ^Condition) -> bool { - if c._handle == nil { + if c._handle.ptr == nil { return false; } - WakeAllConditionVariable(&c._handle); + win32.WakeAllConditionVariable(&c._handle); return true; } condition_wait_for :: proc(c: ^Condition) -> bool { - return cast(bool)SleepConditionVariableCS(&c._handle, &c.mutex._critical_section, win32.INFINITE); + res := win32.SleepConditionVariableSRW(&c._handle, &c.mutex._handle, win32.INFINITE, 0); + return bool(res); } diff --git a/core/sys/win32/general.odin b/core/sys/win32/general.odin index 992fb5514..92d9a1716 100644 --- a/core/sys/win32/general.odin +++ b/core/sys/win32/general.odin @@ -814,9 +814,9 @@ wstring_to_utf8 :: proc(s: Wstring, N: int, allocator := context.temp_allocator) } // If N == -1 the call to wide_char_to_multi_byte assume the wide string is null terminated - // and will scan it to find the first null terminated character. The resulting string will + // and will scan it to find the first null terminated character. The resulting string will // also null terminated. - // If N != -1 it assumes the wide string is not null terminated and the resulting string + // If N != -1 it assumes the wide string is not null terminated and the resulting string // will not be null terminated, we therefore have to force it to be null terminated manually. text := make([]byte, n+1 if N != -1 else n, allocator); diff --git a/core/sys/win32/kernel32.odin b/core/sys/win32/kernel32.odin index fe3a906fe..58650e268 100644 --- a/core/sys/win32/kernel32.odin +++ b/core/sys/win32/kernel32.odin @@ -13,7 +13,7 @@ foreign kernel32 { @(link_name="CreateProcessW") create_process_w :: proc(application_name, command_line: Wstring, process_attributes, thread_attributes: ^Security_Attributes, inherit_handle: Bool, creation_flags: u32, environment: rawptr, - current_direcotry: cstring, startup_info: ^Startup_Info, + current_direcotry: Wstring, startup_info: ^Startup_Info, process_information: ^Process_Information) -> Bool ---; @(link_name="GetExitCodeProcess") get_exit_code_process :: proc(process: Handle, exit: ^u32) -> Bool ---; @(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---; @@ -156,7 +156,7 @@ foreign kernel32 { @(link_name="ReadBarrier") read_barrier :: proc() ---; @(link_name="CreateThread") - create_thread :: proc(thread_attributes: ^Security_Attributes, stack_size: int, start_routine: rawptr, + create_thread :: proc(thread_attributes: ^Security_Attributes, stack_size: uint, start_routine: proc "stdcall" (rawptr) -> u32, parameter: rawptr, creation_flags: u32, thread_id: ^u32) -> Handle ---; @(link_name="ResumeThread") resume_thread :: proc(thread: Handle) -> u32 ---; @(link_name="GetThreadPriority") get_thread_priority :: proc(thread: Handle) -> i32 ---; @@ -165,10 +165,10 @@ foreign kernel32 { @(link_name="TerminateThread") terminate_thread :: proc(thread: Handle, exit_code: u32) -> Bool ---; @(link_name="InitializeCriticalSection") initialize_critical_section :: proc(critical_section: ^Critical_Section) ---; - @(link_name="InitializeCriticalSectionAndSpinCount") initialize_critical_section_and_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) ---; + @(link_name="InitializeCriticalSectionAndSpinCount") initialize_critical_section_and_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) -> b32 ---; @(link_name="DeleteCriticalSection") delete_critical_section :: proc(critical_section: ^Critical_Section) ---; @(link_name="SetCriticalSectionSpinCount") set_critical_section_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) -> u32 ---; - @(link_name="TryEnterCriticalSection") try_enter_critical_section :: proc(critical_section: ^Critical_Section) -> Bool ---; + @(link_name="TryEnterCriticalSection") try_enter_critical_section :: proc(critical_section: ^Critical_Section) -> b8 ---; @(link_name="EnterCriticalSection") enter_critical_section :: proc(critical_section: ^Critical_Section) ---; @(link_name="LeaveCriticalSection") leave_critical_section :: proc(critical_section: ^Critical_Section) ---; diff --git a/core/sys/windows/advapi32.odin b/core/sys/windows/advapi32.odin new file mode 100644 index 000000000..b25ed6ef4 --- /dev/null +++ b/core/sys/windows/advapi32.odin @@ -0,0 +1,12 @@ +package sys_windows + +foreign import advapi32 "system:Advapi32.lib" + +@(default_calling_convention="stdcall") +foreign advapi32 { + @(link_name = "SystemFunction036") + RtlGenRandom :: proc(RandomBuffer: ^u8, RandomBufferLength: ULONG) -> BOOLEAN --- + OpenProcessToken :: proc(ProcessHandle: HANDLE, + DesiredAccess: DWORD, + TokenHandle: ^HANDLE) -> BOOL --- +} diff --git a/core/sys/windows/bcrypt.odin b/core/sys/windows/bcrypt.odin new file mode 100644 index 000000000..5d6c6811f --- /dev/null +++ b/core/sys/windows/bcrypt.odin @@ -0,0 +1,10 @@ +package sys_windows + +foreign import bcrypt "system:Bcrypt.lib" + +BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD : 0x00000002; + +@(default_calling_convention="stdcall") +foreign bcrypt { + BCryptGenRandom :: proc(hAlgorithm: LPVOID, pBuffer: ^u8, cbBuffer: ULONG, dwFlags: ULONG) -> LONG --- +} diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin new file mode 100644 index 000000000..473054393 --- /dev/null +++ b/core/sys/windows/kernel32.odin @@ -0,0 +1,263 @@ +package sys_windows + +foreign import kernel32 "system:Kernel32.lib" + + + +@(default_calling_convention="stdcall") +foreign kernel32 { + ReadConsoleW :: proc(hConsoleInput: HANDLE, + lpBuffer: LPVOID, + nNumberOfCharsToRead: DWORD, + lpNumberOfCharsRead: LPDWORD, + pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL --- + + WriteConsoleW :: proc(hConsoleOutput: HANDLE, + lpBuffer: LPCVOID, + nNumberOfCharsToWrite: DWORD, + lpNumberOfCharsWritten: LPDWORD, + lpReserved: LPVOID) -> BOOL --- + + GetConsoleMode :: proc(hConsoleHandle: HANDLE, + lpMode: LPDWORD) -> BOOL --- + + + GetFileInformationByHandle :: proc(hFile: HANDLE, lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) -> BOOL --- + SetHandleInformation :: proc(hObject: HANDLE, + dwMask: DWORD, + dwFlags: DWORD) -> BOOL --- + AddVectoredExceptionHandler :: proc(FirstHandler: ULONG, VectoredHandler: PVECTORED_EXCEPTION_HANDLER) -> LPVOID --- + AddVectoredContinueHandler :: proc(FirstHandler: ULONG, VectoredHandler: PVECTORED_EXCEPTION_HANDLER) -> LPVOID --- + RemoveVectoredExceptionHandler :: proc(Handle: LPVOID) -> DWORD --- + RemoveVectoredContinueHandler :: proc(Handle: LPVOID) -> DWORD --- + CreateHardLinkW :: proc(lpSymlinkFileName: LPCWSTR, + lpTargetFileName: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES) -> BOOL --- + + GetFileInformationByHandleEx :: proc(hFile: HANDLE, + fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, + lpFileInformation: LPVOID, + dwBufferSize: DWORD) -> BOOL --- + + GetCurrentProcessId :: proc() -> DWORD --- + InitializeCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- + InitializeCriticalSectionAndSpinCount :: proc(CriticalSection: ^CRITICAL_SECTION, dwSpinCount: DWORD) -> BOOL --- + EnterCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- + TryEnterCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) -> BOOLEAN --- + LeaveCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- + DeleteCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) --- + + RemoveDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL --- + SetFileAttributesW :: proc(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL --- + SetLastError :: proc(dwErrCode: DWORD) --- + GetCommandLineW :: proc() -> LPCWSTR --- + GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD --- + GetCurrentProcess :: proc() -> HANDLE --- + GetCurrentThread :: proc() -> HANDLE --- + GetCurrentThreadId :: proc() -> DWORD --- + GetStdHandle :: proc(which: DWORD) -> HANDLE --- + ExitProcess :: proc(uExitCode: c_uint) -> ! --- + DeviceIoControl :: proc( + hDevice: HANDLE, + dwIoControlCode: DWORD, + lpInBuffer: LPVOID, + nInBufferSize: DWORD, + lpOutBuffer: LPVOID, + nOutBufferSize: DWORD, + lpBytesReturned: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL --- + CreateThread :: proc( + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + dwStackSize: SIZE_T, + lpStartAddress: proc "stdcall" (rawptr) -> DWORD, + lpParameter: LPVOID, + dwCreationFlags: DWORD, + lpThreadId: LPDWORD, + ) -> HANDLE --- + SwitchToThread :: proc() -> BOOL --- + ResumeThread :: proc(thread: HANDLE) -> DWORD ---; + GetThreadPriority :: proc(thread: HANDLE) -> c_int ---; + SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL ---; + GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL ---; + TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL ---; + + CreateSemaphoreW :: proc(attributes: LPSECURITY_ATTRIBUTES, initial_count, maximum_count: LONG, name: LPCSTR) -> HANDLE ---; + ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: LONG, previous_count: ^LONG) -> BOOL ---; + + WaitForSingleObject :: proc(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD --- + Sleep :: proc(dwMilliseconds: DWORD) --- + GetProcessId :: proc(handle: HANDLE) -> DWORD --- + CopyFileExW :: proc( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + pbCancel: LPBOOL, + dwCopyFlags: DWORD, + ) -> BOOL --- + FormatMessageW :: proc( + flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: rawptr, + ) -> DWORD --- + TlsAlloc :: proc() -> DWORD --- + TlsGetValue :: proc(dwTlsIndex: DWORD) -> LPVOID --- + TlsSetValue :: proc(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL --- + GetLastError :: proc() -> DWORD --- + QueryPerformanceFrequency :: proc(lpFrequency: ^LARGE_INTEGER) -> BOOL --- + QueryPerformanceCounter :: proc(lpPerformanceCount: ^LARGE_INTEGER) -> BOOL --- + GetExitCodeProcess :: proc(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL --- + TerminateProcess :: proc(hProcess: HANDLE, uExitCode: UINT) -> BOOL --- + CreateProcessW :: proc( + lpApplicationName: LPCWSTR, + lpCommandLine: LPWSTR, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpEnvironment: LPVOID, + lpCurrentDirectory: LPCWSTR, + lpStartupInfo: LPSTARTUPINFO, + lpProcessInformation: LPPROCESS_INFORMATION, + ) -> BOOL --- + GetEnvironmentVariableW :: proc(n: LPCWSTR, v: LPWSTR, nsize: DWORD) -> DWORD --- + SetEnvironmentVariableW :: proc(n: LPCWSTR, v: LPCWSTR) -> BOOL --- + GetEnvironmentStringsW :: proc() -> LPWCH --- + FreeEnvironmentStringsW :: proc(env_ptr: LPWCH) -> BOOL --- + GetModuleFileNameW :: proc(hModule: HMODULE, lpFilename: LPWSTR, nSize: DWORD) -> DWORD --- + CreateDirectoryW :: proc( + lpPathName: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL --- + DeleteFileW :: proc(lpPathName: LPCWSTR) -> BOOL --- + GetCurrentDirectoryW :: proc(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD --- + SetCurrentDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL --- + WideCharToMultiByte :: proc( + CodePage: UINT, + dwFlags: DWORD, + lpWideCharStr: LPCWSTR, + cchWideChar: c_int, + lpMultiByteStr: LPSTR, + cbMultiByte: c_int, + lpDefaultChar: LPCSTR, + lpUsedDefaultChar: LPBOOL, + ) -> c_int --- + MultiByteToWideChar :: proc( + CodePage: UINT, + dwFlags: DWORD, + lpMultiByteStr: LPSTR, + cbMultiByte: c_int, + lpWideCharStr: LPWSTR, + cchWideChar: c_int, + ) -> c_int --- + DuplicateHandle :: proc( + hSourceProcessHandle: HANDLE, + hSourceHandle: HANDLE, + hTargetProcessHandle: HANDLE, + lpTargetHandle: LPHANDLE, + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwOptions: DWORD, + ) -> BOOL --- + ReadFile :: proc( + hFile: HANDLE, + lpBuffer: LPVOID, + nNumberOfBytesToRead: DWORD, + lpNumberOfBytesRead: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL --- + WriteFile :: proc( + hFile: HANDLE, + lpBuffer: LPVOID, + nNumberOfBytesToWrite: DWORD, + lpNumberOfBytesWritten: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL --- + CloseHandle :: proc(hObject: HANDLE) -> BOOL --- + MoveFileExW :: proc(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: DWORD) + -> BOOL --- + SetFilePointerEx :: proc( + hFile: HANDLE, + liDistanceToMove: LARGE_INTEGER, + lpNewFilePointer: PLARGE_INTEGER, + dwMoveMethod: DWORD, + ) -> BOOL --- + FlushFileBuffers :: proc(hFile: HANDLE) -> BOOL --- + CreateFileW :: proc( + lpFileName: LPCWSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE, + ) -> HANDLE --- + + FindFirstFileW :: proc(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE --- + FindNextFileW :: proc(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL --- + FindClose :: proc(findFile: HANDLE) -> BOOL --- + GetModuleHandleW :: proc(lpModuleName: LPCWSTR) -> HMODULE --- + GetSystemTimeAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) --- + CreateEventW :: proc( + lpEventAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: LPCWSTR, + ) -> HANDLE --- + WaitForMultipleObjects :: proc( + nCount: DWORD, + lpHandles: ^HANDLE, + bWaitAll: BOOL, + dwMilliseconds: DWORD, + ) -> DWORD --- + CreateNamedPipeW :: proc( + lpName: LPCWSTR, + dwOpenMode: DWORD, + dwPipeMode: DWORD, + nMaxInstances: DWORD, + nOutBufferSize: DWORD, + nInBufferSize: DWORD, + nDefaultTimeOut: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> HANDLE --- + CancelIo :: proc(handle: HANDLE) -> BOOL --- + GetOverlappedResult :: proc( + hFile: HANDLE, + lpOverlapped: LPOVERLAPPED, + lpNumberOfBytesTransferred: LPDWORD, + bWait: BOOL, + ) -> BOOL --- + GetProcessHeap :: proc() -> HANDLE --- + HeapAlloc :: proc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID --- + HeapReAlloc :: proc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID --- + HeapFree :: proc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL --- + + InitializeSRWLock :: proc(SRWLock: ^SRWLOCK) --- + AcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) --- + TryAcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) -> BOOL --- + ReleaseSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) --- + + InitializeConditionVariable :: proc(ConditionVariable: ^CONDITION_VARIABLE) --- + WakeConditionVariable :: proc(ConditionVariable: ^CONDITION_VARIABLE) --- + WakeAllConditionVariable :: proc(ConditionVariable: ^CONDITION_VARIABLE) --- + SleepConditionVariableCS :: proc(ConditionVariable: ^CONDITION_VARIABLE, CriticalSection: ^CRITICAL_SECTION, dwMilliseconds: DWORD) -> BOOL --- + SleepConditionVariableSRW :: proc(ConditionVariable: ^CONDITION_VARIABLE, SRWLock: ^SRWLOCK, dwMilliseconds: DWORD, Flags: LONG) -> BOOL --- + + + GetFileType :: proc(file_handle: HANDLE) -> DWORD --- + SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: LONG, distance_to_move_high: ^LONG, move_method: DWORD) -> DWORD --- + GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^LARGE_INTEGER) -> BOOL --- + GetFileAttributesExW :: proc(lpFileName: LPCWSTR, fInfoLevelId: GET_FILEEX_INFO_LEVELS, lpFileInformation: LPVOID) -> BOOL --- + GetSystemInfo :: proc(system_info: ^SYSTEM_INFO) --- + GetVersionExW :: proc(osvi: ^OSVERSIONINFOEXW) --- + + LoadLibraryA:: proc(c_str: LPCSTR) -> HMODULE --- + LoadLibraryW:: proc(c_str: LPCWSTR) -> HMODULE --- + FreeLibrary:: proc(h: HMODULE) -> BOOL --- + GetProcAddress:: proc(h: HMODULE, c_str: LPCSTR) -> rawptr --- +} diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin new file mode 100644 index 000000000..b0c7e2dd9 --- /dev/null +++ b/core/sys/windows/shell32.odin @@ -0,0 +1,8 @@ +package sys_windows + +foreign import shell32 "system:Shell32.lib" + +@(default_calling_convention = "std") +foreign shell32 { + CommandLineToArgvW :: proc(cmd_list: wstring, num_args: ^c_int) -> ^wstring --- +} diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin new file mode 100644 index 000000000..a766472aa --- /dev/null +++ b/core/sys/windows/types.odin @@ -0,0 +1,698 @@ +package sys_windows + +import "core:c" + +c_char :: c.char; +c_int :: c.int; +c_uint :: c.uint; +c_long :: c.long; +c_longlong :: c.longlong; +c_ulong :: c.ulong; +c_ushort :: c.ushort; +size_t :: c.size_t; +wchar_t :: c.wchar_t; + +DWORD :: c_ulong; +HANDLE :: distinct LPVOID; +HINSTANCE :: HANDLE; +HMODULE :: distinct HINSTANCE; +HRESULT :: distinct LONG; +BOOL :: distinct b32; +BYTE :: distinct u8; +BOOLEAN :: distinct b8; +GROUP :: distinct c_uint; +LARGE_INTEGER :: distinct c_longlong; +LONG :: c_long; +UINT :: c_uint; +WCHAR :: wchar_t; +USHORT :: c_ushort; +SIZE_T :: uint; +WORD :: u16; +CHAR :: c_char; +ULONG_PTR :: uint; +DWORD_PTR :: ULONG_PTR; +ULONG :: c_ulong; +UCHAR :: BYTE; + +wstring :: ^WCHAR; + +LPBOOL :: ^BOOL; +LPBYTE :: ^BYTE; +LPCSTR :: cstring; +LPCWSTR :: wstring; +LPDWORD :: ^DWORD; +LPHANDLE :: ^HANDLE; +LPOVERLAPPED :: ^OVERLAPPED; +LPPROCESS_INFORMATION :: ^PROCESS_INFORMATION; +LPSECURITY_ATTRIBUTES :: ^SECURITY_ATTRIBUTES; +LPSTARTUPINFO :: ^STARTUPINFO; +LPVOID :: rawptr; +LPWCH :: ^WCHAR; +LPWIN32_FIND_DATAW :: ^WIN32_FIND_DATAW; +LPWSADATA :: ^WSADATA; +LPWSAPROTOCOL_INFO :: ^WSAPROTOCOL_INFO; +LPSTR :: ^CHAR; +LPWSTR :: ^WCHAR; +LPFILETIME :: ^FILETIME; +LPWSABUF :: ^WSABUF; +LPWSAOVERLAPPED :: distinct rawptr; +LPWSAOVERLAPPED_COMPLETION_ROUTINE :: distinct rawptr; +LPCVOID :: rawptr; + +PCONDITION_VARIABLE :: ^CONDITION_VARIABLE; +PLARGE_INTEGER :: ^LARGE_INTEGER; +PSRWLOCK :: ^SRWLOCK; + +SOCKET :: distinct rawptr; // TODO +socklen_t :: c_int; +ADDRESS_FAMILY :: USHORT; + +TRUE :: BOOL(true); +FALSE :: BOOL(false); + +FILE_ATTRIBUTE_READONLY: DWORD : 0x00000001; +FILE_ATTRIBUTE_HIDDEN: DWORD : 0x00000002; +FILE_ATTRIBUTE_SYSTEM: DWORD : 0x00000004; +FILE_ATTRIBUTE_DIRECTORY: DWORD : 0x00000010; +FILE_ATTRIBUTE_ARCHIVE: DWORD : 0x00000020; +FILE_ATTRIBUTE_DEVICE: DWORD : 0x00000040; +FILE_ATTRIBUTE_NORMAL: DWORD : 0x00000080; +FILE_ATTRIBUTE_TEMPORARY: DWORD : 0x00000100; +FILE_ATTRIBUTE_SPARSE_FILE: DWORD : 0x00000200; +FILE_ATTRIBUTE_REPARSE_Point: DWORD : 0x00000400; +FILE_ATTRIBUTE_COMPRESSED: DWORD : 0x00000800; +FILE_ATTRIBUTE_OFFLINE: DWORD : 0x00001000; +FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: DWORD : 0x00002000; +FILE_ATTRIBUTE_ENCRYPTED: DWORD : 0x00004000; + +FILE_SHARE_READ: DWORD : 0x00000001; +FILE_SHARE_WRITE: DWORD : 0x00000002; +FILE_SHARE_DELETE: DWORD : 0x00000004; +FILE_GENERIC_ALL: DWORD : 0x10000000; +FILE_GENERIC_EXECUTE: DWORD : 0x20000000; +FILE_GENERIC_READ: DWORD : 0x80000000; + +CREATE_NEW: DWORD : 1; +CREATE_ALWAYS: DWORD : 2; +OPEN_ALWAYS: DWORD : 4; +OPEN_EXISTING: DWORD : 3; +TRUNCATE_EXISTING: DWORD : 5; + + + +FILE_WRITE_DATA: DWORD : 0x00000002; +FILE_APPEND_DATA: DWORD : 0x00000004; +FILE_WRITE_EA: DWORD : 0x00000010; +FILE_WRITE_ATTRIBUTES: DWORD : 0x00000100; +READ_CONTROL: DWORD : 0x00020000; +SYNCHRONIZE: DWORD : 0x00100000; +GENERIC_READ: DWORD : 0x80000000; +GENERIC_WRITE: DWORD : 0x40000000; +STANDARD_RIGHTS_WRITE: DWORD : READ_CONTROL; +FILE_GENERIC_WRITE: DWORD : STANDARD_RIGHTS_WRITE + | FILE_WRITE_DATA + | FILE_WRITE_ATTRIBUTES + | FILE_WRITE_EA + | FILE_APPEND_DATA + | SYNCHRONIZE; + +FILE_FLAG_OPEN_REPARSE_POINT: DWORD : 0x00200000; +FILE_FLAG_BACKUP_SEMANTICS: DWORD : 0x02000000; +SECURITY_SQOS_PRESENT: DWORD : 0x00100000; + +FIONBIO: c_ulong : 0x8004667e; + + +GET_FILEEX_INFO_LEVELS :: distinct i32; +GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0; +GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1; + + +WIN32_FIND_DATAW :: struct { + dwFileAttributes: DWORD, + ftCreationTime: FILETIME, + ftLastAccessTime: FILETIME, + ftLastWriteTime: FILETIME, + nFileSizeHigh: DWORD, + nFileSizeLow: DWORD, + dwReserved0: DWORD, + dwReserved1: DWORD, + cFileName: [260]wchar_t, // #define MAX_PATH 260 + cAlternateFileName: [14]wchar_t, +} + +WSA_FLAG_OVERLAPPED: DWORD : 0x01; +WSA_FLAG_NO_HANDLE_INHERIT: DWORD : 0x80; + +WSADESCRIPTION_LEN :: 256; +WSASYS_STATUS_LEN :: 128; +WSAPROTOCOL_LEN: DWORD : 255; +INVALID_SOCKET :: SOCKET(~uintptr(0)); + +WSAEACCES: c_int : 10013; +WSAEINVAL: c_int : 10022; +WSAEWOULDBLOCK: c_int : 10035; +WSAEPROTOTYPE: c_int : 10041; +WSAEADDRINUSE: c_int : 10048; +WSAEADDRNOTAVAIL: c_int : 10049; +WSAECONNABORTED: c_int : 10053; +WSAECONNRESET: c_int : 10054; +WSAENOTCONN: c_int : 10057; +WSAESHUTDOWN: c_int : 10058; +WSAETIMEDOUT: c_int : 10060; +WSAECONNREFUSED: c_int : 10061; + +MAX_PROTOCOL_CHAIN: DWORD : 7; + +MAXIMUM_REPARSE_DATA_BUFFER_SIZE :: 16 * 1024; +FSCTL_GET_REPARSE_POINT: DWORD : 0x900a8; +IO_REPARSE_TAG_SYMLINK: DWORD : 0xa000000c; +IO_REPARSE_TAG_MOUNT_POINT: DWORD : 0xa0000003; +SYMLINK_FLAG_RELATIVE: DWORD : 0x00000001; +FSCTL_SET_REPARSE_POINT: DWORD : 0x900a4; + +SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD : 0x1; +SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD : 0x2; + +STD_INPUT_HANDLE: DWORD : ~DWORD(0) -10 + 1; +STD_OUTPUT_HANDLE: DWORD : ~DWORD(0) -11 + 1; +STD_ERROR_HANDLE: DWORD : ~DWORD(0) -12 + 1; + +PROGRESS_CONTINUE: DWORD : 0; + +ERROR_FILE_NOT_FOUND: DWORD : 2; +ERROR_PATH_NOT_FOUND: DWORD : 3; +ERROR_ACCESS_DENIED: DWORD : 5; +ERROR_INVALID_HANDLE: DWORD : 6; +ERROR_NO_MORE_FILES: DWORD : 18; +ERROR_HANDLE_EOF: DWORD : 38; +ERROR_FILE_EXISTS: DWORD : 80; +ERROR_INVALID_PARAMETER: DWORD : 87; +ERROR_BROKEN_PIPE: DWORD : 109; +ERROR_CALL_NOT_IMPLEMENTED: DWORD : 120; +ERROR_INSUFFICIENT_BUFFER: DWORD : 122; +ERROR_ALREADY_EXISTS: DWORD : 183; +ERROR_NO_DATA: DWORD : 232; +ERROR_ENVVAR_NOT_FOUND: DWORD : 203; +ERROR_OPERATION_ABORTED: DWORD : 995; +ERROR_IO_PENDING: DWORD : 997; +ERROR_TIMEOUT: DWORD : 0x5B4; + +E_NOTIMPL :: HRESULT(-0x7fff_bfff); // 0x8000_4001 + +INVALID_HANDLE :: HANDLE(~uintptr(0)); + +FACILITY_NT_BIT: DWORD : 0x1000_0000; + +FORMAT_MESSAGE_FROM_SYSTEM: DWORD : 0x00001000; +FORMAT_MESSAGE_FROM_HMODULE: DWORD : 0x00000800; +FORMAT_MESSAGE_IGNORE_INSERTS: DWORD : 0x00000200; + +TLS_OUT_OF_INDEXES: DWORD : 0xFFFFFFFF; + +DLL_THREAD_DETACH: DWORD : 3; +DLL_PROCESS_DETACH: DWORD : 0; +CREATE_SUSPENDED :: DWORD(0x00000004); + +INFINITE :: ~DWORD(0); + +DUPLICATE_SAME_ACCESS: DWORD : 0x00000002; + +CONDITION_VARIABLE_INIT :: CONDITION_VARIABLE{}; +SRWLOCK_INIT :: SRWLOCK{}; + +DETACHED_PROCESS: DWORD : 0x00000008; +CREATE_NEW_PROCESS_GROUP: DWORD : 0x00000200; +CREATE_UNICODE_ENVIRONMENT: DWORD : 0x00000400; +STARTF_USESTDHANDLES: DWORD : 0x00000100; + +AF_INET: c_int : 2; +AF_INET6: c_int : 23; +SD_BOTH: c_int : 2; +SD_RECEIVE: c_int : 0; +SD_SEND: c_int : 1; +SOCK_DGRAM: c_int : 2; +SOCK_STREAM: c_int : 1; +SOL_SOCKET: c_int : 0xffff; +SO_RCVTIMEO: c_int : 0x1006; +SO_SNDTIMEO: c_int : 0x1005; +SO_REUSEADDR: c_int : 0x0004; +IPPROTO_IP: c_int : 0; +IPPROTO_TCP: c_int : 6; +IPPROTO_IPV6: c_int : 41; +TCP_NODELAY: c_int : 0x0001; +IP_TTL: c_int : 4; +IPV6_V6ONLY: c_int : 27; +SO_ERROR: c_int : 0x1007; +SO_BROADCAST: c_int : 0x0020; +IP_MULTICAST_LOOP: c_int : 11; +IPV6_MULTICAST_LOOP: c_int : 11; +IP_MULTICAST_TTL: c_int : 10; +IP_ADD_MEMBERSHIP: c_int : 12; +IP_DROP_MEMBERSHIP: c_int : 13; +IPV6_ADD_MEMBERSHIP: c_int : 12; +IPV6_DROP_MEMBERSHIP: c_int : 13; +MSG_PEEK: c_int : 0x2; + +ip_mreq :: struct { + imr_multiaddr: in_addr, + imr_interface: in_addr, +} + +ipv6_mreq :: struct { + ipv6mr_multiaddr: in6_addr, + ipv6mr_interface: c_uint, +} + +VOLUME_NAME_DOS: DWORD : 0x0; +MOVEFILE_REPLACE_EXISTING: DWORD : 1; + +FILE_BEGIN: DWORD : 0; +FILE_CURRENT: DWORD : 1; +FILE_END: DWORD : 2; + +WAIT_OBJECT_0: DWORD : 0x00000000; +WAIT_TIMEOUT: DWORD : 258; +WAIT_FAILED: DWORD : 0xFFFFFFFF; + +PIPE_ACCESS_INBOUND: DWORD : 0x00000001; +PIPE_ACCESS_OUTBOUND: DWORD : 0x00000002; +FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD : 0x00080000; +FILE_FLAG_OVERLAPPED: DWORD : 0x40000000; +PIPE_WAIT: DWORD : 0x00000000; +PIPE_TYPE_BYTE: DWORD : 0x00000000; +PIPE_REJECT_REMOTE_CLIENTS: DWORD : 0x00000008; +PIPE_READMODE_BYTE: DWORD : 0x00000000; + +FD_SETSIZE :: 64; + +STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD : 0x00010000; + +INVALID_SET_FILE_POINTER :: ~DWORD(0); + +HEAP_ZERO_MEMORY: DWORD : 0x00000008; + +HANDLE_FLAG_INHERIT: DWORD : 0x00000001; +HANDLE_FLAG_PROTECT_FROM_CLOSE :: 0x00000002; + +TOKEN_READ: DWORD : 0x20008; + +CP_ACP :: 0; // default to ANSI code page +CP_OEMCP :: 1; // default to OEM code page +CP_MACCP :: 2; // default to MAC code page +CP_THREAD_ACP :: 3; // current thread's ANSI code page +CP_SYMBOL :: 42; // SYMBOL translations +CP_UTF7 :: 65000; // UTF-7 translation +CP_UTF8 :: 65001; // UTF-8 translation + +MB_ERR_INVALID_CHARS :: 8; +WC_ERR_INVALID_CHARS :: 128; + + +MAX_PATH :: 0x00000104; +MAX_PATH_WIDE :: 0x8000; + +INVALID_FILE_ATTRIBUTES :: -1; + +FILE_TYPE_DISK :: 0x0001; +FILE_TYPE_CHAR :: 0x0002; +FILE_TYPE_PIPE :: 0x0003; + + + +when size_of(uintptr) == 4 { + WSADATA :: struct { + wVersion: WORD, + wHighVersion: WORD, + szDescription: [WSADESCRIPTION_LEN + 1]u8, + szSystemStatus: [WSASYS_STATUS_LEN + 1]u8, + iMaxSockets: u16, + iMaxUdpDg: u16, + lpVendorInfo: ^u8, + } +} else when size_of(uintptr) == 8 { + WSADATA :: struct { + wVersion: WORD, + wHighVersion: WORD, + iMaxSockets: u16, + iMaxUdpDg: u16, + lpVendorInfo: ^u8, + szDescription: [WSADESCRIPTION_LEN + 1]u8, + szSystemStatus: [WSASYS_STATUS_LEN + 1]u8, + } +} + +WSABUF :: struct { + len: ULONG, + buf: ^CHAR, +} + +WSAPROTOCOL_INFO :: struct { + dwServiceFlags1: DWORD, + dwServiceFlags2: DWORD, + dwServiceFlags3: DWORD, + dwServiceFlags4: DWORD, + dwProviderFlags: DWORD, + ProviderId: GUID, + dwCatalogEntryId: DWORD, + ProtocolChain: WSAPROTOCOLCHAIN, + iVersion: c_int, + iAddressFamily: c_int, + iMaxSockAddr: c_int, + iMinSockAddr: c_int, + iSocketType: c_int, + iProtocol: c_int, + iProtocolMaxOffset: c_int, + iNetworkByteOrder: c_int, + iSecurityScheme: c_int, + dwMessageSize: DWORD, + dwProviderReserved: DWORD, + szProtocol: [WSAPROTOCOL_LEN + 1]u16, +} + +WIN32_FILE_ATTRIBUTE_DATA :: struct { + dwFileAttributes: DWORD, + ftCreationTime: FILETIME, + ftLastAccessTime: FILETIME, + ftLastWriteTime: FILETIME, + nFileSizeHigh: DWORD, + nFileSizeLow: DWORD, +} + +FILE_INFO_BY_HANDLE_CLASS :: enum c_int { + FileBasicInfo = 0, + FileStandardInfo = 1, + FileNameInfo = 2, + FileRenameInfo = 3, + FileDispositionInfo = 4, + FileAllocationInfo = 5, + FileEndOfFileInfo = 6, + FileStreamInfo = 7, + FileCompressionInfo = 8, + FileAttributeTagInfo = 9, + FileIdBothDirectoryInfo = 10, // 0xA + FileIdBothDirectoryRestartInfo = 11, // 0xB + FileIoPriorityHintInfo = 12, // 0xC + FileRemoteProtocolInfo = 13, // 0xD + FileFullDirectoryInfo = 14, // 0xE + FileFullDirectoryRestartInfo = 15, // 0xF + FileStorageInfo = 16, // 0x10 + FileAlignmentInfo = 17, // 0x11 + FileIdInfo = 18, // 0x12 + FileIdExtdDirectoryInfo = 19, // 0x13 + FileIdExtdDirectoryRestartInfo = 20, // 0x14 + MaximumFileInfoByHandlesClass, +} + +FILE_BASIC_INFO :: struct { + CreationTime: LARGE_INTEGER, + LastAccessTime: LARGE_INTEGER, + LastWriteTime: LARGE_INTEGER, + ChangeTime: LARGE_INTEGER, + FileAttributes: DWORD, +} + +FILE_END_OF_FILE_INFO :: struct { + EndOfFile: LARGE_INTEGER, +} + +REPARSE_DATA_BUFFER :: struct { + ReparseTag: c_uint, + ReparseDataLength: c_ushort, + Reserved: c_ushort, + rest: [0]byte, +} + +SYMBOLIC_LINK_REPARSE_BUFFER :: struct { + SubstituteNameOffset: c_ushort, + SubstituteNameLength: c_ushort, + PrintNameOffset: c_ushort, + PrintNameLength: c_ushort, + Flags: c_ulong, + PathBuffer: WCHAR, +} + +MOUNT_POINT_REPARSE_BUFFER :: struct { + SubstituteNameOffset: c_ushort, + SubstituteNameLength: c_ushort, + PrintNameOffset: c_ushort, + PrintNameLength: c_ushort, + PathBuffer: WCHAR, +} + +LPPROGRESS_ROUTINE :: #type proc "stdcall" ( + TotalFileSize: LARGE_INTEGER, + TotalBytesTransferred: LARGE_INTEGER, + StreamSize: LARGE_INTEGER, + StreamBytesTransferred: LARGE_INTEGER, + dwStreamNumber: DWORD, + dwCallbackReason: DWORD, + hSourceFile: HANDLE, + hDestinationFile: HANDLE, + lpData: LPVOID, +) -> DWORD; + +CONDITION_VARIABLE :: struct { + ptr: LPVOID, +} +SRWLOCK :: struct { + ptr: LPVOID, +} +CRITICAL_SECTION :: struct { + CriticalSectionDebug: LPVOID, + LockCount: LONG, + RecursionCount: LONG, + OwningThread: HANDLE, + LockSemaphore: HANDLE, + SpinCount: ULONG_PTR, +} + +REPARSE_MOUNTPOINT_DATA_BUFFER :: struct { + ReparseTag: DWORD, + ReparseDataLength: DWORD, + Reserved: WORD, + ReparseTargetLength: WORD, + ReparseTargetMaximumLength: WORD, + Reserved1: WORD, + ReparseTarget: WCHAR, +} + +GUID :: struct { + Data1: DWORD, + Data2: WORD, + Data3: WORD, + Data4: [8]BYTE, +} + +WSAPROTOCOLCHAIN :: struct { + ChainLen: c_int, + ChainEntries: [MAX_PROTOCOL_CHAIN]DWORD, +} + +SECURITY_ATTRIBUTES :: struct { + nLength: DWORD, + lpSecurityDescriptor: LPVOID, + bInheritHandle: BOOL, +} + +PROCESS_INFORMATION :: struct { + hProcess: HANDLE, + hThread: HANDLE, + dwProcessId: DWORD, + dwThreadId: DWORD, +} + +STARTUPINFO :: struct { + cb: DWORD, + lpReserved: LPWSTR, + lpDesktop: LPWSTR, + lpTitle: LPWSTR, + dwX: DWORD, + dwY: DWORD, + dwXSize: DWORD, + dwYSize: DWORD, + dwXCountChars: DWORD, + dwYCountCharts: DWORD, + dwFillAttribute: DWORD, + dwFlags: DWORD, + wShowWindow: WORD, + cbReserved2: WORD, + lpReserved2: LPBYTE, + hStdInput: HANDLE, + hStdOutput: HANDLE, + hStdError: HANDLE, +} + +SOCKADDR :: struct { + sa_family: ADDRESS_FAMILY, + sa_data: [14]CHAR, +} + +FILETIME :: struct { + dwLowDateTime: DWORD, + dwHighDateTime: DWORD, +} + +OVERLAPPED :: struct { + Internal: ^c_ulong, + InternalHigh: ^c_ulong, + Offset: DWORD, + OffsetHigh: DWORD, + hEvent: HANDLE, +} + +ADDRESS_MODE :: enum c_int { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat, +} + +SOCKADDR_STORAGE_LH :: struct { + ss_family: ADDRESS_FAMILY, + __ss_pad1: [6]CHAR, + __ss_align: i64, + __ss_pad2: [112]CHAR, +} + +ADDRINFOA :: struct { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: ^c_char, + ai_addr: ^SOCKADDR, + ai_next: ^ADDRINFOA, +} + +sockaddr_in :: struct { + sin_family: ADDRESS_FAMILY, + sin_port: USHORT, + sin_addr: in_addr, + sin_zero: [8]CHAR, +} + +sockaddr_in6 :: struct { + sin6_family: ADDRESS_FAMILY, + sin6_port: USHORT, + sin6_flowinfo: c_ulong, + sin6_addr: in6_addr, + sin6_scope_id: c_ulong, +} + +in_addr :: struct { + s_addr: u32, +} + +in6_addr :: struct { + s6_addr: [16]u8, +} + +EXCEPTION_DISPOSITION :: enum c_int { + ExceptionContinueExecution, + ExceptionContinueSearch, + ExceptionNestedException, + ExceptionCollidedUnwind, +} + +fd_set :: struct { + fd_count: c_uint, + fd_array: [FD_SETSIZE]SOCKET, +} + +timeval :: struct { + tv_sec: c_long, + tv_usec: c_long, +} + +EXCEPTION_CONTINUE_SEARCH: LONG : 0; +EXCEPTION_STACK_OVERFLOW: DWORD : 0xc00000fd; +EXCEPTION_MAXIMUM_PARAMETERS :: 15; + +EXCEPTION_RECORD :: struct { + ExceptionCode: DWORD, + ExceptionFlags: DWORD, + ExceptionRecord: ^EXCEPTION_RECORD, + ExceptionAddress: LPVOID, + NumberParameters: DWORD, + ExceptionInformation: [EXCEPTION_MAXIMUM_PARAMETERS]LPVOID, +} + +CONTEXT :: struct{}; // TODO(bill) + +EXCEPTION_POINTERS :: struct { + ExceptionRecord: ^EXCEPTION_RECORD, + ContextRecord: ^CONTEXT, +} + +PVECTORED_EXCEPTION_HANDLER :: #type proc "stdcall" (ExceptionInfo: ^EXCEPTION_POINTERS) -> LONG; + +CONSOLE_READCONSOLE_CONTROL :: struct { + nLength: ULONG, + nInitialChars: ULONG, + dwCtrlWakeupMask: ULONG, + dwControlKeyState: ULONG, +} + +PCONSOLE_READCONSOLE_CONTROL :: ^CONSOLE_READCONSOLE_CONTROL; + +BY_HANDLE_FILE_INFORMATION :: struct { + dwFileAttributes: DWORD, + ftCreationTime: FILETIME, + ftLastAccessTime: FILETIME, + ftLastWriteTime: FILETIME, + dwVolumeSerialNumber: DWORD, + nFileSizeHigh: DWORD, + nFileSizeLow: DWORD, + nNumberOfLinks: DWORD, + nFileIndexHigh: DWORD, + nFileIndexLow: DWORD, +} + +LPBY_HANDLE_FILE_INFORMATION :: ^BY_HANDLE_FILE_INFORMATION; + +FILE_STANDARD_INFO :: struct { + AllocationSize: LARGE_INTEGER, + EndOfFile: LARGE_INTEGER, + NumberOfLinks: DWORD, + DeletePending: BOOLEAN, + Directory: BOOLEAN, +} + + + +// https://docs.microsoft.com/en-gb/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info +SYSTEM_INFO :: struct { + using _: struct #raw_union { + oem_id: DWORD, + using _: struct #raw_union { + wProcessorArchitecture: WORD, + wReserved: WORD, // reserved + }, + }, + dwPageSize: DWORD, + lpMinimumApplicationAddress: LPVOID, + lpMaximumApplicationAddress: LPVOID, + dwActiveProcessorMask: DWORD_PTR, + dwNumberOfProcessors: DWORD, + dwProcessorType: DWORD, + dwAllocationGranularity: DWORD, + wProcessorLevel: WORD, + wProcessorRevision: WORD, +} + +// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw +OSVERSIONINFOEXW :: struct { + os_version_info_size: ULONG, + major_version: ULONG, + minor_version: ULONG, + build_number: ULONG, + platform_id : ULONG, + service_pack_string: [128]WCHAR, + service_pack_major: USHORT, + service_pack_minor: USHORT, + suite_mask: USHORT, + product_type: UCHAR, + reserved: UCHAR, +} diff --git a/core/sys/windows/userenv.odin b/core/sys/windows/userenv.odin new file mode 100644 index 000000000..a701b6ca6 --- /dev/null +++ b/core/sys/windows/userenv.odin @@ -0,0 +1,10 @@ +package sys_windows + +foreign import userenv "system:Userenv.lib" + +@(default_calling_convention="stdcall") +foreign userenv { + GetUserProfileDirectoryW :: proc(hToken: HANDLE, + lpProfileDir: LPWSTR, + lpcchSize: ^DWORD) -> BOOL --- +} diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin new file mode 100644 index 000000000..073a3e854 --- /dev/null +++ b/core/sys/windows/util.odin @@ -0,0 +1,72 @@ +package sys_windows + +utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 { + if len(s) < 1 { + return nil; + } + + b := transmute([]byte)s; + cstr := &b[0]; + n := MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, cstr, i32(len(s)), nil, 0); + if n == 0 { + return nil; + } + + text := make([]u16, n+1, allocator); + + n1 := MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, cstr, i32(len(s)), wstring(&text[0]), i32(n)); + if n1 == 0 { + delete(text, allocator); + return nil; + } + + text[n] = 0; + for n >= 1 && text[n-1] == 0 { + n -= 1; + } + return text[:n]; +} +utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> wstring { + if res := utf8_to_utf16(s, allocator); res != nil { + return wstring(&res[0]); + } + return nil; +} + +wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> string { + if N == 0 { + return ""; + } + + n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), nil, 0, nil, nil); + if n == 0 { + return ""; + } + + // If N == -1 the call to WideCharToMultiByte assume the wide string is null terminated + // and will scan it to find the first null terminated character. The resulting string will + // also null terminated. + // If N != -1 it assumes the wide string is not null terminated and the resulting string + // will not be null terminated, we therefore have to force it to be null terminated manually. + text := make([]byte, n+1 if N != -1 else n, allocator); + + if n1 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), &text[0], n, nil, nil); n1 == 0 { + delete(text, allocator); + return ""; + } + + for i in 0.. string { + if len(s) == 0 do return ""; + return wstring_to_utf8(cast(wstring)&s[0], len(s), allocator); +} + diff --git a/core/sys/windows/ws2_32.odin b/core/sys/windows/ws2_32.odin new file mode 100644 index 000000000..0cd462623 --- /dev/null +++ b/core/sys/windows/ws2_32.odin @@ -0,0 +1,99 @@ +package sys_windows + +foreign import ws2_32 "system:Ws2_32.lib" + +@(default_calling_convention="stdcall") +foreign ws2_32 { + WSAStartup :: proc(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int --- + WSACleanup :: proc() -> c_int --- + WSAGetLastError :: proc() -> c_int --- + WSADuplicateSocketW :: proc( + s: SOCKET, + dwProcessId: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFO, + ) -> c_int --- + WSASend :: proc( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesSent: LPDWORD, + dwFlags: DWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int --- + WSARecv :: proc( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesRecvd: LPDWORD, + lpFlags: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int --- + WSASocketW :: proc( + af: c_int, + kind: c_int, + protocol: c_int, + lpProtocolInfo: LPWSAPROTOCOL_INFO, + g: GROUP, + dwFlags: DWORD, + ) -> SOCKET --- + + ioctlsocket :: proc(s: SOCKET, cmd: c_long, argp: ^c_ulong) -> c_int --- + closesocket :: proc(socket: SOCKET) -> c_int --- + recv :: proc(socket: SOCKET, buf: rawptr, len: c_int, flags: c_int) -> c_int --- + send :: proc(socket: SOCKET, buf: rawptr, len: c_int, flags: c_int) -> c_int --- + recvfrom :: proc( + socket: SOCKET, + buf: rawptr, + len: c_int, + flags: c_int, + addr: ^SOCKADDR, + addrlen: ^c_int, + ) -> c_int --- + sendto :: proc( + socket: SOCKET, + buf: rawptr, + len: c_int, + flags: c_int, + addr: ^SOCKADDR, + addrlen: c_int, + ) -> c_int --- + shutdown :: proc(socket: SOCKET, how: c_int) -> c_int --- + accept :: proc(socket: SOCKET, address: ^SOCKADDR, address_len: ^c_int) -> SOCKET --- + + setsockopt :: proc( + s: SOCKET, + level: c_int, + optname: c_int, + optval: rawptr, + optlen: c_int, + ) -> c_int --- + getsockname :: proc(socket: SOCKET, address: ^SOCKADDR, address_len: ^c_int) -> c_int --- + getpeername :: proc(socket: SOCKET, address: ^SOCKADDR, address_len: ^c_int) -> c_int --- + bind :: proc(socket: SOCKET, address: ^SOCKADDR, address_len: socklen_t) -> c_int --- + listen :: proc(socket: SOCKET, backlog: c_int) -> c_int --- + connect :: proc(socket: SOCKET, address: ^SOCKADDR, len: c_int) -> c_int --- + getaddrinfo :: proc( + node: ^c_char, + service: ^c_char, + hints: ^ADDRINFOA, + res: ^ADDRINFOA, + ) -> c_int --- + freeaddrinfo :: proc(res: ^ADDRINFOA) --- + select :: proc( + nfds: c_int, + readfds: ^fd_set, + writefds: ^fd_set, + exceptfds: ^fd_set, + timeout: ^timeval, + ) -> c_int --- + getsockopt :: proc( + s: SOCKET, + level: c_int, + optname: c_int, + optval: ^c_char, + optlen: ^c_int, + ) -> c_int --- + +} diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 3f4973307..e1627ad2c 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -2,11 +2,11 @@ package thread import "core:runtime" import "core:sync" -import "core:sys/win32" +import win32 "core:sys/windows" Thread_Os_Specific :: struct { - win32_thread: win32.Handle, - win32_thread_id: u32, + win32_thread: win32.HANDLE, + win32_thread_id: win32.DWORD, done: bool, // see note in `is_done` } @@ -24,9 +24,10 @@ _thread_priority_map := map[Thread_Priority]i32{ }; create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread { - win32_thread_id: u32; + win32_thread_id: win32.DWORD; - __windows_thread_entry_proc :: proc "c" (t: ^Thread) -> i32 { + __windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD { + t := (^Thread)(t_); context = runtime.default_context(); c := context; if ic, ok := t.init_context.?; ok { @@ -47,10 +48,9 @@ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^T } - win32_thread_proc := rawptr(__windows_thread_entry_proc); thread := new(Thread); - win32_thread := win32.create_thread(nil, 0, win32_thread_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id); + win32_thread := win32.CreateThread(nil, 0, __windows_thread_entry_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id); if win32_thread == nil { free(thread); return nil; @@ -60,14 +60,14 @@ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^T thread.win32_thread_id = win32_thread_id; thread.init_context = context; - ok := win32.set_thread_priority(win32_thread, _thread_priority_map[priority]); + ok := win32.SetThreadPriority(win32_thread, _thread_priority_map[priority]); assert(ok == true); return thread; } start :: proc(using thread: ^Thread) { - win32.resume_thread(win32_thread); + win32.ResumeThread(win32_thread); } is_done :: proc(using thread: ^Thread) -> bool { @@ -79,8 +79,8 @@ is_done :: proc(using thread: ^Thread) -> bool { join :: proc(using thread: ^Thread) { if win32_thread != win32.INVALID_HANDLE { - win32.wait_for_single_object(win32_thread, win32.INFINITE); - win32.close_handle(win32_thread); + win32.WaitForSingleObject(win32_thread, win32.INFINITE); + win32.CloseHandle(win32_thread); win32_thread = win32.INVALID_HANDLE; } } @@ -90,10 +90,10 @@ destroy :: proc(thread: ^Thread) { free(thread); } -terminate :: proc(using thread : ^Thread, exit_code : u32) { - win32.terminate_thread(win32_thread, exit_code); +terminate :: proc(using thread : ^Thread, exit_code: u32) { + win32.TerminateThread(win32_thread, exit_code); } yield :: proc() { - win32.sleep(0); + win32.Sleep(0); } diff --git a/core/time/time_windows.odin b/core/time/time_windows.odin index 32b930065..a95bce2ac 100644 --- a/core/time/time_windows.odin +++ b/core/time/time_windows.odin @@ -1,20 +1,20 @@ package time -import "core:sys/win32" +import win32 "core:sys/windows" IS_SUPPORTED :: true; now :: proc() -> Time { - file_time: win32.Filetime; + file_time: win32.FILETIME; - win32.get_system_time_as_file_time(&file_time); + win32.GetSystemTimeAsFileTime(&file_time); - ft := i64(u64(file_time.lo) | u64(file_time.hi) << 32); + ft := i64(u64(file_time.dwLowDateTime) | u64(file_time.dwHighDateTime) << 32); ns := (ft - 0x019db1ded53e8000) * 100; return Time{_nsec=ns}; } sleep :: proc(d: Duration) { - win32.sleep(u32(d/Millisecond)); + win32.Sleep(win32.DWORD(d/Millisecond)); } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 560518df9..9e719756e 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -505,9 +505,13 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, typedef bool TypeCheckSig(Type *t); bool sig_compare(TypeCheckSig *a, Type *x, Type *y) { + x = core_type(x); + y = core_type(y); return (a(x) && a(y)); } bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) { + x = core_type(x); + y = core_type(y); if (a == b) { return sig_compare(a, x, y); } @@ -542,6 +546,13 @@ bool signature_parameter_similar_enough(Type *x, Type *y) { return true; } + if (sig_compare(is_type_proc, is_type_proc, x, y)) { + return true; + } + if (sig_compare(is_type_proc, is_type_pointer, x, y)) { + return true; + } + return are_types_identical(x, y); }