8 #include <linux/module.h>
9 #include <linux/wait.h>
11 /* The kcondvar_t struct is protected by mutex taken externally before
12 * calling any of the wait/signal funs, and passed into the wait funs.
14 #define CV_MAGIC 0x346545f4
15 #define CV_POISON 0x95
20 wait_queue_head_t cv_event
;
22 kmutex_t
*cv_mutex
; /* only for verification purposes */
25 typedef enum { CV_DEFAULT
=0, CV_DRIVER
} kcv_type_t
;
27 static __inline__
void
28 cv_init(kcondvar_t
*cvp
, char *name
, kcv_type_t type
, void *arg
)
31 BUG_ON(type
!= CV_DEFAULT
);
34 cvp
->cv_magic
= CV_MAGIC
;
35 init_waitqueue_head(&cvp
->cv_event
);
36 atomic_set(&cvp
->cv_waiters
, 0);
41 cvp
->cv_name
= kmalloc(strlen(name
) + 1, GFP_KERNEL
);
43 strcpy(cvp
->cv_name
, name
);
47 static __inline__
void
48 cv_destroy(kcondvar_t
*cvp
)
51 BUG_ON(cvp
->cv_magic
!= CV_MAGIC
);
52 BUG_ON(atomic_read(&cvp
->cv_waiters
) != 0);
53 BUG_ON(waitqueue_active(&cvp
->cv_event
));
58 memset(cvp
, CV_POISON
, sizeof(*cvp
));
61 static __inline__
void
62 cv_wait(kcondvar_t
*cvp
, kmutex_t
*mtx
)
67 BUG_ON(cvp
== NULL
|| mtx
== NULL
);
68 BUG_ON(cvp
->cv_magic
!= CV_MAGIC
);
69 BUG_ON(!mutex_owned(mtx
));
71 if (cvp
->cv_mutex
== NULL
)
74 /* Ensure the same mutex is used by all callers */
75 BUG_ON(cvp
->cv_mutex
!= mtx
);
78 prepare_to_wait_exclusive(&cvp
->cv_event
, &wait
,
80 /* Must occur after we are added to the list but only once */
82 atomic_inc(&cvp
->cv_waiters
);
86 /* XXX - The correct thing to do here may be to wake up and
87 * force the caller to handle the signal. Spurious wakeups
88 * should already be safely handled by the caller. */
89 if (signal_pending(current
))
90 flush_signals(current
);
92 /* Mutex should be dropped after prepare_to_wait() this
93 * ensures we're linked in to the waiters list and avoids the
94 * race where 'cvp->cv_waiters > 0' but the list is empty. */
99 /* XXX - The correct thing to do here may be to wake up and
100 * force the caller to handle the signal. Spurious wakeups
101 * should already be safely handled by the caller. */
102 if (signal_pending(current
))
108 atomic_dec(&cvp
->cv_waiters
);
109 finish_wait(&cvp
->cv_event
, &wait
);
112 /* 'expire_time' argument is an absolute wall clock time in jiffies.
113 * Return value is time left (expire_time - now) or -1 if timeout occurred.
115 static __inline__
clock_t
116 cv_timedwait(kcondvar_t
*cvp
, kmutex_t
*mtx
, clock_t expire_time
)
122 BUG_ON(cvp
== NULL
|| mtx
== NULL
);
123 BUG_ON(cvp
->cv_magic
!= CV_MAGIC
);
124 BUG_ON(!mutex_owned(mtx
));
126 if (cvp
->cv_mutex
== NULL
)
129 /* XXX - Does not handle jiffie wrap properly */
130 time_left
= expire_time
- jiffies
;
134 /* Ensure the same mutex is used by all callers */
135 BUG_ON(cvp
->cv_mutex
!= mtx
);
138 prepare_to_wait_exclusive(&cvp
->cv_event
, &wait
,
141 atomic_inc(&cvp
->cv_waiters
);
145 /* XXX - The correct thing to do here may be to wake up and
146 * force the caller to handle the signal. Spurious wakeups
147 * should already be safely handled by the caller. */
148 if (signal_pending(current
))
149 flush_signals(current
);
151 /* Mutex should be dropped after prepare_to_wait() this
152 * ensures we're linked in to the waiters list and avoids the
153 * race where 'cvp->cv_waiters > 0' but the list is empty. */
155 time_left
= schedule_timeout(time_left
);
158 /* XXX - The correct thing to do here may be to wake up and
159 * force the caller to handle the signal. Spurious wakeups
160 * should already be safely handled by the caller. */
161 if (signal_pending(current
)) {
165 flush_signals(current
);
171 atomic_dec(&cvp
->cv_waiters
);
172 finish_wait(&cvp
->cv_event
, &wait
);
174 return (time_left
> 0 ? time_left
: -1);
177 static __inline__
void
178 cv_signal(kcondvar_t
*cvp
)
181 BUG_ON(cvp
->cv_magic
!= CV_MAGIC
);
183 /* All waiters are added with WQ_FLAG_EXCLUSIVE so only one
184 * waiter will be set runable with each call to wake_up().
185 * Additionally wake_up() holds a spin_lock assoicated with
186 * the wait queue to ensure we don't race waking up processes. */
187 if (atomic_read(&cvp
->cv_waiters
) > 0)
188 wake_up(&cvp
->cv_event
);
191 static __inline__
void
192 cv_broadcast(kcondvar_t
*cvp
)
195 BUG_ON(cvp
->cv_magic
!= CV_MAGIC
);
197 /* Wake_up_all() will wake up all waiters even those which
198 * have the WQ_FLAG_EXCLUSIVE flag set. */
199 if (atomic_read(&cvp
->cv_waiters
) > 0)
200 wake_up_all(&cvp
->cv_event
);
202 #endif /* _SPL_CONDVAR_H */