]>
Commit | Line | Data |
---|---|---|
e320ef46 | 1 | /* Copyright (C) 2002, 2003 Free Software Foundation, Inc. |
76a50749 UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. | |
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, write to the Free | |
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | 02111-1307 USA. */ | |
19 | ||
8c2e9a29 | 20 | #include <errno.h> |
76a50749 UD |
21 | #include <signal.h> |
22 | #include "pthreadP.h" | |
23 | #include "atomic.h" | |
e814f748 | 24 | #include <sysdep.h> |
76a50749 UD |
25 | |
26 | ||
27 | int | |
28 | pthread_cancel (th) | |
29 | pthread_t th; | |
30 | { | |
31 | volatile struct pthread *pd = (volatile struct pthread *) th; | |
32 | ||
8c2e9a29 UD |
33 | /* Make sure the descriptor is valid. */ |
34 | if (INVALID_TD_P (pd)) | |
35 | /* Not a valid thread handle. */ | |
36 | return ESRCH; | |
37 | ||
38 | int result = 0; | |
76a50749 UD |
39 | while (1) |
40 | { | |
41 | int oldval = pd->cancelhandling; | |
e320ef46 | 42 | int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; |
76a50749 UD |
43 | |
44 | /* Avoid doing unnecessary work. The atomic operation can | |
45 | potentially be expensive if the bug has to be locked and | |
46 | remote cache lines have to be invalidated. */ | |
47 | if (oldval == newval) | |
48 | break; | |
49 | ||
50 | /* If the cancellation is handled asynchronously just send a | |
51 | signal. We avoid this if possible since it's more | |
52 | expensive. */ | |
53 | if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) | |
54 | { | |
e320ef46 UD |
55 | /* Mark the cancellation as "in progress". */ |
56 | atomic_bit_set (&pd->cancelhandling, CANCELING_BIT); | |
57 | ||
76a50749 UD |
58 | /* The cancellation handler will take care of marking the |
59 | thread as canceled. */ | |
e814f748 UD |
60 | INTERNAL_SYSCALL_DECL (err); |
61 | ||
62 | int val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCANCEL); | |
63 | ||
64 | if (INTERNAL_SYSCALL_ERROR_P (val, err)) | |
65 | result = INTERNAL_SYSCALL_ERRNO (val, err); | |
76a50749 UD |
66 | |
67 | break; | |
68 | } | |
69 | ||
70 | /* Mark the thread as canceled. This has to be done | |
71 | atomically since other bits could be modified as well. */ | |
72 | if (atomic_compare_and_exchange_acq (&pd->cancelhandling, newval, | |
73 | oldval) == 0) | |
74 | break; | |
75 | } | |
76 | ||
e9cb48ab | 77 | return result; |
76a50749 | 78 | } |