[PATCH 2/4] nptl: Handle EPIPE on tst-cancel2

Adhemerval Zanella adhemerval.zanella@linaro.org
Tue Aug 20 16:46:00 GMT 2019



On 20/08/2019 12:30, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> For tst-cancel2.c, if I add a sleep (1) between pthread_create and 
>> pthread_cancel you can see this issue more clearly (dump with strace):
>>
>> [pid  2587] set_robust_list(0x7fffabccf290, 24) = 0
>> [pid  2587] write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 100000) = 100000
>> [pid  2587] write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 100000) = 100000
>> [pid  2587] write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 100000) = 100000
>> [pid  2587] write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 100000) = 100000
>> [pid  2587] write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 100000) = 100000
>> [pid  2587] write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 100000) = 100000
>> [pid  2587] write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 100000) = 100000
>> [pid  2587] write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 100000) = 100000
>> [pid  2587] write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 100000 <unfinished ...>
>> [pid  2586] <... nanosleep resumed>0x7ffff0c9e7f0) = 0
>>
>> ########### Cancellation start to act here, by loading the libgcc to unwinding
>> [pid  2586] open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 5
>> [pid  2586] fstat(5, {st_mode=S_IFREG|0644, st_size=63776, ...}) = 0
>> [pid  2586] mmap(NULL, 63776, PROT_READ, MAP_PRIVATE, 5, 0) = 0x7fffabf00000
>> [pid  2586] close(5)                    = 0
>> [pid  2586] open("/lib64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 5
>> [pid  2586] read(5, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\25\0\1\0\0\0\340+\0\0\0\0\0\0"..., 832) = 832
>> [pid  2586] fstat(5, {st_mode=S_IFREG|0755, st_size=133696, ...}) = 0
>> [pid  2586] mmap(NULL, 197688, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 5, 0) = 0x7fffab480000
>> [pid  2586] mmap(0x7fffab4a0000, 131072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 5, 0x10000) = 0x7fffab4a0000
>> [pid  2586] close(5)                    = 0
>> [pid  2586] mprotect(0x7fffab4a0000, 65536, PROT_READ) = 0
>> [pid  2586] munmap(0x7fffabf00000, 63776) = 0
>> [pid  2586] tgkill(2586, 2587, SIGRTMIN) = 0
>> [pid  2586] close(3)                    = 0
>> [pid  2586] futex(0x7fffabccf280, FUTEX_WAIT, 2587, NULL <unfinished ...>
>>
>> ########### Write returns with broken PIPE and __pthread_disable_asynccancel is called
>> [pid  2587] <... write resumed>)        = -1 EPIPE (Broken pipe)
>> [pid  2587] --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=2586, si_uid=61684} ---
>> [pid  2587] --- SIGRTMIN {si_signo=SIGRTMIN, si_code=SI_TKILL, si_pid=2586, si_uid=61684} ---
>> [pid  2587] futex(0x7fffab4b0224, FUTEX_WAKE_PRIVATE, 2147483647) = 0
>>
>> ########### No side-effects reported back to program
>> [pid  2587] madvise(0x7fffab4c0000, 8257536, MADV_DONTNEED) = 0
>> [pid  2587] exit(0)                     = ?
>>
>> With BZ#12683 fix the cancellation is not acted upon and the testcase then fails
>> depending whether the write is interrupted or not by the cancellation signal.
> 
> Hmm.  Which cancellation implementation is this?  At which point in the
> trace do we start unwinding?  I'm surprised that strace reports the
> EPIPE before the SIGPIPE, but maybe that's just a kernel race.  My
> expectation is that the current code unwinds after the system call
> returns with the EPIPE error, never returning it to the application.  I
> think this is the right behavior for the write system call.

This is current implement, more specifically glibc 2.17, CentOS 7.6 on
powerpc64le.  From the trace :

>> [pid  2586] tgkill(2586, 2587, SIGRTMIN) = 0

This where pthread_cancel sends the SIGCANCEL signal to thread.

>> [pid  2586] close(3)                    = 0

This is the

    /* This will cause the write in the child to return.  */
    close (fd[0]);

In tst-cancel2.c.

And finally:

>> [pid  2587] <... write resumed>)        = -1 EPIPE (Broken pipe)
>> [pid  2587] --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=2586, si_uid=61684} ---

SIGPIPE is receives, making the write fail with EPIPE and then

>> [pid  2587] --- SIGRTMIN {si_signo=SIGRTMIN, si_code=SI_TKILL, si_pid=2586, si_uid=61684} ---

sigcancel_handler is issued.  And the implementation *does* unwind after the
syscall is done, the problem is it ignores -1/EPIPE (and it is BZ#12683).



More information about the Libc-alpha mailing list