Advertisement

Blocking and non-blocking RTOS APIs

July 13, 2013

Colin Walls-July 13, 2013

The primary purpose of a real-time operating system (RTOS) is to manage CPU time, distribute it between a number of tasks, and provide services to enable management of other resources such as peripherals. These functions are achieved in a variety of ways, but in most cases there is an opportunity for tasks to give a “hint” that they are able to relinquish the CPU for a while. Blocking system calls are one way to accomplish this. This article reviews how such calls work and when and how they are used.

API calls
At the heart of an RTOS is the kernel, which comprises the task scheduler and a number of services available to be called by application programs. Control of the scheduler and access to these services is by means of the kernel’s application program interface (API). APIs differ from one RTOS to another, although there are some standards, like POSIX, but some characteristics are common to many RTOSes. One of those similarities is the function of blocking and non-blocking calls.

Non-blocking calls
A program may make an API call to request a specific resource or service. Such a call may normally return with the required result and/or a pointer to the requested resources. There may also be the possibility for an error return. But what if the call is valid but the resource or service cannot be provided at this time? An example illustrates the possibilities.

Using Nucleus RTOS, a semaphore may be obtained by making a call of this form:

   STATUS NU_Obtain_Semaphore(NU_SEMAPHORE *semaphore, UNSIGNED suspend)


Like this:
   NU_SEMAPHORE my_semaphore;
   STATUS my_status;
   my_status = NU_Obtain_Semaphore(&my_semaphore, NU_NO_SUSPEND);


The return value, my_status, may have a variety of possible values, many of which indicate error conditions, but the likely ones are NU_SUCCESS, which means that the semaphore was successfully obtained, or NU_UNAVAILABLE, which means that the semaphore could not be obtained. Typically, a semaphore is used to lock a resource and a task needs to wait until the resource is available; i.e. the semaphore can be obtained. This could be achieved thus:

   do
   {
      my_status = NU_Obtain_Semaphore(&my_semaphore, NU_NO_SUSPEND);
   } while (my_status == NU_UNAVAILABLE);


So the code just sits in a loop, repeatedly trying to obtain the semaphore. (This code ignores the other possible error responses.) This is not good practice. It makes much more sense for the code to relinquish the CPU for a while after each try, thus:

   do
   {
     my_status = NU_Obtain_Semaphore(&my_semaphore, NU_NO_SUSPEND);
     if (my_status == NU_UNAVAILABLE)
       NU_Sleep(20);
   } while (my_status == NU_UNAVAILABLE);


or like this:

   while (TRUE)
   {
     my_status = NU_Obtain_Semaphore(&my_semaphore, NU_NO_SUSPEND);
     if (my_status == NU_SUCCESS)
       break;
     NU_Sleep(20);
   }

Here the task waits for 20 timer ticks before trying again. Both ways of writing it are likely to result in the same compiled code.


< Previous
Page 1 of 2
Next >

Loading comments...

Most Commented