Whamcloud - gitweb
LU-1347 build: remove the vim/emacs modelines
[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, cfs_spinlock_t *lock)
290 {
291     if (cfs_atomic_read(v) != 1) {
292         return 0;
293     }
294
295         cfs_spin_lock(lock);
296         if (cfs_atomic_dec_and_test(v))
297                 return 1;
298         cfs_spin_unlock(lock);
299         return 0;
300 }
301
302
303 /*
304  * rw spinlock
305  */
306
307
308 void
309 cfs_rwlock_init(cfs_rwlock_t * rwlock)
310 {
311     cfs_spin_lock_init(&rwlock->guard);
312     rwlock->count = 0;
313 }
314
315 void
316 cfs_rwlock_fini(cfs_rwlock_t * rwlock)
317 {
318 }
319
320 void
321 cfs_read_lock(cfs_rwlock_t * rwlock)
322 {
323     cfs_task_t * task = cfs_current();
324     PTASK_SLOT   slot = NULL;
325
326     if (!task) {
327         /* should bugchk here */
328         cfs_enter_debugger();
329         return;
330     }
331
332     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
333     ASSERT(slot->Magic == TASKSLT_MAGIC);
334    
335     slot->irql = KeRaiseIrqlToDpcLevel();
336
337     while (TRUE) {
338             cfs_spin_lock(&rwlock->guard);
339         if (rwlock->count >= 0)
340             break;
341         cfs_spin_unlock(&rwlock->guard);
342     }
343
344         rwlock->count++;
345         cfs_spin_unlock(&rwlock->guard);
346 }
347
348 void
349 cfs_read_unlock(cfs_rwlock_t * rwlock)
350 {
351     cfs_task_t * task = cfs_current();
352     PTASK_SLOT   slot = NULL;
353
354     if (!task) {
355         /* should bugchk here */
356         cfs_enter_debugger();
357         return;
358     }
359
360     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
361     ASSERT(slot->Magic == TASKSLT_MAGIC);
362    
363     cfs_spin_lock(&rwlock->guard);
364         ASSERT(rwlock->count > 0);
365     rwlock->count--;
366     if (rwlock < 0) {
367         cfs_enter_debugger();
368     }
369         cfs_spin_unlock(&rwlock->guard);
370
371     KeLowerIrql(slot->irql);
372 }
373
374 void
375 cfs_write_lock(cfs_rwlock_t * rwlock)
376 {
377     cfs_task_t * task = cfs_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             cfs_spin_lock(&rwlock->guard);
393         if (rwlock->count == 0)
394             break;
395         cfs_spin_unlock(&rwlock->guard);
396     }
397
398         rwlock->count = -1;
399         cfs_spin_unlock(&rwlock->guard);
400 }
401
402 void
403 cfs_write_unlock(cfs_rwlock_t * rwlock)
404 {
405     cfs_task_t * task = cfs_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     cfs_spin_lock(&rwlock->guard);
418         ASSERT(rwlock->count == -1);
419     rwlock->count = 0;
420         cfs_spin_unlock(&rwlock->guard);
421
422     KeLowerIrql(slot->irql);
423 }