Skip to content

Commit

Permalink
Add test for threads and atomic operations
Browse files Browse the repository at this point in the history
  • Loading branch information
maximecb committed Sep 7, 2024
1 parent eafc62c commit 46924ac
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 5 deletions.
7 changes: 7 additions & 0 deletions ncc/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,13 @@ impl Expr
child.gen_code(sym, out)?;
return Ok(());
}

// If this is a reference to a global
if let Expr::Ref(Decl::Global { name, t }) = child.as_ref() {
// Push the address
out.push_str(&format!("push {};\n", name));
return Ok(());
}
}

child.gen_code(sym, out)?;
Expand Down
58 changes: 58 additions & 0 deletions ncc/tests/threads_lock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <uvm/syscalls.h>
#include <stdio.h>

#define NUM_THREADS 100
#define NUM_INCRS 100

u64 thread_ids[NUM_THREADS];

u64 locked = 0;

u64 counter = 0;

void lock()
{
for (;;)
{
// Try to acquire the lock
u64 val = asm (&locked, 0, 1) -> u64 { atomic_cas_u64; };

// If we got the lock, stop
if (val == 0)
break;
}
}

void unlock()
{
asm (&locked, 0) -> void { atomic_store_u64; };
}

void thread_fn()
{
for (int i = 0; i < NUM_INCRS; ++i)
{
lock();
++counter;
unlock();
}
}

int main()
{
for (int i = 0; i < NUM_THREADS; ++i)
{
thread_ids[i] = thread_spawn(thread_fn, NULL);
}

for (int i = 0; i < NUM_THREADS; ++i)
{
thread_join(thread_ids[i]);
}

// Check that the counter value is correct
assert(counter == NUM_THREADS * NUM_INCRS);
printf("counter = %d\n", counter);

return 0;
}
4 changes: 4 additions & 0 deletions vm/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,10 @@ impl Assembler
"store_u32" => self.code.push_op(Op::store_u32),
"store_u64" => self.code.push_op(Op::store_u64),

"atomic_load_u64" => self.code.push_op(Op::atomic_load_u64),
"atomic_store_u64" => self.code.push_op(Op::atomic_store_u64),
"atomic_cas_u64" => self.code.push_op(Op::atomic_cas_u64),

"jmp" => {
self.code.push_op(Op::jmp);
let label_name = input.parse_ident()?;
Expand Down
11 changes: 6 additions & 5 deletions vm/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,8 +582,9 @@ impl MemView
// Check that the address is aligned
if addr & (align_of::<T>() - 1) != 0 {
panic!(
"attempting to access data of type {} at unaligned address",
std::any::type_name::<T>()
"attempting to access data of type {} at unaligned address {}",
std::any::type_name::<T>(),
addr
);
}

Expand Down Expand Up @@ -1472,7 +1473,7 @@ impl Thread
let addr = self.pop().as_usize();
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
let atomic = unsafe {AtomicU64::from_ptr(heap_ptr) };
atomic.store(1, Ordering::Release);
atomic.store(val, Ordering::Release);
}

// Compare-and-swap
Expand All @@ -1482,9 +1483,9 @@ impl Thread
// atomic_cas (addr) (cmp-val) (store-val)
// Pushes the value found at the memory address
Op::atomic_cas_u64 => {
let addr = self.pop().as_usize();
let cmp_val = self.pop().as_u64();
let store_val = self.pop().as_u64();
let cmp_val = self.pop().as_u64();
let addr = self.pop().as_usize();

let heap_ptr = self.get_heap_ptr_mut(addr, 1);
let atomic = unsafe {AtomicU64::from_ptr(heap_ptr) };
Expand Down

0 comments on commit 46924ac

Please sign in to comment.