Browse Source

Internal changes; thread.odin for windows only

Ginger Bill 8 years ago
parent
commit
dbddec33c8
8 changed files with 245 additions and 62 deletions
  1. 54 7
      code/demo.odin
  2. 6 0
      core/fmt.odin
  3. 5 5
      core/mem.odin
  4. 76 0
      core/thread.odin
  5. 45 7
      src/check_expr.cpp
  6. 1 0
      src/main.cpp
  7. 22 9
      src/parser.cpp
  8. 36 34
      src/types.cpp

+ 54 - 7
code/demo.odin

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

+ 6 - 0
core/fmt.odin

@@ -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 {

+ 5 - 5
core/mem.odin

@@ -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 - 0
core/thread.odin

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

+ 45 - 7
src/check_expr.cpp

@@ -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 - 0
src/main.cpp

@@ -1,4 +1,5 @@
 #define USE_CUSTOM_BACKEND 0
+// #define NO_ARRAY_BOUNDS_CHECK
 
 #include "common.cpp"
 #include "timings.cpp"

+ 22 - 9
src/parser.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);
 		}

+ 36 - 34
src/types.cpp

@@ -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;
 			}