Whamcloud - gitweb
6d25d1b32985964994ec2d781ec7be67cf4aea0f
[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 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  */
34
35
36 # define DEBUG_SUBSYSTEM S_LNET
37
38 #include <libcfs/libcfs.h>
39
40
41 #if defined(_X86_)
42
43 void __declspec (naked) FASTCALL
44 cfs_atomic_add(
45     int i,
46     cfs_atomic_t *v
47     )
48 {
49     // ECX = i
50     // EDX = v ; [EDX][0] = v->counter
51
52     __asm {
53         lock add dword ptr [edx][0], ecx
54         ret
55     }
56 }
57
58 void __declspec (naked) FASTCALL
59 cfs_atomic_sub(
60     int i,
61     cfs_atomic_t *v
62    ) 
63 {
64     // ECX = i
65     // EDX = v ; [EDX][0] = v->counter
66
67     __asm {
68         lock sub dword ptr [edx][0], ecx
69         ret
70     }
71 }
72
73 void __declspec (naked) FASTCALL
74 cfs_atomic_inc(
75     cfs_atomic_t *v
76     )
77 {
78     //InterlockedIncrement((PULONG)(&((v)->counter)));
79
80     //` ECX = v ; [ECX][0] = v->counter
81
82     __asm {
83         lock inc dword ptr [ecx][0]
84         ret
85     }
86 }
87
88 void __declspec (naked) FASTCALL
89 cfs_atomic_dec(
90     cfs_atomic_t *v
91     )
92 {
93     // ECX = v ; [ECX][0] = v->counter
94
95     __asm {
96         lock dec dword ptr [ecx][0]
97         ret
98     }
99 }
100
101 int __declspec (naked) FASTCALL 
102 cfs_atomic_sub_and_test(
103     int i,
104     cfs_atomic_t *v
105     )
106 {
107
108     // ECX = i
109     // EDX = v ; [EDX][0] = v->counter
110
111     __asm {
112         xor eax, eax
113         lock sub dword ptr [edx][0], ecx
114         sete al
115         ret
116     }
117 }
118
119 int __declspec (naked) FASTCALL
120 cfs_atomic_inc_and_test(
121     cfs_atomic_t *v
122     )
123 {
124     // ECX = v ; [ECX][0] = v->counter
125
126     __asm {
127         xor eax, eax
128         lock inc dword ptr [ecx][0]
129         sete al
130         ret
131     }
132 }
133
134 int __declspec (naked) FASTCALL
135 cfs_atomic_dec_and_test(
136     cfs_atomic_t *v
137     )
138 {
139     // ECX = v ; [ECX][0] = v->counter
140
141     __asm {
142         xor eax, eax
143         lock dec dword ptr [ecx][0]
144         sete al
145         ret
146     }
147 }
148
149 #elif defined(_AMD64_)
150
151 void FASTCALL
152 cfs_atomic_add(
153     int i,
154     cfs_atomic_t *v
155     )
156 {
157     InterlockedExchangeAdd( (PULONG)(&((v)->counter)) , (LONG) (i));
158 }
159
160 void FASTCALL
161 cfs_atomic_sub(
162     int i,
163     cfs_atomic_t *v
164    ) 
165 {
166     InterlockedExchangeAdd( (PULONG)(&((v)->counter)) , (LONG) (-1*i));
167 }
168
169 void FASTCALL
170 cfs_atomic_inc(
171     cfs_atomic_t *v
172     )
173 {
174    InterlockedIncrement((PULONG)(&((v)->counter)));
175 }
176
177 void FASTCALL
178 cfs_atomic_dec(
179     cfs_atomic_t *v
180     )
181 {
182     InterlockedDecrement((PULONG)(&((v)->counter)));
183 }
184
185 int FASTCALL 
186 cfs_atomic_sub_and_test(
187     int i,
188     cfs_atomic_t *v
189     )
190 {
191     int counter, result;
192
193     do {
194
195         counter = v->counter;
196         result = counter - i;
197
198     } while ( InterlockedCompareExchange(
199                 &(v->counter),
200                 result,
201                 counter) !=  counter);
202
203     return (result == 0);
204 }
205
206 int FASTCALL
207 cfs_atomic_inc_and_test(
208     cfs_atomic_t *v
209     )
210 {
211     int counter, result;
212
213     do {
214
215         counter = v->counter;
216         result = counter + 1;
217
218     } while ( InterlockedCompareExchange(
219                 &(v->counter),
220                 result,
221                 counter) !=  counter);
222
223     return (result == 0);
224 }
225
226 int FASTCALL
227 cfs_atomic_dec_and_test(
228     cfs_atomic_t *v
229     )
230 {
231     int counter, result;
232
233     do {
234
235         counter = v->counter;
236         result = counter - 1;
237
238     } while ( InterlockedCompareExchange(
239                 &(v->counter),
240                 result,
241                 counter) !=  counter);
242
243     return (result == 0);
244 }
245
246 #else
247
248 #error CPU arch type isn't specified.
249
250 #endif
251
252 /**
253  * atomic_add_return - add integer and return
254  * \param v pointer of type atomic_t
255  * \param i integer value to add
256  *
257  * Atomically adds \a i to \a v and returns \a i + \a v
258  */
259 int FASTCALL cfs_atomic_add_return(int i, cfs_atomic_t *v)
260 {
261     int counter, result;
262
263     do {
264
265         counter = v->counter;
266         result = counter + i;
267
268     } while ( InterlockedCompareExchange(
269                 &(v->counter),
270                 result,
271                 counter) !=  counter);
272
273     return result;
274
275 }
276
277 /**
278  * atomic_sub_return - subtract integer and return
279  * \param v pointer of type atomic_t
280  * \param i integer value to subtract
281  *
282  * Atomically subtracts \a i from \a v and returns \a v - \a i
283  */
284 int FASTCALL cfs_atomic_sub_return(int i, cfs_atomic_t *v)
285 {
286         return cfs_atomic_add_return(-i, v);
287 }
288
289 int FASTCALL cfs_atomic_dec_and_lock(cfs_atomic_t *v, spinlock_t *lock)
290 {
291         if (cfs_atomic_read(v) != 1)
292                 return 0;
293
294         spin_lock(lock);
295         if (cfs_atomic_dec_and_test(v))
296                 return 1;
297         spin_unlock(lock);
298         return 0;
299 }
300
301
302 /*
303  * rw spinlock
304  */
305
306
307 void
308 rwlock_init(rwlock_t *rwlock)
309 {
310         spin_lock_init(&rwlock->guard);
311         rwlock->count = 0;
312 }
313
314 void
315 cfs_rwlock_fini(rwlock_t *rwlock)
316 {
317 }
318
319 void
320 read_lock(rwlock_t *rwlock)
321 {
322     cfs_task_t * task = cfs_current();
323     PTASK_SLOT   slot = NULL;
324
325     if (!task) {
326         /* should bugchk here */
327         cfs_enter_debugger();
328         return;
329     }
330
331     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
332     ASSERT(slot->Magic == TASKSLT_MAGIC);
333    
334     slot->irql = KeRaiseIrqlToDpcLevel();
335
336         while (TRUE) {
337                 spin_lock(&rwlock->guard);
338                         if (rwlock->count >= 0)
339                                 break;
340                 spin_unlock(&rwlock->guard);
341         }
342
343         rwlock->count++;
344         spin_unlock(&rwlock->guard);
345 }
346
347 void
348 read_unlock(rwlock_t *rwlock)
349 {
350     cfs_task_t * task = cfs_current();
351     PTASK_SLOT   slot = NULL;
352
353     if (!task) {
354         /* should bugchk here */
355         cfs_enter_debugger();
356         return;
357     }
358
359     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
360     ASSERT(slot->Magic == TASKSLT_MAGIC);
361
362         spin_lock(&rwlock->guard);
363         ASSERT(rwlock->count > 0);
364         rwlock->count--;
365         if (rwlock < 0)
366                 cfs_enter_debugger();
367         spin_unlock(&rwlock->guard);
368
369         KeLowerIrql(slot->irql);
370 }
371
372 void
373 write_lock(rwlock_t *rwlock)
374 {
375     cfs_task_t * task = cfs_current();
376     PTASK_SLOT   slot = NULL;
377
378     if (!task) {
379         /* should bugchk here */
380         cfs_enter_debugger();
381         return;
382     }
383
384     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
385     ASSERT(slot->Magic == TASKSLT_MAGIC);
386    
387     slot->irql = KeRaiseIrqlToDpcLevel();
388
389         while (TRUE) {
390                 spin_lock(&rwlock->guard);
391                 if (rwlock->count == 0)
392                         break;
393                 spin_unlock(&rwlock->guard);
394         }
395
396         rwlock->count = -1;
397         spin_unlock(&rwlock->guard);
398 }
399
400 void
401 write_unlock(rwlock_t *rwlock)
402 {
403     cfs_task_t * task = cfs_current();
404     PTASK_SLOT   slot = NULL;
405
406     if (!task) {
407         /* should bugchk here */
408         cfs_enter_debugger();
409         return;
410     }
411
412     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
413     ASSERT(slot->Magic == TASKSLT_MAGIC);
414
415         spin_lock(&rwlock->guard);
416         ASSERT(rwlock->count == -1);
417         rwlock->count = 0;
418         spin_unlock(&rwlock->guard);
419
420         KeLowerIrql(slot->irql);
421 }