У меня возникла проблема с системным вызовом Linux futex
( FUTEX_WAIT
), иногда возвращавшимся раньше, по-видимому, без причина. В документации указаны определенные условия, которые могут привести к его преждевременному возврату (без FUTEX_WAKE
), но все они включают ненулевые возвращаемые значения: EAGAIN
, если значение в адресе фьютекса не совпадает. , ETIMEDOUT
для рассчитанного ожидания этого тайм-аута, EINTR
при прерывании сигналом (без перезапуска) и т. Д. Но я вижу возвращаемое значение 0. Что, кроме FUTEX_WAKE
или завершение потока, чей указатель set_tid_address
указывает на фьютекс, может привести к возврату FUTEX_WAIT
с возвращаемым значением 0?
В случае, если он полезно, конкретный фьютекс, который я ожидал, - это tid-адрес потока (установленный системным вызовом clone
с помощью CLONE_CHILD_CLEARTID
), а поток не завершился. Мое (очевидно неверное) предположение, что операция FUTEX_WAIT
, возвращающая 0, могла произойти только тогда, когда поток завершился, что привело к серьезным ошибкам в логике программы, которые я с тех пор исправляю, повторяя и повторяя попытки, даже если он возвращает 0, но теперь мне любопытно, почему это произошло.
Вот минимальный тестовый пример:
#define _GNU_SOURCE
#include <sched.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <linux/futex.h>
#include <signal.h>
static char stack[32768];
static int tid;
static int foo(void *p)
{
syscall(SYS_getpid);
syscall(SYS_getpid);
syscall(SYS_exit, 0);
}
int main()
{
int pid = getpid();
for (;;) {
int x = clone(foo, stack+sizeof stack,
CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND
|CLONE_THREAD|CLONE_SYSVSEM //|CLONE_SETTLS
|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID
|CLONE_DETACHED,
0, &tid, 0, &tid);
syscall(SYS_futex, &tid, FUTEX_WAIT, x, 0);
/* Should fail... */
syscall(SYS_tgkill, pid, tid, SIGKILL);
}
}
Дайте ему поработать некоторое время, в конечном итоге он должен завершиться с помощью Killed
( SIGKILL
), что возможно, только если поток все еще существует, когда возвращается FUTEX_WAIT
.
Прежде чем кто-либо предположит, что это просто ядро пробуждает фьютекс до того, как он завершит уничтожение потока (что на самом деле может происходить в моем минимальном тестовом примере здесь), обратите внимание, что в моем исходном коде я действительно наблюдал запуск кода пользовательского пространства в потоке после возврата FUTEX_WAIT
.