Safer assertions related to __up_sem()
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 6 Jun 2011 20:19:41 +0000 (13:19 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:04 +0000 (17:36 -0700)
When calling __up_sem(), you can ask it to assert that the list is empty
after signalling one.  This is for code that wants a semaphore of only
one item and wants to put in some 'helpful' asserts.  By having __up_sem
do it, we avoid the temptation to check after waking a kthread, but more
importantly we do the check inside the lock.  Doing otherwise might trip
the assert for the wrong reason.

kern/include/kthread.h
kern/src/alarm.c
kern/src/blockdev.c
kern/src/page_alloc.c
kern/src/testing.c

index 9089471..eb4df9e 100644 (file)
@@ -67,8 +67,8 @@ static inline bool __down_sem(struct semaphore *sem, struct kthread *kthread)
 }
 
 /* Ups the semaphore.  If it was < 0, we need to wake up someone, which is the
- * return value. */
-static inline struct kthread *__up_sem(struct semaphore *sem)
+ * return value.  If you think there should be at most one, set exactly_one. */
+static inline struct kthread *__up_sem(struct semaphore *sem, bool exactly_one)
 {
        struct kthread *kthread = 0;
        spin_lock(&sem->lock);
@@ -76,6 +76,8 @@ static inline struct kthread *__up_sem(struct semaphore *sem)
                /* could do something with 'priority' here */
                kthread = TAILQ_FIRST(&sem->waiters);
                TAILQ_REMOVE(&sem->waiters, kthread, link);
+               if (exactly_one)
+                       assert(TAILQ_EMPTY(&sem->waiters));
        } else {
                assert(TAILQ_EMPTY(&sem->waiters));
        }
index 0d24522..22bb4d3 100644 (file)
@@ -102,7 +102,7 @@ static void wake_awaiter(struct alarm_waiter *waiter)
        } else {
                /* Might encaps this */
                struct kthread *sleeper;
-               sleeper = __up_sem(&waiter->sem);
+               sleeper = __up_sem(&waiter->sem, TRUE);
                if (sleeper)
                        kthread_runnable(sleeper);
                /* Don't touch the sleeper or waiter after making the kthread runnable,
index 2ad97cf..453f397 100644 (file)
@@ -139,14 +139,13 @@ int bdev_submit_request(struct block_device *bdev, struct block_request *breq)
 void generic_breq_done(struct block_request *breq)
 {
 #ifdef __i386__        /* Sparc can't restart kthreads yet */
-       struct kthread *sleeper = __up_sem(&breq->sem);
+       struct kthread *sleeper = __up_sem(&breq->sem, TRUE);
        if (!sleeper) {
                /* This shouldn't happen anymore.  Let brho know if it does. */
                warn("[kernel] no one waiting on breq %08p", breq);
                return;
        }
        kthread_runnable(sleeper);
-       assert(TAILQ_EMPTY(&breq->sem.waiters));
 #else
        breq->data = (void*)1;
 #endif
index 6d3c52a..9ed659c 100644 (file)
@@ -311,7 +311,7 @@ void unlock_page(struct page *page)
 {
        struct kthread *sleeper;
        page->pg_flags &= ~PG_LOCKED;
-       sleeper = __up_sem(&page->pg_sem);
+       sleeper = __up_sem(&page->pg_sem, FALSE);
        if (sleeper) {
                printk("Unexpected sleeper on a page!");        /* til we test this */
                kthread_runnable(sleeper);
index fe02daf..3ec3d6f 100644 (file)
@@ -1222,7 +1222,7 @@ void test_kthreads(void)
                struct kthread *kthread;
                printk("[kmsg] Upping the sem to start the kthread, stacktop is %08p\n",
                       get_stack_top());
-               kthread = __up_sem(sem);
+               kthread = __up_sem(sem, FALSE);
                if (!kthread) {
                        printk("[kmsg] Crap, the sem didn't have a kthread waiting!\n");
                        return;