2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * rx_kmutex.c - mutex and condition variable macros for kernel environment.
13 * Linux implementation.
16 #include <afsconfig.h>
17 #include "afs/param.h"
20 #include "rx/rx_kcommon.h"
21 #include "rx_kmutex.h"
22 #include "rx/rx_kernel.h"
24 #ifdef HAVE_LINUX_FREEZER_H
25 # include <linux/freezer.h>
29 afs_mutex_init(afs_kmutex_t * l)
31 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
32 mutex_init(&l->mutex);
33 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
42 afs_mutex_enter(afs_kmutex_t * l)
44 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
45 mutex_lock(&l->mutex);
50 osi_Panic("mutex_enter: 0x%lx held by %d", (unsigned long)l, l->owner);
51 l->owner = current->pid;
55 afs_mutex_tryenter(afs_kmutex_t * l)
57 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
58 if (mutex_trylock(&l->mutex) == 0)
60 if (down_trylock(&l->sem))
63 l->owner = current->pid;
68 afs_mutex_exit(afs_kmutex_t * l)
70 if (l->owner != current->pid)
71 osi_Panic("mutex_exit: 0x%lx held by %d", (unsigned long)l, l->owner);
73 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
74 mutex_unlock(&l->mutex);
80 /* CV_WAIT and CV_TIMEDWAIT sleep until the specified event occurs, or, in the
81 * case of CV_TIMEDWAIT, until the specified timeout occurs.
82 * - NOTE: that on Linux, there are circumstances in which TASK_INTERRUPTIBLE
83 * can wake up, even if all signals are blocked
84 * - TODO: handle signals correctly by passing an indication back to the
85 * caller that the wait has been interrupted and the stack should be cleaned
86 * up preparatory to signal delivery
89 afs_cv_wait(afs_kcondvar_t * cv, afs_kmutex_t * l, int sigok)
91 int seq, isAFSGlocked = ISAFS_GLOCK();
93 #ifdef DECLARE_WAITQUEUE
94 DECLARE_WAITQUEUE(wait, current);
96 struct wait_queue wait = { current, NULL };
98 sigemptyset(&saved_set);
101 set_current_state(TASK_INTERRUPTIBLE);
102 add_wait_queue(&cv->waitq, &wait);
110 saved_set = current->blocked;
111 sigfillset(¤t->blocked);
112 RECALC_SIGPENDING(current);
116 while(seq == cv->seq) {
121 current->flags & PF_FREEZE
123 #if defined(STRUCT_TASK_STRUCT_HAS_TODO)
126 #if defined(STRUCT_TASK_STRUCT_HAS_THREAD_INFO)
127 test_ti_thread_flag(current->thread_info, TIF_FREEZE)
129 test_ti_thread_flag(task_thread_info(current), TIF_FREEZE)
134 #ifdef LINUX_REFRIGERATOR_TAKES_PF_FREEZE
135 refrigerator(PF_FREEZE);
139 set_current_state(TASK_INTERRUPTIBLE);
143 remove_wait_queue(&cv->waitq, &wait);
144 set_current_state(TASK_RUNNING);
148 current->blocked = saved_set;
149 RECALC_SIGPENDING(current);
157 return (sigok && signal_pending(current)) ? EINTR : 0;
161 afs_cv_timedwait(afs_kcondvar_t * cv, afs_kmutex_t * l, int waittime)
163 int seq, isAFSGlocked = ISAFS_GLOCK();
164 long t = waittime * HZ / 1000;
165 #ifdef DECLARE_WAITQUEUE
166 DECLARE_WAITQUEUE(wait, current);
168 struct wait_queue wait = { current, NULL };
172 set_current_state(TASK_INTERRUPTIBLE);
173 add_wait_queue(&cv->waitq, &wait);
179 while(seq == cv->seq) {
180 t = schedule_timeout(t);
181 if (!t) /* timeout */
185 remove_wait_queue(&cv->waitq, &wait);
186 set_current_state(TASK_RUNNING);