Project

General

Profile

Feature #13842

Updated by Joshua M. Clulow 8 months ago

Many modern C/C++ programs use threads.    The mechanics of @errno@ in threaded programs is slightly more complex than in the pre-thread era: while @errno@ must appear to C source as a global variable, it must in reality have a per-thread value. 

 In @/usr/include/errno.h@, we define an @errno@ macro which is implemented in terms of a function, @___errno()@, which returns a pointer to the per-thread version of @errno@ that software should be using: 

 <pre> 
 #if defined(_REENTRANT) || defined(_TS_ERRNO) || _POSIX_C_SOURCE - 0 >= 199506L 
 extern int *___errno(); 
 #define errno (*(___errno())) 
 #else 
 extern int errno; 
 /* ANSI C++ requires that errno be a macro */ 
 #if __cplusplus >= 199711L 
 #define errno errno 
 #endif 
 #endif    /* defined(_REENTRANT) || defined(_TS_ERRNO) */ 
 </pre> 

 By default, neither @_REENTRANT@ nor @_TS_ERRNO@ are defined in the compilation environment, so it is unfortunately very easy for a program that uses threads to be miscompiled to use the global @errno@.    This can result in failures with apparently spurious "Error 0" conditions in messages when software attempts to use, e.g., @strerror()@. 

 In the file @lib/libc/port/threads/thr.c@, in @libc_init()@, we set the per-thread location for @errno@ to the classical global @errno@ (which we cannot remove for binary compatibility reasons): 

 <pre> 
         self->ul_errnop = &errno; 
 </pre> 

 In all other threads, we set it to a location in the thread @ulwp_t@ structure: 

 <pre> 
         ulwp->ul_errnop = &ulwp->ul_errno; 
 </pre> 

 While the "threads":https://illumos.org/man/5/threads https://illumos.org/man/5/threads:"threads" page in the manual does correctly direct people to the use of @-D_REENTRANT@ for multi-threaded programs, it seems that at a minimum we could stop requiring it to get the thread-local @errno@.    We could replace the entire definition in the header with an unconditional: 

 <pre> 
 extern int *___errno(); 
 #define errno (*(___errno())) 
 </pre> 

 @___errno()@ would continue to return the location of the global @errno@ for the first thread, as it does today, and this change would have no impact on the ABI.    It is unlikely that any correct C/C++ program would stop building as a result of this change.

Back