eecddc56cae0999a95355217f7adc8eb1d1de922
[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 /*
63  * CV_WAIT and CV_TIMEDWAIT rely on the fact that the Linux kernel has
64  * a global lock. Thus we can safely drop our locks before calling the
65  * kernel sleep services.
66  * Or not.
67  */
68 int afs_cv_wait(afs_kcondvar_t *cv, afs_kmutex_t *l, int sigok)
69 {
70     int isAFSGlocked = ISAFS_GLOCK();
71     sigset_t saved_set;
72 #ifdef DECLARE_WAITQUEUE
73     DECLARE_WAITQUEUE(wait, current);
74 #else
75     struct wait_queue wait = { current, NULL };
76 #endif
77
78     add_wait_queue(cv, &wait);
79     set_current_state(TASK_INTERRUPTIBLE);
80
81     if (isAFSGlocked) AFS_GUNLOCK();
82     MUTEX_EXIT(l);
83
84     if (!sigok) {
85         spin_lock_irq(&current->sigmask_lock);
86         saved_set = current->blocked;
87         sigfillset(&current->blocked);
88         recalc_sigpending(current);
89         spin_unlock_irq(&current->sigmask_lock);
90     }
91
92     schedule();
93     remove_wait_queue(cv, &wait);
94
95     if (!sigok) {
96         spin_lock_irq(&current->sigmask_lock);
97         current->blocked = saved_set;
98         recalc_sigpending(current);
99         spin_unlock_irq(&current->sigmask_lock);
100     }
101
102     if (isAFSGlocked) AFS_GLOCK();
103     MUTEX_ENTER(l);
104
105     return (sigok && signal_pending(current)) ? EINTR : 0;
106 }
107
108 void afs_cv_timedwait(afs_kcondvar_t *cv, afs_kmutex_t *l, int waittime)
109 {
110     int isAFSGlocked = ISAFS_GLOCK();
111     long t = waittime * HZ / 1000;
112 #ifdef DECLARE_WAITQUEUE
113     DECLARE_WAITQUEUE(wait, current);
114 #else
115     struct wait_queue wait = { current, NULL };
116 #endif
117
118     add_wait_queue(cv, &wait);
119     set_current_state(TASK_INTERRUPTIBLE);
120
121     if (isAFSGlocked) AFS_GUNLOCK();
122     MUTEX_EXIT(l);
123     
124     t = schedule_timeout(t);
125     remove_wait_queue(cv, &wait);
126     
127     if (isAFSGlocked) AFS_GLOCK();
128     MUTEX_ENTER(l);
129 }
130
131 #endif