sem.c

Go to the documentation of this file.
00001 
00041 #include "sem.h"
00042 #include <kern/proc.h>
00043 #include <kern/proc_p.h>
00044 #include <kern/signal.h>
00045 #include <cfg/debug.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 
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 == CurrentProcess))
00086     {
00087         s->owner = CurrentProcess;
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 != CurrentProcess)))
00121     {
00122         /* Append calling process to the wait queue */
00123         ADDTAIL(&s->wait_queue, (Node *)CurrentProcess);
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_schedule();
00132     }
00133     else
00134     {
00135         ASSERT(LIST_EMPTY(&s->wait_queue));
00136 
00137         /* The semaphore was free: lock it */
00138         s->owner = CurrentProcess;
00139         s->nest_count++;
00140         proc_permit();
00141     }
00142 }
00143 
00144 
00158 void sem_release(struct Semaphore *s)
00159 {
00160     proc_forbid();
00161     sem_verify(s);
00162 
00163     ASSERT(s->owner == CurrentProcess);
00164 
00165     /*
00166      * Decrement nesting count and check if the semaphore
00167      * has been fully unlocked.
00168      */
00169     if (--s->nest_count == 0)
00170     {
00171         Process *proc;
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             SCHED_ENQUEUE(proc);
00182         }
00183     }
00184 
00185     proc_permit();
00186 }