mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-29 17:34:34 +00:00
Internal changes; thread.odin for windows only
This commit is contained in:
@@ -1,11 +1,58 @@
|
||||
import "fmt.odin";
|
||||
import "strconv.odin";
|
||||
import (
|
||||
"fmt.odin";
|
||||
"strconv.odin";
|
||||
"thread.odin";
|
||||
win32 "sys/windows.odin";
|
||||
)
|
||||
|
||||
Opaque :: union{};
|
||||
prefix_table := [...]string{
|
||||
"White",
|
||||
"Red",
|
||||
"Orange",
|
||||
"Yellow",
|
||||
"Green",
|
||||
"Blue",
|
||||
"Octarine",
|
||||
"Black",
|
||||
};
|
||||
|
||||
main :: proc() {
|
||||
buf := make([]u8, 0, 10);
|
||||
s := strconv.append_bool(buf, true);
|
||||
fmt.println(s);
|
||||
worker_proc :: proc(t: ^thread.Thread) -> int {
|
||||
do_work :: proc(iteration: int, index: int) {
|
||||
fmt.printf("`%s`: iteration %d\n", prefix_table[index], iteration);
|
||||
win32.sleep(1);
|
||||
}
|
||||
|
||||
for iteration in 1...5 {
|
||||
fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
|
||||
do_work(iteration, t.user_index);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
main :: proc() {
|
||||
threads := make([]^thread.Thread, 0, len(prefix_table));
|
||||
|
||||
for i in 0..len(prefix_table) {
|
||||
if t := thread.create(worker_proc); t != nil {
|
||||
t.init_context = context;
|
||||
t.use_init_context = true;
|
||||
t.user_index = len(threads);
|
||||
append(&threads, t);
|
||||
thread.start(t);
|
||||
}
|
||||
}
|
||||
|
||||
for len(threads) > 0 {
|
||||
for i := 0; i < len(threads); i += 1 {
|
||||
if t := threads[i]; thread.is_done(t) {
|
||||
fmt.printf("Thread %d is done\n", t.user_index);
|
||||
thread.destroy(t);
|
||||
|
||||
threads[i] = threads[len(threads)-1];
|
||||
pop(&threads);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"raw.odin";
|
||||
)
|
||||
|
||||
|
||||
_BUFFER_SIZE :: 1<<12;
|
||||
|
||||
StringBuffer :: union {
|
||||
@@ -749,6 +750,11 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) {
|
||||
fmt_bad_verb(fi, verb);
|
||||
return;
|
||||
}
|
||||
if b.is_raw_union {
|
||||
write_string(fi.buf, info.name);
|
||||
write_string(fi.buf, "{}");
|
||||
return;
|
||||
}
|
||||
write_string(fi.buf, info.name);
|
||||
write_byte(fi.buf, '{');
|
||||
for _, i in b.names {
|
||||
|
||||
@@ -73,17 +73,17 @@ AllocationHeader :: struct {
|
||||
|
||||
allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
|
||||
header.size = size;
|
||||
ptr := cast(^int)(header+1);
|
||||
n := cast(^int)data - ptr;
|
||||
ptr := cast(^uint)(header+1);
|
||||
n := cast(^uint)data - ptr;
|
||||
|
||||
for i in 0..n {
|
||||
(ptr+i)^ = -1;
|
||||
(ptr+i)^ = ~uint(0);
|
||||
}
|
||||
}
|
||||
allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
||||
if data == nil do return nil;
|
||||
p := cast(^int)data;
|
||||
for (p-1)^ == -1 do p = (p-1);
|
||||
p := cast(^uint)data;
|
||||
for (p-1)^ == ~uint(0) do p = (p-1);
|
||||
return cast(^AllocationHeader)(p-1);
|
||||
}
|
||||
|
||||
|
||||
76
core/thread.odin
Normal file
76
core/thread.odin
Normal file
@@ -0,0 +1,76 @@
|
||||
_ :: compile_assert(ODIN_OS == "windows");
|
||||
|
||||
import win32 "sys/windows.odin";
|
||||
|
||||
Thread :: struct {
|
||||
using specific: OsSpecific;
|
||||
procedure: Proc;
|
||||
data: rawptr;
|
||||
user_index: int;
|
||||
|
||||
init_context: Context;
|
||||
use_init_context: bool;
|
||||
|
||||
Proc :: #type proc(^Thread) -> int;
|
||||
OsSpecific :: struct {
|
||||
win32_thread: win32.Handle;
|
||||
win32_thread_id: u32;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
create :: proc(procedure: Thread.Proc) -> ^Thread {
|
||||
win32_thread_id: u32;
|
||||
|
||||
__windows_thread_entry_proc :: proc(data: rawptr) -> i32 #cc_c {
|
||||
if data == nil do return 0;
|
||||
|
||||
t := cast(^Thread)data;
|
||||
|
||||
c := context;
|
||||
if t.use_init_context {
|
||||
c = t.init_context;
|
||||
}
|
||||
|
||||
exit := 0;
|
||||
push_context c {
|
||||
exit = t.procedure(t);
|
||||
}
|
||||
|
||||
return cast(i32)exit;
|
||||
}
|
||||
|
||||
|
||||
win32_thread_proc := cast(rawptr)__windows_thread_entry_proc;
|
||||
thread := new(Thread);
|
||||
|
||||
win32_thread := win32.create_thread(nil, 0, win32_thread_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id);
|
||||
if win32_thread == nil {
|
||||
free(thread);
|
||||
return nil;
|
||||
}
|
||||
thread.procedure = procedure;
|
||||
thread.win32_thread = win32_thread;
|
||||
thread.win32_thread_id = win32_thread_id;
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
start :: proc(using thread: ^Thread) {
|
||||
win32.resume_thread(win32_thread);
|
||||
}
|
||||
|
||||
is_done :: proc(using thread: ^Thread) -> bool {
|
||||
res := win32.wait_for_single_object(win32_thread, 0);
|
||||
return res != win32.WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
join :: proc(using thread: ^Thread) {
|
||||
win32.wait_for_single_object(win32_thread, win32.INFINITE);
|
||||
win32.close_handle(win32_thread);
|
||||
win32_thread = win32.INVALID_HANDLE;
|
||||
}
|
||||
destroy :: proc(thread: ^Thread) {
|
||||
join(thread);
|
||||
free(thread);
|
||||
}
|
||||
@@ -1250,12 +1250,12 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
if (!struct_type->failure && !st->is_packed && !st->is_ordered) {
|
||||
struct_type->failure = false;
|
||||
struct_type->Struct.are_offsets_set = false;
|
||||
struct_type->Struct.offsets = nullptr;
|
||||
gb_zero_item(&struct_type->Struct.offsets);
|
||||
// NOTE(bill): Reorder fields for reduced size/performance
|
||||
|
||||
Array<Entity *> reordered_fields = {};
|
||||
array_init_count(&reordered_fields, c->allocator, fields.count);
|
||||
for_array(i, fields) {
|
||||
for_array(i, reordered_fields) {
|
||||
reordered_fields[i] = struct_type->Struct.fields_in_src_order[i];
|
||||
}
|
||||
|
||||
@@ -1338,10 +1338,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
||||
if (t != nullptr && t != t_invalid) {
|
||||
bool ok = true;
|
||||
t = default_type(t);
|
||||
if (is_type_untyped(t)) {
|
||||
if (is_type_untyped(t) || is_type_empty_union(t)) {
|
||||
ok = false;
|
||||
gbString str = type_to_string(t);
|
||||
error(node, "Invalid type in union `%s`", str);
|
||||
error(node, "Invalid variant type in union `%s`", str);
|
||||
gb_string_free(str);
|
||||
} else {
|
||||
for_array(j, variants) {
|
||||
@@ -1362,6 +1362,44 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
||||
}
|
||||
|
||||
union_type->Union.variants = variants;
|
||||
|
||||
if (ut->align != nullptr) {
|
||||
Operand o = {};
|
||||
check_expr(c, &o, ut->align);
|
||||
if (o.mode != Addressing_Constant) {
|
||||
if (o.mode != Addressing_Invalid) {
|
||||
error(ut->align, "#align must be a constant");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Type *type = base_type(o.type);
|
||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||
if (o.value.kind == ExactValue_Integer) {
|
||||
i64 align = i128_to_i64(o.value.value_integer);
|
||||
if (align < 1 || !gb_is_power_of_two(align)) {
|
||||
error(ut->align, "#align must be a power of 2, got %lld", align);
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE(bill): Success!!!
|
||||
i64 custom_align = gb_clamp(align, 1, build_context.max_align);
|
||||
if (custom_align < align) {
|
||||
warning(ut->align, "Custom alignment has been clamped to %lld from %lld", align, custom_align);
|
||||
}
|
||||
if (variants.count == 0) {
|
||||
error(ut->align, "An empty union cannot have a custom alignment");
|
||||
} else {
|
||||
union_type->Union.custom_align = custom_align;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
error(ut->align, "#align must be an integer");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||
@@ -1653,9 +1691,9 @@ bool check_type_specialization_to(Checker *c, Type *specialization, Type *type,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent) {
|
||||
GB_ASSERT(s->Struct.polymorphic_params != nullptr);
|
||||
GB_ASSERT(t->Struct.polymorphic_params != nullptr);
|
||||
if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent &&
|
||||
s->Struct.polymorphic_params != nullptr &&
|
||||
t->Struct.polymorphic_params != nullptr) {
|
||||
|
||||
TypeTuple *s_tuple = &s->Struct.polymorphic_params->Tuple;
|
||||
TypeTuple *t_tuple = &t->Struct.polymorphic_params->Tuple;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define USE_CUSTOM_BACKEND 0
|
||||
// #define NO_ARRAY_BOUNDS_CHECK
|
||||
|
||||
#include "common.cpp"
|
||||
#include "timings.cpp"
|
||||
|
||||
@@ -427,8 +427,9 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
|
||||
AstNode * align; \
|
||||
}) \
|
||||
AST_NODE_KIND(UnionType, "union type", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> variants; \
|
||||
Token token; \
|
||||
Array<AstNode *> variants; \
|
||||
AstNode * align; \
|
||||
}) \
|
||||
AST_NODE_KIND(EnumType, "enum type", struct { \
|
||||
Token token; \
|
||||
@@ -1460,10 +1461,11 @@ AstNode *ast_struct_type(AstFile *f, Token token, Array<AstNode *> fields, isize
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_union_type(AstFile *f, Token token, Array<AstNode *> variants) {
|
||||
AstNode *ast_union_type(AstFile *f, Token token, Array<AstNode *> variants, AstNode *align) {
|
||||
AstNode *result = make_ast_node(f, AstNode_UnionType);
|
||||
result->UnionType.token = token;
|
||||
result->UnionType.variants = variants;
|
||||
result->UnionType.token = token;
|
||||
result->UnionType.variants = variants;
|
||||
result->UnionType.align = align;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2496,10 +2498,23 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "union");
|
||||
Array<AstNode *> variants = make_ast_node_array(f);
|
||||
isize total_decl_name_count = 0;
|
||||
AstNode *align = nullptr;
|
||||
|
||||
CommentGroup docs = f->lead_comment;
|
||||
Token start_token = f->curr_token;
|
||||
|
||||
while (allow_token(f, Token_Hash)) {
|
||||
Token tag = expect_token_after(f, Token_Ident, "#");
|
||||
if (tag.string == "align") {
|
||||
if (align) {
|
||||
syntax_error(tag, "Duplicate union tag `#%.*s`", LIT(tag.string));
|
||||
}
|
||||
align = parse_expr(f, true);
|
||||
} else {
|
||||
syntax_error(tag, "Invalid union tag `#%.*s`", LIT(tag.string));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while (f->curr_token.kind != Token_CloseBrace &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
@@ -2514,7 +2529,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
return ast_union_type(f, token, variants);
|
||||
return ast_union_type(f, token, variants, align);
|
||||
} break;
|
||||
|
||||
case Token_enum: {
|
||||
@@ -3009,15 +3024,13 @@ AstNode *parse_gen_decl(AstFile *f, Token token, ParseSpecFunc *func) {
|
||||
if (f->curr_token.kind == Token_OpenParen) {
|
||||
specs = make_ast_node_array(f);
|
||||
open = expect_token(f, Token_OpenParen);
|
||||
bool require_semicolon_after_paren = false;
|
||||
while (f->curr_token.kind != Token_CloseParen &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
AstNode *spec = func(f, docs, token);
|
||||
array_add(&specs, spec);
|
||||
}
|
||||
close = expect_token(f, Token_CloseParen);
|
||||
if (require_semicolon_after_paren ||
|
||||
f->curr_token.pos.line == close.pos.line ||
|
||||
if (f->curr_token.pos.line == close.pos.line ||
|
||||
open.pos.line == close.pos.line) {
|
||||
expect_semicolon(f, nullptr);
|
||||
}
|
||||
|
||||
@@ -74,16 +74,16 @@ struct TypeStruct {
|
||||
AstNode *node;
|
||||
Scope * scope;
|
||||
|
||||
i64 * offsets; // == fields.count
|
||||
bool are_offsets_set;
|
||||
bool are_offsets_being_processed;
|
||||
bool is_packed;
|
||||
bool is_ordered;
|
||||
bool is_raw_union;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
Type * polymorphic_params; // Type_Tuple
|
||||
Type * polymorphic_parent;
|
||||
Array<i64> offsets;
|
||||
bool are_offsets_set;
|
||||
bool are_offsets_being_processed;
|
||||
bool is_packed;
|
||||
bool is_ordered;
|
||||
bool is_raw_union;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
Type * polymorphic_params; // Type_Tuple
|
||||
Type * polymorphic_parent;
|
||||
|
||||
i64 custom_align; // NOTE(bill): Only used in structs at the moment
|
||||
Entity * names;
|
||||
@@ -128,8 +128,8 @@ struct TypeStruct {
|
||||
}) \
|
||||
TYPE_KIND(Tuple, struct { \
|
||||
Array<Entity *> variables; /* Entity_Variable */ \
|
||||
bool are_offsets_set; \
|
||||
i64 * offsets; \
|
||||
Array<i64> offsets; \
|
||||
bool are_offsets_set; \
|
||||
}) \
|
||||
TYPE_KIND(Proc, struct { \
|
||||
AstNode *node; \
|
||||
@@ -1831,6 +1831,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
if (t->Union.variants.count == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (t->Union.custom_align > 0) {
|
||||
return gb_clamp(t->Union.custom_align, 1, build_context.max_align);
|
||||
}
|
||||
i64 max = build_context.word_size;
|
||||
for_array(i, t->Union.variants) {
|
||||
Type *variant = t->Union.variants[i];
|
||||
@@ -1848,6 +1851,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
} break;
|
||||
|
||||
case Type_Struct: {
|
||||
if (t->Struct.custom_align > 0) {
|
||||
return gb_clamp(t->Struct.custom_align, 1, build_context.max_align);
|
||||
}
|
||||
if (t->Struct.is_raw_union) {
|
||||
i64 max = 1;
|
||||
for_array(i, t->Struct.fields) {
|
||||
@@ -1863,29 +1869,24 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
}
|
||||
}
|
||||
return max;
|
||||
} else {
|
||||
if (t->Struct.custom_align > 0) {
|
||||
return gb_clamp(t->Struct.custom_align, 1, build_context.max_align);
|
||||
} else if (t->Struct.fields.count > 0) {
|
||||
i64 max = 1;
|
||||
if (t->Struct.is_packed) {
|
||||
max = build_context.word_size;
|
||||
}
|
||||
if (t->Struct.fields.count > 0) {
|
||||
i64 max = 1;
|
||||
if (t->Struct.is_packed) {
|
||||
max = build_context.word_size;
|
||||
for_array(i, t->Struct.fields) {
|
||||
Type *field_type = t->Struct.fields[i]->type;
|
||||
type_path_push(path, field_type);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
for_array(i, t->Struct.fields) {
|
||||
Type *field_type = t->Struct.fields[i]->type;
|
||||
type_path_push(path, field_type);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||
type_path_pop(path);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
}
|
||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||
type_path_pop(path);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -1904,8 +1905,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
return gb_clamp(next_pow2(type_size_of_internal(allocator, t, path)), 1, build_context.word_size);
|
||||
}
|
||||
|
||||
i64 *type_set_offsets_of(gbAllocator allocator, Array<Entity *> fields, bool is_packed, bool is_raw_union) {
|
||||
i64 *offsets = gb_alloc_array(allocator, i64, fields.count);
|
||||
Array<i64> type_set_offsets_of(gbAllocator allocator, Array<Entity *> fields, bool is_packed, bool is_raw_union) {
|
||||
Array<i64> offsets = {};
|
||||
array_init_count(&offsets, allocator, fields.count);
|
||||
i64 curr_offset = 0;
|
||||
if (is_raw_union) {
|
||||
for_array(i, fields) {
|
||||
@@ -2120,7 +2122,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
if (t->Struct.are_offsets_being_processed && t->Struct.offsets == nullptr) {
|
||||
if (t->Struct.are_offsets_being_processed && t->Struct.offsets.data == nullptr) {
|
||||
type_path_print_illegal_cycle(path, path->path.count-1);
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user