Import Upstream version 1.8.5
[hcoop/debian/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
20 #include "rx/rx_kcommon.h"
21 #include "rx_kmutex.h"
22 #include "rx/rx_kernel.h"
23
24 #include "osi_compat.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%lx held by %d", (unsigned long)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%lx held by %d", (unsigned long)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 sigemptyset(&saved_set);
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 afs_try_to_freeze();
117 set_current_state(TASK_INTERRUPTIBLE);
118 }
119
120 remove_wait_queue(&cv->waitq, &wait);
121 set_current_state(TASK_RUNNING);
122
123 if (!sigok) {
124 SIG_LOCK(current);
125 current->blocked = saved_set;
126 RECALC_SIGPENDING(current);
127 SIG_UNLOCK(current);
128 }
129
130 if (isAFSGlocked)
131 AFS_GLOCK();
132 MUTEX_ENTER(l);
133
134 return (sigok && signal_pending(current)) ? EINTR : 0;
135 }
136
137 void
138 afs_cv_timedwait(afs_kcondvar_t * cv, afs_kmutex_t * l, int waittime)
139 {
140 int seq, isAFSGlocked = ISAFS_GLOCK();
141 long t = waittime * HZ / 1000;
142 #ifdef DECLARE_WAITQUEUE
143 DECLARE_WAITQUEUE(wait, current);
144 #else
145 struct wait_queue wait = { current, NULL };
146 #endif
147 seq = cv->seq;
148
149 set_current_state(TASK_INTERRUPTIBLE);
150 add_wait_queue(&cv->waitq, &wait);
151
152 if (isAFSGlocked)
153 AFS_GUNLOCK();
154 MUTEX_EXIT(l);
155
156 while(seq == cv->seq) {
157 t = schedule_timeout(t);
158 if (!t) /* timeout */
159 break;
160 }
161
162 remove_wait_queue(&cv->waitq, &wait);
163 set_current_state(TASK_RUNNING);
164
165 if (isAFSGlocked)
166 AFS_GLOCK();
167 MUTEX_ENTER(l);
168 }