Whamcloud - gitweb
2c1797bbf66899fa48f2fcafde6031cf7e292eac
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-lock.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37
38 # define DEBUG_SUBSYSTEM S_LNET
39
40 #include <libcfs/libcfs.h>
41
42
43 #if defined(_X86_)
44
45 void __declspec (naked) FASTCALL
46 atomic_add(
47     int i,
48     atomic_t *v
49     )
50 {
51     // ECX = i
52     // EDX = v ; [EDX][0] = v->counter
53
54     __asm {
55         lock add dword ptr [edx][0], ecx
56         ret
57     }
58 }
59
60 void __declspec (naked) FASTCALL
61 atomic_sub(
62     int i,
63     atomic_t *v
64    ) 
65 {
66     // ECX = i
67     // EDX = v ; [EDX][0] = v->counter
68
69     __asm {
70         lock sub dword ptr [edx][0], ecx
71         ret
72     }
73 }
74
75 void __declspec (naked) FASTCALL
76 atomic_inc(
77     atomic_t *v
78     )
79 {
80     //InterlockedIncrement((PULONG)(&((v)->counter)));
81
82     //` ECX = v ; [ECX][0] = v->counter
83
84     __asm {
85         lock inc dword ptr [ecx][0]
86         ret
87     }
88 }
89
90 void __declspec (naked) FASTCALL
91 atomic_dec(
92     atomic_t *v
93     )
94 {
95     // ECX = v ; [ECX][0] = v->counter
96
97     __asm {
98         lock dec dword ptr [ecx][0]
99         ret
100     }
101 }
102
103 int __declspec (naked) FASTCALL 
104 atomic_sub_and_test(
105     int i,
106     atomic_t *v
107     )
108 {
109
110     // ECX = i
111     // EDX = v ; [EDX][0] = v->counter
112
113     __asm {
114         xor eax, eax
115         lock sub dword ptr [edx][0], ecx
116         sete al
117         ret
118     }
119 }
120
121 int __declspec (naked) FASTCALL
122 atomic_inc_and_test(
123     atomic_t *v
124     )
125 {
126     // ECX = v ; [ECX][0] = v->counter
127
128     __asm {
129         xor eax, eax
130         lock inc dword ptr [ecx][0]
131         sete al
132         ret
133     }
134 }
135
136 int __declspec (naked) FASTCALL
137 atomic_dec_and_test(
138     atomic_t *v
139     )
140 {
141     // ECX = v ; [ECX][0] = v->counter
142
143     __asm {
144         xor eax, eax
145         lock dec dword ptr [ecx][0]
146         sete al
147         ret
148     }
149 }
150
151 #elif defined(_AMD64_)
152
153 void FASTCALL
154 atomic_add(
155     int i,
156     atomic_t *v
157     )
158 {
159     InterlockedExchangeAdd( (PULONG)(&((v)->counter)) , (LONG) (i));
160 }
161
162 void FASTCALL
163 atomic_sub(
164     int i,
165     atomic_t *v
166    ) 
167 {
168     InterlockedExchangeAdd( (PULONG)(&((v)->counter)) , (LONG) (-1*i));
169 }
170
171 void FASTCALL
172 atomic_inc(
173     atomic_t *v
174     )
175 {
176    InterlockedIncrement((PULONG)(&((v)->counter)));
177 }
178
179 void FASTCALL
180 atomic_dec(
181     atomic_t *v
182     )
183 {
184     InterlockedDecrement((PULONG)(&((v)->counter)));
185 }
186
187 int FASTCALL 
188 atomic_sub_and_test(
189     int i,
190     atomic_t *v
191     )
192 {
193     int counter, result;
194
195     do {
196
197         counter = v->counter;
198         result = counter - i;
199
200     } while ( InterlockedCompareExchange(
201                 &(v->counter),
202                 result,
203                 counter) !=  counter);
204
205     return (result == 0);
206 }
207
208 int FASTCALL
209 atomic_inc_and_test(
210     atomic_t *v
211     )
212 {
213     int counter, result;
214
215     do {
216
217         counter = v->counter;
218         result = counter + 1;
219
220     } while ( InterlockedCompareExchange(
221                 &(v->counter),
222                 result,
223                 counter) !=  counter);
224
225     return (result == 0);
226 }
227
228 int FASTCALL
229 atomic_dec_and_test(
230     atomic_t *v
231     )
232 {
233     int counter, result;
234
235     do {
236
237         counter = v->counter;
238         result = counter - 1;
239
240     } while ( InterlockedCompareExchange(
241                 &(v->counter),
242                 result,
243                 counter) !=  counter);
244
245     return (result == 0);
246 }
247
248 #else
249
250 #error CPU arch type isn't specified.
251
252 #endif
253
254 /**
255  * atomic_add_return - add integer and return
256  * \param v pointer of type atomic_t
257  * \param i integer value to add
258  *
259  * Atomically adds \a i to \a v and returns \a i + \a v
260  */
261 int FASTCALL atomic_add_return(int i, atomic_t *v)
262 {
263     int counter, result;
264
265     do {
266
267         counter = v->counter;
268         result = counter + i;
269
270     } while ( InterlockedCompareExchange(
271                 &(v->counter),
272                 result,
273                 counter) !=  counter);
274
275     return result;
276
277 }
278
279 /**
280  * atomic_sub_return - subtract integer and return
281  * \param v pointer of type atomic_t
282  * \param i integer value to subtract
283  *
284  * Atomically subtracts \a i from \a v and returns \a v - \a i
285  */
286 int FASTCALL atomic_sub_return(int i, atomic_t *v)
287 {
288         return atomic_add_return(-i, v);
289 }
290
291 int FASTCALL atomic_dec_and_lock(atomic_t *v, spinlock_t *lock)
292 {
293         if (atomic_read(v) != 1)
294                 return 0;
295
296         spin_lock(lock);
297         if (atomic_dec_and_test(v))
298                 return 1;
299         spin_unlock(lock);
300         return 0;
301 }
302
303
304 /*
305  * rw spinlock
306  */
307
308
309 void
310 rwlock_init(rwlock_t *rwlock)
311 {
312         spin_lock_init(&rwlock->guard);
313         rwlock->count = 0;
314 }
315
316 void
317 cfs_rwlock_fini(rwlock_t *rwlock)
318 {
319 }
320
321 void
322 read_lock(rwlock_t *rwlock)
323 {
324     struct task_struct * task = current;
325     PTASK_SLOT   slot = NULL;
326
327     if (!task) {
328         /* should bugchk here */
329         cfs_enter_debugger();
330         return;
331     }
332
333     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
334     ASSERT(slot->Magic == TASKSLT_MAGIC);
335    
336     slot->irql = KeRaiseIrqlToDpcLevel();
337
338         while (TRUE) {
339                 spin_lock(&rwlock->guard);
340                         if (rwlock->count >= 0)
341                                 break;
342                 spin_unlock(&rwlock->guard);
343         }
344
345         rwlock->count++;
346         spin_unlock(&rwlock->guard);
347 }
348
349 void
350 read_unlock(rwlock_t *rwlock)
351 {
352     struct task_struct * task = current;
353     PTASK_SLOT   slot = NULL;
354
355     if (!task) {
356         /* should bugchk here */
357         cfs_enter_debugger();
358         return;
359     }
360
361     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
362     ASSERT(slot->Magic == TASKSLT_MAGIC);
363
364         spin_lock(&rwlock->guard);
365         ASSERT(rwlock->count > 0);
366         rwlock->count--;
367         if (rwlock < 0)
368                 cfs_enter_debugger();
369         spin_unlock(&rwlock->guard);
370
371         KeLowerIrql(slot->irql);
372 }
373
374 void
375 write_lock(rwlock_t *rwlock)
376 {
377     struct task_struct * task = current;
378     PTASK_SLOT   slot = NULL;
379
380     if (!task) {
381         /* should bugchk here */
382         cfs_enter_debugger();
383         return;
384     }
385
386     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
387     ASSERT(slot->Magic == TASKSLT_MAGIC);
388    
389     slot->irql = KeRaiseIrqlToDpcLevel();
390
391         while (TRUE) {
392                 spin_lock(&rwlock->guard);
393                 if (rwlock->count == 0)
394                         break;
395                 spin_unlock(&rwlock->guard);
396         }
397
398         rwlock->count = -1;
399         spin_unlock(&rwlock->guard);
400 }
401
402 void
403 write_unlock(rwlock_t *rwlock)
404 {
405     struct task_struct * task = current;
406     PTASK_SLOT   slot = NULL;
407
408     if (!task) {
409         /* should bugchk here */
410         cfs_enter_debugger();
411         return;
412     }
413
414     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
415     ASSERT(slot->Magic == TASKSLT_MAGIC);
416
417         spin_lock(&rwlock->guard);
418         ASSERT(rwlock->count == -1);
419         rwlock->count = 0;
420         spin_unlock(&rwlock->guard);
421
422         KeLowerIrql(slot->irql);
423 }