Redesigned how cancellation unblocks a thread from internal
[kopensolaris-gnu/glibc.git] / linuxthreads / spinlock.h
1 /* Linuxthreads - a simple clone()-based implementation of Posix        */
2 /* threads for Linux.                                                   */
3 /* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr)              */
4 /*                                                                      */
5 /* This program is free software; you can redistribute it and/or        */
6 /* modify it under the terms of the GNU Library General Public License  */
7 /* as published by the Free Software Foundation; either version 2       */
8 /* of the License, or (at your option) any later version.               */
9 /*                                                                      */
10 /* This program 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        */
13 /* GNU Library General Public License for more details.                 */
14
15 #if defined(TEST_FOR_COMPARE_AND_SWAP)
16
17 extern int __pthread_has_cas;
18 extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
19                                       int * spinlock);
20
21 static inline int compare_and_swap(long * ptr, long oldval, long newval,
22                                    int * spinlock)
23 {
24   if (__builtin_expect (__pthread_has_cas, 1))
25     return __compare_and_swap(ptr, oldval, newval);
26   else
27     return __pthread_compare_and_swap(ptr, oldval, newval, spinlock);
28 }
29
30 #elif defined(HAS_COMPARE_AND_SWAP)
31
32 static inline int compare_and_swap(long * ptr, long oldval, long newval,
33                                    int * spinlock)
34 {
35   return __compare_and_swap(ptr, oldval, newval);
36 }
37
38 #else
39
40 extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
41                                       int * spinlock);
42
43 static inline int compare_and_swap(long * ptr, long oldval, long newval,
44                                    int * spinlock)
45 {
46   return __pthread_compare_and_swap(ptr, oldval, newval, spinlock);
47 }
48
49 #endif
50
51 /* Internal locks */
52
53 extern void internal_function __pthread_lock(struct _pthread_fastlock * lock,
54                                              pthread_descr self);
55 extern void internal_function __pthread_unlock(struct _pthread_fastlock *lock);
56
57 static inline void __pthread_init_lock(struct _pthread_fastlock * lock)
58 {
59   lock->__status = 0;
60   lock->__spinlock = 0;
61 }
62
63 static inline int __pthread_trylock (struct _pthread_fastlock * lock)
64 {
65   long oldstatus;
66
67   do {
68     oldstatus = lock->__status;
69     if (oldstatus != 0) return EBUSY;
70   } while(! compare_and_swap(&lock->__status, 0, 1, &lock->__spinlock));
71   return 0;
72 }
73
74 #define LOCK_INITIALIZER {0, 0}
75
76 /* Operations on pthread_atomic, which is defined in internals.h */
77
78 static inline long atomic_increment(struct pthread_atomic *pa)
79 {
80     long oldval;
81
82     do {
83         oldval = pa->p_count;
84     } while (!compare_and_swap(&pa->p_count, oldval, oldval + 1, &pa->p_spinlock));
85
86     return oldval;
87 }
88
89
90 static inline long atomic_decrement(struct pthread_atomic *pa)
91 {
92     long oldval;
93
94     do {
95         oldval = pa->p_count;
96     } while (!compare_and_swap(&pa->p_count, oldval, oldval - 1, &pa->p_spinlock));
97
98     return oldval;
99 }
100
101 #define ATOMIC_INITIALIZER { 0, 0 }
102