From ffc45e8cc239ebf72e38a17a47a57c19e8b4cb39 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 17 Feb 2022 20:48:37 +0000 Subject: Add `intrinsics.constant_utf16_cstring` --- src/check_builtin.cpp | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c7ada8e03..1535f6644 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -223,31 +223,28 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Sliceinfo->objc_msgSend_types, call, data); mutex_unlock(&c->info->objc_types_mutex); - add_package_dependency(c, "runtime", "objc_lookUpClass"); - add_package_dependency(c, "runtime", "sel_registerName"); - add_package_dependency(c, "runtime", "objc_allocateClassPair"); - add_package_dependency(c, "runtime", "objc_msgSend"); add_package_dependency(c, "runtime", "objc_msgSend_fpret"); add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); add_package_dependency(c, "runtime", "objc_msgSend_stret"); } +bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) { + Operand op = {}; + check_expr(c, &op, expr); + if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) { + if (name_) *name_ = op.value.value_string; + return true; + } + gbString e = expr_to_string(op.expr); + gbString t = type_to_string(op.type); + error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; +} + bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { - auto const is_constant_string = [](CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) -> bool { - Operand op = {}; - check_expr(c, &op, expr); - if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) { - if (name_) *name_ = op.value.value_string; - return true; - } - gbString e = expr_to_string(op.expr); - gbString t = type_to_string(op.type); - error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t); - gb_string_free(t); - gb_string_free(e); - return false; - }; String builtin_name = builtin_procs[id].name; if (build_context.metrics.os != TargetOs_darwin) { @@ -371,6 +368,10 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call } operand->mode = Addressing_Value; + + add_package_dependency(c, "runtime", "objc_lookUpClass"); + add_package_dependency(c, "runtime", "sel_registerName"); + add_package_dependency(c, "runtime", "objc_allocateClassPair"); return true; } break; } @@ -4086,6 +4087,18 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } + case BuiltinProc_constant_utf16_cstring: + { + String value = {}; + if (!is_constant_string(c, builtin_name, ce->args[0], &value)) { + return false; + } + operand->mode = Addressing_Value; + operand->type = alloc_type_multi_pointer(t_u16); + operand->value = {}; + break; + } + } -- cgit v1.2.3 From 197b83299229a6d8733b2b6b2b3397ea717fbb17 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 15:56:53 +0000 Subject: Add vendor:directx and vendor:darwin packages for documentation generation --- examples/all/all_vendor.odin | 18 ++++++++++++++++-- src/check_builtin.cpp | 5 +++-- vendor/darwin/Foundation/NSArray.odin | 1 - vendor/darwin/Foundation/NSAutoreleasePool.odin | 1 - vendor/darwin/Foundation/NSBundle.odin | 1 - vendor/darwin/Foundation/NSData.odin | 1 - vendor/darwin/Foundation/NSDate.odin | 1 - vendor/darwin/Foundation/NSDictionary.odin | 1 - vendor/darwin/Foundation/NSEnumerator.odin | 1 - vendor/darwin/Foundation/NSError.odin | 1 - vendor/darwin/Foundation/NSLock.odin | 1 - vendor/darwin/Foundation/NSNotification.odin | 1 - vendor/darwin/Foundation/NSNumber.odin | 7 ++++--- vendor/darwin/Foundation/NSObject.odin | 1 - vendor/darwin/Foundation/NSRange.odin | 1 - vendor/darwin/Foundation/NSString.odin | 1 - vendor/darwin/Foundation/NSTypes.odin | 1 - vendor/darwin/Foundation/NSURL.odin | 1 - vendor/darwin/Foundation/NSWindow.odin | 1 - vendor/darwin/Metal/MetalClasses.odin | 1 - vendor/darwin/Metal/MetalEnums.odin | 1 - vendor/darwin/Metal/MetalErrors.odin | 1 - vendor/darwin/Metal/MetalProcedures.odin | 1 - vendor/darwin/Metal/MetalTypes.odin | 1 - vendor/darwin/QuartzCore/QuartzCore.odin | 1 - 25 files changed, 23 insertions(+), 29 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index f94e092af..9aa109e5b 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -1,7 +1,6 @@ //+build windows package all - import botan "vendor:botan" import ENet "vendor:ENet" import gl "vendor:OpenGL" @@ -25,6 +24,15 @@ import stb_vorbis "vendor:stb/vorbis" import vk "vendor:vulkan" +import D3D11 "vendor:directx/d3d11" +import D3D12 "vendor:directx/d3d12" +import DXGI "vendor:directx/dxgi" + +// note these are technicaly darwin only but they are added to aid with documentation generation +import NS "vendor:darwin/Foundation" +import MTL "vendor:darwin/Metal" +import CA "vendor:darwin/QuartzCore" + _ :: botan _ :: ENet @@ -44,4 +52,10 @@ _ :: stbi _ :: stbrp _ :: stbtt _ :: stb_vorbis -_ :: vk \ No newline at end of file +_ :: vk +_ :: D3D11 +_ :: D3D12 +_ :: DXGI +_ :: NS +_ :: MTL +_ :: CA \ No newline at end of file diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 1535f6644..fb7a6efce 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -248,8 +248,9 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call String builtin_name = builtin_procs[id].name; if (build_context.metrics.os != TargetOs_darwin) { - error(call, "'%.*s' only works on darwin", LIT(builtin_name)); - return false; + if (!build_context.generate_docs) { // allow on doc generation (e.g. Metal stuff) + error(call, "'%.*s' only works on darwin", LIT(builtin_name)); + } } diff --git a/vendor/darwin/Foundation/NSArray.odin b/vendor/darwin/Foundation/NSArray.odin index 4392c2791..d6021838b 100644 --- a/vendor/darwin/Foundation/NSArray.odin +++ b/vendor/darwin/Foundation/NSArray.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import "core:intrinsics" diff --git a/vendor/darwin/Foundation/NSAutoreleasePool.odin b/vendor/darwin/Foundation/NSAutoreleasePool.odin index f0157107e..a388a7146 100644 --- a/vendor/darwin/Foundation/NSAutoreleasePool.odin +++ b/vendor/darwin/Foundation/NSAutoreleasePool.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSAutoreleasePool") diff --git a/vendor/darwin/Foundation/NSBundle.odin b/vendor/darwin/Foundation/NSBundle.odin index 2e9d0df83..5e136378b 100644 --- a/vendor/darwin/Foundation/NSBundle.odin +++ b/vendor/darwin/Foundation/NSBundle.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSBundle") diff --git a/vendor/darwin/Foundation/NSData.odin b/vendor/darwin/Foundation/NSData.odin index b5367af07..3c6369e86 100644 --- a/vendor/darwin/Foundation/NSData.odin +++ b/vendor/darwin/Foundation/NSData.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSData") diff --git a/vendor/darwin/Foundation/NSDate.odin b/vendor/darwin/Foundation/NSDate.odin index 5aef42c13..e30cb07d0 100644 --- a/vendor/darwin/Foundation/NSDate.odin +++ b/vendor/darwin/Foundation/NSDate.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSDate") diff --git a/vendor/darwin/Foundation/NSDictionary.odin b/vendor/darwin/Foundation/NSDictionary.odin index 54f2e3446..3832c05f1 100644 --- a/vendor/darwin/Foundation/NSDictionary.odin +++ b/vendor/darwin/Foundation/NSDictionary.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSDictionary") diff --git a/vendor/darwin/Foundation/NSEnumerator.odin b/vendor/darwin/Foundation/NSEnumerator.odin index 0f1bdc482..1c7ddeed2 100644 --- a/vendor/darwin/Foundation/NSEnumerator.odin +++ b/vendor/darwin/Foundation/NSEnumerator.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import "core:c" diff --git a/vendor/darwin/Foundation/NSError.odin b/vendor/darwin/Foundation/NSError.odin index 868e6acc6..23e6eaba7 100644 --- a/vendor/darwin/Foundation/NSError.odin +++ b/vendor/darwin/Foundation/NSError.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation foreign import "system:Foundation.framework" diff --git a/vendor/darwin/Foundation/NSLock.odin b/vendor/darwin/Foundation/NSLock.odin index 48c3a0e23..c48b5dbad 100644 --- a/vendor/darwin/Foundation/NSLock.odin +++ b/vendor/darwin/Foundation/NSLock.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation Locking :: struct($T: typeid) {using _: Object} diff --git a/vendor/darwin/Foundation/NSNotification.odin b/vendor/darwin/Foundation/NSNotification.odin index da9874bbc..ec8dddab7 100644 --- a/vendor/darwin/Foundation/NSNotification.odin +++ b/vendor/darwin/Foundation/NSNotification.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSNotification") diff --git a/vendor/darwin/Foundation/NSNumber.odin b/vendor/darwin/Foundation/NSNumber.odin index eb28b7099..b0cfbfb40 100644 --- a/vendor/darwin/Foundation/NSNumber.odin +++ b/vendor/darwin/Foundation/NSNumber.odin @@ -1,10 +1,11 @@ -//+build darwin package objc_Foundation import "core:c" -#assert(size_of(c.long) == size_of(int)) -#assert(size_of(c.ulong) == size_of(uint)) +when ODIN_OS == .Darwin { + #assert(size_of(c.long) == size_of(int)) + #assert(size_of(c.ulong) == size_of(uint)) +} @(objc_class="NSValue") Value :: struct{using _: Copying(Value)} diff --git a/vendor/darwin/Foundation/NSObject.odin b/vendor/darwin/Foundation/NSObject.odin index 33ef26a23..1ce17f2f5 100644 --- a/vendor/darwin/Foundation/NSObject.odin +++ b/vendor/darwin/Foundation/NSObject.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import "core:intrinsics" diff --git a/vendor/darwin/Foundation/NSRange.odin b/vendor/darwin/Foundation/NSRange.odin index 48bce5f38..74ce595a3 100644 --- a/vendor/darwin/Foundation/NSRange.odin +++ b/vendor/darwin/Foundation/NSRange.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation Range :: struct { diff --git a/vendor/darwin/Foundation/NSString.odin b/vendor/darwin/Foundation/NSString.odin index 5807db2db..45b5df37b 100644 --- a/vendor/darwin/Foundation/NSString.odin +++ b/vendor/darwin/Foundation/NSString.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation foreign import "system:Foundation.framework" diff --git a/vendor/darwin/Foundation/NSTypes.odin b/vendor/darwin/Foundation/NSTypes.odin index 2cb9000e9..47f75630f 100644 --- a/vendor/darwin/Foundation/NSTypes.odin +++ b/vendor/darwin/Foundation/NSTypes.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import "core:intrinsics" diff --git a/vendor/darwin/Foundation/NSURL.odin b/vendor/darwin/Foundation/NSURL.odin index 995117a65..72e5fc906 100644 --- a/vendor/darwin/Foundation/NSURL.odin +++ b/vendor/darwin/Foundation/NSURL.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation @(objc_class="NSURL") diff --git a/vendor/darwin/Foundation/NSWindow.odin b/vendor/darwin/Foundation/NSWindow.odin index 654009bda..dec5a160c 100644 --- a/vendor/darwin/Foundation/NSWindow.odin +++ b/vendor/darwin/Foundation/NSWindow.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Foundation import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index 4bc43002d..9713bba02 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalEnums.odin b/vendor/darwin/Metal/MetalEnums.odin index 5cfa33558..2a6ab749a 100644 --- a/vendor/darwin/Metal/MetalEnums.odin +++ b/vendor/darwin/Metal/MetalEnums.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalErrors.odin b/vendor/darwin/Metal/MetalErrors.odin index da37b59ff..f214466e5 100644 --- a/vendor/darwin/Metal/MetalErrors.odin +++ b/vendor/darwin/Metal/MetalErrors.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalProcedures.odin b/vendor/darwin/Metal/MetalProcedures.odin index 24ec2f8dd..b76c7f541 100644 --- a/vendor/darwin/Metal/MetalProcedures.odin +++ b/vendor/darwin/Metal/MetalProcedures.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/Metal/MetalTypes.odin b/vendor/darwin/Metal/MetalTypes.odin index 1aabfa83e..673769c09 100644 --- a/vendor/darwin/Metal/MetalTypes.odin +++ b/vendor/darwin/Metal/MetalTypes.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_Metal import NS "vendor:darwin/Foundation" diff --git a/vendor/darwin/QuartzCore/QuartzCore.odin b/vendor/darwin/QuartzCore/QuartzCore.odin index 7bcf216f1..fb6e04b07 100644 --- a/vendor/darwin/QuartzCore/QuartzCore.odin +++ b/vendor/darwin/QuartzCore/QuartzCore.odin @@ -1,4 +1,3 @@ -//+build darwin package objc_QuartzCore import NS "vendor:darwin/Foundation" -- cgit v1.2.3 From 454c92dc64b43934062a661c6e05ea4168b1b78e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 16:05:26 +0000 Subject: Allow objc intrinsics within `odin check` and `odin docs` but disallow for `odin build` --- src/check_builtin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index fb7a6efce..c6b7de506 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -248,7 +248,8 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call String builtin_name = builtin_procs[id].name; if (build_context.metrics.os != TargetOs_darwin) { - if (!build_context.generate_docs) { // allow on doc generation (e.g. Metal stuff) + // allow on doc generation (e.g. Metal stuff) + if (!build_context.command_kind == Command_doc && !builtin_name.command_kind == Command_check) { error(call, "'%.*s' only works on darwin", LIT(builtin_name)); } } -- cgit v1.2.3 From 1843d522173a646786a226320e1443d43591fbca Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 16:07:06 +0000 Subject: Fix typo --- src/check_builtin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c6b7de506..f440aa4d5 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -249,7 +249,7 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call if (build_context.metrics.os != TargetOs_darwin) { // allow on doc generation (e.g. Metal stuff) - if (!build_context.command_kind == Command_doc && !builtin_name.command_kind == Command_check) { + if (build_context.command_kind != Command_doc && build_context.command_kind != Command_check) { error(call, "'%.*s' only works on darwin", LIT(builtin_name)); } } -- cgit v1.2.3 From 5f8137025d0abb946c186dc01271495cf839a871 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 18 Feb 2022 16:12:21 +0000 Subject: Use `try_to_add_package_dependency` --- src/check_builtin.cpp | 14 +++++++------- src/checker.cpp | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 8 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index f440aa4d5..eb9d7f293 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -223,10 +223,10 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Sliceinfo->objc_msgSend_types, call, data); mutex_unlock(&c->info->objc_types_mutex); - add_package_dependency(c, "runtime", "objc_msgSend"); - add_package_dependency(c, "runtime", "objc_msgSend_fpret"); - add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); - add_package_dependency(c, "runtime", "objc_msgSend_stret"); + try_to_add_package_dependency(c, "runtime", "objc_msgSend"); + try_to_add_package_dependency(c, "runtime", "objc_msgSend_fpret"); + try_to_add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); + try_to_add_package_dependency(c, "runtime", "objc_msgSend_stret"); } bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) { @@ -371,9 +371,9 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call } operand->mode = Addressing_Value; - add_package_dependency(c, "runtime", "objc_lookUpClass"); - add_package_dependency(c, "runtime", "sel_registerName"); - add_package_dependency(c, "runtime", "objc_allocateClassPair"); + try_to_add_package_dependency(c, "runtime", "objc_lookUpClass"); + try_to_add_package_dependency(c, "runtime", "sel_registerName"); + try_to_add_package_dependency(c, "runtime", "objc_allocateClassPair"); return true; } break; } diff --git a/src/checker.cpp b/src/checker.cpp index 81e6f256e..f8aa8d45b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -733,12 +733,25 @@ void add_package_dependency(CheckerContext *c, char const *package_name, char co String n = make_string_c(name); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); Entity *e = scope_lookup(p->scope, n); - e->flags |= EntityFlag_Used; GB_ASSERT_MSG(e != nullptr, "%s", name); GB_ASSERT(c->decl != nullptr); + e->flags |= EntityFlag_Used; + add_dependency(c->info, c->decl, e); +} + +void try_to_add_package_dependency(CheckerContext *c, char const *package_name, char const *name) { + String n = make_string_c(name); + AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); + Entity *e = scope_lookup(p->scope, n); + if (e == nullptr) { + return; + } + GB_ASSERT(c->decl != nullptr); + e->flags |= EntityFlag_Used; add_dependency(c->info, c->decl, e); } + void add_declaration_dependency(CheckerContext *c, Entity *e) { if (e == nullptr) { return; -- cgit v1.2.3 From 5676c9e7ebcec9af526c59ece1faf2e8b15e457c Mon Sep 17 00:00:00 2001 From: Sébastien Marie Date: Fri, 25 Feb 2022 08:49:25 +0000 Subject: initial OpenBSD support --- Makefile | 6 + core/c/libc/errno.odin | 13 + core/c/libc/stdio.odin | 25 ++ core/c/libc/time.odin | 9 +- core/c/libc/wctype.odin | 5 + core/crypto/rand_generic.odin | 2 +- core/crypto/rand_openbsd.odin | 12 + core/dynlib/lib_unix.odin | 2 +- core/os/dir_openbsd.odin | 71 ++++ core/os/os_openbsd.odin | 706 +++++++++++++++++++++++++++++++ core/os/stat_unix.odin | 2 +- core/path/filepath/path_unix.odin | 7 +- core/runtime/entry_unix.odin | 2 +- core/sync/channel_unix.odin | 2 +- core/sync/sync2/futex_openbsd.odin | 78 ++++ core/sync/sync2/primitives_openbsd.odin | 9 + core/sync/sync2/primitives_pthreads.odin | 2 +- core/sync/sync_openbsd.odin | 36 ++ core/sync/sync_unix.odin | 2 +- core/sys/unix/pthread_openbsd.odin | 65 +++ core/sys/unix/pthread_unix.odin | 2 +- core/thread/thread_unix.odin | 2 +- core/time/time_unix.odin | 34 +- src/bug_report.cpp | 14 +- src/build_settings.cpp | 18 + src/check_builtin.cpp | 1 + src/checker.cpp | 1 + src/common.cpp | 2 +- src/gb/gb.h | 46 +- src/threading.cpp | 2 +- 30 files changed, 1151 insertions(+), 27 deletions(-) create mode 100644 core/crypto/rand_openbsd.odin create mode 100644 core/os/dir_openbsd.odin create mode 100644 core/os/os_openbsd.odin create mode 100644 core/sync/sync2/futex_openbsd.odin create mode 100644 core/sync/sync2/primitives_openbsd.odin create mode 100644 core/sync/sync_openbsd.odin create mode 100644 core/sys/unix/pthread_openbsd.odin (limited to 'src/check_builtin.cpp') diff --git a/Makefile b/Makefile index d3d3c6a2d..99c71ccd9 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,12 @@ ifeq ($(OS), Linux) CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs) endif +ifeq ($(OS), OpenBSD) + LLVM_CONFIG=/usr/local/bin/llvm-config + + CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags) + LDFLAGS:=$(LDFLAGS) -liconv $(shell $(LLVM_CONFIG) --libs core native --system-libs) +endif all: debug demo diff --git a/core/c/libc/errno.odin b/core/c/libc/errno.odin index ecde6af59..53437f42f 100644 --- a/core/c/libc/errno.odin +++ b/core/c/libc/errno.odin @@ -27,6 +27,19 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD { ERANGE :: 34 } +when ODIN_OS == .OpenBSD { + @(private="file") + @(default_calling_convention="c") + foreign libc { + @(link_name="__errno") + _get_errno :: proc() -> ^int --- + } + + EDOM :: 33 + EILSEQ :: 84 + ERANGE :: 34 +} + when ODIN_OS == .Windows { @(private="file") @(default_calling_convention="c") diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index 9c4a1a708..fc65b954a 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -78,6 +78,31 @@ when ODIN_OS == .Linux { } } +when ODIN_OS == .OpenBSD { + fpos_t :: i64 + + _IOFBF :: 0 + _IOLBF :: 1 + _IONBF :: 1 + + BUFSIZ :: 1024 + + EOF :: int(-1) + + FOPEN_MAX :: 20 + FILENAME_MAX :: 1024 + + SEEK_SET :: 0 + SEEK_CUR :: 1 + SEEK_END :: 2 + + foreign libc { + stderr: ^FILE + stdin: ^FILE + stdout: ^FILE + } +} + when ODIN_OS == .Darwin { fpos_t :: distinct i64 diff --git a/core/c/libc/time.odin b/core/c/libc/time.odin index b3539a227..b337e139a 100644 --- a/core/c/libc/time.odin +++ b/core/c/libc/time.odin @@ -45,7 +45,7 @@ when ODIN_OS == .Windows { } } -when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin { +when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD { @(default_calling_convention="c") foreign libc { // 7.27.2 Time manipulation functions @@ -63,7 +63,12 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin { strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t --- } - CLOCKS_PER_SEC :: 1000000 + when ODIN_OS == .OpenBSD { + CLOCKS_PER_SEC :: 100 + } else { + CLOCKS_PER_SEC :: 1000000 + } + TIME_UTC :: 1 time_t :: distinct i64 diff --git a/core/c/libc/wctype.odin b/core/c/libc/wctype.odin index 942726ba6..f833af51f 100644 --- a/core/c/libc/wctype.odin +++ b/core/c/libc/wctype.odin @@ -25,6 +25,11 @@ when ODIN_OS == .Darwin { wctype_t :: distinct u32 } +when ODIN_OS == .OpenBSD { + wctrans_t :: distinct rawptr + wctype_t :: distinct rawptr +} + @(default_calling_convention="c") foreign libc { // 7.30.2.1 Wide character classification functions diff --git a/core/crypto/rand_generic.odin b/core/crypto/rand_generic.odin index be6987ee2..10edc1c8a 100644 --- a/core/crypto/rand_generic.odin +++ b/core/crypto/rand_generic.odin @@ -1,6 +1,6 @@ package crypto -when ODIN_OS != .Linux { +when ODIN_OS != .Linux && ODIN_OS != .OpenBSD { _rand_bytes :: proc (dst: []byte) { unimplemented("crypto: rand_bytes not supported on this OS") } diff --git a/core/crypto/rand_openbsd.odin b/core/crypto/rand_openbsd.odin new file mode 100644 index 000000000..bae97e8f0 --- /dev/null +++ b/core/crypto/rand_openbsd.odin @@ -0,0 +1,12 @@ +package crypto + +import "core:c" + +foreign import libc "system:c" +foreign libc { + arc4random_buf :: proc "c" (buf: rawptr, nbytes: c.size_t) --- +} + +_rand_bytes :: proc (dst: []byte) { + arc4random_buf(raw_data(dst), len(dst)) +} diff --git a/core/dynlib/lib_unix.odin b/core/dynlib/lib_unix.odin index bb8affb79..e52ade153 100644 --- a/core/dynlib/lib_unix.odin +++ b/core/dynlib/lib_unix.odin @@ -1,4 +1,4 @@ -// +build linux, darwin, freebsd +// +build linux, darwin, freebsd, openbsd package dynlib import "core:os" diff --git a/core/os/dir_openbsd.odin b/core/os/dir_openbsd.odin new file mode 100644 index 000000000..465fd35ae --- /dev/null +++ b/core/os/dir_openbsd.odin @@ -0,0 +1,71 @@ +package os + +import "core:strings" +import "core:mem" + +read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { + dirp: Dir + dirp, err = _fdopendir(fd) + if err != ERROR_NONE { + return + } + + defer _closedir(dirp) + + // XXX OpenBSD + dirpath: string + dirpath, err = absolute_path_from_handle(fd) + + if err != ERROR_NONE { + return + } + + defer delete(dirpath) + + n := n + size := n + if n <= 0 { + n = -1 + size = 100 + } + + dfi := make([dynamic]File_Info, 0, size, allocator) + + for { + entry: Dirent + end_of_stream: bool + entry, err, end_of_stream = _readdir(dirp) + if err != ERROR_NONE { + for fi_ in dfi { + file_info_delete(fi_, allocator) + } + delete(dfi) + return + } else if end_of_stream { + break + } + + fi_: File_Info + filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) + + if filename == "." || filename == ".." { + continue + } + + fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) + defer delete(fullpath, context.temp_allocator) + + fi_, err = stat(fullpath, allocator) + if err != ERROR_NONE { + for fi__ in dfi { + file_info_delete(fi__, allocator) + } + delete(dfi) + return + } + + append(&dfi, fi_) + } + + return dfi[:], ERROR_NONE +} diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin new file mode 100644 index 000000000..3862851a1 --- /dev/null +++ b/core/os/os_openbsd.odin @@ -0,0 +1,706 @@ +package os + +foreign import libc "system:c" + +import "core:runtime" +import "core:strings" +import "core:c" + +Handle :: distinct i32 +Pid :: distinct i32 +File_Time :: distinct u64 +Errno :: distinct i32 + +INVALID_HANDLE :: ~Handle(0) + +ERROR_NONE: Errno: 0 + +EPERM: Errno: 1 +ENOENT: Errno: 2 +ESRCH: Errno: 3 +EINTR: Errno: 4 +EIO: Errno: 5 +ENXIO: Errno: 6 +E2BIG: Errno: 7 +ENOEXEC: Errno: 8 +EBADF: Errno: 9 +ECHILD: Errno: 10 +EDEADLK: Errno: 11 +ENOMEM: Errno: 12 +EACCES: Errno: 13 +EFAULT: Errno: 14 +ENOTBLK: Errno: 15 +EBUSY: Errno: 16 +EEXIST: Errno: 17 +EXDEV: Errno: 18 +ENODEV: Errno: 19 +ENOTDIR: Errno: 20 +EISDIR: Errno: 21 +EINVAL: Errno: 22 +ENFILE: Errno: 23 +EMFILE: Errno: 24 +ENOTTY: Errno: 25 +ETXTBSY: Errno: 26 +EFBIG: Errno: 27 +ENOSPC: Errno: 28 +ESPIPE: Errno: 29 +EROFS: Errno: 30 +EMLINK: Errno: 31 +EPIPE: Errno: 32 +EDOM: Errno: 33 +ERANGE: Errno: 34 +EAGAIN: Errno: 35 +EWOULDBLOCK: Errno: EAGAIN +EINPROGRESS: Errno: 36 +EALREADY: Errno: 37 +ENOTSOCK: Errno: 38 +EDESTADDRREQ: Errno: 39 +EMSGSIZE: Errno: 40 +EPROTOTYPE: Errno: 41 +ENOPROTOOPT: Errno: 42 +EPROTONOSUPPORT: Errno: 43 +ESOCKTNOSUPPORT: Errno: 44 +EOPNOTSUPP: Errno: 45 +EPFNOSUPPORT: Errno: 46 +EAFNOSUPPORT: Errno: 47 +EADDRINUSE: Errno: 48 +EADDRNOTAVAIL: Errno: 49 +ENETDOWN: Errno: 50 +ENETUNREACH: Errno: 51 +ENETRESET: Errno: 52 +ECONNABORTED: Errno: 53 +ECONNRESET: Errno: 54 +ENOBUFS: Errno: 55 +EISCONN: Errno: 56 +ENOTCONN: Errno: 57 +ESHUTDOWN: Errno: 58 +ETOOMANYREFS: Errno: 59 +ETIMEDOUT: Errno: 60 +ECONNREFUSED: Errno: 61 +ELOOP: Errno: 62 +ENAMETOOLONG: Errno: 63 +EHOSTDOWN: Errno: 64 +EHOSTUNREACH: Errno: 65 +ENOTEMPTY: Errno: 66 +EPROCLIM: Errno: 67 +EUSERS: Errno: 68 +EDQUOT: Errno: 69 +ESTALE: Errno: 70 +EREMOTE: Errno: 71 +EBADRPC: Errno: 72 +ERPCMISMATCH: Errno: 73 +EPROGUNAVAIL: Errno: 74 +EPROGMISMATCH: Errno: 75 +EPROCUNAVAIL: Errno: 76 +ENOLCK: Errno: 77 +ENOSYS: Errno: 78 +EFTYPE: Errno: 79 +EAUTH: Errno: 80 +ENEEDAUTH: Errno: 81 +EIPSEC: Errno: 82 +ENOATTR: Errno: 83 +EILSEQ: Errno: 84 +ENOMEDIUM: Errno: 85 +EMEDIUMTYPE: Errno: 86 +EOVERFLOW: Errno: 87 +ECANCELED: Errno: 88 +EIDRM: Errno: 89 +ENOMSG: Errno: 90 +ENOTSUP: Errno: 91 +EBADMSG: Errno: 92 +ENOTRECOVERABLE: Errno: 93 +EOWNERDEAD: Errno: 94 +EPROTO: Errno: 95 + +O_RDONLY :: 0x00000 +O_WRONLY :: 0x00001 +O_RDWR :: 0x00002 +O_NONBLOCK :: 0x00004 +O_APPEND :: 0x00008 +O_ASYNC :: 0x00040 +O_SYNC :: 0x00080 +O_CREATE :: 0x00200 +O_TRUNC :: 0x00400 +O_EXCL :: 0x00800 +O_NOCTTY :: 0x08000 +O_CLOEXEC :: 0x10000 + +SEEK_SET :: 0 +SEEK_CUR :: 1 +SEEK_END :: 2 + +RTLD_LAZY :: 0x001 +RTLD_NOW :: 0x002 +RTLD_LOCAL :: 0x000 +RTLD_GLOBAL :: 0x100 +RTLD_TRACE :: 0x200 +RTLD_NODELETE :: 0x400 + +MAX_PATH :: 1024 + +// "Argv" arguments converted to Odin strings +args := _alloc_command_line_arguments() + +pid_t :: i32 +time_t :: i64 +mode_t :: u32 +dev_t :: i32 +ino_t :: u64 +nlink_t :: u32 +uid_t :: u32 +gid_t :: u32 +off_t :: i64 +blkcnt_t :: u64 +blksize_t :: i32 + +Unix_File_Time :: struct { + seconds: time_t, + nanoseconds: c.long, +} + +OS_Stat :: struct { + mode: mode_t, // inode protection mode + device_id: dev_t, // inode's device + serial: ino_t, // inode's number + nlink: nlink_t, // number of hard links + uid: uid_t, // user ID of the file's owner + gid: gid_t, // group ID of the file's group + rdev: dev_t, // device type + + last_access: Unix_File_Time, // time of last access + modified: Unix_File_Time, // time of last data modification + status_change: Unix_File_Time, // time of last file status change + + size: off_t, // file size, in bytes + blocks: blkcnt_t, // blocks allocated for file + block_size: blksize_t, // optimal blocksize for I/O + + flags: u32, // user defined flags for file + gen: u32, // file generation number + birthtime: Unix_File_Time, // time of file creation +} + +MAXNAMLEN :: 255 + +// NOTE(laleksic, 2021-01-21): Comment and rename these to match OS_Stat above +Dirent :: struct { + ino: ino_t, // file number of entry + off: off_t, // offset after this entry + reclen: u16, // length of this record + type: u8, // file type + namlen: u8, // length of string in name + _padding: [4]u8, + name: [MAXNAMLEN + 1]byte, // name +} + +Dir :: distinct rawptr // DIR* + +// File type +S_IFMT :: 0o170000 // Type of file mask +S_IFIFO :: 0o010000 // Named pipe (fifo) +S_IFCHR :: 0o020000 // Character special +S_IFDIR :: 0o040000 // Directory +S_IFBLK :: 0o060000 // Block special +S_IFREG :: 0o100000 // Regular +S_IFLNK :: 0o120000 // Symbolic link +S_IFSOCK :: 0o140000 // Socket +S_ISVTX :: 0o001000 // Save swapped text even after use + +// File mode + // Read, write, execute/search by owner +S_IRWXU :: 0o0700 // RWX mask for owner +S_IRUSR :: 0o0400 // R for owner +S_IWUSR :: 0o0200 // W for owner +S_IXUSR :: 0o0100 // X for owner + + // Read, write, execute/search by group +S_IRWXG :: 0o0070 // RWX mask for group +S_IRGRP :: 0o0040 // R for group +S_IWGRP :: 0o0020 // W for group +S_IXGRP :: 0o0010 // X for group + + // Read, write, execute/search by others +S_IRWXO :: 0o0007 // RWX mask for other +S_IROTH :: 0o0004 // R for other +S_IWOTH :: 0o0002 // W for other +S_IXOTH :: 0o0001 // X for other + +S_ISUID :: 0o4000 // Set user id on execution +S_ISGID :: 0o2000 // Set group id on execution +S_ISTXT :: 0o1000 // Sticky bit + +S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK } +S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG } +S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR } +S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR } +S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK } +S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO } +S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK } + +F_OK :: 0x00 // Test for file existance +X_OK :: 0x01 // Test for execute permission +W_OK :: 0x02 // Test for write permission +R_OK :: 0x04 // Test for read permission + +AT_FDCWD :: -100 +AT_EACCESS :: 0x01 +AT_SYMLINK_NOFOLLOW :: 0x02 +AT_SYMLINK_FOLLOW :: 0x04 +AT_REMOVEDIR :: 0x08 + +@(default_calling_convention="c") +foreign libc { + @(link_name="__errno") __errno :: proc() -> ^int --- + + @(link_name="fork") _unix_fork :: proc() -> pid_t --- + @(link_name="getthrid") _unix_getthrid :: proc() -> int --- + + @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- + @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- + @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- + @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- + @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t --- + @(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int --- + @(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int --- + @(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int --- + @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t --- + @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int --- + @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- + @(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int --- + @(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int --- + @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int --- + @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int --- + @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int --- + + @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int --- + @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- + @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- + @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- + @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- + + @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr --- + @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr --- + @(link_name="free") _unix_free :: proc(ptr: rawptr) --- + @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- + + @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- + @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + + @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- + + @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr --- + @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr --- + @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int --- + @(link_name="dlerror") _unix_dlerror :: proc() -> cstring --- +} + +is_path_separator :: proc(r: rune) -> bool { + return r == '/' +} + +get_last_error :: proc() -> int { + return __errno()^ +} + +fork :: proc() -> (Pid, Errno) { + pid := _unix_fork() + if pid == -1 { + return Pid(-1), Errno(get_last_error()) + } + return Pid(pid), ERROR_NONE +} + +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + handle := _unix_open(cstr, c.int(flags), c.int(mode)) + if handle == -1 { + return INVALID_HANDLE, Errno(get_last_error()) + } + return handle, ERROR_NONE +} + +close :: proc(fd: Handle) -> Errno { + result := _unix_close(fd) + if result == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +read :: proc(fd: Handle, data: []byte) -> (int, Errno) { + bytes_read := _unix_read(fd, &data[0], c.size_t(len(data))) + if bytes_read == -1 { + return -1, Errno(get_last_error()) + } + return int(bytes_read), ERROR_NONE +} + +write :: proc(fd: Handle, data: []byte) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE + } + bytes_written := _unix_write(fd, &data[0], c.size_t(len(data))) + if bytes_written == -1 { + return -1, Errno(get_last_error()) + } + return int(bytes_written), ERROR_NONE +} + +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { + res := _unix_seek(fd, offset, c.int(whence)) + if res == -1 { + return -1, Errno(get_last_error()) + } + return res, ERROR_NONE +} + +file_size :: proc(fd: Handle) -> (i64, Errno) { + s, err := _fstat(fd) + if err != ERROR_NONE { + return -1, err + } + return s.size, ERROR_NONE +} + +rename :: proc(old_path, new_path: string) -> Errno { + old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) + new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) + res := _unix_rename(old_path_cstr, new_path_cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +remove :: proc(path: string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_unlink(path_cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_mkdir(path_cstr, mode) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +remove_directory :: proc(path: string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_rmdir(path_cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +is_file_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISREG(s.mode) +} + +is_file_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISREG(s.mode) +} + +is_dir_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISDIR(s.mode) +} + +is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISDIR(s.mode) +} + +is_file :: proc {is_file_path, is_file_handle} +is_dir :: proc {is_dir_path, is_dir_handle} + +// NOTE(bill): Uses startup to initialize it + +stdin: Handle = 0 +stdout: Handle = 1 +stderr: Handle = 2 + +/* TODO(zangent): Implement these! +last_write_time :: proc(fd: Handle) -> File_Time {} +last_write_time_by_name :: proc(name: string) -> File_Time {} +*/ +last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { + s, err := _fstat(fd) + if err != ERROR_NONE { + return 0, err + } + modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds + return File_Time(modified), ERROR_NONE +} + +last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { + s, err := _stat(name) + if err != ERROR_NONE { + return 0, err + } + modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds + return File_Time(modified), ERROR_NONE +} + +@private +_stat :: proc(path: string) -> (OS_Stat, Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + + // deliberately uninitialized + s: OS_Stat = --- + res := _unix_stat(cstr, &s) + if res == -1 { + return s, Errno(get_last_error()) + } + return s, ERROR_NONE +} + +@private +_lstat :: proc(path: string) -> (OS_Stat, Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + + // deliberately uninitialized + s: OS_Stat = --- + res := _unix_lstat(cstr, &s) + if res == -1 { + return s, Errno(get_last_error()) + } + return s, ERROR_NONE +} + +@private +_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { + // deliberately uninitialized + s: OS_Stat = --- + res := _unix_fstat(fd, &s) + if res == -1 { + return s, Errno(get_last_error()) + } + return s, ERROR_NONE +} + +@private +_fdopendir :: proc(fd: Handle) -> (Dir, Errno) { + dirp := _unix_fdopendir(fd) + if dirp == cast(Dir)nil { + return nil, Errno(get_last_error()) + } + return dirp, ERROR_NONE +} + +@private +_closedir :: proc(dirp: Dir) -> Errno { + rc := _unix_closedir(dirp) + if rc != 0 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +@private +_rewinddir :: proc(dirp: Dir) { + _unix_rewinddir(dirp) +} + +@private +_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) { + result: ^Dirent + rc := _unix_readdir_r(dirp, &entry, &result) + + if rc != 0 { + err = Errno(get_last_error()) + return + } + err = ERROR_NONE + + if result == nil { + end_of_stream = true + return + } + + return +} + +@private +_readlink :: proc(path: string) -> (string, Errno) { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + + bufsz : uint = MAX_PATH + buf := make([]byte, MAX_PATH) + for { + rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) + if rc == -1 { + delete(buf) + return "", Errno(get_last_error()) + } else if rc == int(bufsz) { + bufsz += MAX_PATH + delete(buf) + buf = make([]byte, bufsz) + } else { + return strings.string_from_ptr(&buf[0], rc), ERROR_NONE + } + } + unreachable() +} + +// XXX OpenBSD +absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { + return "", Errno(ENOSYS) +} + +absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { + rel := rel + if rel == "" { + rel = "." + } + + rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) + + path_ptr := _unix_realpath(rel_cstr, nil) + if path_ptr == nil { + return "", Errno(get_last_error()) + } + defer _unix_free(path_ptr) + + path_cstr := transmute(cstring)path_ptr + path = strings.clone( string(path_cstr) ) + + return path, ERROR_NONE +} + +access :: proc(path: string, mask: int) -> (bool, Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_access(cstr, c.int(mask)) + if res == -1 { + return false, Errno(get_last_error()) + } + return true, ERROR_NONE +} + +heap_alloc :: proc(size: int) -> rawptr { + assert(size >= 0) + return _unix_calloc(1, c.size_t(size)) +} + +heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on + // POSIX platforms. Ensure your caller takes this into account. + return _unix_realloc(ptr, c.size_t(new_size)) +} + +heap_free :: proc(ptr: rawptr) { + _unix_free(ptr) +} + +getenv :: proc(name: string) -> (string, bool) { + path_str := strings.clone_to_cstring(name, context.temp_allocator) + cstr := _unix_getenv(path_str) + if cstr == nil { + return "", false + } + return string(cstr), true +} + +get_current_directory :: proc() -> string { + buf := make([dynamic]u8, MAX_PATH) + for { + cwd := _unix_getcwd(cstring(raw_data(buf)), c.size_t(len(buf))) + if cwd != nil { + return string(cwd) + } + if Errno(get_last_error()) != ERANGE { + return "" + } + resize(&buf, len(buf) + MAX_PATH) + } + unreachable() +} + +set_current_directory :: proc(path: string) -> (err: Errno) { + cstr := strings.clone_to_cstring(path, context.temp_allocator) + res := _unix_chdir(cstr) + if res == -1 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +exit :: proc "contextless" (code: int) -> ! { + _unix_exit(c.int(code)) +} + +current_thread_id :: proc "contextless" () -> int { + return _unix_getthrid() +} + +dlopen :: proc(filename: string, flags: int) -> rawptr { + cstr := strings.clone_to_cstring(filename, context.temp_allocator) + handle := _unix_dlopen(cstr, c.int(flags)) + return handle +} +dlsym :: proc(handle: rawptr, symbol: string) -> rawptr { + assert(handle != nil) + cstr := strings.clone_to_cstring(symbol, context.temp_allocator) + proc_handle := _unix_dlsym(handle, cstr) + return proc_handle +} +dlclose :: proc(handle: rawptr) -> bool { + assert(handle != nil) + return _unix_dlclose(handle) == 0 +} +dlerror :: proc() -> string { + return string(_unix_dlerror()) +} + +get_page_size :: proc() -> int { + // NOTE(tetra): The page size never changes, so why do anything complicated + // if we don't have to. + @static page_size := -1 + if page_size != -1 { + return page_size + } + + page_size = int(_unix_getpagesize()) + return page_size +} + + +_alloc_command_line_arguments :: proc() -> []string { + res := make([]string, len(runtime.args__)) + for arg, i in runtime.args__ { + res[i] = string(arg) + } + return res +} diff --git a/core/os/stat_unix.odin b/core/os/stat_unix.odin index 08c6f53c4..2aa9fc283 100644 --- a/core/os/stat_unix.odin +++ b/core/os/stat_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package os import "core:time" diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin index 3e49c4710..d0eaa3635 100644 --- a/core/path/filepath/path_unix.odin +++ b/core/path/filepath/path_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package filepath when ODIN_OS == .Darwin { @@ -59,6 +59,11 @@ when ODIN_OS == .Darwin { foreign libc { @(link_name="__error") __error :: proc() -> ^i32 --- } +} else when ODIN_OS == .OpenBSD { + @(private) + foreign libc { + @(link_name="__errno") __error :: proc() -> ^i32 --- + } } else { @(private) foreign libc { diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin index dd1e06625..1a3def200 100644 --- a/core/runtime/entry_unix.odin +++ b/core/runtime/entry_unix.odin @@ -1,5 +1,5 @@ //+private -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package runtime import "core:intrinsics" diff --git a/core/sync/channel_unix.odin b/core/sync/channel_unix.odin index d6bac2d71..47aa46004 100644 --- a/core/sync/channel_unix.odin +++ b/core/sync/channel_unix.odin @@ -1,4 +1,4 @@ -// +build linux, darwin, freebsd +// +build linux, darwin, freebsd, openbsd package sync import "core:time" diff --git a/core/sync/sync2/futex_openbsd.odin b/core/sync/sync2/futex_openbsd.odin new file mode 100644 index 000000000..dbc80747b --- /dev/null +++ b/core/sync/sync2/futex_openbsd.odin @@ -0,0 +1,78 @@ +//+private +//+build openbsd +package sync2 + +import "core:c" +import "core:os" +import "core:time" + +FUTEX_WAIT :: 1 +FUTEX_WAKE :: 2 + +FUTEX_PRIVATE_FLAG :: 128 + +FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) +FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) + +foreign import libc "system:c" + +foreign libc { + @(link_name="futex") + _unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int --- +} + +_futex_wait :: proc(f: ^Futex, expected: u32) -> bool { + res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil) + + if res != -1 { + return true + } + + if os.Errno(os.get_last_error()) == os.ETIMEDOUT { + return false + } + + panic("futex_wait failure") +} + +_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool { + if duration <= 0 { + return false + } + + timespec_t :: struct { + tv_sec: c.long, + tv_nsec: c.long, + } + + res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, ×pec_t{ + tv_sec = (c.long)(duration/1e9), + tv_nsec = (c.long)(duration%1e9), + }) + + if res != -1 { + return true + } + + if os.Errno(os.get_last_error()) == os.ETIMEDOUT { + return false + } + + panic("futex_wait_with_timeout failure") +} + +_futex_signal :: proc(f: ^Futex) { + res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil) + + if res == -1 { + panic("futex_wake_single failure") + } +} + +_futex_broadcast :: proc(f: ^Futex) { + res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil) + + if res == -1 { + panic("_futex_wake_all failure") + } +} diff --git a/core/sync/sync2/primitives_openbsd.odin b/core/sync/sync2/primitives_openbsd.odin new file mode 100644 index 000000000..ef122b02e --- /dev/null +++ b/core/sync/sync2/primitives_openbsd.odin @@ -0,0 +1,9 @@ +//+build openbsd +//+private +package sync2 + +import "core:os" + +_current_thread_id :: proc "contextless" () -> int { + return os.current_thread_id() +} diff --git a/core/sync/sync2/primitives_pthreads.odin b/core/sync/sync2/primitives_pthreads.odin index 8d2c3986d..28053f9cc 100644 --- a/core/sync/sync2/primitives_pthreads.odin +++ b/core/sync/sync2/primitives_pthreads.odin @@ -1,4 +1,4 @@ -//+build linux, freebsd +//+build linux, freebsd, openbsd //+private package sync2 diff --git a/core/sync/sync_openbsd.odin b/core/sync/sync_openbsd.odin new file mode 100644 index 000000000..926655f5b --- /dev/null +++ b/core/sync/sync_openbsd.odin @@ -0,0 +1,36 @@ +package sync + +import "core:sys/unix" +import "core:os" + +current_thread_id :: proc "contextless" () -> int { + return os.current_thread_id() +} + +// The Darwin docs say it best: +// A semaphore is much like a lock, except that a finite number of threads can hold it simultaneously. +// Semaphores can be thought of as being much like piles of tokens; multiple threads can take these tokens, +// but when there are none left, a thread must wait until another thread returns one. +Semaphore :: struct #align 16 { + handle: unix.sem_t, +} + +semaphore_init :: proc(s: ^Semaphore, initial_count := 0) { + assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0) +} + +semaphore_destroy :: proc(s: ^Semaphore) { + assert(unix.sem_destroy(&s.handle) == 0) + s.handle = {} +} + +semaphore_post :: proc(s: ^Semaphore, count := 1) { + // NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop. + for in 0.. ^sem_t --- + + sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int --- + sem_destroy :: proc(sem: ^sem_t) -> c.int --- + sem_post :: proc(sem: ^sem_t) -> c.int --- + sem_wait :: proc(sem: ^sem_t) -> c.int --- + sem_trywait :: proc(sem: ^sem_t) -> c.int --- + //sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int --- + + // NOTE: unclear whether pthread_yield is well-supported on Linux systems, + // see https://linux.die.net/man/3/pthread_yield + pthread_yield :: proc() --- +} diff --git a/core/sys/unix/pthread_unix.odin b/core/sys/unix/pthread_unix.odin index ccd8f7844..62e3701ab 100644 --- a/core/sys/unix/pthread_unix.odin +++ b/core/sys/unix/pthread_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package unix foreign import "system:pthread" diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 6cb91df86..b6679bbc2 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -1,4 +1,4 @@ -// +build linux, darwin, freebsd +// +build linux, darwin, freebsd, openbsd // +private package thread diff --git a/core/time/time_unix.odin b/core/time/time_unix.odin index 9c5c5cc35..37fc1fd3e 100644 --- a/core/time/time_unix.odin +++ b/core/time/time_unix.odin @@ -1,4 +1,4 @@ -//+build linux, darwin, freebsd +//+build linux, darwin, freebsd, openbsd package time IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC. @@ -22,16 +22,28 @@ TimeSpec :: struct { tv_nsec : i64, /* nanoseconds */ } -CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time. -CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep. -CLOCK_PROCESS_CPUTIME_ID :: 2 -CLOCK_THREAD_CPUTIME_ID :: 3 -CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP. -CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained." -CLOCK_MONOTONIC_COARSE :: 6 -CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep. -CLOCK_REALTIME_ALARM :: 8 -CLOCK_BOOTTIME_ALARM :: 9 +when ODIN_OS == .OpenBSD { + CLOCK_REALTIME :: 0 + CLOCK_PROCESS_CPUTIME_ID :: 2 + CLOCK_MONOTONIC :: 3 + CLOCK_THREAD_CPUTIME_ID :: 4 + CLOCK_UPTIME :: 5 + CLOCK_BOOTTIME :: 6 + + // CLOCK_MONOTONIC_RAW doesn't exist, use CLOCK_MONOTONIC + CLOCK_MONOTONIC_RAW :: CLOCK_MONOTONIC +} else { + CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time. + CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep. + CLOCK_PROCESS_CPUTIME_ID :: 2 + CLOCK_THREAD_CPUTIME_ID :: 3 + CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP. + CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained." + CLOCK_MONOTONIC_COARSE :: 6 + CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep. + CLOCK_REALTIME_ALARM :: 8 + CLOCK_BOOTTIME_ALARM :: 9 +} // TODO(tetra, 2019-11-05): The original implementation of this package for Darwin used this constants. // I do not know if Darwin programmers are used to the existance of these constants or not, so diff --git a/src/bug_report.cpp b/src/bug_report.cpp index 4dd251f24..7f6b668e8 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -17,6 +17,10 @@ #include #endif +#if defined(GB_SYSTEM_OPENBSD) + #include +#endif + /* NOTE(Jeroen): This prints the Windows product edition only, to be called from `print_platform_details`. */ @@ -643,6 +647,14 @@ void print_bug_report_help() { } else { gb_printf("macOS: Unknown\n"); } + #elif defined(GB_SYSTEM_OPENBSD) + struct utsname un; + + if (uname(&un) != -1) { + gb_printf("%s %s %s %s\n", un.sysname, un.release, un.version, un.machine); + } else { + gb_printf("OpenBSD: Unknown\n"); + } #else gb_printf("Unknown\n"); @@ -657,4 +669,4 @@ void print_bug_report_help() { And RAM info. */ report_ram_info(); -} \ No newline at end of file +} diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 610e4f847..72a4b35cc 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -16,6 +16,7 @@ enum TargetOsKind { TargetOs_linux, TargetOs_essence, TargetOs_freebsd, + TargetOs_openbsd, TargetOs_wasi, TargetOs_js, @@ -53,6 +54,7 @@ String target_os_names[TargetOs_COUNT] = { str_lit("linux"), str_lit("essence"), str_lit("freebsd"), + str_lit("openbsd"), str_lit("wasi"), str_lit("js"), @@ -354,6 +356,15 @@ gb_global TargetMetrics target_freebsd_amd64 = { str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; +gb_global TargetMetrics target_openbsd_amd64 = { + TargetOs_openbsd, + TargetArch_amd64, + 8, + 16, + str_lit("x86_64-unknown-openbsd-elf"), + str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"), +}; + gb_global TargetMetrics target_essence_amd64 = { TargetOs_essence, TargetArch_amd64, @@ -417,6 +428,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("windows_amd64"), &target_windows_amd64 }, { str_lit("freebsd_386"), &target_freebsd_386 }, { str_lit("freebsd_amd64"), &target_freebsd_amd64 }, + { str_lit("openbsd_amd64"), &target_openbsd_amd64 }, { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, { str_lit("js_wasm32"), &target_js_wasm32 }, @@ -723,6 +735,7 @@ String internal_odin_root_dir(void) { #elif defined(GB_SYSTEM_DRAGONFLYBSD) len = readlink("/proc/curproc/file", &path_buf[0], path_buf.count); #else + // XXX OpenBSD len = readlink("/proc/self/exe", &path_buf[0], path_buf.count); #endif if(len == 0) { @@ -922,6 +935,8 @@ void init_build_context(TargetMetrics *cross_target) { #endif #elif defined(GB_SYSTEM_FREEBSD) metrics = &target_freebsd_amd64; + #elif defined(GB_SYSTEM_OPENBSD) + metrics = &target_openbsd_amd64; #elif defined(GB_CPU_ARM) metrics = &target_linux_arm64; #else @@ -980,6 +995,9 @@ void init_build_context(TargetMetrics *cross_target) { case TargetOs_freebsd: bc->link_flags = str_lit("-arch x86-64 "); break; + case TargetOs_openbsd: + bc->link_flags = str_lit("-arch x86-64 "); + break; } } else if (bc->metrics.arch == TargetArch_i386) { switch (bc->metrics.os) { diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index eb9d7f293..69cc40de8 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3506,6 +3506,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case TargetOs_linux: case TargetOs_essence: case TargetOs_freebsd: + case TargetOs_openbsd: switch (build_context.metrics.arch) { case TargetArch_i386: case TargetArch_amd64: diff --git a/src/checker.cpp b/src/checker.cpp index f440b7c9a..5a7ece263 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -906,6 +906,7 @@ void init_universal(void) { {"Linux", TargetOs_linux}, {"Essence", TargetOs_essence}, {"FreeBSD", TargetOs_freebsd}, + {"OpenBSD", TargetOs_openbsd}, {"WASI", TargetOs_wasi}, {"JS", TargetOs_js}, {"Freestanding", TargetOs_freestanding}, diff --git a/src/common.cpp b/src/common.cpp index d3ee95b76..aaacda04b 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -848,7 +848,7 @@ ReadDirectoryError read_directory(String path, Array *fi) { return ReadDirectory_None; } -#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) +#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) #include diff --git a/src/gb/gb.h b/src/gb/gb.h index a9d6378c9..293e5063a 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -79,6 +79,10 @@ extern "C" { #ifndef GB_SYSTEM_FREEBSD #define GB_SYSTEM_FREEBSD 1 #endif + #elif defined(__OpenBSD__) + #ifndef GB_SYSTEM_OPENBSD + #define GB_SYSTEM_OPENBSD 1 + #endif #else #error This UNIX operating system is not supported #endif @@ -199,7 +203,7 @@ extern "C" { #endif #include // NOTE(bill): malloc on linux #include - #if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) + #if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #include #endif #include @@ -235,6 +239,15 @@ extern "C" { #define sendfile(out, in, offset, count) sendfile(out, in, offset, count, NULL, NULL, 0) #endif +#if defined(GB_SYSTEM_OPENBSD) + #include + #include + #define lseek64 lseek + + // XXX OpenBSD + #define sendfile(out, in, offset, count) (-1) +#endif + #if defined(GB_SYSTEM_UNIX) #include #endif @@ -783,6 +796,13 @@ typedef struct gbAffinity { isize thread_count; isize threads_per_core; } gbAffinity; +#elif defined(GB_SYSTEM_OPENBSD) +typedef struct gbAffinity { + b32 is_accurate; + isize core_count; + isize thread_count; + isize threads_per_core; +} gbAffinity; #else #error TODO(bill): Unknown system #endif @@ -3678,6 +3698,30 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) { return true; } +isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { + GB_ASSERT(0 <= core && core < a->core_count); + return a->threads_per_core; +} + +#elif defined(GB_SYSTEM_OPENBSD) +#include + +void gb_affinity_init(gbAffinity *a) { + a->core_count = sysconf(_SC_NPROCESSORS_ONLN); + a->threads_per_core = 1; + a->is_accurate = a->core_count > 0; + a->core_count = a->is_accurate ? a->core_count : 1; + a->thread_count = a->core_count; +} + +void gb_affinity_destroy(gbAffinity *a) { + gb_unused(a); +} + +b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) { + return true; +} + isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { GB_ASSERT(0 <= core && core < a->core_count); return a->threads_per_core; diff --git a/src/threading.cpp b/src/threading.cpp index 50d0dfed1..63e3415b2 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -486,7 +486,7 @@ void thread_set_name(Thread *t, char const *name) { #elif defined(GB_SYSTEM_OSX) // TODO(bill): Test if this works pthread_setname_np(name); -#elif defined(GB_SYSTEM_FREEBSD) +#elif defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) pthread_set_name_np(t->posix_handle, name); #else // TODO(bill): Test if this works -- cgit v1.2.3 From 49fecbdc5e6579956346e484a418b9501dfddd71 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Mar 2022 14:49:05 +0000 Subject: Improve error message when there is "no field" found for a large anonymous struct --- src/check_builtin.cpp | 8 ++++---- src/check_expr.cpp | 8 ++++---- src/types.cpp | 37 +++++++++++++++++++++++-------------- 3 files changed, 31 insertions(+), 22 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 69cc40de8..aeeeb9e4d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1106,7 +1106,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Selection sel = lookup_field(type, field_name, false); if (sel.entity == nullptr) { - gbString type_str = type_to_string(type); + gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "'%s' has no field named '%.*s'", type_str, LIT(field_name)); gb_string_free(type_str); @@ -1118,7 +1118,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } if (sel.indirect) { - gbString type_str = type_to_string(type); + gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); gb_string_free(type_str); @@ -1179,7 +1179,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Selection sel = lookup_field(type, field_name, false); if (sel.entity == nullptr) { - gbString type_str = type_to_string(type); + gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "'%s' has no field named '%.*s'", type_str, LIT(field_name)); gb_string_free(type_str); @@ -1191,7 +1191,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } if (sel.indirect) { - gbString type_str = type_to_string(type); + gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str); gb_string_free(type_str); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e07dc3d60..614da2368 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4470,7 +4470,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ if (entity == nullptr) { gbString op_str = expr_to_string(op_expr); - gbString type_str = type_to_string(operand->type); + gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str); @@ -4511,7 +4511,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ } gbString op_str = expr_to_string(op_expr); - gbString type_str = type_to_string(operand->type); + gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str); gb_string_free(sel_str); @@ -4536,7 +4536,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ } gbString op_str = expr_to_string(op_expr); - gbString type_str = type_to_string(operand->type); + gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str); gb_string_free(sel_str); @@ -4549,7 +4549,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ if (expr_entity != nullptr && is_type_polymorphic(expr_entity->type)) { gbString op_str = expr_to_string(op_expr); - gbString type_str = type_to_string(operand->type); + gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); error(op_expr, "Cannot access field '%s' from non-specialized polymorphic type '%s'", sel_str, op_str); gb_string_free(sel_str); diff --git a/src/types.cpp b/src/types.cpp index 74080334a..58ccdf5b9 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -703,7 +703,7 @@ struct TypePath; i64 type_size_of (Type *t); i64 type_align_of (Type *t); i64 type_offset_of (Type *t, i32 index); -gbString type_to_string (Type *type); +gbString type_to_string (Type *type, bool shorthand=false); i64 type_size_of_internal(Type *t, TypePath *path); void init_map_internal_types(Type *type); Type * bit_set_to_int(Type *t); @@ -3936,7 +3936,7 @@ Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type -gbString write_type_to_string(gbString str, Type *type) { +gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { if (type == nullptr) { return gb_string_appendc(str, ""); } @@ -4051,15 +4051,21 @@ gbString write_type_to_string(gbString str, Type *type) { if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union"); if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align); str = gb_string_appendc(str, " {"); - for_array(i, type->Struct.fields) { - Entity *f = type->Struct.fields[i]; - GB_ASSERT(f->kind == Entity_Variable); - if (i > 0) { - str = gb_string_appendc(str, ", "); + + + if (shorthand && type->Struct.fields.count > 16) { + str = gb_string_append_fmt(str, "%lld fields...", cast(long long)type->Struct.fields.count); + } else { + for_array(i, type->Struct.fields) { + Entity *f = type->Struct.fields[i]; + GB_ASSERT(f->kind == Entity_Variable); + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = gb_string_append_length(str, f->token.string.text, f->token.string.len); + str = gb_string_appendc(str, ": "); + str = write_type_to_string(str, f->type); } - str = gb_string_append_length(str, f->token.string.text, f->token.string.len); - str = gb_string_appendc(str, ": "); - str = write_type_to_string(str, f->type); } str = gb_string_append_rune(str, '}'); } break; @@ -4234,13 +4240,16 @@ gbString write_type_to_string(gbString str, Type *type) { } -gbString type_to_string(Type *type, gbAllocator allocator) { - return write_type_to_string(gb_string_make(allocator, ""), type); +gbString type_to_string(Type *type, gbAllocator allocator, bool shorthand=false) { + return write_type_to_string(gb_string_make(allocator, ""), type, shorthand); } -gbString type_to_string(Type *type) { - return write_type_to_string(gb_string_make(heap_allocator(), ""), type); +gbString type_to_string(Type *type, bool shorthand) { + return write_type_to_string(gb_string_make(heap_allocator(), ""), type, shorthand); } +gbString type_to_string_shorthand(Type *type) { + return type_to_string(type, true); +} -- cgit v1.2.3 From a5dde78f0882cc6db0b329f356dc7345d47798ca Mon Sep 17 00:00:00 2001 From: Joakim Hentula Date: Wed, 2 Mar 2022 16:44:33 +0000 Subject: Add relative slice to type checks for built in len --- src/check_builtin.cpp | 2 +- src/llvm_backend_proc.cpp | 4 ++-- src/llvm_backend_utility.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index aeeeb9e4d..365d3434f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -952,7 +952,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 mode = Addressing_Constant; value = exact_value_i64(at->EnumeratedArray.count); type = t_untyped_integer; - } else if (is_type_slice(op_type) && id == BuiltinProc_len) { + } else if ((is_type_slice(op_type) || is_type_relative_slice(op_type)) && id == BuiltinProc_len) { mode = Addressing_Value; } else if (is_type_dynamic_array(op_type)) { mode = Addressing_Value; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7ead77c2c..eb6c89b85 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1042,7 +1042,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, return lb_string_len(p, v); } else if (is_type_array(t)) { GB_PANIC("Array lengths are constant"); - } else if (is_type_slice(t)) { + } else if (is_type_slice(t) || is_type_relative_slice(t)) { return lb_slice_len(p, v); } else if (is_type_dynamic_array(t)) { return lb_dynamic_array_len(p, v); @@ -1068,7 +1068,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, GB_PANIC("Unreachable"); } else if (is_type_array(t)) { GB_PANIC("Array lengths are constant"); - } else if (is_type_slice(t)) { + } else if (is_type_slice(t) || is_type_relative_slice(t)) { return lb_slice_len(p, v); } else if (is_type_dynamic_array(t)) { return lb_dynamic_array_cap(p, v); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 98b7e07f0..431cfea9b 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1373,7 +1373,7 @@ lbValue lb_slice_elem(lbProcedure *p, lbValue slice) { return lb_emit_struct_ev(p, slice, 0); } lbValue lb_slice_len(lbProcedure *p, lbValue slice) { - GB_ASSERT(is_type_slice(slice.type)); + GB_ASSERT(is_type_slice(slice.type) || is_type_relative_slice(slice.type)); return lb_emit_struct_ev(p, slice, 1); } lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) { -- cgit v1.2.3