man-page-bash-bashish-20060308
[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 defined(AFS_LINUX24_ENV)
30     init_MUTEX(&l->sem);
31 #else
32     l->sem = MUTEX;
33 #endif
34     l->owner = 0;
35 }
36
37 void
38 afs_mutex_enter(afs_kmutex_t * l)
39 {
40     down(&l->sem);
41     if (l->owner)
42         osi_Panic("mutex_enter: 0x%x held by %d", l, l->owner);
43     l->owner = current->pid;
44 }
45
46 int
47 afs_mutex_tryenter(afs_kmutex_t * l)
48 {
49     if (down_trylock(&l->sem))
50         return 0;
51     l->owner = current->pid;
52     return 1;
53 }
54
55 void
56 afs_mutex_exit(afs_kmutex_t * l)
57 {
58     if (l->owner != current->pid)
59         osi_Panic("mutex_exit: 0x%x held by %d", l, l->owner);
60     l->owner = 0;
61     up(&l->sem);
62 }
63
64 /* CV_WAIT and CV_TIMEDWAIT sleep until the specified event occurs, or, in the
65  * case of CV_TIMEDWAIT, until the specified timeout occurs.
66  * - NOTE: that on Linux, there are circumstances in which TASK_INTERRUPTIBLE
67  *   can wake up, even if all signals are blocked
68  * - TODO: handle signals correctly by passing an indication back to the
69  *   caller that the wait has been interrupted and the stack should be cleaned
70  *   up preparatory to signal delivery
71  */
72 int
73 afs_cv_wait(afs_kcondvar_t * cv, afs_kmutex_t * l, int sigok)
74 {
75     int seq, isAFSGlocked = ISAFS_GLOCK();
76     sigset_t saved_set;
77 #ifdef DECLARE_WAITQUEUE
78     DECLARE_WAITQUEUE(wait, current);
79 #else
80     struct wait_queue wait = { current, NULL };
81 #endif
82
83     seq = cv->seq;
84     
85     set_current_state(TASK_INTERRUPTIBLE);
86     add_wait_queue(&cv->waitq, &wait);
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     while(seq == cv->seq) {
101         schedule();
102 #ifdef AFS_LINUX26_ENV
103 #ifdef CONFIG_PM
104         if (
105 #ifdef PF_FREEZE
106             current->flags & PF_FREEZE
107 #else
108             !current->todo
109 #endif
110             )
111 #ifdef LINUX_REFRIGERATOR_TAKES_PF_FREEZE
112             refrigerator(PF_FREEZE);
113 #else
114             refrigerator();
115 #endif
116             set_current_state(TASK_INTERRUPTIBLE);
117 #endif
118 #endif
119     }
120
121     remove_wait_queue(&cv->waitq, &wait);
122     set_current_state(TASK_RUNNING);
123
124     if (!sigok) {
125         SIG_LOCK(current);
126         current->blocked = saved_set;
127         RECALC_SIGPENDING(current);
128         SIG_UNLOCK(current);
129     }
130
131     if (isAFSGlocked)
132         AFS_GLOCK();
133     MUTEX_ENTER(l);
134
135     return (sigok && signal_pending(current)) ? EINTR : 0;
136 }
137
138 void
139 afs_cv_timedwait(afs_kcondvar_t * cv, afs_kmutex_t * l, int waittime)
140 {
141     int seq, isAFSGlocked = ISAFS_GLOCK();
142     long t = waittime * HZ / 1000;
143 #ifdef DECLARE_WAITQUEUE
144     DECLARE_WAITQUEUE(wait, current);
145 #else
146     struct wait_queue wait = { current, NULL };
147 #endif
148     seq = cv->seq;
149
150     set_current_state(TASK_INTERRUPTIBLE);
151     add_wait_queue(&cv->waitq, &wait);
152
153     if (isAFSGlocked)
154         AFS_GUNLOCK();
155     MUTEX_EXIT(l);
156
157     while(seq == cv->seq) {
158         t = schedule_timeout(t);
159         if (!t)         /* timeout */
160             break;
161     }
162     
163     remove_wait_queue(&cv->waitq, &wait);
164     set_current_state(TASK_RUNNING);
165
166     if (isAFSGlocked)
167         AFS_GLOCK();
168     MUTEX_ENTER(l);
169 }