JackAtomic.h 4.54 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
Copyright (C) 2004-2006 Grame  

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef __JackAtomic__
#define __JackAtomic__

typedef unsigned short UInt16;
typedef unsigned long UInt32;
typedef long SInt32;
#ifdef WIN32
	#include <windows.h>

typedef ULONGLONG UInt64;
#else

typedef unsigned long long UInt64;
#endif

#if defined(__APPLE__)

#if defined(__ppc__)

static inline int CAS(register UInt32 value, register UInt32 newvalue, register volatile void* addr)
{
    register int result;
    asm volatile (
        "# CAS					\n"
        "	lwarx	r0, 0, %1	\n"         // creates a reservation on addr
        "	cmpw	r0, %2		\n"			//  test value at addr
        "	bne-	1f          \n"
        "	sync            	\n"         //  synchronize instructions
        "	stwcx.	%3, 0, %1	\n"         //  if the reservation is not altered
        //  stores the new value at addr
        "	bne-	1f          \n"
        "   li      %0, 1       \n"
        "	b		2f          \n"
        "1:                     \n"
        "   li      %0, 0       \n"
        "2:                     \n"
    : "=r" (result)
                : "r" (addr), "r" (value), "r" (newvalue)
                : "r0"
            );
    return result;
}

#endif

#if defined(__i386__) || defined(__x86_64__)

#ifdef __SMP__
#	define LOCK "lock ; "
#else
#	define LOCK ""
#endif

static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr)
{
    register char ret;
    __asm__ __volatile__ (
        "# CAS \n\t"
        LOCK "cmpxchg %2, (%1) \n\t"
        "sete %0               \n\t"
    : "=a" (ret)
                : "c" (addr), "d" (newvalue), "a" (value)
            );
    return ret;
}

#endif

#endif

#ifdef __linux__

#ifdef __PPC__

static inline int CAS(register UInt32 value, register UInt32 newvalue, register volatile void* addr)
{
    register int result;
    register UInt32 tmp;
    asm volatile (
        "# CAS					\n"
        "	lwarx	%4, 0, %1	\n"         // creates a reservation on addr
        "	cmpw	%4, %2		\n"        //  test value at addr
        "	bne-	1f          \n"
        "	sync            	\n"         //  synchronize instructions
        "	stwcx.	%3, 0, %1	\n"         //  if the reservation is not altered
        //  stores the new value at addr
        "	bne-	1f          \n"
        "   li      %0, 1       \n"
        "	b		2f          \n"
        "1:                     \n"
        "   li      %0, 0       \n"
        "2:                     \n"
    : "=r" (result)
                : "r" (addr), "r" (value), "r" (newvalue), "r" (tmp)
            );
    return result;
}

#endif

#if defined(__i386__) || defined(__x86_64__)

#ifdef __SMP__
#	define LOCK "lock ; "
#else
#	define LOCK ""
#endif

static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr)
{
    register char ret;
    __asm__ __volatile__ (
        "# CAS \n\t"
        LOCK "cmpxchg %2, (%1) \n\t"
        "sete %0               \n\t"
    : "=a" (ret)
                : "c" (addr), "d" (newvalue), "a" (value)
            );
    return ret;
}

#endif

#endif

#ifdef WIN32

#ifdef __SMP__
#	define LOCK lock
#else
#	define LOCK
#endif

#define inline __inline

//----------------------------------------------------------------
// CAS functions
//----------------------------------------------------------------
inline char CAS (volatile UInt32 value, UInt32 newvalue, volatile void * addr)
{
    register char c;
    __asm {
        push	ebx
        push	esi
        mov	esi, addr
        mov	eax, value
        mov	ebx, newvalue
        LOCK cmpxchg dword ptr [esi], ebx
        sete	c
        pop	esi
        pop	ebx
    }
    return c;
}

#endif

static inline long INC_ATOMIC(volatile SInt32* val)
{
    SInt32 actual;
    do {
        actual = *val;
    } while (!CAS(actual, actual + 1, val));
    return actual;
}

static inline long DEC_ATOMIC(volatile SInt32* val)
{
    SInt32 actual;
    do {
        actual = *val;
    } while (!CAS(actual, actual - 1, val));
    return actual;
}

#endif