linux-note-we-use-interruptible-sleeps-in-non-compliant-manner-20020731
[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("$Header$");
20
21 #include "../rx/rx_kcommon.h"
22 #include "../rx/rx_kmutex.h"
23 #include "../rx/rx_kernel.h"
24
25 #ifdef CONFIG_SMP
26
27 void 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 afs_mutex_enter(afs_kmutex_t *l)
38 {
39     down(&l->sem);
40     if (l->owner)
41         osi_Panic("mutex_enter: 0x%x held by %d", l, l->owner);
42     l->owner = current->pid;
43 }
44                                                               
45 int afs_mutex_tryenter(afs_kmutex_t *l)
46 {
47     if (down_trylock(&l->sem))
48         return 0;
49     l->owner = current->pid;
50     return 1;
51 }
52
53 void afs_mutex_exit(afs_kmutex_t *l)
54 {
55     if (l->owner != current->pid)
56         osi_Panic("mutex_exit: 0x%x held by %d",
57                   l, l->owner);
58     l->owner = 0;
59     up(&l->sem);
60 }
61
62 /* CV_WAIT and CV_TIMEDWAIT sleep until the specified event occurs, or, in the
63  * case of CV_TIMEDWAIT, until the specified timeout occurs.
64  * - NOTE: that on Linux, there are circumstances in which TASK_INTERRUPTIBLE
65  *   can wake up, even if all signals are blocked
66  * - TODO: handle signals correctly by passing an indication back to the
67  *   caller that the wait has been interrupted and the stack should be cleaned
68  *   up preparatory to signal delivery
69  */
70 int afs_cv_wait(afs_kcondvar_t *cv, afs_kmutex_t *l, int sigok)
71 {
72     int isAFSGlocked = ISAFS_GLOCK();
73     sigset_t saved_set;
74 #ifdef DECLARE_WAITQUEUE
75     DECLARE_WAITQUEUE(wait, current);
76 #else
77     struct wait_queue wait = { current, NULL };
78 #endif
79
80     add_wait_queue(cv, &wait);
81     set_current_state(TASK_INTERRUPTIBLE);
82
83     if (isAFSGlocked) AFS_GUNLOCK();
84     MUTEX_EXIT(l);
85
86     if (!sigok) {
87         spin_lock_irq(&current->sigmask_lock);
88         saved_set = current->blocked;
89         sigfillset(&current->blocked);
90         recalc_sigpending(current);
91         spin_unlock_irq(&current->sigmask_lock);
92     }
93
94     schedule();
95     remove_wait_queue(cv, &wait);
96
97     if (!sigok) {
98         spin_lock_irq(&current->sigmask_lock);
99         current->blocked = saved_set;
100         recalc_sigpending(current);
101         spin_unlock_irq(&current->sigmask_lock);
102     }
103
104     if (isAFSGlocked) AFS_GLOCK();
105     MUTEX_ENTER(l);
106
107     return (sigok && signal_pending(current)) ? EINTR : 0;
108 }
109
110 void afs_cv_timedwait(afs_kcondvar_t *cv, afs_kmutex_t *l, int waittime)
111 {
112     int isAFSGlocked = ISAFS_GLOCK();
113     long t = waittime * HZ / 1000;
114 #ifdef DECLARE_WAITQUEUE
115     DECLARE_WAITQUEUE(wait, current);
116 #else
117     struct wait_queue wait = { current, NULL };
118 #endif
119
120     add_wait_queue(cv, &wait);
121     set_current_state(TASK_INTERRUPTIBLE);
122
123     if (isAFSGlocked) AFS_GUNLOCK();
124     MUTEX_EXIT(l);
125     
126     t = schedule_timeout(t);
127     remove_wait_queue(cv, &wait);
128     
129     if (isAFSGlocked) AFS_GLOCK();
130     MUTEX_ENTER(l);
131 }
132
133 #endif