|
@@ -126,7 +126,7 @@ __rwsem_wake_one_writer(struct rw_semaphore *sem)
|
|
|
/*
|
|
|
* get a read lock on the semaphore
|
|
|
*/
|
|
|
-void __sched __down_read(struct rw_semaphore *sem)
|
|
|
+int __sched __down_read_common(struct rw_semaphore *sem, int state)
|
|
|
{
|
|
|
struct rwsem_waiter waiter;
|
|
|
unsigned long flags;
|
|
@@ -140,8 +140,6 @@ void __sched __down_read(struct rw_semaphore *sem)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- set_current_state(TASK_UNINTERRUPTIBLE);
|
|
|
-
|
|
|
/* set up my own style of waitqueue */
|
|
|
waiter.task = current;
|
|
|
waiter.type = RWSEM_WAITING_FOR_READ;
|
|
@@ -149,20 +147,41 @@ void __sched __down_read(struct rw_semaphore *sem)
|
|
|
|
|
|
list_add_tail(&waiter.list, &sem->wait_list);
|
|
|
|
|
|
- /* we don't need to touch the semaphore struct anymore */
|
|
|
- raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
|
|
|
-
|
|
|
/* wait to be given the lock */
|
|
|
for (;;) {
|
|
|
if (!waiter.task)
|
|
|
break;
|
|
|
+ if (signal_pending_state(state, current))
|
|
|
+ goto out_nolock;
|
|
|
+ set_current_state(state);
|
|
|
+ raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
|
|
|
schedule();
|
|
|
- set_current_state(TASK_UNINTERRUPTIBLE);
|
|
|
+ raw_spin_lock_irqsave(&sem->wait_lock, flags);
|
|
|
}
|
|
|
|
|
|
- __set_current_state(TASK_RUNNING);
|
|
|
+ raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
|
|
|
out:
|
|
|
- ;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out_nolock:
|
|
|
+ /*
|
|
|
+ * We didn't take the lock, so that there is a writer, which
|
|
|
+ * is owner or the first waiter of the sem. If it's a waiter,
|
|
|
+ * it will be woken by current owner. Not need to wake anybody.
|
|
|
+ */
|
|
|
+ list_del(&waiter.list);
|
|
|
+ raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
|
|
|
+ return -EINTR;
|
|
|
+}
|
|
|
+
|
|
|
+void __sched __down_read(struct rw_semaphore *sem)
|
|
|
+{
|
|
|
+ __down_read_common(sem, TASK_UNINTERRUPTIBLE);
|
|
|
+}
|
|
|
+
|
|
|
+int __sched __down_read_killable(struct rw_semaphore *sem)
|
|
|
+{
|
|
|
+ return __down_read_common(sem, TASK_KILLABLE);
|
|
|
}
|
|
|
|
|
|
/*
|