summaryrefslogtreecommitdiff
path: root/src/thread
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2012-05-23 15:45:41 -0400
committerRich Felker <dalias@aerifal.cx>2012-05-23 15:45:41 -0400
commit4da268f74b90696563db4f5d9d2b8e1c1351bdc6 (patch)
tree6248d447902f2a011c70e2b207e600718bed77a4 /src/thread
parentcfd892fde9454e014d9b291a56ce5740d8bc4a78 (diff)
downloadmusl-4da268f74b90696563db4f5d9d2b8e1c1351bdc6.tar.gz
fix issue with longjmp out of signal handlers and cancellation
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.
Diffstat (limited to 'src/thread')
-rw-r--r--src/thread/arm/syscall_cp.s18
-rw-r--r--src/thread/cancel_impl.c15
-rw-r--r--src/thread/i386/syscall_cp.s36
-rw-r--r--src/thread/x86_64/syscall_cp.s18
4 files changed, 35 insertions, 52 deletions
diff --git a/src/thread/arm/syscall_cp.s b/src/thread/arm/syscall_cp.s
index 59924fc5..0cc23b1f 100644
--- a/src/thread/arm/syscall_cp.s
+++ b/src/thread/arm/syscall_cp.s
@@ -3,20 +3,18 @@
__syscall_cp_asm:
mov ip,sp
stmfd sp!,{r4,r5,r6,r7,lr}
- stmfd sp!,{r0}
- bl 1f
-1: mov r4,#(1f-.)
- add r4,r4,lr
- str r4,[r0,#4]
- str sp,[r0]
+.global __cp_begin
+__cp_begin:
+ ld r0,[r0]
+ cmp r0,#0
+ blne __cancel
mov r7,r1
mov r0,r2
mov r1,r3
ldmfd ip,{r2,r3,r4,r5,r6}
-1: svc 0
- ldmfd sp!,{r1}
- mov r2,#0
- str r2,[r1]
+ svc 0
+.global __cp_end
+__cp_end:
ldmfd sp!,{r4,r5,r6,r7,lr}
tst lr,#1
moveq pc,lr
diff --git a/src/thread/cancel_impl.c b/src/thread/cancel_impl.c
index 7652a7c9..3bf1e392 100644
--- a/src/thread/cancel_impl.c
+++ b/src/thread/cancel_impl.c
@@ -14,19 +14,12 @@ long __syscall_cp_asm(volatile void *, long, long, long, long, long, long, long)
long (__syscall_cp)(long nr, long u, long v, long w, long x, long y, long z)
{
pthread_t self;
- uintptr_t old_sp, old_ip;
long r;
if (!libc.main_thread || (self = __pthread_self())->canceldisable)
return __syscall(nr, u, v, w, x, y, z);
- old_sp = self->cp_sp;
- old_ip = self->cp_ip;
- self->cp_sp = 0;
- self->cp_ip = 0;
- r = __syscall_cp_asm(&self->cp_sp, nr, u, v, w, x, y, z);
- self->cp_ip = old_ip;
- self->cp_sp = old_sp;
+ r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z);
if (r==-EINTR && nr!=SYS_close && self->cancel && !self->canceldisable)
__cancel();
return r;
@@ -42,14 +35,14 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx)
{
pthread_t self = __pthread_self();
ucontext_t *uc = ctx;
- uintptr_t sp = ((uintptr_t *)&uc->uc_mcontext)[CANCEL_REG_SP];
- uintptr_t ip = ((uintptr_t *)&uc->uc_mcontext)[CANCEL_REG_IP];
+ const char *ip = ((char **)&uc->uc_mcontext)[CANCEL_REG_IP];
+ extern const char __cp_begin[1], __cp_end[1];
if (!self->cancel || self->canceldisable) return;
_sigaddset(&uc->uc_sigmask, SIGCANCEL);
- if (self->cancelasync || sp == self->cp_sp && ip <= self->cp_ip) {
+ if (self->cancelasync || ip >= __cp_begin && ip < __cp_end) {
self->canceldisable = 1;
pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, 0);
__cancel();
diff --git a/src/thread/i386/syscall_cp.s b/src/thread/i386/syscall_cp.s
index 05e867a1..3bf52c1f 100644
--- a/src/thread/i386/syscall_cp.s
+++ b/src/thread/i386/syscall_cp.s
@@ -2,34 +2,28 @@
.global __syscall_cp_asm
.type __syscall_cp_asm,@function
__syscall_cp_asm:
+ mov 4(%esp),%ecx
pushl %ebx
pushl %esi
pushl %edi
pushl %ebp
- leal 20(%esp),%ebp
- call 1f
-1: popl %eax
- movl (%ebp),%ecx
- addl $[1f-1b],%eax
- movl %eax,4(%ecx)
- movl %esp,(%ecx)
- movl 8(%ecx),%eax
+.global __cp_begin
+__cp_begin:
+ movl (%ecx),%eax
testl %eax,%eax
- jnz 2f
- movl 4(%ebp),%eax
- movl 8(%ebp),%ebx
- movl 12(%ebp),%ecx
- movl 16(%ebp),%edx
- movl 20(%ebp),%esi
- movl 24(%ebp),%edi
- movl 28(%ebp),%ebp
-1: int $128
+ jnz __cancel
+ movl 24(%esp),%eax
+ movl 28(%esp),%ebx
+ movl 32(%esp),%ecx
+ movl 36(%esp),%edx
+ movl 40(%esp),%esi
+ movl 44(%esp),%edi
+ movl 48(%esp),%ebp
+ int $128
+.global __cp_end
+__cp_end:
popl %ebp
popl %edi
popl %esi
popl %ebx
- xorl %edx,%edx
- movl 4(%esp),%ecx
- movl %edx,(%ecx)
ret
-2: call __cancel
diff --git a/src/thread/x86_64/syscall_cp.s b/src/thread/x86_64/syscall_cp.s
index b0363547..788c53cc 100644
--- a/src/thread/x86_64/syscall_cp.s
+++ b/src/thread/x86_64/syscall_cp.s
@@ -2,12 +2,12 @@
.global __syscall_cp_asm
.type __syscall_cp_asm,@function
__syscall_cp_asm:
- lea 1f(%rip),%rax
- mov %rax,8(%rdi)
- mov %rsp,(%rdi)
- mov 16(%rdi),%eax
+
+.global __cp_begin
+__cp_begin:
+ mov (%rdi),%eax
test %eax,%eax
- jnz 2f
+ jnz __cancel
mov %rdi,%r11
mov %rsi,%rax
mov %rdx,%rdi
@@ -17,9 +17,7 @@ __syscall_cp_asm:
mov 8(%rsp),%r8
mov 16(%rsp),%r9
mov %r11,8(%rsp)
-1: syscall
- xor %ecx,%ecx
- mov 8(%rsp),%rdi
- mov %rcx,(%rdi)
+ syscall
+.global __cp_end
+__cp_end:
ret
-2: call __cancel