mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
added io::stdout().flush() - to force printing test name before possible deadlock
mem::scoped() and long jump resilience fixed #1963 fixed --test-nosort argument + extra test for teardown_fn memory leak Some renaming. Simplify robust test allocator handling. Pop temp allocators in test runner. `Thread` no longer allocates memory on posix. Update unprintable struct output. Correctly give an error if a character literal contains a line break.
This commit is contained in:
committed by
Christoffer Lerno
parent
535151a2a5
commit
5046608d1f
@@ -3,6 +3,7 @@
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::core::runtime;
|
||||
import std::core::test @public;
|
||||
import std::core::mem::allocator @public;
|
||||
import libc, std::time, std::io, std::sort;
|
||||
import std::os::env;
|
||||
|
||||
@@ -30,8 +31,12 @@ struct TestContext
|
||||
char* error_buffer;
|
||||
usz error_buffer_capacity;
|
||||
File fake_stdout;
|
||||
File orig_stdout;
|
||||
File orig_stderr;
|
||||
struct stored
|
||||
{
|
||||
File stdout;
|
||||
File stderr;
|
||||
Allocator allocator;
|
||||
}
|
||||
}
|
||||
|
||||
struct TestUnit
|
||||
@@ -107,43 +112,29 @@ fn void test_panic(String message, String file, String function, uint line) @loc
|
||||
}
|
||||
|
||||
test_context.is_in_panic = false;
|
||||
allocator::thread_allocator = test_context.stored.allocator;
|
||||
libc::longjmp(&test_context.buf, 1);
|
||||
}
|
||||
|
||||
fn void mute_output() @local
|
||||
{
|
||||
if (!test_context.fake_stdout.file) return;
|
||||
assert(!test_context.orig_stderr.file);
|
||||
assert(!test_context.orig_stdout.file);
|
||||
|
||||
File* stdout = io::stdout();
|
||||
File* stderr = io::stderr();
|
||||
|
||||
test_context.orig_stderr = *stderr;
|
||||
test_context.orig_stdout = *stdout;
|
||||
|
||||
File* stderr = io::stderr();
|
||||
*stderr = test_context.fake_stdout;
|
||||
*stdout = test_context.fake_stdout;
|
||||
|
||||
(void)test_context.fake_stdout.seek(0, Seek.SET)!!;
|
||||
}
|
||||
|
||||
fn void unmute_output(bool has_error) @local
|
||||
{
|
||||
if (!test_context.fake_stdout.file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
assert(test_context.orig_stderr.file);
|
||||
assert(test_context.orig_stdout.file);
|
||||
if (!test_context.fake_stdout.file) return;
|
||||
|
||||
File* stdout = io::stdout();
|
||||
File* stderr = io::stderr();
|
||||
|
||||
*stderr = test_context.orig_stderr;
|
||||
*stdout = test_context.orig_stdout;
|
||||
test_context.orig_stderr.file = null;
|
||||
test_context.orig_stdout.file = null;
|
||||
*stderr = test_context.stored.stderr;
|
||||
*stdout = test_context.stored.stdout;
|
||||
|
||||
usz log_size = test_context.fake_stdout.seek(0, Seek.CURSOR)!!;
|
||||
if (has_error)
|
||||
@@ -187,6 +178,9 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
|
||||
.breakpoint_on_assert = false,
|
||||
.test_filter = "",
|
||||
.has_ansi_codes = terminal_has_ansi_codes(),
|
||||
.stored.allocator = allocator::heap(),
|
||||
.stored.stderr = *io::stderr(),
|
||||
.stored.stdout = *io::stdout(),
|
||||
};
|
||||
for (int i = 1; i < args.len; i++)
|
||||
{
|
||||
@@ -221,9 +215,9 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
|
||||
|
||||
// Buffer for hijacking the output
|
||||
$if (!env::NO_LIBC):
|
||||
test_context.fake_stdout.file = libc::tmpfile();
|
||||
context.fake_stdout.file = libc::tmpfile();
|
||||
$endif
|
||||
if (test_context.fake_stdout.file == null)
|
||||
if (context.fake_stdout.file == null)
|
||||
{
|
||||
io::print("Failed to hijack stdout, tests will print everything");
|
||||
}
|
||||
@@ -241,39 +235,49 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
|
||||
name.append_repeat('-', len - len / 2);
|
||||
io::printn(name);
|
||||
name.clear();
|
||||
TempState temp_state = mem::temp_push();
|
||||
defer mem::temp_pop(temp_state);
|
||||
foreach(unit : tests)
|
||||
{
|
||||
if (test_context.test_filter && !unit.name.contains(test_context.test_filter))
|
||||
mem::temp_pop(temp_state);
|
||||
if (context.test_filter && !unit.name.contains(context.test_filter))
|
||||
{
|
||||
tests_skipped++;
|
||||
continue;
|
||||
}
|
||||
test_context.setup_fn = null;
|
||||
test_context.teardown_fn = null;
|
||||
test_context.current_test_name = unit.name;
|
||||
context.setup_fn = null;
|
||||
context.teardown_fn = null;
|
||||
context.current_test_name = unit.name;
|
||||
|
||||
defer name.clear();
|
||||
name.appendf("Testing %s ", unit.name);
|
||||
name.append_repeat('.', max_name - unit.name.len + 2);
|
||||
io::printf("%s ", name.str_view());
|
||||
(void)io::stdout().flush();
|
||||
TrackingAllocator mem;
|
||||
mem.init(allocator::heap());
|
||||
|
||||
mem.init(context.stored.allocator);
|
||||
if (libc::setjmp(&context.buf) == 0)
|
||||
{
|
||||
mute_output();
|
||||
mem.clear();
|
||||
mem::@scoped(&mem)
|
||||
allocator::thread_allocator = &mem;
|
||||
$if(!$$OLD_TEST):
|
||||
unit.func();
|
||||
$else
|
||||
if (catch err = unit.func())
|
||||
{
|
||||
io::printf("[FAIL] Failed due to: %s", err);
|
||||
continue;
|
||||
}
|
||||
$endif
|
||||
// track cleanup that may take place in teardown_fn
|
||||
if (test_context.teardown_fn)
|
||||
{
|
||||
$if(!$$OLD_TEST):
|
||||
unit.func();
|
||||
$else
|
||||
if (catch err = unit.func())
|
||||
{
|
||||
io::printf("[FAIL] Failed due to: %s", err);
|
||||
continue;
|
||||
}
|
||||
$endif
|
||||
};
|
||||
test_context.teardown_fn();
|
||||
}
|
||||
allocator::thread_allocator = context.stored.allocator;
|
||||
|
||||
unmute_output(false); // all good, discard output
|
||||
if (mem.has_leaks())
|
||||
{
|
||||
@@ -286,10 +290,6 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
|
||||
io::printfn(test_context.has_ansi_codes ? "[\e[0;32mPASS\e[0m]" : "[PASS]");
|
||||
tests_passed++;
|
||||
}
|
||||
if (test_context.teardown_fn)
|
||||
{
|
||||
test_context.teardown_fn();
|
||||
}
|
||||
}
|
||||
mem.free();
|
||||
}
|
||||
|
||||
@@ -145,7 +145,10 @@ fn usz! Formatter.print_with_function(&self, Printable arg)
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
|
||||
fn usz! Formatter.out_unknown(&self, String category, any arg) @private
|
||||
{
|
||||
return self.out_substr("[") + self.out_substr(category) + self.out_substr(" type:") + self.ntoa((iptr)arg.type, false, 16) + self.out_substr(", addr:") + self.ntoa((iptr)arg.ptr, false, 16) + self.out_substr("]");
|
||||
}
|
||||
fn usz! Formatter.out_str(&self, any arg) @private
|
||||
{
|
||||
switch (arg.type.kindof)
|
||||
@@ -199,13 +202,13 @@ fn usz! Formatter.out_str(&self, any arg) @private
|
||||
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);
|
||||
return self.out_substr(arg.type.names[i]);
|
||||
case STRUCT:
|
||||
return self.out_substr("<struct>");
|
||||
return self.out_unknown("struct", arg);
|
||||
case UNION:
|
||||
return self.out_substr("<union>");
|
||||
return self.out_unknown("union", arg);
|
||||
case BITSTRUCT:
|
||||
return self.out_substr("<bitstruct>");
|
||||
return self.out_unknown("bitstruct", arg);
|
||||
case FUNC:
|
||||
return self.out_substr("<function>");
|
||||
return self.out_unknown("function", arg);
|
||||
case DISTINCT:
|
||||
if (arg.type == String.typeid)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,14 @@ struct NativeMutex
|
||||
}
|
||||
|
||||
def NativeConditionVariable = Pthread_cond_t;
|
||||
def NativeThread = Pthread_t;
|
||||
|
||||
struct NativeThread
|
||||
{
|
||||
inline Pthread_t pthread;
|
||||
ThreadFn thread_fn;
|
||||
void* arg;
|
||||
}
|
||||
|
||||
def NativeOnceFlag = Pthread_once_t;
|
||||
|
||||
<*
|
||||
@@ -148,59 +155,49 @@ fn void! NativeConditionVariable.wait_timeout(&cond, NativeMutex* mtx, ulong ms)
|
||||
}
|
||||
}
|
||||
|
||||
tlocal PosixThreadData *_thread_data @private;
|
||||
tlocal NativeThread current_thread @private;
|
||||
|
||||
fn void free_thread_data() @private
|
||||
{
|
||||
if (_thread_data)
|
||||
{
|
||||
allocator::free(_thread_data.allocator, _thread_data);
|
||||
_thread_data = null;
|
||||
}
|
||||
}
|
||||
fn void* callback(void* arg) @private
|
||||
{
|
||||
_thread_data = arg;
|
||||
defer free_thread_data();
|
||||
return (void*)(iptr)_thread_data.thread_fn(_thread_data.arg);
|
||||
NativeThread* thread = arg;
|
||||
current_thread = *thread;
|
||||
return (void*)(iptr)thread.thread_fn(thread.arg);
|
||||
}
|
||||
|
||||
fn void! NativeThread.create(&thread, ThreadFn thread_fn, void* arg)
|
||||
{
|
||||
PosixThreadData *thread_data = mem::new(PosixThreadData, { .thread_fn = thread_fn, .arg = arg, .allocator = allocator::heap() });
|
||||
if (posix::pthread_create(thread, null, &callback, thread_data) != 0)
|
||||
thread.thread_fn = thread_fn;
|
||||
thread.arg = arg;
|
||||
if (posix::pthread_create(&thread.pthread, null, &callback, thread) != 0)
|
||||
{
|
||||
*thread = null;
|
||||
free(thread_data);
|
||||
return ThreadFault.INIT_FAILED?;
|
||||
}
|
||||
}
|
||||
|
||||
fn void! NativeThread.detach(thread)
|
||||
{
|
||||
if (posix::pthread_detach(thread)) return ThreadFault.DETACH_FAILED?;
|
||||
if (posix::pthread_detach(thread.pthread)) return ThreadFault.DETACH_FAILED?;
|
||||
}
|
||||
|
||||
fn void native_thread_exit(int result)
|
||||
{
|
||||
free_thread_data();
|
||||
posix::pthread_exit((void*)(iptr)result);
|
||||
}
|
||||
|
||||
fn NativeThread native_thread_current()
|
||||
{
|
||||
return (NativeThread)posix::pthread_self();
|
||||
return current_thread;
|
||||
}
|
||||
|
||||
fn bool NativeThread.equals(thread, NativeThread other)
|
||||
{
|
||||
return (bool)posix::pthread_equal(thread, other);
|
||||
return (bool)posix::pthread_equal(thread.pthread, other.pthread);
|
||||
}
|
||||
|
||||
fn int! NativeThread.join(thread)
|
||||
{
|
||||
void *pres;
|
||||
if (posix::pthread_join(thread, &pres)) return ThreadFault.JOIN_FAILED?;
|
||||
if (posix::pthread_join(thread.pthread, &pres)) return ThreadFault.JOIN_FAILED?;
|
||||
return (int)(iptr)pres;
|
||||
}
|
||||
|
||||
@@ -214,13 +211,6 @@ fn void native_thread_yield()
|
||||
posix::sched_yield();
|
||||
}
|
||||
|
||||
struct PosixThreadData @private
|
||||
{
|
||||
ThreadFn thread_fn;
|
||||
void* arg;
|
||||
Allocator allocator;
|
||||
}
|
||||
|
||||
fn void! native_sleep_nano(NanoDuration nano)
|
||||
{
|
||||
if (nano <= 0) return;
|
||||
|
||||
@@ -13,7 +13,7 @@ distinct TimedMutex = inline Mutex;
|
||||
distinct RecursiveMutex = inline Mutex;
|
||||
distinct TimedRecursiveMutex = inline Mutex;
|
||||
distinct ConditionVariable = NativeConditionVariable;
|
||||
distinct Thread = NativeThread;
|
||||
distinct Thread = inline NativeThread;
|
||||
distinct OnceFlag = NativeOnceFlag;
|
||||
def OnceFn = fn void();
|
||||
|
||||
@@ -59,11 +59,10 @@ macro void! ConditionVariable.wait_timeout(&cond, Mutex* mutex, ulong ms)
|
||||
return NativeConditionVariable.wait_timeout((NativeConditionVariable*)cond, (NativeMutex*)mutex, ms);
|
||||
}
|
||||
|
||||
|
||||
macro void! Thread.create(&thread, ThreadFn thread_fn, void* arg) => NativeThread.create((NativeThread*)thread, thread_fn, arg);
|
||||
macro void! Thread.detach(thread) => NativeThread.detach((NativeThread)thread);
|
||||
macro int! Thread.join(thread) => NativeThread.join((NativeThread)thread);
|
||||
macro bool Thread.equals(thread, Thread other) => NativeThread.equals((NativeThread)thread, (NativeThread)other);
|
||||
macro void! Thread.create(&thread, ThreadFn thread_fn, void* arg) => NativeThread.create(thread, thread_fn, arg);
|
||||
macro void! Thread.detach(thread) => NativeThread.detach(thread);
|
||||
macro int! Thread.join(thread) => NativeThread.join(thread);
|
||||
macro bool Thread.equals(thread, Thread other) => NativeThread.equals(thread, other);
|
||||
|
||||
macro void OnceFlag.call(&flag, OnceFn func) => NativeOnceFlag.call_once((NativeOnceFlag*)flag, func);
|
||||
|
||||
|
||||
@@ -6,9 +6,14 @@
|
||||
- Increase precedence of `(Foo) { 1, 2 }`
|
||||
- Add `--enable-new-generics` to enable `Foo{int}` generic syntax.
|
||||
- `{| |}` expression blocks deprecated.
|
||||
- c3c `--test-leak-report` flag for displaying full memory lead report if any
|
||||
|
||||
### Fixes
|
||||
- Bug appearing when `??` was combined with boolean in some cases.
|
||||
- Test runner --test-disable-sort didn't work, c3c was expecting --test-nosort
|
||||
- Test runner with tracking allocator assertion at failed test #1963
|
||||
- Test runner with tracking allocator didn't properly handle teardown_fn
|
||||
- Correctly give an error if a character literal contains a line break.
|
||||
|
||||
### Stdlib changes
|
||||
|
||||
@@ -34,6 +39,7 @@
|
||||
- Test runner will also check for leaks.
|
||||
- Improve inference on `??` #1943.
|
||||
- Detect unaligned loads #1951.
|
||||
- `Thread` no longer allocates memory on posix.
|
||||
|
||||
### Fixes
|
||||
- Fix issue requiring prefix on a generic interface declaration.
|
||||
|
||||
@@ -135,7 +135,7 @@ static void usage(bool full)
|
||||
print_opt("--ansi=<yes|no>", "Set colour output using ansi on/off, default is to try to detect it.");
|
||||
print_opt("--test-filter <arg>", "Set a filter when running tests, running only matching tests.");
|
||||
print_opt("--test-breakpoint", "When running tests, trigger a breakpoint on failure.");
|
||||
print_opt("--test-disable-sort", "Do not sort tests.");
|
||||
print_opt("--test-nosort", "Do not sort tests.");
|
||||
}
|
||||
PRINTF("");
|
||||
print_opt("-l <library>", "Link with the static or dynamic library provided.");
|
||||
|
||||
@@ -5,7 +5,7 @@ import std::atomic;
|
||||
uint a;
|
||||
float fa;
|
||||
|
||||
fn void add() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void add() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a = 0;
|
||||
@@ -42,7 +42,7 @@ fn void add() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
assert(a == ts.len * 10 * 5, "Threads returned %d, expected %d", a, ts.len * 10 * 5);
|
||||
}
|
||||
|
||||
fn void sub() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void sub() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a = ts.len * 10 * 5;
|
||||
@@ -79,7 +79,7 @@ fn void sub() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
assert(a == 0, "Threads returned %d, expected %d", a, 0);
|
||||
}
|
||||
|
||||
fn void div() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void div() @test
|
||||
{
|
||||
Thread[8] ts;
|
||||
a = 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 * 8;
|
||||
@@ -98,7 +98,7 @@ fn void div() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
assert(a == 8, "Threads returned %d, expected %d", a, 8);
|
||||
}
|
||||
|
||||
fn void max() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void max() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a = 0;
|
||||
@@ -134,7 +134,7 @@ fn void max() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
assert(a == 5, "Threads returned %d, expected %d", a, 5);
|
||||
}
|
||||
|
||||
fn void min() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void min() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a = 10;
|
||||
@@ -170,7 +170,7 @@ fn void min() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
assert(a == 0, "Threads returned %d, expected %d", a, 0);
|
||||
}
|
||||
|
||||
fn void fadd() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void fadd() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
fa = 0;
|
||||
@@ -207,7 +207,7 @@ fn void fadd() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
assert(fa == ts.len * 10 * 0.5, "Threads returned %f, expected %f", fa, ts.len * 10 * 0.5);
|
||||
}
|
||||
|
||||
fn void fsub() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void fsub() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
fa = ts.len * 10 * 0.5;
|
||||
|
||||
@@ -7,7 +7,7 @@ def AtomicFloat = Atomic(<float>);
|
||||
AtomicUint a;
|
||||
AtomicFloat fa;
|
||||
|
||||
fn void add() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void add() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a.store(0);
|
||||
@@ -44,7 +44,7 @@ fn void add() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
assert(a.load() == ts.len * 10 * 5, "Threads returned %d, expected %d", a.load(), ts.len * 10 * 5);
|
||||
}
|
||||
|
||||
fn void sub() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void sub() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
a.store(ts.len * 10 * 5);
|
||||
@@ -81,7 +81,7 @@ fn void sub() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
assert(a.load() == 0, "Threads returned %d, expected %d", a.load(), 0);
|
||||
}
|
||||
|
||||
fn void fadd() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void fadd() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
fa.store(0);
|
||||
@@ -118,7 +118,7 @@ fn void fadd() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
assert(fa.load() == ts.len * 10 * 0.5, "Threads returned %f, expected %f", fa.load(), ts.len * 10 * 0.5);
|
||||
}
|
||||
|
||||
fn void fsub() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void fsub() @test
|
||||
{
|
||||
Thread[100] ts;
|
||||
fa.store(ts.len * 10 * 0.5);
|
||||
|
||||
@@ -14,6 +14,7 @@ struct TestState
|
||||
TestFn teardown_fn;
|
||||
PanicFn old_panic; // original test panic, use it when it's really fails
|
||||
PanicFn panic_mock_fn; // mock panic, for testing the test:: failed
|
||||
void* buf;
|
||||
}
|
||||
|
||||
TestState state =
|
||||
@@ -25,6 +26,7 @@ TestState state =
|
||||
|
||||
assert (runtime::test_context.assert_print_backtrace);
|
||||
assert (builtin::panic != state.panic_mock_fn, "missing finalization of panic");
|
||||
state.buf = mem::alloc(int);
|
||||
|
||||
state.old_panic = builtin::panic;
|
||||
builtin::panic = state.panic_mock_fn;
|
||||
@@ -42,6 +44,7 @@ TestState state =
|
||||
state.n_fails = 0;
|
||||
state.expected_fail = false;
|
||||
state.n_runs = 0;
|
||||
mem::free(state.buf);
|
||||
},
|
||||
.panic_mock_fn = fn void (String message, String file, String function, uint line)
|
||||
{
|
||||
@@ -139,6 +142,8 @@ fn void setup_no_teardown()
|
||||
test::eq(state.n_fails, 0);
|
||||
test::eq(state.expected_fail, false);
|
||||
|
||||
mem::free(state.buf);
|
||||
|
||||
// WARNING: reverting back original panic func
|
||||
builtin::panic = state.old_panic;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import std::os;
|
||||
|
||||
const TEST_MAGNITUDE = 10;
|
||||
|
||||
|
||||
fn void lock_control_test() @test
|
||||
{
|
||||
Mutex m;
|
||||
@@ -37,7 +36,7 @@ fn void! own_mutex(Mutex* m)
|
||||
m.unlock()!;
|
||||
}
|
||||
|
||||
fn void ensure_owner_checks() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void ensure_owner_checks() @test
|
||||
{
|
||||
Mutex m;
|
||||
m.init()!!;
|
||||
@@ -77,7 +76,7 @@ fn void shared_mutex_decrement(ArgsWrapper1* args)
|
||||
args.m.unlock()!!;
|
||||
}
|
||||
|
||||
fn void shared_mutex() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void shared_mutex() @test
|
||||
{
|
||||
Mutex m;
|
||||
m.init()!!;
|
||||
@@ -127,7 +126,7 @@ fn void acquire_recursively(RecursiveMutex* m)
|
||||
}
|
||||
}
|
||||
|
||||
fn void test_recursive_mutex() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void test_recursive_mutex() @test
|
||||
{
|
||||
RecursiveMutex m;
|
||||
m.init()!!;
|
||||
|
||||
@@ -5,7 +5,7 @@ import std::thread::pool;
|
||||
|
||||
def Pool = ThreadPool(<4>);
|
||||
|
||||
fn void init_destroy() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void init_destroy() @test
|
||||
{
|
||||
for (usz i = 0; i < 20; i++)
|
||||
{
|
||||
@@ -15,7 +15,7 @@ fn void init_destroy() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
}
|
||||
}
|
||||
|
||||
fn void push_destroy() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void push_destroy() @test
|
||||
{
|
||||
for FOO: (usz i = 0; i < 20; i++)
|
||||
{
|
||||
@@ -42,7 +42,7 @@ fn void push_destroy() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
}
|
||||
}
|
||||
|
||||
fn void push_stop() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void push_stop() @test
|
||||
{
|
||||
for (usz i = 0; i < 20; i++)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ import std::io;
|
||||
|
||||
int a;
|
||||
|
||||
fn void testrun() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void testrun() @test
|
||||
{
|
||||
Thread t;
|
||||
a = 0;
|
||||
@@ -18,7 +18,7 @@ fn void testrun() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
|
||||
Mutex m_global;
|
||||
|
||||
fn void testrun_mutex() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void testrun_mutex()
|
||||
{
|
||||
Thread[20] ts;
|
||||
a = 0;
|
||||
@@ -48,7 +48,7 @@ fn void testrun_mutex() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
m_global.destroy()!!;
|
||||
}
|
||||
|
||||
fn void testrun_mutex_try() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void testrun_mutex_try() @test
|
||||
{
|
||||
Mutex m;
|
||||
m.init()!!;
|
||||
@@ -59,7 +59,7 @@ fn void testrun_mutex_try() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
m.unlock()!!;
|
||||
}
|
||||
|
||||
fn void testrun_mutex_timeout() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void testrun_mutex_timeout() @test
|
||||
{
|
||||
TimedMutex m;
|
||||
m.init()!!;
|
||||
@@ -80,7 +80,7 @@ fn void call_once()
|
||||
x_once += 100;
|
||||
}
|
||||
|
||||
fn void testrun_once() @test => mem::@scoped(&allocator::LIBC_ALLOCATOR)
|
||||
fn void testrun_once() @test
|
||||
{
|
||||
OnceFlag once;
|
||||
once.call(&call_once);
|
||||
|
||||
Reference in New Issue
Block a user