Skip to content

Latest commit

 

History

History
204 lines (147 loc) · 4.88 KB

INTRODUCTION.md

File metadata and controls

204 lines (147 loc) · 4.88 KB

libosal Build Status

libosal is an operating system abstraction layer Library. It's purpose is to write os-independent code for easy portability between different systems and architectures.

Features:

Timers

The timer framework of libosal provides functions for sleeping and waiting for some defined amount of time. It is also used by the other components of libosal e.g. specifying a timeout while waiting on some events.

Here are some common example on how to use the timer frameworks:

wait for timeout example

This example can be used to do some work until a specified timeout occured or is finished otherwise.

osal_timer_t timeout;
osal_timer_init(&timeout, 1000000000); // values are in nanoseconds

do {
  // your work goes here
} while (osal_timer_expired(&timeout) != OSAL_ERR_TIMEOUT);

deterministic 1 ms loop example

This example implements a loop which can be used as deterministic (with appropriate priority) clock source for a control appllication.

osal_uint64_t cycle_rate = 1000000; // values are in nanoseconds
osal_uint64_t abs_timeout = osal_timer_gettime_nsec();
osal_retval_t ret;

do { 
  // your work goes here
  
  abs_timeout += cycle_rate;
  ret = osal_sleep_until_nsec(abs_timeout);
} while (ret == OSAL_OK);

Mutexes

The mutexes are mutual exclusion locks which are commonly used to protect shared memory structures from concurrent access.

Mutex example with 2 tasks

osal_mutex_t mtx;
some_struct_protected_by_mutex_t obj;

void *task_1(void *) {
  while (1) {
    osal_mutex_lock(&mtx);
    // wait for event, do some stuff on 'obj'
    osal_mutex_unlock(&mtx);
    
    // do other work
  }
  return NULL;
}

void *task_2(void *) {
  while (1) {
    osal_mutex_lock(&mtx);
    // wait for event, do some stuff on 'obj'
    osal_mutex_unlock(&mtx);
    
    // do other work
  }
  return NULL;
}

void main(int argc, char **argv) {
  osal_mutex_init(&mtx, NULL);
  // create tasks, do other things...
  
  return 0;
}

Semaphores

Semaphores are a synchronization mechanism with a counter. They are usually used to synchronize two ore more tasks. The counter counts how often \ref osal_semaphore_post was called. One of the wait function can be called as often as the counter is still greater than 0 without blocking.

Synychronization example with semaphores

osal_semaphore_t mysem;

void *task_1(void *) {
  while (1) {
    osal_semaphore_wait(&mysem);
    // do other work
  }
  return NULL;
}

void *task_2(void *) {
  while (1) {   
    // wait for event, do some stuff
    osal_semaphore_post(&mysem);
  }
  return NULL;
}

Binary Semaphores

Binary semaphores are a special case of a semaphore for signalling one event to one waiter. The state of the semaphore is be preserved until a waiter has consumed it. It is guaranteed that no event will be missed e.g. because of no one was waiting on the semaphore while it was posted.

Synychronization example with binary semaphores

osal_binary_semaphore_t binsem;

void *task_1(void *) {
  while (1) {
    osal_binary_semaphore_wait(&binsem);
    // do other work
  }
  return NULL;
}

void *task_2(void *) {
  while (1) {   
    // wait for event, do some stuff
    osal_binary_semaphore_post(&binsem);
  }
  return NULL;
}

Conditions

Conditions are another thread synchronization mechanism.

Spinlocks

Spinlocks are similar to mutexes but if locking a spinlock does not succeed it does busy-waiting until it is available.

They are used the same as a mutex. For an example please look at 'mutexes'.

Tasks

Task/Thread abstraction.

Task creation example

void *my_task_handler(void *arg) {
  // do task work
  return NULL;
}

int main(int argc, char **argv) {
  osal_task_create(&my_task_handle, NULL, my_task_handler, NULL);
  
  // do other work
  return 0;
}

Trace

The trace framework is used to do time-tracing of cyclic/periodic tasks.

This is an example of how this is meant to be used:

Debug tracing example

osal_trace_t my_trace;

void *cyclic_task(void *arg) {
  osal_uint64_t cycle_rate = 1000000; // values are in nanoseconds
  osal_uint64_t abs_timeout = osal_timer_gettime_nsec();
  osal_retval_t ret;

  do { 
    osal_trace_point(&my_trace);
    
    // your work goes here
  
    abs_timeout += cycle_rate;
    ret = osal_sleep_until_nsec(abs_timeout);
  } while (ret == OSAL_OK);
  return NULL;
}

void *print_task(void *arg) {
  osal_uint64_t avg, avg_jit, max_jit;
  while (1) {
    osal_timer_t timeout;
    osal_timer_init(&timeout, 1000000000);
    if (osal_trace_timedwait(&my_trace, &timeout) == OSAL_OK)) {
      osal_trace_analyze(&my_trace, &avg, &avg_jit, &max_jit);
      // print this
    }
  }
  return NULL;
}