BeRTOS
|
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 }