69 lines
1.8 KiB
C++
69 lines
1.8 KiB
C++
#include "water.hpp"
|
|
|
|
#include <rt/task.hpp>
|
|
#include <rt/trap.hpp>
|
|
|
|
#include <rt/assert.h>
|
|
#include <rt/atomic.h>
|
|
|
|
static rt_atomic_uint32_t hydrogen_bonded = 0;
|
|
static rt_atomic_uint32_t oxygen_bonded = 0;
|
|
static rt_atomic_uint32_t water_formed = 0;
|
|
|
|
void make_water(void)
|
|
{
|
|
rt_atomic_fetch_add(&water_formed, 1, RT_ATOMIC_RELAXED);
|
|
}
|
|
|
|
#define TICKS_TO_RUN 1000
|
|
|
|
static void timeout(void)
|
|
{
|
|
rt::task::drop_privilege();
|
|
rt::task::sleep(TICKS_TO_RUN);
|
|
|
|
const uint32_t w = rt_atomic_load(&water_formed, RT_ATOMIC_RELAXED);
|
|
const uint32_t h = rt_atomic_load(&hydrogen_bonded, RT_ATOMIC_RELAXED);
|
|
const uint32_t o = rt_atomic_load(&oxygen_bonded, RT_ATOMIC_RELAXED);
|
|
|
|
/* The oxygen or hydrogen may not have bonded by the time rt::trap is called
|
|
* after making a water molecule, so allow for o and h to be one molecule's
|
|
* worth below expected value or exactly equal to it. */
|
|
const uint32_t o_lo = w - 1;
|
|
const uint32_t o_hi = w;
|
|
const uint32_t h_lo = (w - 1) * 2;
|
|
const uint32_t h_hi = w * 2;
|
|
|
|
rt_assert(o >= o_lo, "not enough oxygen was bonded");
|
|
rt_assert(o <= o_hi, "too much oxygen was bonded");
|
|
rt_assert(h >= h_lo, "not enough hydrogen was bonded");
|
|
rt_assert(h <= h_hi, "too much hydrogen was bonded");
|
|
|
|
rt::trap();
|
|
}
|
|
|
|
static void oxygen_loop(void)
|
|
{
|
|
rt::task::drop_privilege();
|
|
for (;;)
|
|
{
|
|
oxygen();
|
|
rt_atomic_fetch_add(&oxygen_bonded, 1, RT_ATOMIC_RELAXED);
|
|
}
|
|
}
|
|
|
|
static void hydrogen_loop(void)
|
|
{
|
|
rt::task::drop_privilege();
|
|
for (;;)
|
|
{
|
|
hydrogen();
|
|
rt_atomic_fetch_add(&hydrogen_bonded, 1, RT_ATOMIC_RELAXED);
|
|
}
|
|
}
|
|
|
|
RT_TASK(timeout, RT_STACK_MIN, 3);
|
|
RT_TASK(hydrogen_loop, RT_STACK_MIN, 1);
|
|
RT_TASK(hydrogen_loop, RT_STACK_MIN, 1);
|
|
RT_TASK(oxygen_loop, RT_STACK_MIN, 2);
|