sem.c

Go to the documentation of this file.
00001 
00039 #include "sem.h"
00040 #include <cpu/irq.h> // ASSERT_IRQ_DISABLED()
00041 #include <kern/proc.h>
00042 #include <kern/proc_p.h>
00043 #include <kern/signal.h>
00044 #include <cfg/debug.h>
00045 
00046 INLINE void sem_verify(struct Semaphore *s)
00047 {
00048     (void)s;
00049     ASSERT(s);
00050     LIST_ASSERT_VALID(&s->wait_queue);
00051     ASSERT(s->nest_count >= 0);
00052     ASSERT(s->nest_count < 128);   // heuristic max
00053 }
00054 
00055 
00059 void sem_init(struct Semaphore *s)
00060 {
00061     LIST_INIT(&s->wait_queue);
00062     s->owner = NULL;
00063     s->nest_count = 0;
00064 }
00065 
00066 
00078 bool sem_attempt(struct Semaphore *s)
00079 {
00080     bool result = false;
00081 
00082     proc_forbid();
00083     sem_verify(s);
00084     if ((!s->owner) || (s->owner == CurrentProcess))
00085     {
00086         s->owner = CurrentProcess;
00087         s->nest_count++;
00088         result = true;
00089     }
00090     proc_permit();
00091 
00092     return result;
00093 }
00094 
00095 
00113 void sem_obtain(struct Semaphore *s)
00114 {
00115     proc_forbid();
00116     sem_verify(s);
00117 
00118     /* Is the semaphore already locked by another process? */
00119     if (UNLIKELY(s->owner && (s->owner != CurrentProcess)))
00120     {
00121         /* Append calling process to the wait queue */
00122         ADDTAIL(&s->wait_queue, (Node *)CurrentProcess);
00123 
00124         /*
00125          * We will wake up only when the current owner calls
00126          * sem_release(). Then, the semaphore will already
00127          * be locked for us.
00128          */
00129         proc_permit();
00130         proc_switch();
00131     }
00132     else
00133     {
00134         ASSERT(LIST_EMPTY(&s->wait_queue));
00135 
00136         /* The semaphore was free: lock it */
00137         s->owner = CurrentProcess;
00138         s->nest_count++;
00139         proc_permit();
00140     }
00141 }
00142 
00143 
00157 void sem_release(struct Semaphore *s)
00158 {
00159     proc_forbid();
00160     sem_verify(s);
00161 
00162     ASSERT(s->owner == CurrentProcess);
00163 
00164     /*
00165      * Decrement nesting count and check if the semaphore
00166      * has been fully unlocked.
00167      */
00168     if (--s->nest_count == 0)
00169     {
00170         Process *proc;
00171 
00172         /* Disown semaphore */
00173         s->owner = NULL;
00174 
00175         /* Give semaphore to the first applicant, if any */
00176         if (UNLIKELY((proc = (Process *)list_remHead(&s->wait_queue))))
00177         {
00178             s->nest_count = 1;
00179             s->owner = proc;
00180             ATOMIC(SCHED_ENQUEUE(proc));
00181         }
00182     }
00183 
00184     proc_permit();
00185 }