sem.c

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