Concepts

This presents an overview of several concepts used in libctr. libctr tries to be an excellent example of software engineering, exemplifying many of the best professional practices and metrics in software development.

Thread-safety provides an overview for how libctr achieves thread-safety. Contexts provides an overview for how libctr prefers to encapsule data into a structure versus using global variables.

Thread-safety

Concurrency and parallelism are first-class topics in libctr. Everything should be thread-safe. To make this possible, as well as practical, libctr does not expose any init() functions to the user. The replacement makes heavy use of a GCC extension: constructor/destructor attributes. Any module or service which needs an init() function should instead declare an init() and fini() function in the source code file. As an example, consider the file gsp.c:

void gspInit() CTR_INIT;
void gspExit() CTR_FINI;

After the init() function for a module is called, all other functions should be completely thread-safe. init() functions are automatically called by the CRT0 startup function during program startup, which is the only time the program can be certain that there is only one thread running.

The init() function should do only one thing: Create the global context data.

The exit() function is optional, though highly recommended. It should free up any resources allocated, including the global context variable.

It is important to remember this: GCC Constructors/Destructors will only be called if the file they are declared in is used. As an example, if a sample program uses the Filesystem API but not the GSP API, the init function for filesystem will be called, but the init function for GSP will not be called.

Contexts

A context in libctr is a data structure which encapsulates all access to the data of a particular service or module. Because a context data structure is thread-safe once allocated, this makes them excellent replacements for global variables. A context data structure can be shared by as many threads as needed, provided that the context data was initialized before being passed to any threads.

Each module has one global context, and can be referenced by using the macro named CTR_<MODULE_NAME>_THIS. As an example, to refer to the global filesystem context data, use CTR_FS_THIS.

A context data structure can contain as many data fields as needed. The only required part is the service handle. This means that every time a new context data is created for a particular service, a new session for that service is opened with the kernel. The session will be closed when the context data is freed.

Although not mandatory, it is strongly encouraged to use atomic operations to ensure exclusive access, instead of mutex variables. The reason for this is because atomic operations do not block. An example of using atomic operations in a context data structure can be found in gsp.c.