linux-rx-spinlocks-for-preempt-20050320
[openafs.git] / src / rx / LINUX / rx_kmutex.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * rx_kmutex.c - mutex and condition variable macros for kernel environment.
12  *
13  * Linux implementation.
14  */
15
16 #include <afsconfig.h>
17 #include "afs/param.h"
18
19 RCSID
20     ("$Header$");
21
22 #include "rx/rx_kcommon.h"
23 #include "rx_kmutex.h"
24 #include "rx/rx_kernel.h"
25
26 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
27
28 void
29 afs_mutex_init(afs_kmutex_t * l)
30 {
31 #if defined(AFS_LINUX24_ENV)
32     init_MUTEX(&l->sem);
33 #else
34     l->sem = MUTEX;
35 #endif
36     l->owner = 0;
37 }
38
39 void
40 afs_mutex_enter(afs_kmutex_t * l)
41 {
42     down(&l->sem);
43     if (l->owner)
44         osi_Panic("mutex_enter: 0x%x held by %d", l, l->owner);
45     l->owner = current->pid;
46 }
47
48 int
49 afs_mutex_tryenter(afs_kmutex_t * l)
50 {
51     if (down_trylock(&l->sem))
52         return 0;
53     l->owner = current->pid;
54     return 1;
55 }
56
57 void
58 afs_mutex_exit(afs_kmutex_t * l)
59 {
60     if (l->owner != current->pid)
61         osi_Panic("mutex_exit: 0x%x held by %d", l, l->owner);
62     l->owner = 0;
63     up(&l->sem);
64 }
65
66 /* CV_WAIT and CV_TIMEDWAIT sleep until the specified event occurs, or, in the
67  * case of CV_TIMEDWAIT, until the specified timeout occurs.
68  * - NOTE: that on Linux, there are circumstances in which TASK_INTERRUPTIBLE
69  *   can wake up, even if all signals are blocked
70  * - TODO: handle signals correctly by passing an indication back to the
71  *   caller that the wait has been interrupted and the stack should be cleaned
72  *   up preparatory to signal delivery
73  */
74 int
75 afs_cv_wait(afs_kcondvar_t * cv, afs_kmutex_t * l, int sigok)
76 {
77     int isAFSGlocked = ISAFS_GLOCK();
78     sigset_t saved_set;
79 #ifdef DECLARE_WAITQUEUE
80     DECLARE_WAITQUEUE(wait, current);
81 #else
82     struct wait_queue wait = { current, NULL };
83 #endif
84
85     add_wait_queue(cv, &wait);
86     set_current_state(TASK_INTERRUPTIBLE);
87
88     if (isAFSGlocked)
89         AFS_GUNLOCK();
90     MUTEX_EXIT(l);
91
92     if (!sigok) {
93         SIG_LOCK(current);
94         saved_set = current->blocked;
95         sigfillset(&current->blocked);
96         RECALC_SIGPENDING(current);
97         SIG_UNLOCK(current);
98     }
99
100     schedule();
101     remove_wait_queue(cv, &wait);
102
103     if (!sigok) {
104         SIG_LOCK(current);
105         current->blocked = saved_set;
106         RECALC_SIGPENDING(current);
107         SIG_UNLOCK(current);
108     }
109
110     if (isAFSGlocked)
111         AFS_GLOCK();
112     MUTEX_ENTER(l);
113
114     return (sigok && signal_pending(current)) ? EINTR : 0;
115 }
116
117 void
118 afs_cv_timedwait(afs_kcondvar_t * cv, afs_kmutex_t * l, int waittime)
119 {
120     int isAFSGlocked = ISAFS_GLOCK();
121     long t = waittime * HZ / 1000;
122 #ifdef DECLARE_WAITQUEUE
123     DECLARE_WAITQUEUE(wait, current);
124 #else
125     struct wait_queue wait = { current, NULL };
126 #endif
127
128     add_wait_queue(cv, &wait);
129     set_current_state(TASK_INTERRUPTIBLE);
130
131     if (isAFSGlocked)
132         AFS_GUNLOCK();
133     MUTEX_EXIT(l);
134
135     t = schedule_timeout(t);
136     remove_wait_queue(cv, &wait);
137
138     if (isAFSGlocked)
139         AFS_GLOCK();
140     MUTEX_ENTER(l);
141 }
142
143 #endif