Wystąpił problem z działaniem systemu Linux futex
(FUTEX_WAIT
), czasami powracający wcześnie pozornie bez przyczyny. Dokumentacja określa pewne warunki, które mogą spowodować, że powróci wcześniej (bez wartości FUTEX_WAKE
), ale wszystkie z nich obejmują niezerowe wartości zwracane: EAGAIN
, jeśli wartość na adresie futex nie jest zgodna, ETIMEDOUT
dla oczekiwania na czas, który upłynął, EINTR
po przerwaniu przez a (bez ponownego uruchamiania) sygnału itp. Ale widzę wartość zwracaną równą 0. Co, poza FUTEX_WAKE
lub zakończeniem wątku, którego wskaźnik wskazuje na futex, może spowodować powrót do wartości z wartością zwracaną przez: FUTEX_WAIT
0?Linux futex syscall fałszywy budzi się z wartością zwracaną 0?
W przypadku, jest to przydatne, szczególny futex Czekałem na to adres wątek tid (ustawiony przez clone
syscall z CLONE_CHILD_CLEARTID
), a nić miał nie zakończone. Moje (najwyraźniej niepoprawne) założenie, że operacja FUTEX_WAIT
powracająca do 0 może się zdarzyć tylko wtedy, gdy zakończony wątek prowadzi do poważnych błędów w logice programu, które od tego czasu naprawiłem przez zapętlenie i ponowienie, nawet jeśli zwraca 0, ale teraz jestem ciekawy jak dlaczego tak się stało.
Oto minimalne przypadek testowy:
#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);
}
}
Niech go uruchomić na chwilę, co powinno ostatecznie zakończyć z Killed
(SIGKILL
), co jest możliwe tylko wtedy, gdy nitka wciąż istnieje, gdy FUTEX_WAIT
zyski.
Zanim ktokolwiek pójdzie, zakładając, że to tylko jądro budzi futex, zanim skończy się niszczenie nici (co w rzeczywistości może się zdarzyć w moim minimalnym przypadku testowym tutaj), proszę zauważyć, że w moim oryginalnym kodzie faktycznie zaobserwowałem kod obszaru użytkownika uruchomione w wątku po powrocie FUTEX_WAIT
.
Myślę, że możemy potrzebować zobaczyć minimalny przykład; ciężko jest wymyślić znaczną radę, ponieważ tak wiele jest nieznanych (w każdym razie opowiem moje przeczucie jako tymczasową odpowiedź, bo to jest wielkie na komentarz) – sehe
Rzeczywiście, zobaczę, czy mogę zebrać minimalne przykład. –
hm, myślę, że strona man jest dość niejasna. warunki pod zwracaną wartością "FUTEX_WAIT" kwalifikują warunki inne niż zerowe jako warunki * błędu *, a nie tylko diagnostykę. Później mówi: "W przypadku błędu wszystkie operacje zwracają -1 i ustawiają errno, aby wskazać błąd." Z drugiej strony warunki tutaj nie są powtarzane w sekcji ** ERRORS **. –