/* This program can be used to test waiting for a semaphore in the presence of signals that might interrupt the `wait()` call. In particular the effect of Boehm-GC can be investigated. To do so compile this program with `v -gc boehm semaphore_wait.v` and run is as `./semaphore_wait > /dev/null` to test `sem.wait()` or `./semaphore_wait -t > /dev/null` to test `sem.timedwait()` on Windows: `.\semaphore_wait > NUL` or `.\semaphore_wait -t > NUL` On success (no interrupted `wait`) the output (from stderr) should like like: time: 524.228 result: `true` time: 521.122 result: `true` time: 523.714 result: `true` time: 527.001 result: `true` time: 521.696 result: `true` ... Finished (The "result" is only printed with `-t`.) */ import os import time import rand import math import sync struct DataObj { mut: data []f64 } struct PtrObj { mut: nxt []&DataObj } struct PtrPtrObj { mut: nxt []&PtrObj } const log2n = 9 const n = 1 << log2n const n4 = f64(u64(1) << (4 * log2n)) fn waste_mem() ! { mut objs := PtrPtrObj{ nxt: unsafe { []&PtrObj{len: n} } } for { sz := rand.int_in_range(10, 1000)! mut new_obj := &PtrObj{ nxt: unsafe { []&DataObj{len: sz} } } sz2 := rand.int_in_range(10, 500000)! new_obj2 := &DataObj{ data: []f64{len: sz2} } idx2 := rand.int_in_range(0, sz)! new_obj.nxt[idx2] = new_obj2 // non-equally distributed random index idx := int(math.sqrt(math.sqrt(rand.f64n(n4)!))) objs.nxt[idx] = new_obj } } fn do_rec(mut sem sync.Semaphore, timed bool) { mut start := time.sys_mono_now() for { r := if timed { sem.timed_wait(600 * time.millisecond) } else { sem.wait() false } end := time.sys_mono_now() dur := f64(end - start) / f64(time.millisecond) res_str := if timed { ' result: `${r}`' } else { '' } if dur < 450.0 || dur > 550.0 { eprintln('Problem: time: ${dur:.3f}${res_str}') } else { eprintln('time: ${dur:.3f}${res_str}') } start = end } } fn do_send(mut sem sync.Semaphore) { for { time.sleep(500 * time.millisecond) sem.post() } } fn usage() { eprintln('usage:\n\t${os.args[0]} [-t] [num_iterations]') exit(1) } fn main() { mut n_iterations := 5_000_000 mut timed := false if os.args.len > 3 { usage() } for i in 1 .. os.args.len { if os.args[i][0].is_digit() { if i > 1 && !timed { usage() } n_iterations = os.args[1].int() } else if os.args[i] == '-t' { timed = true } else { usage() } } if os.args.len > 3 || n_iterations <= 0 { eprintln('usage:\n\t${os.args[0]} [num_iterations]') exit(1) } mut sem := sync.new_semaphore() spawn do_rec(mut sem, timed) spawn do_send(mut sem) for _ in 0 .. 4 { spawn waste_mem() } mut last := time.sys_mono_now() for _ in 0 .. n_iterations { now := time.sys_mono_now() interval := now - last println(f64(interval) / f64(time.millisecond)) last = now } sem.destroy() eprintln('Finished') }