This article focuses on a possible bug in the implementation of pthread_yield() service in the GLIBC.
In GLIBC 2.31, the source code of pthread_yield() is in the nptl/pthread_yield.c file in the source tree of the library:
int pthread_yield (void) { return sched_yield (); } |
The above GLIBC source code for pthread_yield() results in an unusual pthread API behavior which may be an implementation bug as it returns directly the result of sched_yield(). Like most of the Linux system calls, the latter returns -1 and sets errno if it fails (even if the manual specifies that it actually never returns in error). So, theoretically, this makes pthread_yield() return -1 and set errno in case of error although the pthread API usually returns 0 if successful and the error number in case of error (errno is not supposed to be set). So, the manual is wrong or at least does not comply with the GLIBC's implementation when it describes the returned value as:
RETURN VALUE On success, pthread_yield() returns 0; on error, it returns an error number. |
The expected source code for pthread_yield() could be something like:
int pthread_yield (void) { return sched_yield() == -1 ? errno : 0; } |
For example, pthread_sigmask() is coded as:
int pthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask) { [...] return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0; [...] } |
This complies with its manual:
RETURN VALUE On success, pthread_sigmask() returns 0; on error, it returns an error number. |
The GLIBC maintainers agree with the fact that it is worth to fix this problem eventhough sched_yield() never fails. They propose something which uses the INTERNAL_SYSCALL_CALL macro:
int pthread_yield (void) { int val; int result = 0; INTERNAL_SYSCALL_DECL (err); val = INTERNAL_SYSCALL_CALL (sched_yield, err); if (INTERNAL_SYSCALL_ERROR_P (val, err)) result = INTERNAL_SYSCALL_ERRNO (val, err); return result; } |
The author is an engineer in computer sciences located in France. He can be contacted here.