[DISCUSSION] A thought experiment, let's remake ChibiOS/RT in Safer C (rev #1, 2018-1-18)

A place of insane ideas, nothing to see here.
User avatar
Site Admin
Posts: 10818
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 318 times
Been thanked: 268 times

[DISCUSSION] A thought experiment, let's remake ChibiOS/RT in Safer C (rev #1, 2018-1-18)

Postby Giovanni » Thu Jan 18, 2018 10:25 am

One important step in order to validate the concept is trying to use the new constructs to make something. We can use ChibiOS/RT as example, I think writing an RTOS is the perfect use case for a language dedicated to embedded systems.

In ChibiOS/RT (and most other RTOSes) there are two distinct asynchronous contexts: threads and ISRs, we need to handle synchronizations among those.

You may remember that in ChibiOS API the function suffix indicates the compatible context for functions, a runtime "state checker" makes sure that functions are called from the proper context. In Safer C the compiler should be able to do the very same thing at compile time without runtime overhead.

Let's define two asynchronous contexts:


The class name would be "thread", all thread functions would be declared as follow:

Code: Select all

root async <thread> void my_thread(void *p) {
   /* Thread code.*/

Any RTOS function meant to be called from thread context would be declared as follow:

Code: Select all

async <thread> msg_t chSemWaitTimeout(semaphore_t *semp, sysinterval_t timeout) {
  /* Semaphore code.*/

The compatibility mechanism makes sure that the function chSemWaitTimeout() can be called only from a thread asynchronous functions. This is equivalent to the ChibiOS/RT functions without suffix but checked at compile time instead of runtime.


ISRs would have asynchronous class "isr" and be declared as:

Code: Select all

async <isr> void my_isr(void) {
   /* ISR code.*/


This context defines a kernel critical zones, in ChibiOS/RT those are implemented by calling chSysLock(), chSysLockFromISR() etc. Let's define a construct for this.

Code: Select all

cdef async <thread> <isr> kernel {
async_enter <thread>:
async_leave <thread>:
async_enter <isr>:
async_leave <isr>:

From this "kernel" construct it is possible to access functions and data structures marked as "kernel". Let's try with semaphores. The construct can only be used by "isr" and "thread" classes asynchronous functions. Note that the implementation of the critical zone is different if used from "thread" or "isr" functions.

Code: Select all

/* The semaphore data structure can only be manipulated from a "kernel" context.*/
typedef kernel struct {
  /* Semaphore data.*/
} semaphore_t;

/* The function can only be called from thread context, the semaphore data is accessed
   from kernel context. Note that returning from within a kernel {} construct implicitly
   leaves the compound statement, it is not possible to forget a chSysUnlock().*/
async <thread> msg_t chSemWaitTimeout(semaphore_t *semp, sysinterval_t timeout) {

  context kernel {
    if (--sp->cnt < (cnt_t)0) {
      if (TIME_IMMEDIATE == timeout) {
        return MSG_TIMEOUT;
      currp->u.wtsemp = sp;
      sem_insert(currp, &sp->queue);
      return chSchGoSleepTimeoutS(CH_STATE_WTSEM, timeout);
    return MSG_OK;

/* Can only be called from "kernel" context (within a critical zone).*/
kernel void chSemSignalI(semaphore_t *semp) {
  if (++sp->cnt <= (cnt_t)0) {
    thread_t *tp = queue_fifo_remove(&sp->queue);
    tp->u.rdymsg = MSG_OK;
    (void) chSchReadyI(tp);

/* Variant to be called from "isr" class functions.*/
async <isr> chSemSignalFromISR(semaphore_t *semp) {

  context kernel {

Note how context compatibility is enforced at compile time rather than at runtime, critical data access (the semaphore) is enforced to be performed from within a critical zone, it cannot be manipulated in other ways.


Return to “Safer C”

Who is online

Users browsing this forum: No registered users and 0 guests