dbd3b32e122345fcd8e9177f94246b8ffb947d92
[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 void
27 afs_mutex_init(afs_kmutex_t * l)
28 {
29 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
30     mutex_init(&l->mutex);
31 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
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 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
43     mutex_lock(&l->mutex);
44 #else
45     down(&l->sem);
46 #endif
47     if (l->owner)
48         osi_Panic("mutex_enter: 0x%x held by %d", l, l->owner);
49     l->owner = current->pid;
50 }
51
52 int
53 afs_mutex_tryenter(afs_kmutex_t * l)
54 {
55 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
56     if (mutex_trylock(&l->mutex) == 0)
57 #else
58     if (down_trylock(&l->sem))
59 #endif
60         return 0;
61     l->owner = current->pid;
62     return 1;
63 }
64
65 void
66 afs_mutex_exit(afs_kmutex_t * l)
67 {
68     if (l->owner != current->pid)
69         osi_Panic("mutex_exit: 0x%x held by %d", l, l->owner);
70     l->owner = 0;
71 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
72     mutex_unlock(&l->mutex);
73 #else
74     up(&l->sem);
75 #endif
76 }
77
78 /* CV_WAIT and CV_TIMEDWAIT sleep until the specified event occurs, or, in the
79  * case of CV_TIMEDWAIT, until the specified timeout occurs.
80  * - NOTE: that on Linux, there are circumstances in which TASK_INTERRUPTIBLE
81  *   can wake up, even if all signals are blocked
82  * - TODO: handle signals correctly by passing an indication back to the
83  *   caller that the wait has been interrupted and the stack should be cleaned
84  *   up preparatory to signal delivery
85  */
86 int
87 afs_cv_wait(afs_kcondvar_t * cv, afs_kmutex_t * l, int sigok)
88 {
89     int seq, isAFSGlocked = ISAFS_GLOCK();
90     sigset_t saved_set;
91 #ifdef DECLARE_WAITQUEUE
92     DECLARE_WAITQUEUE(wait, current);
93 #else
94     struct wait_queue wait = { current, NULL };
95 #endif
96
97     seq = cv->seq;
98     
99     set_current_state(TASK_INTERRUPTIBLE);
100     add_wait_queue(&cv->waitq, &wait);
101
102     if (isAFSGlocked)
103         AFS_GUNLOCK();
104     MUTEX_EXIT(l);
105
106     if (!sigok) {
107         SIG_LOCK(current);
108         saved_set = current->blocked;
109         sigfillset(&current->blocked);
110         RECALC_SIGPENDING(current);
111         SIG_UNLOCK(current);
112     }
113
114     while(seq == cv->seq) {
115         schedule();
116 #ifdef AFS_LINUX26_ENV
117 #ifdef CONFIG_PM
118         if (
119 #ifdef PF_FREEZE
120             current->flags & PF_FREEZE
121 #else
122             !current->todo
123 #endif
124             )
125 #ifdef LINUX_REFRIGERATOR_TAKES_PF_FREEZE
126             refrigerator(PF_FREEZE);
127 #else
128             refrigerator();
129 #endif
130             set_current_state(TASK_INTERRUPTIBLE);
131 #endif
132 #endif
133     }
134
135     remove_wait_queue(&cv->waitq, &wait);
136     set_current_state(TASK_RUNNING);
137
138     if (!sigok) {
139         SIG_LOCK(current);
140         current->blocked = saved_set;
141         RECALC_SIGPENDING(current);
142         SIG_UNLOCK(current);
143     }
144
145     if (isAFSGlocked)
146         AFS_GLOCK();
147     MUTEX_ENTER(l);
148
149     return (sigok && signal_pending(current)) ? EINTR : 0;
150 }
151
152 void
153 afs_cv_timedwait(afs_kcondvar_t * cv, afs_kmutex_t * l, int waittime)
154 {
155     int seq, isAFSGlocked = ISAFS_GLOCK();
156     long t = waittime * HZ / 1000;
157 #ifdef DECLARE_WAITQUEUE
158     DECLARE_WAITQUEUE(wait, current);
159 #else
160     struct wait_queue wait = { current, NULL };
161 #endif
162     seq = cv->seq;
163
164     set_current_state(TASK_INTERRUPTIBLE);
165     add_wait_queue(&cv->waitq, &wait);
166
167     if (isAFSGlocked)
168         AFS_GUNLOCK();
169     MUTEX_EXIT(l);
170
171     while(seq == cv->seq) {
172         t = schedule_timeout(t);
173         if (!t)         /* timeout */
174             break;
175     }
176     
177     remove_wait_queue(&cv->waitq, &wait);
178     set_current_state(TASK_RUNNING);
179
180     if (isAFSGlocked)
181         AFS_GLOCK();
182     MUTEX_ENTER(l);
183 }