// casts to all other pointer types.
null :: cast(rawptr) 0
-//
-// `null_proc` is a special function that breaks the normal rules of type
-// checking. `null_proc`, or any procedure marked with `#null`, is assignable
-// to any function type, regardless of if the types match. For example,
-//
-// f: (i32) -> i32 = null_proc;
-//
-// Even though `null_proc` is a `() -> void` function, it bypasses that check
-// and gets assigned to `f`. If f is called, there will be a runtime exception.
-// This is by design.
+#doc """
+ `null_proc` is a special function that breaks the normal rules of type
+ checking. `null_proc`, or any procedure marked with `#null`, is assignable
+ to any function type, regardless of if the types match. For example,
+
+ f: (i32) -> i32 = null_proc;
+
+ Even though `null_proc` is a `() -> void` function, it bypasses that check
+ and gets assigned to `f`. If f is called, there will be a runtime exception.
+ This is by design.
+"""
null_proc :: () -> void #null ---
//
}
-//
-// Represents a generic "iterator" or "generator" of a specific
-// type. Can be used in a for-loop natively.
-//
-// `data` is used for contextual information and is passed to
-// the `next`, `close`, and `remove` procedures.
-//
-// `next` is used to extract the next value out of the iterator.
-// It returns the next value, and a continuation flag. If the
-// flag is false, the value should be ignored and iteration should
-// stop.
-//
-// `close` should called when the iterator has ended. This is
-// done automatically in for-loops, and in the `core.iter` library.
-// In for-loops, `close` is called no matter which way the for-loop
-// exits (`break`, `return`, etc). Using this rule, iterator can
-// be used to create "resources" that automatically close when you
-// are done with them.
-//
-// `remove` is used to tell the iterator to remove the last value
-// returned from some underlying data store. Invoked automatically
-// using the `#remove` directive in a for-loop.
+#doc """
+ Represents a generic "iterator" or "generator" of a specific
+ type. Can be used in a for-loop natively.
+
+ `data` is used for contextual information and is passed to
+ the `next`, `close`, and `remove` procedures.
+
+ `next` is used to extract the next value out of the iterator.
+ It returns the next value, and a continuation flag. If the
+ flag is false, the value should be ignored and iteration should
+ stop.
+
+ `close` should called when the iterator has ended. This is
+ done automatically in for-loops, and in the `core.iter` library.
+ In for-loops, `close` is called no matter which way the for-loop
+ exits (`break`, `return`, etc). Using this rule, iterator can
+ be used to create "resources" that automatically close when you
+ are done with them.
+
+ `remove` is used to tell the iterator to remove the last value
+ returned from some underlying data store. Invoked automatically
+ using the `#remove` directive in a for-loop.
+"""
Iterator :: struct (Iter_Type: type_expr) {
data: rawptr;
next: (data: rawptr) -> (Iter_Type, bool);
}
-//
-// Optional represents the possibility of a value being empty, without
-// resorting to pointers and null-pointers. Most of the functionality
-// for Optional is defined in core/containers/optional.onyx. This
-// definition exists here because the compiler use it as the template
-// for types like '? i32'. In other words, '? i32' is equivalent to
-// 'Optional(i32)'.
+#doc """
+ Optional represents the possibility of a value being empty, without
+ resorting to pointers and null-pointers. Most of the functionality
+ for Optional is defined in core/containers/optional.onyx. This
+ definition exists here because the compiler use it as the template
+ for types like '? i32'. In other words, '? i32' is equivalent to
+ 'Optional(i32)'.
+"""
Optional :: struct (Value_Type: type_expr) {
has_value: bool;
value: Value_Type;
-//
-// This structure represents the result of a '#callsite' expression. Currently,
-// #callsite is only valid (and parsed) as a default value for a procedure parameter.
-// It allows the function to get the address of the calling site, which can be
-// used for error printing, unique hashes, and much more.
+#doc """
+ This structure represents the result of a '#callsite' expression. Currently,
+ #callsite is only valid (and parsed) as a default value for a procedure parameter.
+ It allows the function to get the address of the calling site, which can be
+ used for error printing, unique hashes, and much more.
+"""
CallSite :: struct {
file : str;
line : u32;
}
-//
-// This structure is used to represent any value in the language.
-// It contains a pointer to the data, and the type of the value.
-// Using the `core.misc` library, you can easily manipulate `any`s
-// and build runtime polymorphism.
+#doc """
+ This structure is used to represent any value in the language.
+ It contains a pointer to the data, and the type of the value.
+ Using the `core.misc` library, you can easily manipulate `any`s
+ and build runtime polymorphism.
+"""
any :: struct {
data: rawptr;
type: type_expr;
}
-//
-// Represents a code block that can be passed around at compile-time.
-// This is commonly used with macros or polymorphic procedures to create
-// very power extensions to the syntax.
+#doc """
+ Represents a code block that can be passed around at compile-time.
+ This is commonly used with macros or polymorphic procedures to create
+ very power extensions to the syntax.
+"""
Code :: struct {_:i32;}
-//
-// Define aliases for common datastructures in the core library, if the core library is available.
-// I'm on the fence about keeping this, as the programmer may want to use these names for their own
-// structures, but for the moment I don't see any harm. I'm also thinking about removing the '[..]'
-// syntax for dynamic arrays and just make them like Map's and Set's, i.e. Array(T). This would
-// remove some confusion around the 3 different array types as dynamic arrays would clearly just be
-// normal structures. With the recent addition of macros and iterators, there really wouldn't be much
-// difference anyway.
+#doc """
+ Define aliases for common datastructures in the core library, if the core library is available.
+ I'm on the fence about keeping this, as the programmer may want to use these names for their own
+ structures, but for the moment I don't see any harm. I'm also thinking about removing the '[..]'
+ syntax for dynamic arrays and just make them like Map's and Set's, i.e. Array(T). This would
+ remove some confusion around the 3 different array types as dynamic arrays would clearly just be
+ normal structures. With the recent addition of macros and iterators, there really wouldn't be much
+ difference anyway.
+"""
#if #defined((package core.map).Map) {
Map :: (package core.map).Map;
}
}
-//
-// This procedure is a special compiler generated procedure that initializes all the data segments
-// in the program. It should only be called once, by the main thread, at the start of execution. It
-// is undefined behaviour if it is called more than once.
+#doc """
+ This procedure is a special compiler generated procedure that initializes all the data segments
+ in the program. It should only be called once, by the main thread, at the start of execution. It
+ is undefined behaviour if it is called more than once.
+"""
__initialize_data_segments :: () -> void ---
-//
-// This is also a special compiler generated procedure that calls all procedures specified with
-// #init, in the specified order. It should theoretically only be called once on the main thread.
+#doc """
+ This is a special compiler generated procedure that calls all procedures specified with `#init`
+ in the specified order. It should theoretically only be called once on the main thread.
+"""
__run_init_procedures :: () -> void ---
-//
-// This overloaded procedure allow you to define an implicit rule for how to convert any value
-// into a boolean. A default is provided for ALL pointer types and array types, but this can
-// be used for structures or distinct types.
+#doc """
+ This overloaded procedure allow you to define an implicit rule for how to convert any value
+ into a boolean. A default is provided for ALL pointer types and array types, but this can
+ be used for structures or distinct types.
+"""
__implicit_bool_cast :: #match -> bool {}
-//
-// Defines all options for changing the memory layout, imports and exports,
-// and more of an Onyx binary.
+#doc """
+ Defines all options for changing the memory layout, imports and exports,
+ and more of an Onyx binary.
+"""
Link_Options :: struct {
// By default the memory layout of a binary is:
// reserved | static-data | stack | heap
}
-//
-// Special type used to represent a package at runtime.
-// For example,
-//
-// x: package_id = package main
-//
-// Currently, there is not much you can do with this; it is
-// only used by the runtime.info library if you want to filter
-// tags based on which package they are coming from.
+#doc """
+ Special type used to represent a package at runtime.
+ For example,
+
+ x: package_id = package main
+
+ Currently, there is not much you can do with this; it is
+ only used by the runtime.info library if you want to filter
+ tags based on which package they are coming from.
+"""
package_id :: #distinct u32
//
use core {string, math}
-//
-// Converts a string into an integer. Works with positive and
-// negative integers. If given a pointer to a string, will
-// modify the string to extract the integer part.
+#doc """
+ Converts a string into an integer. Works with positive and
+ negative integers. If given a pointer to a string, will
+ modify the string to extract the integer part.
+"""
str_to_i64 :: #match #local {}
#overload
}
-//
-// Converts a string to a floating point number.
+#doc "Converts a string to a floating point number."
str_to_f64 :: #match #local {}
#overload
}
-//
-// Converts an integer into a string using the buffer provided.
-// Supports upto base 64. If prefix is true, binary numbers are
-// prefixed with '0b' and hexadecimal numbers are prefixed with
-// '0x'.
+#doc """
+ Converts an integer into a string using the buffer provided.
+ Supports upto base 64. If prefix is true, binary numbers are
+ prefixed with '0b' and hexadecimal numbers are prefixed with
+ '0x'.
+"""
i64_to_str :: (n: i64, base: u64, buf: [] u8, min_length := 0, prefix := false) -> str {
is_neg := false;
if n < 0 && base == 10 {
}
-//
-// Converts an unsigned number into a string using the buffer provided.
-// Behaves like i64_to_str.
+#doc """
+ Converts an unsigned number into a string using the buffer provided.
+ Behaves like i64_to_str.
+"""
u64_to_str :: (n: u64, base: u64, buf: [] u8, min_length := 0, prefix := false) -> str {
c: [&] u8 = &buf[buf.count - 1];
len := 0;
return str.{ data = c + 1, count = len };
}
-//
-// Converts a floating point number into a string, using
-// the buffer provided.
-//
-// This is better than what used to be, but still relies on converting the integer
-// part of the float to an integer, which could overflow.
+#doc """
+ Converts a floating point number into a string, using
+ the buffer provided.
+
+ This is better than what used to be, but still relies on converting the integer
+ part of the float to an integer, which could overflow.
+"""
f64_to_str :: (f: f64, buf: [] u8, digits_after_decimal := 4) -> str {
if math.is_nan(f) {
return format(buf, "NaN");
custom_parsers : Map(type_expr, #type (rawptr, str, Allocator) -> bool);
}
-//
-// This procedure is run before main() as it is an #init procedure.
-// It looks for all custom formatting and parsing definitions and
-// registers them to be used in format_any and parse_any.
+#doc """
+ This procedure is run before main() as it is an #init procedure.
+ It looks for all custom formatting and parsing definitions and
+ registers them to be used in format_any and parse_any.
+"""
custom_formatters_initialized :: #init () {
map.init(&custom_formatters, default=null_proc);
map.init(&custom_parsers, default=null_proc);
}
}
-//
-// Registers a formatting function for a particular type. This type is
-// inferred from the type of the third argument in the given function.
+#doc """
+ Registers a formatting function for a particular type. This type is
+ inferred from the type of the third argument in the given function.
+"""
register_custom_formatter :: (formatter: (&Format_Output, &Format, &$T) -> void) {
custom_formatters[T] = formatter;
}
-//
-// Registers a parsing function for a particular type. This type is
-// inferred from the type of the first argument in the given function.
+#doc """
+ Registers a parsing function for a particular type. This type is
+ inferred from the type of the first argument in the given function.
+"""
register_custom_parser :: (parser: (&$T, str, Allocator) -> bool) {
custom_parsers[T] = parser;
}
-//
-// Tag-type used to specify how to format a structure.
-//
-// @conv.Custom_Format.{ format_structure }
-// TheStructure :: struct { ... }
-//
+#doc """
+ Tag-type used to specify how to format a structure.
+
+ @conv.Custom_Format.{ format_structure }
+ TheStructure :: struct { ... }
+"""
Custom_Format :: struct {
format: (&Format_Output, &Format, rawptr) -> void;
}
-//
-// Tag-type used to specify that a certain procedure should be used
-// to format a type.
-//
-// @conv.Custom_Format_Proc.{ TheStructure }
-// format_structure :: (output: &conv.Format_Output, format: &conv.Format, data: &TheStructure) { ... }
-//
+#doc """
+ Tag-type used to specify that a certain procedure should be used
+ to format a type.
+
+ @conv.Custom_Format_Proc.{ TheStructure }
+ format_structure :: (output: &conv.Format_Output, format: &conv.Format, data: &TheStructure) { ... }
+"""
Custom_Format_Proc :: struct {
type: type_expr;
}
-//
-// Tag-type used to specify how to parse a structure.
-//
-// @conv.Custom_Parse.{ parse_structure }
-// TheStructure :: struct { ... }
-//
+#doc """
+ Tag-type used to specify how to parse a structure.
+
+ @conv.Custom_Parse.{ parse_structure }
+ TheStructure :: struct { ... }
+"""
Custom_Parse :: struct {
parse: (rawptr, str, Allocator) -> bool;
}
-//
-// Tag-type used to specify that a certain procedure should be used
-// to parse a type.
-//
-// @conv.Custom_Parse_Proc.{ TheStructure }
-// parse_structure :: (data: &TheStructure, input: str, allocator: Allocator) -> bool { ... }
-//
+#doc """
+ Tag-type used to specify that a certain procedure should be used
+ to parse a type.
+
+ @conv.Custom_Parse_Proc.{ TheStructure }
+ parse_structure :: (data: &TheStructure, input: str, allocator: Allocator) -> bool { ... }
+
+"""
Custom_Parse_Proc :: struct {
type: type_expr;
}
-//
-// Passed to any custom formatter. Wraps outputting data to any source,
-// using a `flush` callback function. Use `write` to output a string.
-// When the internal buffer is filled, `flush` is called to empty the
-// buffer to the final destination.
+#doc """
+ Passed to any custom formatter. Wraps outputting data to any source,
+ using a `flush` callback function. Use `write` to output a string.
+ When the internal buffer is filled, `flush` is called to empty the
+ buffer to the final destination.
+"""
Format_Output :: struct {
data: [&] u8;
count: u32;
}
-//
-// Formatting options passed to a custom formatter.
+#doc "Formatting options passed to a custom formatter."
Format :: struct {
pretty_printing := false; // p
quote_strings := false; // "
str_format_va :: format_va
-//
-// Formats a string using the provided arguments and format specified string.
-// This has many overloads to make it easy to work with.
+#doc """
+ Formats a string using the provided arguments and format specified string.
+ This has many overloads to make it easy to work with.
+"""
format :: #match {}
#overload
return *buffer;
}
-//
-// Like format(), but takes the arguments as an array of `any`s, not a variadic argument array.
+#doc """
+ Like `format`, but takes the arguments as an array of `any`s, not a variadic argument array.
+"""
format_va :: #match {}
#overload
}
-//
-// This procedure converts any value into a string, using the type information system.
-// If a custom formatter is specified for the type, that is used instead.
-// This procedure is generally not used directly; instead, through format or format_va.
+#doc """
+ This procedure converts any value into a string, using the type information system.
+ If a custom formatter is specified for the type, that is used instead.
+ This procedure is generally not used directly; instead, through format or format_va.
+"""
format_any :: (output: &Format_Output, formatting: &Format, v: any) {
use package runtime.info
array :: package core.array;
use core {map, string, array, math}
-//
-// Parses many different types from a string into a value.
-// Uses a custom parser if one has been specified for the type given.
+#doc """
+ Parses many different types from a string into a value.
+ Uses a custom parser if one has been specified for the type given.
+"""
parse_any :: #match {}
#overload
return cast(&T) a.data;
}
-//
-// Dereference a pointer any.
+#doc "Dereference a pointer any."
any_dereference :: (v: any) -> any {
t := get_type_info(v.type);
if t.kind == .Pointer {
return v;
}
-//
-// Subscript an array-like any.
+
+#doc "Subscript an array-like any."
any_subscript :: (v: any, index: i32) -> any {
base_ptr, elem_type, count := any_as_array(v);
if index >= count || index < 0 {
};
}
-//
-// Select a member from an any.
+#doc "Select a member from an any."
any_selector :: (v: any, member_name: str) -> any {
t := get_type_info(v.type);
if t.kind == .Struct {
return .{null, void};
}
-//
-// This selector works with selecting "foo.bar.joe"
+#doc "Like `any_selector`, but works with selecting \"foo.bar.joe\"."
any_nested_selector :: (v: any, member_name: str) -> any {
t := get_type_info(v.type);
if t.kind != .Struct do return .{};
return .{null, void};
}
-//
-// Convert a structure or pointer to a structure to a Map with
-// keys representing the fields of the structure, and values
-// representing the value of each field.
-//
-// T :: struct {
-// x := 123;
-// y := "test";
-// }
-//
-// m := any_to_map(T.{});
-//
-// `m` would have two keys, "x" and "y".
-//
+#doc """
+ Convert a structure or pointer to a structure to a Map with
+ keys representing the fields of the structure, and values
+ representing the value of each field.
+
+ T :: struct {
+ x := 123;
+ y := "test";
+ }
+
+ m := any_to_map(T.{});
+
+ `m` would have two keys, "x" and "y".
+"""
any_to_map :: (v: any) -> (Map(str, any), success: bool) {
vals := v;
if get_type_info(vals.type).kind == .Pointer {
return out, true;
}
-//
-// Creates an iterator out of an array-like any.
+#doc "Creates an iterator out of an array-like any."
any_iter :: (arr: any) -> Iterator(any) {
base_ptr, elem_type, count := any_as_array(arr);
if count == 0 {
// continue processing.
//
-//
-// Represents a generational barrier, so the same barrier
-// can be used safely multiple times.
+#doc """
+ Represents a generational barrier, so the same barrier
+ can be used safely multiple times.
+"""
Barrier :: struct {
mutex : Mutex;
cond : Condition_Variable;
thread_count : i32;
}
-//
-// Initializes a new generational barrier with `thread_count` threads.
+
+#doc "Initializes a new generational barrier with `thread_count` threads."
barrier_init :: (b: &Barrier, thread_count: i32) {
mutex_init(&b.mutex);
condition_init(&b.cond);
b.thread_count = thread_count;
}
-//
-// Destroys a generational barrier.
+
+#doc "Destroys a generational barrier."
barrier_destroy :: (b: &Barrier) {
mutex_destroy(&b.mutex);
condition_destroy(&b.cond);
}
-//
-// Signals that a thread has reached the barrier.
-// The last thread to reach the barrier will wake up all other threads.
+#doc """
+ Signals that a thread has reached the barrier.
+ The last thread to reach the barrier will wake up all other threads.
+"""
barrier_wait :: (b: &Barrier) {
mutex_lock(&b.mutex);
defer mutex_unlock(&b.mutex);
// TODO: Free the semaphores after they are used.
-//
-// A condition variable is used to implement a queue of threads
-// waiting for a condition to be true. Each thread joins the queue
-// using `condition_wait`. Then, another thread can signal that
-// the condition has changed and can "wake up" the first thread in
-// the queue using `condition_signal`. Alternatively, all threads
-// can be woken up using `condition_broadcast`.
-//
-// Condition variables are generally used to prevent spin checking
-// a condition and waiting for it to change. Instead, the thread
-// joins a wait-queue, and leave it up to another thread to wake
-// it up to continue processing. However sadly, in WebAssembly this
-// is not possible because with the atomic_wait and atomic_notify
-// instructions, which currently are not supported by any runtime
-// outside of the browser.
-//
-
-//
-// Represents a condition variable, with a mutex used to
-// protect the queue operations.
+#doc """
+ A condition variable is used to implement a queue of threads
+ waiting for a condition to be true. Each thread joins the queue
+ using `condition_wait`. Then, another thread can signal that
+ the condition has changed and can "wake up" the first thread in
+ the queue using `condition_signal`. Alternatively, all threads
+ can be woken up using `condition_broadcast`.
+
+ Condition variables are generally used to prevent spin checking
+ a condition and waiting for it to change. Instead, the thread
+ joins a wait-queue, and leave it up to another thread to wake
+ it up to continue processing. However sadly, in WebAssembly this
+ is not possible because with the atomic_wait and atomic_notify
+ instructions, which currently are not supported by any runtime
+ outside of the browser.
+"""
Condition_Variable :: struct {
Node :: struct {
semaphore : Semaphore;
queue: &Node;
}
-//
-// Initializes a new condition variable.
+#doc "Initializes a new condition variable."
condition_init :: (c: &Condition_Variable) {
mutex_init(&c.mutex);
c.queue = null;
}
-//
-// Destroys a condition variable.
+#doc "Destroys a condition variable."
condition_destroy :: (c: &Condition_Variable) {
if c.queue != null do condition_broadcast(c);
mutex_destroy(&c.mutex);
}
-//
-// Enters the thread in the wait-queue of the condition variable.
-// If `m` is not null, the mutex will first be released before
-// entering the queue, and then relocked before returning.
+#doc """
+ Enters the thread in the wait-queue of the condition variable.
+ If `m` is not null, the mutex will first be released before
+ entering the queue, and then relocked before returning.
+"""
condition_wait :: (c: &Condition_Variable, m: &Mutex) {
node: Condition_Variable.Node;
if m != null do mutex_lock(m);
}
-//
-// Wakes up one thread from the wait-queue.
+
+#doc "Wakes up one thread from the wait-queue."
condition_signal :: (c: &Condition_Variable) {
scoped_mutex(&c.mutex);
}
}
-//
-// Wakes up all threads from the wait-queue.
+
+#doc "Wakes up all threads from the wait-queue."
condition_broadcast :: (c: &Condition_Variable) {
scoped_mutex(&c.mutex);
use core.intrinsics.atomics
use core.thread { Thread_ID }
-//
-// A mutex represents a resource that can only be held by one
-// thread at a time. It is used to create sections of code that
-// only one thread can be in at a time.
-//
-// Mutexes in WebAssembly are very cheap, because they simply
-// use the atomic_cmpxchg intrinsic to operate. This only uses
-// memory, so no real resource allocation is necessary.
-//
-// `lock` has two states: 0, and 1.
-// 0 means unlocked
-// 1 means locked
-//
-// To lock it:
-// Try to store 1 if the value was already 0
-// Otherwise, if it was already 1, wait until it goes to 0.
-//
-// To unlock it:
-// Atomically set it to 0.
-// Notify at most 1 other thread about this change.
-//
+#doc """
+ A mutex represents a resource that can only be held by one
+ thread at a time. It is used to create sections of code that
+ only one thread can be in at a time.
+
+ Mutexes in WebAssembly are very cheap, because they simply
+ use the atomic_cmpxchg intrinsic to operate. This only uses
+ memory, so no real resource allocation is necessary.
+
+ `lock` has two states: 0, and 1.
+ 0 means unlocked, 1 means locked
+
+ To lock it:
+ Try to store 1 if the value was already 0.
+ Otherwise, if it was already 1, wait until it goes to 0.
+
+ To unlock it:
+ Atomically set it to 0.
+ Notify at most 1 other thread about this change.
+"""
Mutex :: struct {
lock : i32;
owner : Thread_ID;
}
-//
-// Initializes a new mutex.
+
+#doc "Initializes a new mutex."
mutex_init :: (m: &Mutex) {
m.lock = 0;
m.owner = -1;
}
-//
-// Destroys a mutex.
+
+#doc "Destroys a mutex."
mutex_destroy :: (m: &Mutex) {
m.lock = -1;
m.owner = -1;
}
-//
-// Locks a mutex. If the mutex is currently held by another thread,
-// this function enters a spin loop until the mutex is unlocked.
-// In a JavaScript based implementation, the __atomic_wait intrinsic
-// is used to avoid having to spin loop.
+#doc """
+ Locks a mutex. If the mutex is currently held by another thread,
+ this function enters a spin loop until the mutex is unlocked.
+ In a JavaScript based implementation, the __atomic_wait intrinsic
+ is used to avoid having to spin loop.
+"""
mutex_lock :: (m: &Mutex) {
while __atomic_cmpxchg(&m.lock, 0, 1) == 1 {
if m.owner == context.thread_id do return;
m.owner = context.thread_id;
}
-//
-// Unlocks a mutex, if the calling thread currently holds the mutex.
-// In a JavaScript based implementation, the __atomic_notify intrinsic
-// is used to wake up one waiting thread.
+#doc """
+ Unlocks a mutex, if the calling thread currently holds the mutex.
+ In a JavaScript based implementation, the __atomic_notify intrinsic
+ is used to wake up one waiting thread.
+"""
mutex_unlock :: (m: &Mutex) {
if m.owner != context.thread_id do return;
}
}
-//
-// Helpful macro for making a particular block be protected by a macro.
-//
-// m: sync.Mutx;
-// sync.mutex_init(&m);
-//
-// {
-// sync.scoped_mutex(&m);
-// // Everything here is done by one thread at a time.
-// }
-//
+#doc """
+ Helpful macro for making a particular block be protected by a macro.
+
+ m: sync.Mutx;
+ sync.mutex_init(&m);
+
+ {
+ sync.scoped_mutex(&m);
+ // Everything here is done by one thread at a time.
+ }
+"""
scoped_mutex :: macro (m: &Mutex) {
ml :: mutex_lock
mu :: mutex_unlock
defer mu(m);
}
-//
-// Abstracts the pattern decribed in scoped_mutex by automatically
-// calling scoped_mutex in the block of code given.
-//
-// m: sync.Mutx;
-// sync.mutex_init(&m);
-//
-// sync.critical_section(&m) {
-// // Everything here is done by one thread at a time.
-// }
-//
+#doc """
+ Abstracts the pattern decribed in scoped_mutex by automatically
+ calling scoped_mutex in the block of code given.
+
+ m: sync.Mutx;
+ sync.mutex_init(&m);
+
+ sync.critical_section(&m) {
+ // Everything here is done by one thread at a time.
+ }
+"""
critical_section :: macro (m: &Mutex, body: Code) -> i32 {
scoped_mutex :: scoped_mutex;
scoped_mutex(m);
// function only once. It is simply a flag with a mutex.
//
-//
-// Represents something will only happen once.
+#doc "Represents something will only happen once."
Once :: struct {
done: bool;
mutex: Mutex;
#inject Once.exec :: #match #local {}
-//
-// Run a function with no arguments once.
+#doc "Run a function with no arguments once."
#overload
Once.exec :: (o: &Once, f: () -> $R) {
scoped_mutex(&o.mutex);
f();
}
-//
-// Run a function with one argument once.
+#doc "Run a function with one argument once."
#overload
Once.exec :: (o: &Once, ctx: $Ctx, f: (Ctx) -> $R) {
scoped_mutex(&o.mutex);
use core.intrinsics.atomics
-//
-// A semaphore represents a counter that can only be incremented
-// and decremented by one thread at a time. "Waiting" on a semaphore
-// means decrementing the counter by 1 if it is greater than 0, otherwise
-// waiting until the counter is incremented. "Posting" on a semaphore
-// means incrementing the counter by a certain value, in turn releasing
-// other threads that might have been waiting for the value to change.
-//
-// Semaphores are generally used for controlling access to shared
-// resources. For a contrived example, say only 4 threads can use
-// a given network connection at a time. A semaphore would be created
-// with a value of 4. When a thread wants to use the network connection,
-// it would use `semaphore_wait` to obtain the resource, or wait if
-// the network is currently available. When it is done using the
-// network, it would call `semaphore_post` to release the resource,
-// allowing another thread to use it.
-//
+#doc """
+ A semaphore represents a counter that can only be incremented
+ and decremented by one thread at a time. "Waiting" on a semaphore
+ means decrementing the counter by 1 if it is greater than 0, otherwise
+ waiting until the counter is incremented. "Posting" on a semaphore
+ means incrementing the counter by a certain value, in turn releasing
+ other threads that might have been waiting for the value to change.
+
+ Semaphores are generally used for controlling access to shared
+ resources. For a contrived example, say only 4 threads can use
+ a given network connection at a time. A semaphore would be created
+ with a value of 4. When a thread wants to use the network connection,
+ it would use `semaphore_wait` to obtain the resource, or wait if
+ the network is currently available. When it is done using the
+ network, it would call `semaphore_post` to release the resource,
+ allowing another thread to use it.
+"""
Semaphore :: struct {
mutex : Mutex;
counter : i32;
}
-//
-// Initializes a semaphore with the specified value.
+#doc "Initializes a semaphore with the specified value."
semaphore_init :: (s: &Semaphore, value: i32) {
s.counter = value;
mutex_init(&s.mutex);
}
-//
-// Destroys a semaphore.
+
+#doc "Destroys a semaphore."
semaphore_destroy :: (s: &Semaphore) {
mutex_destroy(&s.mutex);
}
-//
-// Increment the counter in a semaphore by `count`.
+
+#doc "Increment the counter in a semaphore by `count`."
semaphore_post :: (s: &Semaphore, count := 1) {
if count == 0 do return;
}
}
-//
-// Waits until the thread is able to decrement one from the semaphore.
+#doc "Waits until the thread is able to decrement one from the semaphore."
semaphore_wait :: (s: &Semaphore) {
while true {
mutex_lock(&s.mutex);
thread_map : Map(Thread_ID, &Thread);
}
-//
-// An id of a thread.
+
+#doc "An id of a thread."
Thread_ID :: #type i32
-//
-// Represents a thread. Currently, this is very simple; just the id
-// of the thread and whether or not it is alive.
+#doc """
+ Represents a thread. Currently, this is very simple; just the id
+ of the thread and whether or not it is alive.
+"""
Thread :: struct {
id : Thread_ID;
alive : bool;
}
-//
-// Spawns a new thread using the runtime.__spawn_thread function.
-// The primary job of this function is to create the thread-local
-// storage and stack for the new thread, and pass those on.
-// Currently the stack size is not controllable, but that could
-// be remedied.
+#doc """
+ Spawns a new thread using the runtime.__spawn_thread function.
+ The primary job of this function is to create the thread-local
+ storage and stack for the new thread, and pass those on.
+ Currently the stack size is not controllable, but that could
+ be remedied.
+"""
spawn :: (t: &Thread, data: &$T, func: (&T) -> void) {
sync.scoped_mutex(&thread_mutex);
runtime.platform.__spawn_thread(t.id, tls_base, stack_base, func, data);
}
-//
-// Waits for a thread to finish before returning.
-// If the thread was not alive in the first place,
-// immediately return.
+#doc """
+ Waits for a thread to finish before returning.
+ If the thread was not alive in the first place,
+ immediately return.
+"""
join :: (t: &Thread) {
while t.alive {
#if runtime.Wait_Notify_Available {
}
}
-//
-// Forcefully kill a thread using runtime.__kill_thread.
-// Does nothing if the thread was not alive.
+#doc """
+ Forcefully kill a thread using runtime.__kill_thread.
+ Does nothing if the thread was not alive.
+"""
kill :: (t: &Thread) -> i32 {
if !t.alive do return -1;
return 1;
}
-//
-// Special procedure that should only be called once globally
-// that initialize the map of thread ids to thread data.
+#doc """
+ Special procedure that should only be called once globally
+ that initialize the map of thread ids to thread data.
+"""
__initialize :: () {
thread_map->init();
}
-//
-// Special procedure that is called when a thread exits,
-// or by kill() above.
+#doc """
+ Special procedure that is called when a thread exits,
+ or by kill() above.
+"""
__exited :: (id: i32) {
sync.scoped_mutex(&thread_mutex);