1/* Copyright (C) 2009 Free Software Foundation, Inc.
2   This file is part of the GNU C Library.
3   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library; if not, see
17   <http://www.gnu.org/licenses/>.  */
18
19#include <sysdep.h>
20#include <tcb-offsets.h>
21#include <bits/kernel-features.h>
22#include "lowlevellock.h"
23
24#ifdef IS_IN_libpthread
25# ifdef SHARED
26#  define __pthread_unwind __GI___pthread_unwind
27# endif
28#else
29# ifndef SHARED
30	.weak __pthread_unwind
31# endif
32#endif
33
34
35#ifdef __ASSUME_PRIVATE_FUTEX
36# define LOAD_PRIVATE_FUTEX_WAIT(reg) \
37	movl	$(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
38#else
39# if FUTEX_WAIT == 0
40#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
41	movl	%fs:PRIVATE_FUTEX, reg
42# else
43#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
44	movl	%fs:PRIVATE_FUTEX, reg ; \
45	orl	$FUTEX_WAIT, reg
46# endif
47#endif
48
49/* It is crucial that the functions in this file don't modify registers
50   other than %rax and %r11.  The syscall wrapper code depends on this
51   because it doesn't explicitly save the other registers which hold
52   relevant values.  */
53	.text
54
55	.hidden __pthread_enable_asynccancel
56ENTRY(__pthread_enable_asynccancel)
57	movl	%fs:CANCELHANDLING, %eax
582:	movl	%eax, %r11d
59	orl	$TCB_CANCELTYPE_BITMASK, %r11d
60	cmpl	%eax, %r11d
61	je	1f
62
63	lock
64	cmpxchgl %r11d, %fs:CANCELHANDLING
65	jnz	2b
66
67	andl	$(TCB_CANCELSTATE_BITMASK|TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK|TCB_EXITING_BITMASK|TCB_CANCEL_RESTMASK|TCB_TERMINATED_BITMASK), %r11d
68	cmpl	$(TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK), %r11d
69	je	3f
70
711:	ret
72
733:	movq	$TCB_PTHREAD_CANCELED, %fs:RESULT
74	lock
75	orl	$TCB_EXITING_BITMASK, %fs:CANCELHANDLING
76	movq	%fs:CLEANUP_JMP_BUF, %rdi
77#ifdef SHARED
78	call	__pthread_unwind@PLT
79#else
80	call	__pthread_unwind
81#endif
82	hlt
83END(__pthread_enable_asynccancel)
84
85
86	.hidden __pthread_disable_asynccancel
87ENTRY(__pthread_disable_asynccancel)
88	testl	$TCB_CANCELTYPE_BITMASK, %edi
89	jnz	1f
90
91	movl	%fs:CANCELHANDLING, %eax
922:	movl	%eax, %r11d
93	andl	$~TCB_CANCELTYPE_BITMASK, %r11d
94	lock
95	cmpxchgl %r11d, %fs:CANCELHANDLING
96	jnz	2b
97
98	movl	%r11d, %eax
993:	andl	$(TCB_CANCELING_BITMASK|TCB_CANCELED_BITMASK), %eax
100	cmpl	$TCB_CANCELING_BITMASK, %eax
101	je	4f
1021:	ret
103
104	/* Performance doesn't matter in this loop.  We will
105	   delay until the thread is canceled.  And we will unlikely
106	   enter the loop twice.  */
1074:	movq	%fs:0, %rdi
108	movl	$__NR_futex, %eax
109	xorq	%r10, %r10
110	addq	$CANCELHANDLING, %rdi
111	LOAD_PRIVATE_FUTEX_WAIT (%esi)
112	syscall
113	movl	%fs:CANCELHANDLING, %eax
114	jmp	3b
115END(__pthread_disable_asynccancel)
116