add C++ interfaces

This commit is contained in:
Chris Copeland 2023-07-06 23:55:29 -07:00
parent 98fdc15b33
commit 4d615506d8
Signed by: chrisnc
GPG Key ID: 14550DA72485DF30
54 changed files with 1500 additions and 29 deletions

View File

@ -8,6 +8,7 @@ RUN apt-get update && \
clang \
gdb \
less \
libc++-dev \
llvm \
scons

View File

@ -62,6 +62,7 @@ if "TERM" in os.environ:
env["ENV"]["TERM"] = os.environ["TERM"]
env["CC"] = "clang"
env["CXX"] = "clang++"
env.Append(
CCFLAGS=[
"-pthread",
@ -109,3 +110,24 @@ example_env.Append(
SConscript(
dirs="examples", variant_dir="build", duplicate=False, exports={"env": example_env}
)
cxx_example_env = example_env.Clone()
cxx_example_env.Append(
CPPPATH=[Dir("cxx/include").srcnode()],
CXXFLAGS=[
"-std=gnu++17",
"-stdlib=libc++",
"-Wno-c++98-compat-pedantic",
"-Wno-c99-designator",
"-Wno-c11-extensions",
"-Wno-global-constructors",
"-Wno-old-style-cast",
],
)
SConscript(
dirs="cxx/examples",
variant_dir="build/cxx",
duplicate=False,
exports={"env": cxx_example_env},
)

View File

@ -2,6 +2,10 @@
#include <rt/mpu.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef RT_MPU_NUM_REGIONS
#define RT_MPU_NUM_REGIONS 8
#endif
@ -384,3 +388,7 @@ static inline void rt_mpu_enable(void)
#define RT_MPU_PRIV_DATA(name) __attribute__((section(".priv_data." #name)))
#endif // RT_MPU_ENABLE
#ifdef __cplusplus
}
#endif

View File

@ -2,6 +2,10 @@
#include <rt/mpu.h>
#ifdef __cplusplus
extern "C" {
#endif
#if RT_MPU_ENABLE
#define RT_STACK_ALIGN(n) RT_MPU_ALIGN(n)
@ -25,3 +29,7 @@
#ifndef RT_STACK_MIN
#define RT_STACK_MIN 128
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,9 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// x86_64 and aarch64 both have a 16-byte alignment requirement
#ifndef RT_STACK_ALIGN
#define RT_STACK_ALIGN(n) 16UL
@ -12,3 +16,7 @@
#else
#define RT_STACK_SECTION(name) ".bss." #name
#endif
#ifdef __cplusplus
}
#endif

14
cxx/examples/SConscript Normal file
View File

@ -0,0 +1,14 @@
Import("env")
env.Program("mutex.cpp")
env.Program("notify.cpp")
env.Program("once.cpp")
env.Program("queue.cpp")
env.Program("rwlock.cpp")
env.Program("sem.cpp")
env.Program("sleep.cpp")
water = env.Object("water/water.cpp")
env.Program(["water/barrier.cpp", water])
env.Program(["water/cond.cpp", water])
env.Program(["water/sem.cpp", water])

84
cxx/examples/mutex.cpp Normal file
View File

@ -0,0 +1,84 @@
#include <rt/mutex.hpp>
#include <rt/rt.hpp>
#include <rt/sem.hpp>
#include <rt/sleep.hpp>
#include <rt/task.hpp>
static rt::mutex mutex;
static unsigned x = 0;
#define NUM_TASKS 3
#define ITERATIONS 10000U
static void stop_last(void)
{
static rt::sem stop_sem(NUM_TASKS - 1);
/* Only the last task to finish will call rt_stop. */
if (!stop_sem.trywait())
{
rt::stop();
}
}
static void increment_lock(void)
{
rt::task::drop_privilege();
for (unsigned i = 0; i < ITERATIONS; ++i)
{
rt::lock_guard lock(mutex);
++x;
}
stop_last();
}
static void increment_trylock(void)
{
rt::task::drop_privilege();
for (unsigned i = 0; i < ITERATIONS; ++i)
{
while (!mutex.trylock())
{
rt::sleep(1);
}
rt::lock_guard lock(mutex, rt::adopt_lock);
++x;
}
stop_last();
}
static void increment_timedlock(void)
{
rt::task::drop_privilege();
for (unsigned i = 0; i < ITERATIONS; ++i)
{
while (!mutex.timedlock(1))
{
}
rt::lock_guard lock(mutex, rt::adopt_lock);
++x;
}
stop_last();
}
static volatile bool timed_out = false;
static void timeout(void)
{
rt::sleep(1000);
timed_out = true;
rt::stop();
}
int main(void)
{
RT_TASK(increment_lock, RT_STACK_MIN, 1);
RT_TASK(increment_trylock, RT_STACK_MIN, 1);
RT_TASK(increment_timedlock, RT_STACK_MIN, 1);
RT_TASK(timeout, RT_STACK_MIN, 2);
rt::start();
if (timed_out || (x != (ITERATIONS * NUM_TASKS)))
{
return 1;
}
}

55
cxx/examples/notify.cpp Normal file
View File

@ -0,0 +1,55 @@
#include <rt/notify.hpp>
#include <rt/rt.hpp>
#include <rt/sleep.hpp>
#include <rt/task.hpp>
static const int n = 10;
static rt::notify note(0);
static void notifier(void)
{
rt::task::drop_privilege();
for (int i = 1; i <= n; ++i)
{
rt::sleep(5);
note.orr(1);
}
rt::sleep(15);
note.nop();
}
static volatile bool wait_failed = false;
static void waiter(void)
{
rt::task::drop_privilege();
uint32_t value;
for (int i = 1; i <= n; ++i)
{
if (!note.timedwait_clear(value, 1, 10))
{
wait_failed = true;
}
}
if (note.timedwait(value, 10))
{
wait_failed = true;
}
rt::stop();
}
int main(void)
{
RT_TASK(notifier, RT_STACK_MIN, 1);
RT_TASK(waiter, RT_STACK_MIN, 1);
rt::start();
if (wait_failed)
{
return 1;
}
}

41
cxx/examples/once.cpp Normal file
View File

@ -0,0 +1,41 @@
#include <rt/once.hpp>
#include <rt/rt.hpp>
#include <rt/sem.hpp>
#include <rt/task.hpp>
static rt::once once;
static rt::sem sem;
static volatile unsigned long x = 0;
static void fn(void)
{
x += 1;
}
static void oncer(void)
{
rt::task::drop_privilege();
once.call(fn);
sem.wait();
rt::stop();
}
static void twicer(void)
{
rt::task::drop_privilege();
once.call(fn);
sem.post();
}
int main(void)
{
RT_TASK(oncer, RT_STACK_MIN, 1);
RT_TASK(twicer, RT_STACK_MIN, 1);
rt::start();
if (x != 1)
{
return 1;
}
}

72
cxx/examples/queue.cpp Normal file
View File

@ -0,0 +1,72 @@
#include <rt/queue.hpp>
#include <rt/rt.hpp>
#include <rt/sleep.hpp>
#include <rt/task.hpp>
#include <stdint.h>
static rt::queue<uint32_t, 10> queue;
static void pusher(uintptr_t i)
{
rt::task::drop_privilege();
uint32_t x = (uint32_t)i;
for (;;)
{
queue.push(x);
++x;
}
}
#define NPUSHERS 3
#define TASK_INC UINT32_C(0x1000000)
static volatile bool out_of_order = false;
static uint32_t max_elem[NPUSHERS] = {0};
static volatile size_t num_popped = 0;
static void popper(void)
{
rt::task::drop_privilege();
uint32_t x;
for (;;)
{
queue.pop(x);
num_popped += 1;
uint32_t task = x / TASK_INC;
uint32_t elem = x % TASK_INC;
if (elem < max_elem[task])
{
out_of_order = true;
}
max_elem[task] = elem;
}
}
static void timeout(void)
{
rt::task::drop_privilege();
rt::sleep(1000);
rt::stop();
}
int main(void)
{
static RT_STACKS(pusher_stacks, RT_STACK_MIN, NPUSHERS);
static struct rt_task pushers[NPUSHERS];
for (uintptr_t i = 0; i < NPUSHERS; ++i)
{
rt_task_init_arg(&pushers[i], pusher, i * TASK_INC, "pusher", 1,
pusher_stacks[i], RT_STACK_MIN);
}
RT_TASK(popper, RT_STACK_MIN, 1);
RT_TASK(timeout, RT_STACK_MIN, 2);
rt::start();
if (out_of_order)
{
return 1;
}
}

68
cxx/examples/rwlock.cpp Normal file
View File

@ -0,0 +1,68 @@
#include <rt/rt.hpp>
#include <rt/rwlock.hpp>
#include <rt/sleep.hpp>
#include <rt/task.hpp>
static rt::rwlock lock;
static unsigned x = 0;
static unsigned y = 0;
#define NUM_READERS 3
static volatile bool mismatch = false;
static void reader(void)
{
rt::task::drop_privilege();
for (;;)
{
rt::rlock_guard rlock(lock);
const unsigned rx = x;
const unsigned ry = y;
if (rx != ry)
{
mismatch = true;
}
}
}
static void writer(void)
{
rt::task::drop_privilege();
for (;;)
{
{
rt::wlock_guard wlock(lock);
++x;
++y;
}
rt::sleep(1);
}
}
static void timeout(void)
{
rt::task::drop_privilege();
rt::sleep(1000);
rt::stop();
}
int main(void)
{
static RT_STACKS(reader_stacks, RT_STACK_MIN, NUM_READERS);
static struct rt_task reader_tasks[NUM_READERS];
for (int i = 0; i < NUM_READERS; ++i)
{
rt_task_init(&reader_tasks[i], reader, "reader", 1, reader_stacks[i],
RT_STACK_MIN);
}
RT_TASK(writer, RT_STACK_MIN, 1);
RT_TASK(timeout, RT_STACK_MIN, 2);
rt::start();
if (mismatch)
{
return 1;
}
}

52
cxx/examples/sem.cpp Normal file
View File

@ -0,0 +1,52 @@
#include <rt/rt.hpp>
#include <rt/sem.hpp>
#include <rt/sleep.hpp>
#include <rt/task.hpp>
static const int n = 10;
static rt::sem sem(0);
static void poster(void)
{
rt::task::drop_privilege();
for (int i = 1; i <= n; ++i)
{
rt::sleep(5);
sem.post();
}
rt::sleep(15);
sem.post();
}
static volatile bool wait_failed = false;
static void waiter(void)
{
rt::task::drop_privilege();
for (int i = 1; i <= n; ++i)
{
if (!sem.timedwait(10))
{
wait_failed = true;
}
}
if (sem.timedwait(10))
{
wait_failed = true;
}
rt::stop();
}
int main(void)
{
RT_TASK(poster, RT_STACK_MIN, 1);
RT_TASK(waiter, RT_STACK_MIN, 1);
rt::start();
if (wait_failed)
{
return 1;
}
}

42
cxx/examples/sleep.cpp Normal file
View File

@ -0,0 +1,42 @@
#include <rt/rt.hpp>
#include <rt/sem.hpp>
#include <rt/sleep.hpp>
#include <rt/task.hpp>
#include <rt/tick.hpp>
static const int nloops = 5;
static volatile bool wrong_tick = false;
static void sleep_periodic(uintptr_t period)
{
rt::task::drop_privilege();
unsigned long last_wake_tick = 0;
for (int i = 0; i < nloops; ++i)
{
rt::sleep_periodic(last_wake_tick, period);
unsigned long wake_tick = rt::tick_count();
if (wake_tick != last_wake_tick)
{
wrong_tick = true;
}
}
/* Only the second task to finish will call rt_stop. */
static rt::sem stop_sem(1);
if (!stop_sem.trywait())
{
rt::stop();
}
}
int main(void)
{
RT_TASK_ARG(sleep_periodic, 5, RT_STACK_MIN, 2);
RT_TASK_ARG(sleep_periodic, 10, RT_STACK_MIN, 1);
rt::start();
if (wrong_tick)
{
return 1;
}
}

View File

@ -0,0 +1,45 @@
#include "water.hpp"
#include <rt/barrier.hpp>
#include <rt/sem.hpp>
class reaction
{
public:
reaction() : h(rt::sem(2)), o(rt::sem(1)), barrier(rt::barrier(3))
{
}
void hydrogen()
{
h.wait();
barrier.wait();
barrier.wait();
h.post();
}
void oxygen()
{
o.wait();
barrier.wait();
make_water();
barrier.wait();
o.post();
}
private:
rt::sem h, o;
rt::barrier barrier;
};
static reaction rxn;
void hydrogen()
{
rxn.hydrogen();
}
void oxygen()
{
rxn.oxygen();
}

View File

@ -0,0 +1,52 @@
#include "water.hpp"
#include <rt/cond.hpp>
#include <rt/mutex.hpp>
class reaction
{
public:
reaction() : h(0)
{
}
void hydrogen()
{
rt::lock_guard lock(m);
++h;
hready.signal();
hdone.wait(m);
}
void oxygen()
{
{
rt::lock_guard lock(m);
while (h < 2)
{
hready.wait(m);
}
make_water();
h -= 2;
}
hdone.signal();
hdone.signal();
}
private:
int h;
rt::cond hready, hdone;
rt::mutex m;
};
static reaction rxn;
void hydrogen()
{
rxn.hydrogen();
}
void oxygen()
{
rxn.oxygen();
}

View File

@ -0,0 +1,44 @@
#include "water.hpp"
#include <rt/sem.hpp>
class reaction
{
public:
reaction() : h(0)
{
}
void hydrogen()
{
unsigned oldh = rt_atomic_fetch_add(&h, 1, RT_ATOMIC_RELAXED);
if ((oldh & 1) == 1)
{
h2ready.post();
}
hdone.wait();
}
void oxygen()
{
h2ready.wait();
make_water();
hdone.post(2);
}
private:
rt::sem h2ready, hdone;
rt_atomic_uint h;
};
static reaction rxn;
void hydrogen()
{
rxn.hydrogen();
}
void oxygen()
{
rxn.oxygen();
}

View File

@ -0,0 +1,72 @@
#include "water.hpp"
#include <rt/rt.hpp>
#include <rt/sleep.hpp>
#include <rt/task.hpp>
#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::sleep(TICKS_TO_RUN);
rt::stop();
}
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);
}
}
int main(void)
{
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);
rt::start();
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_stop 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;
if ((o < o_lo) || (o > o_hi) || (h < h_lo) || (h > h_hi))
{
return 1;
}
}

View File

@ -0,0 +1,7 @@
#pragma once
void hydrogen();
void oxygen();
void make_water();

View File

@ -0,0 +1,24 @@
#pragma once
#include <rt/barrier.h>
namespace rt
{
class barrier
{
public:
constexpr barrier(int count) : b(RT_BARRIER_INIT(b, count))
{
}
bool wait()
{
return rt_barrier_wait(&this->b);
}
private:
struct rt_barrier b;
};
} // namespace rt

44
cxx/include/rt/cond.hpp Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include <rt/cond.h>
#include <rt/mutex.hpp>
namespace rt
{
class cond
{
public:
constexpr cond() : c(RT_COND_INIT(c))
{
}
void signal()
{
rt_cond_signal(&this->c);
}
void broadcast()
{
rt_cond_broadcast(&this->c);
}
void wait(mutex &m)
{
return rt_cond_wait(&this->c, &m.m);
}
bool timedwait(mutex &m, unsigned long ticks)
{
return rt_cond_timedwait(&this->c, &m.m, ticks);
}
cond(const cond &) = delete;
cond &operator=(const cond &) = delete;
private:
struct rt_cond c;
};
} // namespace rt

75
cxx/include/rt/mutex.hpp Normal file
View File

@ -0,0 +1,75 @@
#pragma once
#include <rt/mutex.h>
namespace rt
{
class mutex
{
public:
constexpr mutex() : m(RT_MUTEX_INIT(m))
{
}
void lock()
{
rt_mutex_lock(&this->m);
}
void unlock()
{
rt_mutex_unlock(&this->m);
}
bool trylock()
{
return rt_mutex_trylock(&this->m);
}
bool timedlock(unsigned long ticks)
{
return rt_mutex_timedlock(&this->m, ticks);
}
friend class cond;
mutex(const mutex &) = delete;
mutex &operator=(const mutex &) = delete;
private:
struct rt_mutex m;
};
struct adopt_lock_t
{
explicit adopt_lock_t() = default;
};
inline constexpr adopt_lock_t adopt_lock{};
class lock_guard
{
public:
explicit lock_guard(mutex &m) : mtx(m)
{
mtx.lock();
}
lock_guard(mutex &m, adopt_lock_t) : mtx(m)
{
}
~lock_guard()
{
mtx.unlock();
}
lock_guard(const lock_guard &) = delete;
lock_guard &operator=(const lock_guard &) = delete;
private:
mutex &mtx;
};
} // namespace rt

72
cxx/include/rt/notify.hpp Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <rt/notify.h>
namespace rt
{
class notify
{
public:
constexpr notify(uint32_t value = 0) : n(RT_NOTIFY_INIT(n, value))
{
}
void nop()
{
rt_notify_post(&this->n);
}
void orr(uint32_t value)
{
rt_notify_or(&this->n, value);
}
void add(uint32_t value)
{
rt_notify_add(&this->n, value);
}
void set(uint32_t value)
{
rt_notify_set(&this->n, value);
}
uint32_t wait()
{
return rt_notify_wait(&this->n);
}
uint32_t wait_clear(uint32_t clear)
{
return rt_notify_wait_clear(&this->n, clear);
}
bool trywait(uint32_t &value)
{
return rt_notify_trywait(&this->n, &value);
}
bool trywait_clear(uint32_t &value, uint32_t clear)
{
return rt_notify_trywait_clear(&this->n, &value, clear);
}
bool timedwait(uint32_t &value, unsigned long ticks)
{
return rt_notify_timedwait(&this->n, &value, ticks);
}
bool timedwait_clear(uint32_t &value, uint32_t clear, unsigned long ticks)
{
return rt_notify_timedwait_clear(&this->n, &value, clear, ticks);
}
notify(const notify &) = delete;
notify &operator=(const notify &) = delete;
private:
struct rt_notify n;
};
} // namespace rt

27
cxx/include/rt/once.hpp Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <rt/once.h>
namespace rt
{
class once
{
public:
constexpr once() : o(RT_ONCE_INIT(o))
{
}
void call(void (*fn)(void))
{
rt_once_call(&this->o, fn);
}
once(const once &) = delete;
once &operator=(const once &) = delete;
private:
struct rt_once o;
};
} // namespace rt

70
cxx/include/rt/queue.hpp Normal file
View File

@ -0,0 +1,70 @@
#pragma once
#include <rt/queue.h>
namespace rt
{
template <typename T, size_t num> class queue
{
public:
constexpr queue() : q(RT_QUEUE_INIT(q, T, num, slots, elems))
{
}
void push(const T &e)
{
rt_queue_push(&this->q, &e);
}
void pop(T &e)
{
rt_queue_pop(&this->q, &e);
}
void peek(T &e)
{
rt_queue_peek(&this->q, &e);
}
bool trypush(const T &e)
{
return rt_queue_trypush(&this->q, &e);
}
bool trypop(T &e)
{
return rt_queue_trypop(&this->q, &e);
}
bool trypeek(T &e)
{
return rt_queue_trypeek(&this->q, &e);
}
bool timedpush(const T &e, unsigned long ticks)
{
return rt_queue_timedpush(&this->q, &e, ticks);
}
bool timedpop(T &e, unsigned long ticks)
{
return rt_queue_timedpop(&this->q, &e, ticks);
}
bool timedpeek(T &e, unsigned long ticks)
{
return rt_queue_timedpeek(&this->q, &e, ticks);
}
queue(const queue &) = delete;
queue &operator=(const queue &) = delete;
private:
static_assert(num <= RT_QUEUE_MAX_SIZE, "queue is too large");
T elems[num];
rt_atomic_uchar slots[num];
struct rt_queue q;
};
} // namespace rt

18
cxx/include/rt/rt.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <rt/rt.h>
namespace rt
{
static inline void start(void)
{
rt_start();
}
static inline void stop(void)
{
rt_stop();
}
} // namespace rt

92
cxx/include/rt/rwlock.hpp Normal file
View File

@ -0,0 +1,92 @@
#pragma once
#include <rt/rwlock.h>
#include <rt/mutex.hpp>
namespace rt
{
class rwlock
{
public:
constexpr rwlock() : l(RT_RWLOCK_INIT(l))
{
}
void rlock()
{
rt_rwlock_rlock(&this->l);
}
void runlock()
{
rt_rwlock_runlock(&this->l);
}
void wlock()
{
rt_rwlock_wlock(&this->l);
}
void wunlock()
{
rt_rwlock_wunlock(&this->l);
}
rwlock(const rwlock &) = delete;
rwlock &operator=(const rwlock &) = delete;
private:
struct rt_rwlock l;
};
class rlock_guard
{
public:
explicit rlock_guard(rwlock &l) : rwl(l)
{
rwl.rlock();
}
rlock_guard(rwlock &l, adopt_lock_t) : rwl(l)
{
}
~rlock_guard()
{
rwl.runlock();
}
rlock_guard(const rlock_guard &) = delete;
rlock_guard &operator=(const rlock_guard &) = delete;
private:
rwlock &rwl;
};
class wlock_guard
{
public:
explicit wlock_guard(rwlock &l) : rwl(l)
{
rwl.wlock();
}
wlock_guard(rwlock &l, adopt_lock_t) : rwl(l)
{
}
~wlock_guard()
{
rwl.wunlock();
}
wlock_guard(const wlock_guard &) = delete;
wlock_guard &operator=(const wlock_guard &) = delete;
private:
rwlock &rwl;
};
} // namespace rt

48
cxx/include/rt/sem.hpp Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include <rt/sem.h>
namespace rt
{
class sem
{
public:
constexpr sem(int count = 0, int max = INT_MAX)
: s(RT_SEM_INIT_MAX(s, count, max))
{
}
constexpr static sem binary()
{
return sem(0, 1);
}
void post(int n = 1)
{
rt_sem_post_n(&this->s, n);
}
void wait()
{
rt_sem_wait(&this->s);
}
bool trywait()
{
return rt_sem_trywait(&this->s);
}
bool timedwait(unsigned long ticks)
{
return rt_sem_timedwait(&this->s, ticks);
}
sem(const sem &) = delete;
sem &operator=(const sem &) = delete;
private:
struct rt_sem s;
};
} // namespace rt

19
cxx/include/rt/sleep.hpp Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include <rt/sleep.h>
namespace rt
{
static inline void sleep(unsigned long ticks)
{
rt_sleep(ticks);
}
static inline void sleep_periodic(unsigned long &last_wake_tick,
unsigned long period)
{
rt_sleep_periodic(&last_wake_tick, period);
}
} // namespace rt

66
cxx/include/rt/task.hpp Normal file
View File

@ -0,0 +1,66 @@
#pragma once
#include <rt/task.h>
namespace rt
{
class task
{
public:
task(void (*fn)(void), const char *name, unsigned int priority, void *stack,
size_t stack_size)
: t(RT_TASK_INIT(t, name, priority, RT_TASK_STATE_EXITED))
{
t.ctx = rt_context_init(fn, stack, stack_size);
rt_mpu_config_init(&t.mpu_config);
rt_mpu_config_set(&t.mpu_config, RT_MPU_TASK_REGION_START_ID,
(uintptr_t)stack, stack_size, RT_MPU_STACK_ATTR);
rt_syscall_push(&t.record);
rt_syscall_pend();
}
task(void (*fn)(uintptr_t), uintptr_t arg, const char *name,
unsigned int priority, void *stack, size_t stack_size)
: t(RT_TASK_INIT(t, name, priority, RT_TASK_STATE_EXITED))
{
t.ctx = rt_context_init_arg(fn, arg, stack, stack_size);
rt_mpu_config_init(&t.mpu_config);
rt_mpu_config_set(&t.mpu_config, RT_MPU_TASK_REGION_START_ID,
(uintptr_t)stack, stack_size, RT_MPU_STACK_ATTR);
rt_syscall_push(&t.record);
rt_syscall_pend();
}
task() = delete;
const char *name() const
{
return t.name;
}
static void yield()
{
rt_task_yield();
}
static void exit()
{
rt_task_exit();
}
static void enable_fp()
{
rt_task_enable_fp();
}
static void drop_privilege()
{
rt_task_drop_privilege();
}
private:
struct rt_task t;
};
} // namespace rt

18
cxx/include/rt/tick.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <rt/tick.h>
namespace rt
{
static inline void tick_advance(void)
{
rt_tick_advance();
}
static unsigned long tick_count(void)
{
return rt_tick_count();
}
} // namespace rt

View File

@ -1,20 +1,24 @@
#ifndef RT_ATOMIC_H
#define RT_ATOMIC_H
#include <stdint.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef atomic_bool rt_atomic_bool;
typedef atomic_uchar rt_atomic_uchar;
typedef atomic_int rt_atomic_int;
typedef atomic_uint rt_atomic_uint;
typedef atomic_long rt_atomic_long;
typedef atomic_ulong rt_atomic_ulong;
typedef atomic_size_t rt_atomic_size_t;
typedef atomic_uintptr_t rt_atomic_uintptr_t;
typedef _Atomic uint32_t rt_atomic_uint32_t;
#ifdef __cplusplus
extern "C" {
#endif
typedef _Atomic(bool) rt_atomic_bool;
typedef _Atomic(unsigned char) rt_atomic_uchar;
typedef _Atomic(int) rt_atomic_int;
typedef _Atomic(unsigned int) rt_atomic_uint;
typedef _Atomic(long) rt_atomic_long;
typedef _Atomic(unsigned long) rt_atomic_ulong;
typedef _Atomic(size_t) rt_atomic_size_t;
typedef _Atomic(uintptr_t) rt_atomic_uintptr_t;
typedef _Atomic(uint32_t) rt_atomic_uint32_t;
#define rt_atomic_load atomic_load_explicit
#define rt_atomic_store atomic_store_explicit
@ -50,4 +54,8 @@ typedef rt_atomic_bool rt_atomic_flag;
#define rt_atomic_flag_test_and_set(f, mo) atomic_exchange_explicit(f, true, mo)
#define rt_atomic_flag_clear(f, mo) atomic_store_explicit(f, false, mo)
#ifdef __cplusplus
}
#endif
#endif /* RT_ATOMIC_H */

View File

@ -7,6 +7,10 @@
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
struct rt_barrier;
void rt_barrier_init(struct rt_barrier *barrier, int count);
@ -36,4 +40,8 @@ struct rt_barrier
#define RT_BARRIER(name, count) \
struct rt_barrier name = RT_BARRIER_INIT(name, count)
#ifdef __cplusplus
}
#endif
#endif /* RT_BARRIER_H */

View File

@ -5,6 +5,10 @@
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
struct rt_cond;
struct rt_mutex;
@ -31,4 +35,8 @@ struct rt_cond
#define RT_COND(name) struct rt_cond name = RT_COND_INIT(name)
#ifdef __cplusplus
}
#endif
#endif /* RT_COND_H */

View File

@ -4,7 +4,15 @@
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define rt_container_of(ptr, type, member) \
((type *)((uintptr_t)(ptr)-offsetof(type, member)))
#ifdef __cplusplus
}
#endif
#endif /* RT_CONTAINER_H */

View File

@ -4,6 +4,10 @@
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Initialize the given stack with a new context that will execute fn().
*/
@ -21,4 +25,8 @@ void *rt_context_init_arg(void (*fn)(uintptr_t), uintptr_t arg, void *stack,
*/
extern void **rt_context_prev;
#ifdef __cplusplus
}
#endif
#endif /* RT_CONTEXT_H */