У меня возникла проблема с системным вызовом Linux futex
(операция FUTEX_WAIT
), который иногда возвращался рано без видимой причины. В документации указаны некоторые условия, которые могут привести к его раннему возврату (без FUTEX_WAKE
), но все они включают ненулевые возвращаемые значения: EAGAIN
, если значение по адресу futex не совпадает, ETIMEDOUT
для синхронизированных ожиданий, которые тайм-аут, EINTR
при прерывании (без перезапуска) сигнала и т. д. Но я вижу возвращаемое значение 0. Что, кроме FUTEX_WAKE
или завершение потока, указатель set_tid_address
которого указывает на futex, может привести к возвращению FUTEX_WAIT
со значением возврата 0?
В случае, если это полезно, конкретный futex, на котором я ожидал, это адрес tid потока (установленный с помощью системного вызова clone
с помощью CLONE_CHILD_CLEARTID
), и у потока not завершено. Мое (очевидно неверное) предположение, что операция 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, прежде чем оно завершит уничтожение потока (что на самом деле может происходить в моем минимальном тестовом примере здесь), пожалуйста, обратите внимание, что в моем исходном коде я действительно наблюдал, как выполняется код пользовательского пространства. в теме хорошо после FUTEX_WAIT
вернулся.