mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Begin migration from sys/win32 to sys/windows
This commit is contained in:
@@ -1,25 +1,25 @@
|
|||||||
// +build windows
|
// +build windows
|
||||||
package dynlib
|
package dynlib
|
||||||
|
|
||||||
import "core:sys/win32"
|
import win32 "core:sys/windows"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
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
|
// 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);
|
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;
|
return handle, handle != nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
unload_library :: proc(library: Library) -> bool {
|
unload_library :: proc(library: Library) -> bool {
|
||||||
ok := win32.free_library(cast(win32.Hmodule)library);
|
ok := win32.FreeLibrary(cast(win32.HMODULE)library);
|
||||||
return bool(ok);
|
return bool(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
||||||
c_str := strings.clone_to_cstring(symbol, context.temp_allocator);
|
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;
|
found = ptr != nil;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+59
-59
@@ -1,7 +1,7 @@
|
|||||||
// +build windows
|
// +build windows
|
||||||
package os
|
package os
|
||||||
|
|
||||||
import "core:sys/win32"
|
import win32 "core:sys/windows"
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
|
||||||
OS :: "windows";
|
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);
|
share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
|
||||||
sa: ^win32.Security_Attributes = nil;
|
sa: ^win32.SECURITY_ATTRIBUTES = nil;
|
||||||
sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = true};
|
sa_inherit := win32.SECURITY_ATTRIBUTES{nLength = size_of(win32.SECURITY_ATTRIBUTES), bInheritHandle = true};
|
||||||
if mode&O_CLOEXEC == 0 {
|
if mode&O_CLOEXEC == 0 {
|
||||||
sa = &sa_inherit;
|
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;
|
create_mode = win32.OPEN_EXISTING;
|
||||||
}
|
}
|
||||||
wide_path := win32.utf8_to_wstring(path);
|
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;
|
if handle != INVALID_HANDLE do return handle, ERROR_NONE;
|
||||||
|
|
||||||
err := Errno(win32.get_last_error());
|
err := Errno(win32.GetLastError());
|
||||||
return INVALID_HANDLE, err;
|
return INVALID_HANDLE, err;
|
||||||
}
|
}
|
||||||
|
|
||||||
close :: proc(fd: Handle) -> Errno {
|
close :: proc(fd: Handle) -> Errno {
|
||||||
if win32.close_handle(win32.Handle(fd)) == 0 {
|
if !win32.CloseHandle(win32.HANDLE(fd)) {
|
||||||
return Errno(win32.get_last_error());
|
return Errno(win32.GetLastError());
|
||||||
}
|
}
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
@@ -123,18 +123,18 @@ close :: proc(fd: Handle) -> Errno {
|
|||||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
if len(data) == 0 do return 0, ERROR_NONE;
|
if len(data) == 0 do return 0, ERROR_NONE;
|
||||||
|
|
||||||
single_write_length: i32;
|
single_write_length: win32.DWORD;
|
||||||
total_write: i64;
|
total_write: i64;
|
||||||
length := i64(len(data));
|
length := i64(len(data));
|
||||||
|
|
||||||
for total_write < length {
|
for total_write < length {
|
||||||
remaining := length - total_write;
|
remaining := length - total_write;
|
||||||
MAX :: 1<<31-1;
|
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 {
|
if single_write_length <= 0 || !e {
|
||||||
err := Errno(win32.get_last_error());
|
err := Errno(win32.GetLastError());
|
||||||
return int(total_write), err;
|
return int(total_write), err;
|
||||||
}
|
}
|
||||||
total_write += i64(single_write_length);
|
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) {
|
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
if len(data) == 0 do return 0, ERROR_NONE;
|
if len(data) == 0 do return 0, ERROR_NONE;
|
||||||
|
|
||||||
single_read_length: i32;
|
single_read_length: win32.DWORD;
|
||||||
total_read: i64;
|
total_read: i64;
|
||||||
length := i64(len(data));
|
length := i64(len(data));
|
||||||
|
|
||||||
for total_read < length {
|
for total_read < length {
|
||||||
remaining := length - total_read;
|
remaining := length - total_read;
|
||||||
MAX :: 1<<32-1;
|
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 {
|
if single_read_length <= 0 || !e {
|
||||||
err := Errno(win32.get_last_error());
|
err := Errno(win32.GetLastError());
|
||||||
return int(total_read), err;
|
return int(total_read), err;
|
||||||
}
|
}
|
||||||
total_read += i64(single_read_length);
|
total_read += i64(single_read_length);
|
||||||
@@ -173,37 +173,37 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
|||||||
}
|
}
|
||||||
hi := i32(offset>>32);
|
hi := i32(offset>>32);
|
||||||
lo := i32(offset);
|
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;
|
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 {
|
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
|
||||||
err := Errno(win32.get_last_error());
|
err := Errno(win32.GetLastError());
|
||||||
return 0, err;
|
return 0, err;
|
||||||
}
|
}
|
||||||
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
|
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||||
length: i64;
|
length: win32.LARGE_INTEGER;
|
||||||
err: Errno;
|
err: Errno;
|
||||||
if !win32.get_file_size_ex(win32.Handle(fd), &length) {
|
if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) {
|
||||||
err = Errno(win32.get_last_error());
|
err = Errno(win32.GetLastError());
|
||||||
}
|
}
|
||||||
return length, err;
|
return i64(length), err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): Uses startup to initialize it
|
// NOTE(bill): Uses startup to initialize it
|
||||||
stdin := get_std_handle(win32.STD_INPUT_HANDLE);
|
stdin := get_std_handle(int(win32.STD_INPUT_HANDLE));
|
||||||
stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
|
stdout := get_std_handle(int(win32.STD_OUTPUT_HANDLE));
|
||||||
stderr := get_std_handle(win32.STD_ERROR_HANDLE);
|
stderr := get_std_handle(int(win32.STD_ERROR_HANDLE));
|
||||||
|
|
||||||
|
|
||||||
get_std_handle :: proc "contextless" (h: int) -> Handle {
|
get_std_handle :: proc "contextless" (h: int) -> Handle {
|
||||||
fd := win32.get_std_handle(i32(h));
|
fd := win32.GetStdHandle(win32.DWORD(h));
|
||||||
win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
||||||
return Handle(fd);
|
return Handle(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,32 +212,32 @@ get_std_handle :: proc "contextless" (h: int) -> Handle {
|
|||||||
|
|
||||||
|
|
||||||
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
|
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
|
||||||
file_info: win32.By_Handle_File_Information;
|
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
||||||
if !win32.get_file_information_by_handle(win32.Handle(fd), &file_info) {
|
if !win32.GetFileInformationByHandle(win32.HANDLE(fd), &file_info) {
|
||||||
return 0, Errno(win32.get_last_error());
|
return 0, Errno(win32.GetLastError());
|
||||||
}
|
}
|
||||||
lo := File_Time(file_info.last_write_time.lo);
|
lo := File_Time(file_info.ftLastWriteTime.dwLowDateTime);
|
||||||
hi := File_Time(file_info.last_write_time.hi);
|
hi := File_Time(file_info.ftLastWriteTime.dwHighDateTime);
|
||||||
return lo | hi << 32, ERROR_NONE;
|
return lo | hi << 32, ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
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);
|
wide_path := win32.utf8_to_wstring(name);
|
||||||
if !win32.get_file_attributes_ex_w(wide_path, win32.GetFileExInfoStandard, &data) {
|
if !win32.GetFileAttributesExW(auto_cast wide_path, win32.GetFileExInfoStandard, &data) {
|
||||||
return 0, Errno(win32.get_last_error());
|
return 0, Errno(win32.GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
l := File_Time(data.last_write_time.lo);
|
l := File_Time(data.ftLastWriteTime.dwLowDateTime);
|
||||||
h := File_Time(data.last_write_time.hi);
|
h := File_Time(data.ftLastWriteTime.dwHighDateTime);
|
||||||
return l | h << 32, ERROR_NONE;
|
return l | h << 32, ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
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 {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
if new_size == 0 {
|
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);
|
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) {
|
heap_free :: proc(ptr: rawptr) {
|
||||||
if ptr == nil do return;
|
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 {
|
get_page_size :: proc() -> int {
|
||||||
@@ -259,9 +259,9 @@ get_page_size :: proc() -> int {
|
|||||||
@static page_size := -1;
|
@static page_size := -1;
|
||||||
if page_size != -1 do return page_size;
|
if page_size != -1 do return page_size;
|
||||||
|
|
||||||
info: win32.System_Info;
|
info: win32.SYSTEM_INFO;
|
||||||
win32.get_system_info(&info);
|
win32.GetSystemInfo(&info);
|
||||||
page_size = int(info.page_size);
|
page_size = int(info.dwPageSize);
|
||||||
return page_size;
|
return page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,10 +274,10 @@ get_page_size :: proc() -> int {
|
|||||||
get_current_directory :: proc() -> string {
|
get_current_directory :: proc() -> string {
|
||||||
for intrinsics.atomic_xchg(&cwd_gate, true) {}
|
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.
|
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.
|
assert(int(sz_utf16)+1 == len(dir_buf_wstr)); // the second time, it _excludes_ the NUL.
|
||||||
|
|
||||||
intrinsics.atomic_store(&cwd_gate, false);
|
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) {}
|
for intrinsics.atomic_xchg(&cwd_gate, true) {}
|
||||||
defer intrinsics.atomic_store(&cwd_gate, false);
|
defer intrinsics.atomic_store(&cwd_gate, false);
|
||||||
|
|
||||||
res := win32.set_current_directory_w(wstr);
|
res := win32.SetCurrentDirectoryW(auto_cast wstr);
|
||||||
if res == 0 do return Errno(win32.get_last_error());
|
if !res do return Errno(win32.GetLastError());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -300,29 +300,29 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
|
|||||||
|
|
||||||
|
|
||||||
exit :: proc(code: int) -> ! {
|
exit :: proc(code: int) -> ! {
|
||||||
win32.exit_process(u32(code));
|
win32.ExitProcess(win32.DWORD(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
current_thread_id :: proc "contextless" () -> int {
|
current_thread_id :: proc "contextless" () -> int {
|
||||||
return int(win32.get_current_thread_id());
|
return int(win32.GetCurrentThreadId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
arg_count: i32;
|
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));
|
arg_list := make([]string, int(arg_count));
|
||||||
for _, i in arg_list {
|
for _, i in arg_list {
|
||||||
wc_str := (^win32.Wstring)(uintptr(arg_list_ptr) + size_of(win32.Wstring)*uintptr(i))^;
|
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,
|
olen := win32.WideCharToMultiByte(win32.CP_UTF8, 0, wc_str, -1,
|
||||||
nil, 0, nil, nil);
|
nil, 0, nil, nil);
|
||||||
|
|
||||||
buf := make([]byte, int(olen));
|
buf := make([]byte, int(olen));
|
||||||
n := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1,
|
n := win32.WideCharToMultiByte(win32.CP_UTF8, 0, wc_str, -1,
|
||||||
cstring(&buf[0]), olen, nil, nil);
|
&buf[0], olen, nil, nil);
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
n -= 1;
|
n -= 1;
|
||||||
}
|
}
|
||||||
@@ -332,10 +332,10 @@ _alloc_command_line_arguments :: proc() -> []string {
|
|||||||
return arg_list;
|
return arg_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_windows_version_ansi :: proc() -> win32.OS_Version_Info_Ex_A {
|
get_windows_version_ansi :: proc() -> win32.OSVERSIONINFOEXW {
|
||||||
osvi : win32.OS_Version_Info_Ex_A;
|
osvi : win32.OSVERSIONINFOEXW;
|
||||||
osvi.os_version_info_size = size_of(win32.OS_Version_Info_Ex_A);
|
osvi.os_version_info_size = size_of(win32.OSVERSIONINFOEXW);
|
||||||
win32.get_version(&osvi);
|
win32.GetVersionExW(&osvi);
|
||||||
return osvi;
|
return osvi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+90
-101
@@ -2,6 +2,7 @@ package sync
|
|||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import "core:fmt"
|
||||||
import "core:math/rand"
|
import "core:math/rand"
|
||||||
|
|
||||||
_, _ :: time, 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
|
unbuffered_msg: T, // Will be used as the backing to the queue if no `cap` is given
|
||||||
|
|
||||||
mutex: Mutex,
|
mutex: Mutex,
|
||||||
r_cond: Condition,
|
r_mutex: Mutex,
|
||||||
w_cond: Condition,
|
w_mutex: Mutex,
|
||||||
|
r_cond: Condition,
|
||||||
|
w_cond: Condition,
|
||||||
|
|
||||||
closed: bool,
|
is_buffered: bool,
|
||||||
r_waiting: int,
|
is_closed: bool,
|
||||||
w_waiting: int,
|
r_waiting: int,
|
||||||
|
w_waiting: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
channel_init :: proc(c: ^$C/Channel($T), cap: int = 0, allocator := context.allocator) {
|
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;
|
ch.allocator = allocator;
|
||||||
|
|
||||||
mutex_init(&ch.mutex);
|
mutex_init(&ch.mutex);
|
||||||
|
mutex_init(&ch.r_mutex);
|
||||||
|
mutex_init(&ch.w_mutex);
|
||||||
condition_init(&ch.r_cond, &ch.mutex);
|
condition_init(&ch.r_cond, &ch.mutex);
|
||||||
condition_init(&ch.w_cond, &ch.mutex);
|
condition_init(&ch.w_cond, &ch.mutex);
|
||||||
ch.closed = false;
|
ch.is_closed = false;
|
||||||
ch.r_waiting = 0;
|
ch.r_waiting = 0;
|
||||||
ch.w_waiting = 0;
|
ch.w_waiting = 0;
|
||||||
ch.unbuffered_msg = T{};
|
ch.unbuffered_msg = T{};
|
||||||
|
|
||||||
if cap > 0 {
|
if cap > 0 {
|
||||||
|
ch.is_buffered = true;
|
||||||
ch.queue = make([dynamic]T, 0, cap, ch.allocator);
|
ch.queue = make([dynamic]T, 0, cap, ch.allocator);
|
||||||
} else {
|
} else {
|
||||||
|
ch.is_buffered = false;
|
||||||
d := mem.Raw_Dynamic_Array{
|
d := mem.Raw_Dynamic_Array{
|
||||||
data = &ch.unbuffered_msg,
|
data = &ch.unbuffered_msg,
|
||||||
len = 0,
|
len = 0,
|
||||||
@@ -67,6 +75,8 @@ channel_destroy :: proc(ch: $C/Channel($T)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_destroy(&ch.mutex);
|
mutex_destroy(&ch.mutex);
|
||||||
|
mutex_destroy(&ch.r_mutex);
|
||||||
|
mutex_destroy(&ch.w_mutex);
|
||||||
condition_destroy(&ch.r_cond);
|
condition_destroy(&ch.r_cond);
|
||||||
condition_destroy(&ch.w_cond);
|
condition_destroy(&ch.w_cond);
|
||||||
free(ch.internal, ch.allocator);
|
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) {
|
channel_close :: proc(ch: $C/Channel($T)) -> (ok: bool) {
|
||||||
mutex_lock(&ch.mutex);
|
mutex_lock(&ch.mutex);
|
||||||
|
|
||||||
if !ch.closed {
|
if !ch.is_closed {
|
||||||
ch.closed = true;
|
ch.is_closed = true;
|
||||||
condition_broadcast(&ch.r_cond);
|
condition_broadcast(&ch.r_cond);
|
||||||
condition_broadcast(&ch.w_cond);
|
condition_broadcast(&ch.w_cond);
|
||||||
ok = true;
|
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) {
|
channel_write :: proc(ch: $C/Channel($T), msg: T) -> (ok: bool) {
|
||||||
mutex_lock(&ch.mutex);
|
mutex_lock(&ch.mutex);
|
||||||
defer mutex_unlock(&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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for !channel_can_write(ch) {
|
||||||
for len(ch.queue) == cap(ch.queue) {
|
|
||||||
ch.w_waiting += 1;
|
ch.w_waiting += 1;
|
||||||
condition_wait_for(&ch.w_cond);
|
condition_wait_for(&ch.w_cond);
|
||||||
ch.w_waiting -= 1;
|
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);
|
append(&ch.queue, msg);
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
assert(ch.w_waiting >= 0);
|
||||||
|
ch.w_waiting += 1;
|
||||||
|
|
||||||
if ch.r_waiting > 0 {
|
if ch.r_waiting > 0 {
|
||||||
condition_signal(&ch.r_cond);
|
condition_signal(&ch.r_cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
condition_wait_for(&ch.w_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
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 {
|
channel_read :: proc(ch: $C/Channel($T)) -> (msg: T, ok: bool) #optional_ok {
|
||||||
mutex_lock(&ch.mutex);
|
mutex_lock(&ch.mutex);
|
||||||
defer mutex_unlock(&ch.mutex);
|
defer mutex_unlock(&ch.mutex);
|
||||||
|
// fmt.println("channel_read");
|
||||||
|
// defer fmt.println("channel_read done");
|
||||||
|
|
||||||
for len(ch.queue) == 0 {
|
if ch.is_closed {
|
||||||
if ch.closed {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
for !channel_can_read(ch) {
|
||||||
|
|
||||||
ch.r_waiting += 1;
|
ch.r_waiting += 1;
|
||||||
condition_wait_for(&ch.r_cond);
|
condition_wait_for(&ch.r_cond);
|
||||||
ch.r_waiting -= 1;
|
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);
|
condition_signal(&ch.w_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
channel_size :: proc(ch: $C/Channel($T)) -> (size: int) {
|
channel_len :: proc(ch: $C/Channel($T)) -> (size: int) {
|
||||||
if channel_is_buffered(ch) {
|
if channel_is_buffered(ch) {
|
||||||
mutex_lock(&ch.mutex);
|
mutex_lock(&ch.mutex);
|
||||||
size = len(ch.queue);
|
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 {
|
channel_is_closed :: proc(ch: $C/Channel($T)) -> bool {
|
||||||
mutex_lock(&ch.mutex);
|
mutex_lock(&ch.mutex);
|
||||||
closed := ch.closed;
|
closed := ch.is_closed;
|
||||||
mutex_unlock(&ch.mutex);
|
mutex_unlock(&ch.mutex);
|
||||||
return closed;
|
return closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
channel_is_buffered :: proc(ch: $C/Channel($T)) -> bool {
|
channel_is_buffered :: proc(ch: $C/Channel($T)) -> bool {
|
||||||
q := transmute(mem.Raw_Dynamic_Array)ch.queue;
|
return ch.is_buffered;
|
||||||
return q.cap != 0 && (q.data != &ch.unbuffered_msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
channel_can_write :: proc(ch: $C/Channel($T)) -> bool {
|
channel_can_write :: proc(ch: $C/Channel($T)) -> bool {
|
||||||
mutex_lock(&ch.mutex);
|
mutex_lock(&ch.mutex);
|
||||||
defer mutex_unlock(&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 {
|
channel_can_read :: proc(ch: $C/Channel($T)) -> bool {
|
||||||
mutex_lock(&ch.mutex);
|
mutex_lock(&ch.mutex);
|
||||||
defer mutex_unlock(&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 {
|
channel_can_read_write :: proc(ch: $C/Channel($T)) -> bool {
|
||||||
mutex_lock(&ch.mutex);
|
mutex_lock(&ch.mutex);
|
||||||
defer mutex_unlock(&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) {
|
channel_iterator :: proc(ch: $C/Channel($T)) -> (elem: T, ok: bool) {
|
||||||
mutex_lock(&ch.mutex);
|
mutex_lock(&ch.mutex);
|
||||||
defer mutex_unlock(&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 channel_read(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
return T{}, false;
|
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
@@ -1,20 +1,23 @@
|
|||||||
// +build windows
|
// +build windows
|
||||||
package sync
|
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 {
|
Mutex :: struct {
|
||||||
_critical_section: win32.Critical_Section,
|
_handle: win32.SRWLOCK,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Recursive_Mutex :: struct {
|
||||||
|
_handle: win32.CRITICAL_SECTION,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Blocks until signalled.
|
// Blocks until signalled.
|
||||||
// When signalled, awakens exactly one waiting thread.
|
// When signalled, awakens exactly one waiting thread.
|
||||||
Condition :: struct {
|
Condition :: struct {
|
||||||
_handle: WIN32_CONDITION_VARIABLE,
|
_handle: win32.CONDITION_VARIABLE,
|
||||||
|
|
||||||
mutex: ^Mutex,
|
mutex: ^Mutex,
|
||||||
}
|
}
|
||||||
@@ -22,87 +25,98 @@ Condition :: struct {
|
|||||||
// When waited upon, blocks until the internal count is greater than zero, then subtracts one.
|
// 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.
|
// Posting to the semaphore increases the count by one, or the provided amount.
|
||||||
Semaphore :: struct {
|
Semaphore :: struct {
|
||||||
_handle: win32.Handle,
|
_handle: win32.HANDLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
semaphore_init :: proc(s: ^Semaphore, initial_count := 0) {
|
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) {
|
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||||
win32.close_handle(s._handle);
|
win32.CloseHandle(s._handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore_post :: proc(s: ^Semaphore, count := 1) {
|
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) {
|
semaphore_wait_for :: proc(s: ^Semaphore) {
|
||||||
// NOTE(tetra, 2019-10-30): wait_for_single_object decrements the count before it returns.
|
// NOTE(tetra, 2019-10-30): WaitForSingleObject decrements the count before it returns.
|
||||||
result := win32.wait_for_single_object(s._handle, win32.INFINITE);
|
result := win32.WaitForSingleObject(s._handle, win32.INFINITE);
|
||||||
assert(result != win32.WAIT_FAILED);
|
assert(result != win32.WAIT_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mutex_init :: proc(m: ^Mutex, spin_count := 0) {
|
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) {
|
mutex_destroy :: proc(m: ^Mutex) {
|
||||||
win32.delete_critical_section(&m._critical_section);
|
win32.ReleaseSRWLockExclusive(&m._handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock :: proc(m: ^Mutex) {
|
mutex_lock :: proc(m: ^Mutex) {
|
||||||
win32.enter_critical_section(&m._critical_section);
|
win32.AcquireSRWLockExclusive(&m._handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
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) {
|
mutex_unlock :: proc(m: ^Mutex) {
|
||||||
win32.leave_critical_section(&m._critical_section);
|
win32.ReleaseSRWLockExclusive(&m._handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@private WIN32_CONDITION_VARIABLE :: distinct rawptr;
|
|
||||||
@private
|
recursive_mutex_init :: proc(m: ^Recursive_Mutex, spin_count := 0) {
|
||||||
foreign kernel32 {
|
win32.InitializeCriticalSectionAndSpinCount(&m._handle, u32(spin_count));
|
||||||
InitializeConditionVariable :: proc(ConditionVariable: ^WIN32_CONDITION_VARIABLE) ---
|
}
|
||||||
WakeConditionVariable :: proc(ConditionVariable: ^WIN32_CONDITION_VARIABLE) ---
|
|
||||||
WakeAllConditionVariable :: proc(ConditionVariable: ^WIN32_CONDITION_VARIABLE) ---
|
recursive_mutex_destroy :: proc(m: ^Recursive_Mutex) {
|
||||||
SleepConditionVariableCS :: proc(ConditionVariable: ^WIN32_CONDITION_VARIABLE, CriticalSection: ^win32.Critical_Section, dwMilliseconds: u32) -> b32 ---
|
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 {
|
condition_init :: proc(c: ^Condition, mutex: ^Mutex) -> bool {
|
||||||
assert(mutex != nil);
|
assert(mutex != nil);
|
||||||
InitializeConditionVariable(&c._handle);
|
win32.InitializeConditionVariable(&c._handle);
|
||||||
c.mutex = mutex;
|
c.mutex = mutex;
|
||||||
return c._handle != nil;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
condition_destroy :: proc(c: ^Condition) {
|
condition_destroy :: proc(c: ^Condition) {
|
||||||
if c._handle != nil {
|
// Does nothing
|
||||||
WakeAllConditionVariable(&c._handle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
condition_signal :: proc(c: ^Condition) -> bool {
|
condition_signal :: proc(c: ^Condition) -> bool {
|
||||||
if c._handle == nil {
|
if c._handle.ptr == nil {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WakeConditionVariable(&c._handle);
|
win32.WakeConditionVariable(&c._handle);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
condition_broadcast :: proc(c: ^Condition) -> bool {
|
condition_broadcast :: proc(c: ^Condition) -> bool {
|
||||||
if c._handle == nil {
|
if c._handle.ptr == nil {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WakeAllConditionVariable(&c._handle);
|
win32.WakeAllConditionVariable(&c._handle);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
condition_wait_for :: proc(c: ^Condition) -> bool {
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// 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.
|
// 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.
|
// 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);
|
text := make([]byte, n+1 if N != -1 else n, allocator);
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ foreign kernel32 {
|
|||||||
@(link_name="CreateProcessW") create_process_w :: proc(application_name, command_line: Wstring,
|
@(link_name="CreateProcessW") create_process_w :: proc(application_name, command_line: Wstring,
|
||||||
process_attributes, thread_attributes: ^Security_Attributes,
|
process_attributes, thread_attributes: ^Security_Attributes,
|
||||||
inherit_handle: Bool, creation_flags: u32, environment: rawptr,
|
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 ---;
|
process_information: ^Process_Information) -> Bool ---;
|
||||||
@(link_name="GetExitCodeProcess") get_exit_code_process :: proc(process: Handle, exit: ^u32) -> Bool ---;
|
@(link_name="GetExitCodeProcess") get_exit_code_process :: proc(process: Handle, exit: ^u32) -> Bool ---;
|
||||||
@(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---;
|
@(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---;
|
||||||
@@ -156,7 +156,7 @@ foreign kernel32 {
|
|||||||
@(link_name="ReadBarrier") read_barrier :: proc() ---;
|
@(link_name="ReadBarrier") read_barrier :: proc() ---;
|
||||||
|
|
||||||
@(link_name="CreateThread")
|
@(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 ---;
|
parameter: rawptr, creation_flags: u32, thread_id: ^u32) -> Handle ---;
|
||||||
@(link_name="ResumeThread") resume_thread :: proc(thread: Handle) -> u32 ---;
|
@(link_name="ResumeThread") resume_thread :: proc(thread: Handle) -> u32 ---;
|
||||||
@(link_name="GetThreadPriority") get_thread_priority :: proc(thread: Handle) -> i32 ---;
|
@(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="TerminateThread") terminate_thread :: proc(thread: Handle, exit_code: u32) -> Bool ---;
|
||||||
|
|
||||||
@(link_name="InitializeCriticalSection") initialize_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
@(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="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="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="EnterCriticalSection") enter_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||||
@(link_name="LeaveCriticalSection") leave_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
@(link_name="LeaveCriticalSection") leave_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||||
|
|
||||||
|
|||||||
@@ -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 ---
|
||||||
|
}
|
||||||
@@ -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 ---
|
||||||
|
}
|
||||||
@@ -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 ---
|
||||||
|
}
|
||||||
@@ -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 ---
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -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 ---
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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 ---
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,11 +2,11 @@ package thread
|
|||||||
|
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
import "core:sync"
|
import "core:sync"
|
||||||
import "core:sys/win32"
|
import win32 "core:sys/windows"
|
||||||
|
|
||||||
Thread_Os_Specific :: struct {
|
Thread_Os_Specific :: struct {
|
||||||
win32_thread: win32.Handle,
|
win32_thread: win32.HANDLE,
|
||||||
win32_thread_id: u32,
|
win32_thread_id: win32.DWORD,
|
||||||
done: bool, // see note in `is_done`
|
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 {
|
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();
|
context = runtime.default_context();
|
||||||
c := context;
|
c := context;
|
||||||
if ic, ok := t.init_context.?; ok {
|
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);
|
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 {
|
if win32_thread == nil {
|
||||||
free(thread);
|
free(thread);
|
||||||
return nil;
|
return nil;
|
||||||
@@ -60,14 +60,14 @@ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^T
|
|||||||
thread.win32_thread_id = win32_thread_id;
|
thread.win32_thread_id = win32_thread_id;
|
||||||
thread.init_context = context;
|
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);
|
assert(ok == true);
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
start :: proc(using thread: ^Thread) {
|
start :: proc(using thread: ^Thread) {
|
||||||
win32.resume_thread(win32_thread);
|
win32.ResumeThread(win32_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
is_done :: proc(using thread: ^Thread) -> bool {
|
is_done :: proc(using thread: ^Thread) -> bool {
|
||||||
@@ -79,8 +79,8 @@ is_done :: proc(using thread: ^Thread) -> bool {
|
|||||||
|
|
||||||
join :: proc(using thread: ^Thread) {
|
join :: proc(using thread: ^Thread) {
|
||||||
if win32_thread != win32.INVALID_HANDLE {
|
if win32_thread != win32.INVALID_HANDLE {
|
||||||
win32.wait_for_single_object(win32_thread, win32.INFINITE);
|
win32.WaitForSingleObject(win32_thread, win32.INFINITE);
|
||||||
win32.close_handle(win32_thread);
|
win32.CloseHandle(win32_thread);
|
||||||
win32_thread = win32.INVALID_HANDLE;
|
win32_thread = win32.INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,10 +90,10 @@ destroy :: proc(thread: ^Thread) {
|
|||||||
free(thread);
|
free(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
terminate :: proc(using thread : ^Thread, exit_code : u32) {
|
terminate :: proc(using thread : ^Thread, exit_code: u32) {
|
||||||
win32.terminate_thread(win32_thread, exit_code);
|
win32.TerminateThread(win32_thread, exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield :: proc() {
|
yield :: proc() {
|
||||||
win32.sleep(0);
|
win32.Sleep(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
package time
|
package time
|
||||||
|
|
||||||
import "core:sys/win32"
|
import win32 "core:sys/windows"
|
||||||
|
|
||||||
IS_SUPPORTED :: true;
|
IS_SUPPORTED :: true;
|
||||||
|
|
||||||
now :: proc() -> Time {
|
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;
|
ns := (ft - 0x019db1ded53e8000) * 100;
|
||||||
return Time{_nsec=ns};
|
return Time{_nsec=ns};
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep :: proc(d: Duration) {
|
sleep :: proc(d: Duration) {
|
||||||
win32.sleep(u32(d/Millisecond));
|
win32.Sleep(win32.DWORD(d/Millisecond));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -505,9 +505,13 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
|
|||||||
|
|
||||||
typedef bool TypeCheckSig(Type *t);
|
typedef bool TypeCheckSig(Type *t);
|
||||||
bool sig_compare(TypeCheckSig *a, Type *x, Type *y) {
|
bool sig_compare(TypeCheckSig *a, Type *x, Type *y) {
|
||||||
|
x = core_type(x);
|
||||||
|
y = core_type(y);
|
||||||
return (a(x) && a(y));
|
return (a(x) && a(y));
|
||||||
}
|
}
|
||||||
bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) {
|
bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) {
|
||||||
|
x = core_type(x);
|
||||||
|
y = core_type(y);
|
||||||
if (a == b) {
|
if (a == b) {
|
||||||
return sig_compare(a, x, y);
|
return sig_compare(a, x, y);
|
||||||
}
|
}
|
||||||
@@ -542,6 +546,13 @@ bool signature_parameter_similar_enough(Type *x, Type *y) {
|
|||||||
return true;
|
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);
|
return are_types_identical(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user