Skip to content

glib: reset errno to 0 when futex() returns EAGAIN

Daniel P. Berrange requested to merge dberrange/glib:futex-errno-kersplato into main

In the GMutex backend that is based on futux() the g_mutex_lock() method will periodically clobber errno setting it to EAGAIN. This is because the futex usage pattern is inherantly racey (in a safe manner), such that we'll sometimes call futex() even if it is not required. In such cases futex() returns EAGAIN.

Most of the time this is not a problem, as for the vast majority of APIs errno is irrelevant, and where it is relevant, it will only be examined if the function return value already indicated failure.

The g_ascii_strto* functions are special, however, in that the return value cannot tell you if they failed or not. It is required to set errno to zero before calling them and check for non-zero errno afterwards. Unfortunately the g_ascii_* functions call a helper which uses mutexes, so when GMutex is built with futex, the g_ascii_* functions will sometimes end up returning with errno set to EAGAIN which the callers interpret as failure.

To address this we must reset errno to its original value, if futex returns with errno == EAGAIN, as this is a success scenario.

Since this is a race condition, reproducing it is somewhat non-deterministic. Thus for a test case we create a few threads and let them process 1000 mutex lock/unlock calls. This has been sufficient to detect the failure / validate the fix on local development machines.

Closes: #3034 (closed) Signed-off-by: Daniel P. Berrangé berrange@redhat.com

Merge request reports