Added PowerPC interlocked functions from glib.
[reactos.git] / reactos / lib / rosrtl / misc / intrlck.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/ntdll/rtl/intrlck.c
5 * PURPOSE: Inter lock increments
6 * UPDATE HISTORY:
7 * Created 30/09/99
8 */
9
10 /*
11 * Win32 kernel functions
12 *
13 * Copyright 1995 Martin von Loewis
14 * Copyright 1997 Onno Hovers
15 * Copied from kernel32
16 */
17
18 /* PowerPC Functions from gatomic.c in glib
19 *
20 * GLIB - Library of useful routines for C programming
21 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
22 *
23 * g_atomic_*: atomic operations.
24 * Copyright (C) 2003 Sebastian Wilhelmi
25 *
26 * This library is free software; you can redistribute it and/or
27 * modify it under the terms of the GNU Lesser General Public
28 * License as published by the Free Software Foundation; either
29 * version 2 of the License, or (at your option) any later version.
30 *
31 * This library is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34 * Lesser General Public License for more details.
35 *
36 * You should have received a copy of the GNU Lesser General Public
37 * License along with this library; if not, write to the
38 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
39 * Boston, MA 02111-1307, USA.
40 */
41
42 /************************************************************************
43 * InterlockedIncrement *
44 * *
45 * InterlockedIncrement adds 1 to a long variable and returns *
46 * - a negative number if the result < 0 *
47 * - zero if the result == 0 *
48 * - a positive number if the result > 0 *
49 * *
50 * The returned number need not be equal to the result!!!! *
51 * note: *
52 * *
53 ************************************************************************/
54
55 #include <windows.h>
56
57 LONG
58 STDCALL
59 InterlockedIncrement(PLONG Addend)
60 {
61 long ret = 0;
62 #ifdef _M_IX86
63 __asm__
64 (
65 "\tlock\n" /* for SMP systems */
66 "\tincl (%1)\n"
67 "\tje 2f\n"
68 "\tjl 1f\n"
69 "\tincl %0\n"
70 "\tjmp 2f\n"
71 "1:\tdec %0\n"
72 "2:\n"
73 :"=r" (ret):"r" (Addend), "0" (0): "memory"
74 );
75 #elif defined(_M_PPC)
76 ret = *Addend;
77 ret = InterlockedExchangeAdd( Addend, ret + 1 );
78 #endif
79 return ret;
80 }
81
82 /************************************************************************
83 * InterlockedDecrement *
84 * *
85 * InterlockedIncrement adds 1 to a long variable and returns *
86 * - a negative number if the result < 0 *
87 * - zero if the result == 0 *
88 * - a positive number if the result > 0 *
89 * *
90 * The returned number need not be equal to the result!!!! *
91 ************************************************************************/
92
93 LONG
94 STDCALL
95 InterlockedDecrement(LPLONG lpAddend)
96 {
97 long ret;
98 #ifdef _M_IX86
99 __asm__
100 (
101 "\tlock\n" /* for SMP systems */
102 "\tdecl (%1)\n"
103 "\tje 2f\n"
104 "\tjl 1f\n"
105 "\tincl %0\n"
106 "\tjmp 2f\n"
107 "1:\tdec %0\n"
108 "2:\n"
109 :"=r" (ret):"r" (lpAddend), "0" (0): "memory"
110 );
111 #elif defined(_M_PPC)
112 ret = *lpAddend;
113 ret = InterlockedExchangeAdd( lpAddend, ret - 1 );
114 #endif
115 return ret;
116
117
118 }
119
120 /************************************************************************
121 * InterlockedExchange
122 *
123 * Atomically exchanges a pair of values.
124 *
125 * RETURNS
126 * Prior value of value pointed to by Target
127 */
128
129 LONG
130 STDCALL
131 InterlockedExchange(LPLONG target, LONG value )
132 {
133 long ret;
134 #ifdef _M_IX86
135 __asm__ ( /* lock for SMP systems */
136 "lock\n\txchgl %0,(%1)"
137 :"=r" (ret):"r" (target), "0" (value):"memory" );
138 #elif defined(_M_PPC)
139 ret = *target;
140 while( InterlockedCompareExchange( target, value, ret ) != value );
141 #endif
142 return ret;
143 }
144
145 /************************************************************************
146 * InterlockedCompareExchange
147 *
148 * Atomically compares Destination and Comperand, and if found equal exchanges
149 * the value of Destination with Exchange
150 *
151 * RETURNS
152 * Prior value of value pointed to by Destination
153 */
154 LONG
155 STDCALL
156 InterlockedCompareExchange(
157 LPLONG Destination,
158 LONG Exchange,
159 LONG Comperand )
160 {
161 LONG ret;
162 #ifdef _M_IX86
163 __asm__ __volatile__( "lock; cmpxchgl %2,(%1)"
164 : "=a" (ret) : "r" (Destination), "r" (Exchange), "0" (Comperand) : "memory" );
165 #elif defined(_M_PPC)
166 __asm__ __volatile__ ("sync\n"
167 "1: lwarx %0,0,%1\n"
168 " subf. %0,%2,%0\n"
169 " bne 2f\n"
170 " stwcx. %3,0,%1\n"
171 " bne- 1b\n"
172 "2: isync"
173 : "=&r" (ret)
174 : "b" (Destination), "r" (Comperand), "r" (Exchange)
175 : "cr0", "memory");
176 #endif
177 return ret;
178 }
179
180 /************************************************************************
181 * InterlockedExchangeAdd
182 *
183 * Atomically adds Increment to Addend and returns the previous value of
184 * Addend
185 *
186 * RETURNS
187 * Prior value of value pointed to by Addend
188 */
189 LONG
190 STDCALL
191 InterlockedExchangeAdd(
192 PLONG Addend,
193 LONG Increment
194 )
195 {
196 LONG ret;
197 #ifdef _M_IX86
198 __asm__ ( /* lock for SMP systems */
199 "lock\n\t"
200 "xaddl %0,(%1)"
201 :"=r" (ret)
202 :"r" (Addend), "0" (Increment)
203 :"memory" );
204 #elif defined(_M_PPC)
205 do
206 ret = *Addend;
207 while (!InterlockedCompareExchange(Addend, ret, ret + Increment));
208 #endif
209 return ret;
210 }