Last update: 20-Dec-2020
Author: R. Koucha
Possible bug in pthread_yield()
Introduction

This article focuses on a possible bug in the implementation of pthread_yield() service in the GLIBC.

Current implementation

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 ();
}
Unusual return code

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.
Possible fix

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.
Conclusion

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;
}
About the author

The author is an engineer in computer sciences located in France. He can be contacted here.