add tests for Mutex (#925)

* std/lib: add tests for Mutex

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>

* lib/collections: add missing import

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>

* std/collections: add RingBuffer

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>

---------

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
Pierre Curto
2023-08-13 17:39:09 +02:00
committed by GitHub
parent d83f591184
commit c060569599
7 changed files with 171 additions and 6 deletions

View File

@@ -2,6 +2,7 @@
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::list(<Type>);
import std::io;
import std::math;
def ElementPredicate = fn bool(Type *type);

View File

@@ -0,0 +1,88 @@
module collections::ringbuffer(<Type, SIZE>);
struct RingBuffer
{
Type[SIZE] buf;
usz written;
usz head;
}
fn void RingBuffer.init(&self) @inline
{
*self = {};
}
fn void RingBuffer.putc(&self, Type c)
{
if (self.written < SIZE)
{
self.buf[self.written] = c;
self.written++;
}
else
{
self.buf[self.head] = c;
self.head = (self.head + 1) % SIZE;
}
}
fn Type RingBuffer.getc(&self, usz index)
{
index %= SIZE;
usz avail = SIZE - self.head;
if (index < avail)
{
return self.buf[self.head + index];
}
return self.buf[index - avail];
}
fn usz RingBuffer.get(&self, usz index, Type[] buffer)
{
index %= SIZE;
if (self.written < SIZE)
{
if (index >= self.written) return 0;
usz end = self.written - index;
usz n = min(end, buffer.len);
buffer[:n] = self.buf[index:n];
return n;
}
usz end = SIZE - self.head;
if (index >= end)
{
index -= end;
if (index >= self.head) return 0;
usz n = min(self.head - index, buffer.len);
buffer[:n] = self.buf[index:n];
return n;
}
if (buffer.len <= SIZE - index)
{
usz n = buffer.len;
buffer[:n] = self.buf[self.head + index:n];
return n;
}
usz n1 = SIZE - index;
buffer[:n1] = self.buf[self.head + index:n1];
buffer = buffer[n1..];
index -= n1;
usz n2 = min(self.head - index, buffer.len);
buffer[:n2] = self.buf[index:n2];
return n1 + n2;
}
fn void RingBuffer.push(&self, Type[] buffer)
{
usz i;
while (self.written < SIZE && i < buffer.len)
{
self.buf[self.written] = buffer[i++];
self.written++;
}
foreach (c : buffer[i..])
{
self.buf[self.head] = c;
self.head = (self.head + 1) % SIZE;
}
}

View File

@@ -48,7 +48,7 @@ fn void! NativeMutex.lock(&self)
/**
* @require mtx.is_initialized() : "Mutex was not initialized"
**/
fn void! NativeMutex.lock_timeoutout(&mtx, ulong ms)
fn void! NativeMutex.lock_timeout(&mtx, ulong ms)
{
/* Try to acquire the lock and, if we fail, sleep for 5ms. */
Errno result;

View File

@@ -88,9 +88,9 @@ fn void! NativeMutex.lock(&mtx)
/**
* @require mtx.timed "Only available for timed locks"
**/
fn void! NativeMutex.lock_timeout(&mtx, uint ms)
fn void! NativeMutex.lock_timeout(&mtx, usz ms)
{
switch (win32::waitForSingleObject(mtx.handle, ms))
switch (win32::waitForSingleObject(mtx.handle, (uint)ms))
{
case win32::WAIT_OBJECT_0:
break;

View File

@@ -33,7 +33,7 @@ fault ThreadFault
macro void! Mutex.init(&mutex, MutexType type = MUTEX_PLAIN) => NativeMutex.init((NativeMutex*)mutex, type);
macro void! Mutex.destroy(&mutex) => NativeMutex.destroy((NativeMutex*)mutex);
macro void! Mutex.lock(&mutex) => NativeMutex.lock((NativeMutex*)mutex);
macro void! Mutex.lock_timeout(&mutex, ulong ms) => NativeMutex.lock((NativeMutex*)mutex, ms);
macro void! Mutex.lock_timeout(&mutex, ulong ms) => NativeMutex.lock_timeout((NativeMutex*)mutex, ms);
macro bool Mutex.try_lock(&mutex) => NativeMutex.try_lock((NativeMutex*)mutex);
macro void! Mutex.unlock(&mutex) => NativeMutex.unlock((NativeMutex*)mutex);
@@ -56,7 +56,7 @@ 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 OnceFlag.call_once(&flag, OnceFn func) => NativeOnceFlag.call_once((NativeOnceFlag*)flag, func);
macro void OnceFlag.call(&flag, OnceFn func) => NativeOnceFlag.call_once((NativeOnceFlag*)flag, func);
macro void yield() => os::native_thread_yield();
macro Thread current() => os::native_thread_current();

View File

@@ -0,0 +1,26 @@
module ringbuffer_test @test;
import collections::ringbuffer;
import std::io;
def Buffer = RingBuffer(<char, 4>);
fn void putc_getc()
{
Buffer rb;
rb.init();
rb.putc(1);
rb.putc(2);
rb.putc(3);
rb.putc(4);
assert(rb.getc(0) == 1);
assert(rb.getc(1) == 2);
assert(rb.getc(2) == 3);
assert(rb.getc(3) == 4);
rb.putc(5);
assert(rb.getc(0) == 2);
assert(rb.getc(1) == 3);
assert(rb.getc(2) == 4);
assert(rb.getc(3) == 5);
}

View File

@@ -1,6 +1,8 @@
import std::thread;
import std::io;
int a;
fn void! testrun() @test
{
Thread t;
@@ -8,6 +10,9 @@ fn void! testrun() @test
t.create(fn int(void* arg) { a++; return 0; }, null)!;
assert(t.join()! == 0);
assert(a == 1);
t.create(fn int(void* arg) { return 10; }, null)!;
assert(t.join()! == 10);
}
Mutex m;
@@ -34,9 +39,54 @@ fn void! testrun_mutex() @test
return 0;
}, null)!;
}
foreach (i, &t : ts)
foreach (&t : ts)
{
assert(t.join()! == 0);
}
assert(a == 100);
m.destroy()!;
}
fn void! testrun_mutex_try() @test
{
Mutex m;
m.init()!;
m.lock()!;
assert(m.try_lock() == false);
m.unlock()!;
assert(m.try_lock() == true);
m.unlock()!;
}
fn void! testrun_mutex_timeout() @test
{
Mutex m;
m.init()!;
m.lock()!;
if (catch m.lock_timeout(100))
{
}
else
{
assert(false, "lock_timeout should fail");
}
m.unlock()!;
m.lock_timeout(100)!;
m.unlock()!;
}
int x_once = 100;
fn void call_once()
{
x_once += 100;
}
fn void! testrun_once() @test
{
OnceFlag once;
once.call(&call_once);
assert(x_once == 200);
once.call(&call_once);
assert(x_once == 200);
}