First pass at better signal handling:
[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  */
67 int afs_cv_wait(afs_kcondvar_t *cv, afs_kmutex_t *l, int sigok)
68 {
69     int isAFSGlocked = ISAFS_GLOCK();
70     sigset_t saved_set;
71
72     if (isAFSGlocked) AFS_GUNLOCK();
73     MUTEX_EXIT(l);
74
75     if (!sigok) {
76         spin_lock_irq(&current->sigmask_lock);
77         saved_set = current->blocked;
78         sigfillset(&current->blocked);
79         recalc_sigpending(current);
80         spin_unlock_irq(&current->sigmask_lock);
81     }
82
83 #if defined(AFS_LINUX24_ENV)
84     interruptible_sleep_on((wait_queue_head_t *)cv);
85 #else
86     interruptible_sleep_on((struct wait_queue**)cv);
87 #endif
88
89     if (!sigok) {
90         spin_lock_irq(&current->sigmask_lock);
91         current->blocked = saved_set;
92         recalc_sigpending(current);
93         spin_unlock_irq(&current->sigmask_lock);
94     }
95
96     MUTEX_ENTER(l);
97     if (isAFSGlocked) AFS_GLOCK();
98
99     return (sigok && signal_pending(current)) ? EINTR : 0;
100 }
101
102 void afs_cv_timedwait(afs_kcondvar_t *cv, afs_kmutex_t *l, int waittime)
103 {
104     int isAFSGlocked = ISAFS_GLOCK();
105     long t = waittime * HZ / 1000;
106
107     if (isAFSGlocked) AFS_GUNLOCK();
108     MUTEX_EXIT(l);
109     
110 #if defined(AFS_LINUX24_ENV)
111     t = interruptible_sleep_on_timeout((wait_queue_head_t *)cv, t);
112 #else
113     t = interruptible_sleep_on_timeout((struct wait_queue**)cv, t);
114 #endif
115     
116     MUTEX_ENTER(l);
117     if (isAFSGlocked) AFS_GLOCK();
118 }
119
120 #endif