BeRTOS
sem.c
Go to the documentation of this file.
00001 
00038 #include "sem.h"
00039 #include <cfg/debug.h>
00040 
00041 #include <cpu/irq.h> // ASSERT_IRQ_DISABLED()
00042 
00043 #include <kern/proc.h>
00044 #include <kern/proc_p.h>
00045 #include <kern/signal.h>
00046 
00047 INLINE void sem_verify(struct Semaphore *s)
00048 {
00049     (void)s;
00050     ASSERT(s);
00051     LIST_ASSERT_VALID(&s->wait_queue);
00052     ASSERT(s->nest_count >= 0);
00053     ASSERT(s->nest_count < 128);   // heuristic max
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 == current_process))
00085     {
00086         s->owner = current_process;
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 != current_process)))
00120     {
00121         /* Append calling process to the wait queue */
00122         ADDTAIL(&s->wait_queue, (Node *)current_process);
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 = current_process;
00138         s->nest_count++;
00139         proc_permit();
00140     }
00141 }
00142 
00143 
00157 void sem_release(struct Semaphore *s)
00158 {
00159     Process *proc = NULL;
00160 
00161     proc_forbid();
00162     sem_verify(s);
00163 
00164     ASSERT(s->owner == current_process);
00165 
00166     /*
00167      * Decrement nesting count and check if the semaphore
00168      * has been fully unlocked.
00169      */
00170     if (--s->nest_count == 0)
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         }
00181     }
00182     proc_permit();
00183 
00184     if (proc)
00185         ATOMIC(proc_wakeup(proc));
00186 }