Whamcloud - gitweb
b=20500
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-lock.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
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
297         spin_lock(lock);
298         if (atomic_dec_and_test(v))
299                 return 1;
300         spin_unlock(lock);
301         return 0;
302 }
303
304
305 /*
306  * rw spinlock
307  */
308
309
310 void
311 rwlock_init(rwlock_t * rwlock)
312 {
313     spin_lock_init(&rwlock->guard);
314     rwlock->count = 0;
315 }
316
317 void
318 rwlock_fini(rwlock_t * rwlock)
319 {
320 }
321
322 void
323 read_lock(rwlock_t * rwlock)
324 {
325     cfs_task_t * task = cfs_current();
326     PTASK_SLOT   slot = NULL;
327
328     if (!task) {
329         /* should bugchk here */
330         cfs_enter_debugger();
331         return;
332     }
333
334     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
335     ASSERT(slot->Magic == TASKSLT_MAGIC);
336    
337     slot->irql = KeRaiseIrqlToDpcLevel();
338
339     while (TRUE) {
340             spin_lock(&rwlock->guard);
341         if (rwlock->count >= 0)
342             break;
343         spin_unlock(&rwlock->guard);
344     }
345
346         rwlock->count++;
347         spin_unlock(&rwlock->guard);
348 }
349
350 void
351 read_unlock(rwlock_t * rwlock)
352 {
353     cfs_task_t * task = cfs_current();
354     PTASK_SLOT   slot = NULL;
355
356     if (!task) {
357         /* should bugchk here */
358         cfs_enter_debugger();
359         return;
360     }
361
362     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
363     ASSERT(slot->Magic == TASKSLT_MAGIC);
364    
365     spin_lock(&rwlock->guard);
366         ASSERT(rwlock->count > 0);
367     rwlock->count--;
368     if (rwlock < 0) {
369         cfs_enter_debugger();
370     }
371         spin_unlock(&rwlock->guard);
372
373     KeLowerIrql(slot->irql);
374 }
375
376 void
377 write_lock(rwlock_t * rwlock)
378 {
379     cfs_task_t * task = cfs_current();
380     PTASK_SLOT   slot = NULL;
381
382     if (!task) {
383         /* should bugchk here */
384         cfs_enter_debugger();
385         return;
386     }
387
388     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
389     ASSERT(slot->Magic == TASKSLT_MAGIC);
390    
391     slot->irql = KeRaiseIrqlToDpcLevel();
392
393     while (TRUE) {
394             spin_lock(&rwlock->guard);
395         if (rwlock->count == 0)
396             break;
397         spin_unlock(&rwlock->guard);
398     }
399
400         rwlock->count = -1;
401         spin_unlock(&rwlock->guard);
402 }
403
404 void
405 write_unlock(rwlock_t * rwlock)
406 {
407     cfs_task_t * task = cfs_current();
408     PTASK_SLOT   slot = NULL;
409
410     if (!task) {
411         /* should bugchk here */
412         cfs_enter_debugger();
413         return;
414     }
415
416     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
417     ASSERT(slot->Magic == TASKSLT_MAGIC);
418    
419     spin_lock(&rwlock->guard);
420         ASSERT(rwlock->count == -1);
421     rwlock->count = 0;
422         spin_unlock(&rwlock->guard);
423
424     KeLowerIrql(slot->irql);
425 }