What is UNIX

Thread-safety and POSIX.1

Thread-safe Versions of POSIX.1 and C-language Functions

POSIX.1 and C-language functions were written to work in an environment of single-threaded processes. Reentrancy was not an issue in their design: the possibility of a process attempting to "re-enter" a function through concurrent invocations was not considered, because threads - the enabler of concurrency within a process - were not anticipated.

So, as it turns out, some POSIX.1 and C-language functions are inherently non-reentrant with respect to threads; that is, their interface specifications preclude reentrancy.1 For example, some functions (such as asctime()) return a pointer to a result stored in memory space allocated by the function on a per-process basis. Such a function is non-reentrant, because its result can be overwritten by successive invocations. Other POSIX.1 and C-language functions, while not inherently non-reentrant, may be implemented in ways that lead to non-reentrancy. For example, some functions (such as rand()) store state information (such as a seed value, which survives multiple function invocations) in memory space allocated by the function on a per-process basis. The implementation of such a function is non-reentrant if the implementation fails to synchronize invocations of the function and thus fails to protect the state information. The problem is that when the state information is not protected, concurrent invocations can interfere with one another (for example, see the same seed value).

Functions must be reentrant in an environment of multithreaded processes, in order to ensure that they can be safely invoked by concurrently executing threads. POSIX.1c takes three actions in the pursuit of reentrancy. First, POSIX.1c imposes reentrancy as a general rule: all functions, unless explicitly singled out as exceptions to the rule, must be implemented in a way that preserves reentrancy. Second, POSIX.1c redefines errno, as described below in . Third, for those functions whose interface specifications preclude reentrancy, POSIX.1c defines alternative "reentrant" versions as follows:

The specifications introduced by POSIX.1c for the purpose of ensuring reentrancy of POSIX.1 and C-language functions are mandatory for operating system implementations that support threads. They are optional for implementations that do not support threads. This is accomplished in the standard by associating the reentrancy specifications with a separate option, {_POSIX_THREAD_SAFE_FUNCTIONS}, which is declared to be mandatory for implementations supporting the threads option. Accordingly, this option is mandatory for conformance to the ISO/IEC 9945:1-1996.

Redefinition of errno

In POSIX.1, errno is defined as an external global variable. But this definition is unacceptable in a multithreaded environment, because its use can result in nondeterministic results. The problem is that two or more threads can encounter errors, all causing the same errno to be set. Under these circumstances, a thread might end up checking errno after it has already been updated by another thread.

To circumvent the resulting nondeterminism, POSIX.1c redefines errno as a service that can access the per-thread error number as follows (ISO/IEC 9945:1-1996, §2.4):

Some functions may provide the error number in a variable accessed through the symbol errno. The symbol errno is defined by including the header <errno.h>, as specified by the C Standard ... For each thread of a process, the value of errno shall not be affected by function calls or assignments to errno by other threads.

In addition, all POSIX.1c functions avoid using errno and, instead, return the error number directly as the function return value, with a return value of zero indicating that no error was detected. This strategy is, in fact, being followed on a POSIX-wide basis for all new functions.


Footnotes

1.
In POSIX.1c, a "reentrant function" is defined as a "function whose effect, when called by two or more threads, is guaranteed to be as if the threads each executed the function one after another in an undefined order, even if the actual execution is interleaved" (ISO/IEC 9945:1-1996, §2.2.2).

2.
It should be noted that the flockfile() function, like the pthread_mutex_lock() function, can lead to priority inversion. The application developer should take this into account when designing an application and analyzing its performance.

This text is extracted from Chapter 10 of the Authorized Guide to the Single UNIX Specification Version 2.


Single UNIX Specification UNIX Documentation Registered Products catalog White papers UNIX API Tables
UNIX and the Year 2000 Test tool downloads About The Open Group The Authorized Guide to UNIX 98 UNIX Resources

UNIX is a registered trademark of The Open Group.

Copyright © 1997-1999 , The Open Group.