Blocking and non-blocking RTOS APIs

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 callsAt 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 callsA 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)

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:

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: