Chris O'Byrne - YAVRTOS

How do I?

How do I use malloc() and free() safely?

It depends on whether you intend to use malloc() or free() from within ISRs (which is highly discouraged) or from within idle tasks (i.e. tasks with a zero priority). Note that create_task() and reserve_task() can call malloc().

Using malloc() and free() when they are going to be used from within ISRs and/or idle tasks

If you are going to use malloc() or free() from within an ISR and/or an idle task, you will need to disable interrupts either side of you call to malloc() and free()

void proc() {
  int *data = 0;
  interrupt_store_t interrupts;

  interrupts = disable_interrupts();
  data = malloc(REQUIRED_INTS * sizeof(int));
  restore_interrupts(interrupts);
  ...
  interrupts = disable_interrupts();
  free(data);
  restore_interrupts(interrupts);
  ...
}

The reason why we use the interrupt_store_t is because our proc() may have been called by another function that disabled interrupts for its own purposes, and it could be disastrous to unexpectedly enable interrupts on it.

We also want to disable interrupts for the shortest possible period of time, as disabling interrupts disables the all-important tick.

Note that interrupts will be disabled for the duration of the call to malloc() and free(). Depending on the algorithm used by malloc() and free(), and depending on what your time margin for the launch of ISRs is, interrupts could be disabled for "too long". And note that malloc() is called by reserve_task(), and can be called by create_task(), so using create_task() and reserve_task() in such time-critical situations could break your application.

Using malloc() and free() when they are not going to be used from within ISRs or idle tasks

If you are not going to use malloc() or free() from within ISRs or idle tasks, then you can create a mutex for the microcontroller's memory.

mutex_t memory_mutex;

void proc() {
  int *data = 0;

  lock_on(&memory_mutex);
  data = malloc(REQUIRED_INTS * sizeof(int));
  lock_off(&memory_mutex);
  ...
  lock_on(&memory_mutex);
  free(data);
  lock_off(&memory_mutex);
  ...
}

If you do this, then you must specify wait_for_mutexes in stop_task() when stopping any task that uses the memory mutex. This is because stop_task() could be called when the task is in the middle of executing malloc() or free(), and if malloc() or free() are not allowed to complete themselves, corruption of the tables used by malloc() and free() could result.

Using a memory mutex, however, has the significant advantage that interrupts are only disabled for a very short period of time during lock_on() and lock_off().

If you are using a mutex for the microcontrollers' memory, remember to use that mutex in all calls to create_task() and reserve_task(). (If you haven't yet started the RTOS with task_switcher_start(), then the memory_mutex argument to create_task() and reserve_task() will be ignored, and interrupts will be disabled during the calls to malloc()).

mutex_t memory_mutex;

void proc() {
  int *data = 0;

  lock_on(&memory_mutex);
  data = malloc(REQUIRED_INTS * sizeof(int));
  lock_off(&memory_mutex);
  ...
  // We must use the mutex in all calls to create_task() and reserve_task()!
  create_task(task2, 0, 0, 55, 20, &memory_mutex);
  ...
  lock_on(&memory_mutex);
  free(data);
  lock_off(&memory_mutex);
  ...
}

How do I write my own ISR?

For instance, we will write an ISR for the INT0 interrupt.

// Define the ISR prototype, so that the TASK_ISR() macro can reference our ISR function "int0_isr()"
uint8_t int0_isr();

// Set up the INT0 vector so that it calls the ISR
TASK_ISR(INT0_vect, int0_isr())

// Now, we can write the ISR function itself. It should return non-zero if a task switch should occur.
// It is recommended that it returns non-zero - the only time it would be safe for it to return zero
// would be if it didn't do anything to any task, semaphore, mailbox or mutex (i.e. if it didn't do anything
// that could un-suspend a suspended task).
uint8_t int0_isr() {
  ...
}

Upon entry into the int0_isr function, interrupts will be disabled, and the system stack will be in use.


YAVRTOS and YAVRTOS documentation Copyright © 2007-2008 Chris O'Byrne. Email - chris <at> obyrne <dot> com