Age | Commit message (Collapse) | Author | Lines |
|
the bug was that cancellation requests which arrived while a
cancellation point was interrupted by a signal handler would not be
acted upon when the signal handler returns. this was because cp_sp was
never set; it's no longer needed or used.
instead, just always re-raise the signal when cancellation was not
acted upon. this wastes a tiny amount of time in the rare case where
it even matters, but it ensures correctness and simplifies the code.
|
|
stale state information indicating that a thread was possibly blocked
at a cancellation point could get left behind if longjmp was used to
exit a signal handler that interrupted a cancellation point.
to fix the issue, we throw away the state information entirely and
simply compare the saved instruction pointer to a range of code
addresses in the __syscall_cp_asm function. all the ugly PIC work
(which becomes minimal anyway with this approach) is defered to
cancellation time instead of happening at every syscall, which should
improve performance too.
this commit also fixes cancellation on arm, which was mildly broken
(race condition, not checking cancellation flag once inside the
cancellation point zone). apparently i forgot to implement that. the
new arm code is untested, but appears correct; i'll test and fix it
later if there are problems.
|
|
even a single-threaded program can be cancellable, e.g. if it's called
pthread_cancel(pthread_self()). the correct predicate to check is not
whether multiple threads have been invoked, but whether pthread_self
has been invoked.
|
|
|
|
normally we allow cancellation to be acted upon when a syscall fails
with EINTR, since there is no useful status to report to the caller in
this case, and the signal that caused the interruption was almost
surely the cancellation request, anyway.
however, unlike all other syscalls, close has actually performed its
resource-deallocation function whenever it returns, even when it
returned an error. if we allow cancellation at this point, the caller
has no way of informing the program that the file descriptor was
closed, and the program may later try to close the file descriptor
again, possibly closing a different, newly-opened file.
the workaround looks ugly (special-casing one syscall), but it's
actually the case that close is the one and only syscall (at least
among cancellation points) with this ugly property.
|
|
|
|
sigaddset was not accepting SIGCANCEL as a valid signal number.
|
|
we already checked before making the syscall, but it's possible that a
signal handler interrupted the blocking syscall and disabled
cancellation, and that this is the cause of EINTR. in this case, the
old behavior was testably wrong.
|
|
|
|
x86_64 was just plain wrong in the cancel-flag-already-set path, and
crashing.
the more subtle error was not clearing the saved stack pointer before
returning to c code. this could result in the signal handler
misidentifying c code as the pre-syscall part of the asm, and acting
on cancellation at the wrong time, and thus resource leak race
conditions.
also, now __cancel (in the c code) is responsible for clearing the
saved sp in the already-cancelled branch. this means we have to use
call rather than jmp to ensure the stack pointer in the c will never
match what the asm saved.
|
|
|
|
signals were wrongly left masked, and cancellability state was not
switched to disabled, during the execution of cleanup handlers.
|
|
this patch improves the correctness, simplicity, and size of
cancellation-related code. modulo any small errors, it should now be
completely conformant, safe, and resource-leak free.
the notion of entering and exiting cancellation-point context has been
completely eliminated and replaced with alternative syscall assembly
code for cancellable syscalls. the assembly is responsible for setting
up execution context information (stack pointer and address of the
syscall instruction) which the cancellation signal handler can use to
determine whether the interrupted code was in a cancellable state.
these changes eliminate race conditions in the previous generation of
cancellation handling code (whereby a cancellation request received
just prior to the syscall would not be processed, leaving the syscall
to block, potentially indefinitely), and remedy an issue where
non-cancellable syscalls made from signal handlers became cancellable
if the signal handler interrupted a cancellation point.
x86_64 asm is untested and may need a second try to get it right.
|