Browse Source

Begin migration from sys/win32 to sys/windows

gingerBill 5 years ago
parent
commit
6bd05ef5d7

+ 4 - 4
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;
 }

+ 59 - 59
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;
 }
 

+ 90 - 101
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 {
+			condition_signal(&ch.w_cond);
+		}
+	} else {
+		assert(ch.w_waiting > 0);
+		assert(len(ch.queue) > 0);
+		msg, ok = pop_front_safe(&ch.queue);
 
-	if ch.w_waiting > 0 {
+		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;
-}

+ 47 - 33
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);
+}
+
+
+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);
 }
 
-@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_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);
 }

+ 2 - 2
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);
 

+ 4 - 4
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) ---;
 

+ 12 - 0
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 ---
+}

+ 10 - 0
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 ---
+}

+ 263 - 0
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 ---
+}

+ 8 - 0
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 ---
+}

+ 698 - 0
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,
+}

+ 10 - 0
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 ---
+}

+ 72 - 0
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..<n {
+		if text[i] == 0 {
+			n = i;
+			break;
+		}
+	}
+
+	return string(text[:n]);
+}
+
+utf16_to_utf8 :: proc(s: []u16, allocator := context.temp_allocator) -> string {
+	if len(s) == 0 do return "";
+	return wstring_to_utf8(cast(wstring)&s[0], len(s), allocator);
+}
+

+ 99 - 0
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 ---
+
+}

+ 14 - 14
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);
 }

+ 5 - 5
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));
 }

+ 11 - 0
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);
 }