Skip to content

POSIX API

Peter Corke edited this page Sep 17, 2018 · 2 revisions

POSIX threading API

The following table lists all STL functions. Where relevant there is a pointer to details of the underlying POSIX function.

MATLAB method Purpose POSIX reference
stl.argc Get number of command line arguments
stl.argv Get command line argument
stl.log Print to log
stl.launch Create a thread pthread_create
stl.cancel Cancel a thread pthread_cancel
stl.join Wait for thread to complete pthread_join
stl.semaphore Create semaphore sem_create
stl.semaphore_post Post semaphore sem_post
stl.semaphore_wait Wait for semaphore sem_wait
stl.semaphore_try Test semaphore (non blocking) sem_wait
stl.mutex Create a mutex pthread_mutex_create
stl.mutex_lock Lock a mutex pthread_mutex_lock
stl.mutex_try Lock a mutex (non blocking) pthread_mutex_lock
stl.mutex_unlock Unlock a mutex pthread_mutex_unlock
stl.timer Periodically set semaphore timer_create

Each operation is defined by a short method in stl/stl.m which essentially wraps a function defined by stl.c which is called using coder.ceval.

Threads

Each additional thread must be defined as a separate MATLAB "entry point function", that is, in a separate m-file.

If the function returns then the thread is terminated. Typically a thread would be a loop, perhaps even an infinite loop. The loop must contain some blocking operation such as waiting for:

  • a semaphore or mutex
  • a read or write transaction to some device (serial port, I2C etc.)
  • a Linux system call.
This is not a cooperative threading environment, threads that do busy/wait polling will be preempted by the scheduler

Semaphores

Semaphores are used to allow threads to block or enable other threads. For the specific case of protecting a shared resource use a mutex.

id = stl.semaphore(name) returns the id of a new semaphore, initially not raised.

stl.semaphore_wait(id) blocks the thread until the semaphore is raised.

v = stl.semaphore_try(id,true) tests if the semaphore is raised without blocking. If the semaphore is raised it returns true, otherwise it returns false.

stl.semaphore.post(id) the semaphore is raised and one of threads which are waiting on the semaphore is awakened.

Mutexes

Mutexes are a good tool to protecting a resource shared by multiple threads. Only one thread at a time can lock the mutex.

id = stl.mutex(name) returns the id of a new mutex, initially unlocked.

stl.mutex_lock(id) blocks the thread until the mutex is unlocked and then this thread locks it.

stl.mutex_try(id,true) tests if the mutex can be locked, without blocking. If the mutex is unlocked it returns true and locks the mutex, otherwise it returns false.

stl.mutex_unlock(id) the mutex is unlocked and it is available for other threads to lock.

Timers

A timer (Linux only) periodically posts a semaphore at a periodic interval. This is useful for periodic tasks where regularity is important (minimize jitter) and where the execution time is variable.

id = stl.timer(name, interval, sem) creates a new timer that fires every interval seconds (a double) and posts the semaphore sem.

This capability is not available for MacOS, see discussion here. A workaround is to use sleep within a thread loop, but this can lead to timing jitter and drift.

Implementation details

STL comprises a set of MATLAB functions which in turn call functions written in C that interface with the operating system's POSIX libraries.

Design principles

STL supports a useful subset of POSIX functionality: threads, semaphores and mutexes. Each of these objects is referenced by a small integer handle. The actual POSIX objects/pointers are kept in arrays within stl.c, the maximum number of threads, semaphores, timers and mutexes (currently 8) can be adjusted by parameters at the top of stl.c.

All objects have string names (MATLAB character arrays) to assist in debugging, these are shown in the log message stream.

When a resource is freed its STL handle is recycled.

Object Handle range Comment
thread 0 main thread
thread 1 → NTHREADS-1 user threads
semaphore 0 → NSEMAPHORES-1
mutex 0 → NMUTEXS-1
timer 0 → NTIMERS-1

An error is thrown if attempting to allocate, at any one time, more objects than the current maximum.

main.c

The C-language main function is provided by stl/main.c which performs some initialization and then calls user.m.

Command line arguments

% ./user bob alice 123.5

Command line arguments are not passed through to user but are kept by STL and made available via functions.

stl.argc returns the number of arguments, always one or more. In the example above it will return 4.

stl.argv(i) returns the i'th argument as a string. i=0 gives the name of the command, and the maximum value of i is one less than the value returned by stl.argc. In the example above stl.argv(0) = './user' which is the command used to invoke the program, and stl.argv(3) = '123.5'.

Debugging

Detailed logging of all events to the log channel can be enabled.

stl.debug(true)

Events include object creation, thread launch and exit, semaphore post and wait, mutex lock and unlock. Each entry lists the date and time (to μs precision) and the name of the thread that was executing.

An example log file enabled by debugging is:

2018-08-27 09:25:02.480656 [thread2] hello from thread2, id #2
2018-08-27 09:25:03.479300 [user] cancelling thread #2 <thread2>
2018-08-27 09:25:03.479371 [user] waiting for thread #2 <thread2>
2018-08-27 09:25:03.479435 [user] thread complete #2 <thread2>
2018-08-27 09:25:05.479844 [user] creating semaphore #0 <sem1>
2018-08-27 09:25:05.479977 [user] sem id 0
2018-08-27 09:25:06.481025 [user] thread id 1
2018-08-27 09:25:06.481079 [thread3] starting posix thread <thread3> (0xA162220)
2018-08-27 09:25:06.481109 [thread3] waiting for semaphore #0 <sem1>

MATLAB wrapper

Rather than have one M-files for every STL function, they have been written as static methods in the class stl.m.