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>
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);
00054 }
00055
00056 #if CONFIG_KERN_PRI && CONFIG_KERN_PRI_INHERIT
00057
00058 #define proc_updatePri(proc) (proc_setPri(proc, (proc)->orig_pri))
00059
00060
00074 INLINE void pri_inheritBlock(Semaphore *s)
00075 {
00076 Process *owner = s->owner;
00077
00078
00079
00080
00081
00082
00083 current_process->inh_link.pri = __prio_proc(current_process);
00084 LIST_ENQUEUE(&owner->inh_list, ¤t_process->inh_link);
00085 current_process->inh_blocked_by = s;
00086
00087
00088
00089
00090
00091 while (current_process->inh_link.pri > prio_proc(owner)) {
00092 Process *p = owner;
00093
00094
00095 proc_updatePri(p);
00096
00097
00098 if (!p->inh_blocked_by)
00099 break;
00100
00101
00102
00103
00104
00105
00106
00107 REMOVE(&p->inh_link.link);
00108 p->inh_link.pri = prio_proc(p);
00109 owner = p->inh_blocked_by->owner;
00110 LIST_ENQUEUE(&owner->inh_list, &p->inh_link);
00111 }
00112 }
00113
00114
00124 INLINE void pri_inheritUnblock(Semaphore *s, Process *proc)
00125 {
00126 Process *owner = s->owner;
00127 Node *n, *temp;
00128 Process *p;
00129
00130
00131
00132
00133
00134 REMOVE(&proc->inh_link.link);
00135 proc->inh_blocked_by = NULL;
00136
00137
00138
00139
00140
00141
00142
00143
00144 FOREACH_NODE_SAFE(n, temp, &owner->inh_list) {
00145 p = containerof(n, Process, inh_link.link);
00146
00147 if (p->inh_blocked_by == s) {
00148 REMOVE(&p->inh_link.link);
00149 LIST_ENQUEUE(&proc->inh_list, &p->inh_link);
00150
00151
00152 if (p->inh_link.pri > prio_proc(proc))
00153 proc_updatePri(proc);
00154 }
00155 }
00156
00157 proc_updatePri(owner);
00158 }
00159 #else
00160 INLINE void pri_inheritBlock(UNUSED_ARG(Semaphore *, s))
00161 {
00162 }
00163
00164 INLINE void pri_inheritUnblock(UNUSED_ARG(Semaphore *, s), UNUSED_ARG(Process *, proc))
00165 {
00166 }
00167 #endif
00168
00169
00173 void sem_init(struct Semaphore *s)
00174 {
00175 LIST_INIT(&s->wait_queue);
00176 s->owner = NULL;
00177 s->nest_count = 0;
00178 }
00179
00180
00192 bool sem_attempt(struct Semaphore *s)
00193 {
00194 bool result = false;
00195
00196 proc_forbid();
00197 sem_verify(s);
00198 if ((!s->owner) || (s->owner == current_process))
00199 {
00200 s->owner = current_process;
00201 s->nest_count++;
00202 result = true;
00203 }
00204 proc_permit();
00205
00206 return result;
00207 }
00208
00209
00227 void sem_obtain(struct Semaphore *s)
00228 {
00229 proc_forbid();
00230 sem_verify(s);
00231
00232
00233 if (UNLIKELY(s->owner && (s->owner != current_process)))
00234 {
00235
00236 ADDTAIL(&s->wait_queue, (Node *)current_process);
00237
00238
00239 pri_inheritBlock(s);
00240
00241
00242
00243
00244
00245
00246 proc_permit();
00247 proc_switch();
00248 }
00249 else
00250 {
00251 ASSERT(LIST_EMPTY(&s->wait_queue));
00252
00253
00254 s->owner = current_process;
00255 s->nest_count++;
00256 proc_permit();
00257 }
00258 }
00259
00260
00274 void sem_release(struct Semaphore *s)
00275 {
00276 Process *proc = NULL;
00277
00278 proc_forbid();
00279 sem_verify(s);
00280
00281 ASSERT(s->owner == current_process);
00282
00283
00284
00285
00286
00287 if (--s->nest_count == 0)
00288 {
00289
00290 if (UNLIKELY((proc = (Process *)list_remHead(&s->wait_queue))))
00291 {
00292
00293 pri_inheritUnblock(s, proc);
00294
00295 s->nest_count = 1;
00296 s->owner = proc;
00297 } else {
00298
00299 s->owner = NULL;
00300 }
00301 }
00302 proc_permit();
00303
00304 if (proc)
00305 ATOMIC(proc_wakeup(proc));
00306 }