Semi-decennial update. 50% code inflation.
[cbaos.git] / kernel / sem.c
blob2a4f2421f5e21d8a3740f72c4d35f2a0094d035b
1 /* Author: Domen Puncer <domen@cba.si>. License: WTFPL, see file LICENSE */
2 #include <sem.h>
3 #include <lock.h>
4 #include <sched.h>
6 #include <errno.h>
7 #include <stdio.h>
10 void sem_init(struct sem *sem, int count)
12 sem->count = count;
13 list_init(&sem->tasks);
14 lock_init(&sem->lock);
17 __attribute__ ((warn_unused_result)) int down(struct sem *sem, u32 timeout)
19 /* count and list operations are protected by lock */
20 lock(&sem->lock);
21 list_add_tail(&sem->tasks, &current->waiting);
23 //printf("%s: %p, count:%i\n", __func__, sem, sem->count);
24 do {
25 // SMP: while (TAS(&foo)) ;
26 if (sem->count > 0) {
27 sem->count--;
28 /* success! */
29 current->dont_reschedule = 0;
30 list_del(&current->waiting);
31 // SMP: foo = 0
32 unlock(&sem->lock);
33 //printf("%s: %p, count:%i, ok\n", __func__, sem, sem->count);
34 return 0;
36 // SMP: foo = 0
37 unlock(&sem->lock);
39 /* if up() is called here, don't reschedule will be set, and
40 * sched_timeout will return */
42 timeout = sched_timeout(timeout);
43 lock(&sem->lock);
45 } while (timeout > 0);
47 list_del(&current->waiting);
48 //printf("%s: %p, count:%i, fail\n", __func__, sem, sem->count);
49 unlock(&sem->lock);
51 return -ETIMEDOUT;
54 void up(struct sem *sem)
56 struct task *task;
57 int resched = 0;
58 lock(&sem->lock);
59 // SMP: while (TAS(&foo)) ;
60 if (!list_empty(&sem->tasks)) {
61 task = list_entry(sem->tasks.next, struct task, waiting);
62 task->dont_reschedule = 1;
63 task_wake(task);
64 // fprintf(stderr, "waking %s\n", task->name);
65 resched = 1;
67 sem->count++;
68 //printf("%s: %p, count:%i\n", __func__, sem, sem->count);
69 // SMP: foo = 0
70 unlock(&sem->lock);
71 /* also call scheduler? well... maybe, but only !in_interrupt() */
73 /* must call scheduler, to get the woken task running */
74 if (resched)
75 arch_sched_next_interrupt(1); /* now, this is ok, since we only schedule it. but it's still some delay that i don't like */
76 // sched_yield();
77 // arch_task_switch(task);
78 // ^ this is problematic... if up() is called from interrupt, then it's not quite normal to call SVC here, were not in task context! fuck
82 /* mutexes are similar... except that multiple consecutive up() will only enable one down() to succeed */
83 // TODO rewrite w/o lock if possible - but it's needed for list? maybe not
84 void mutex_init(struct mutex *mutex, int locked)
86 mutex->locked = locked;
87 list_init(&mutex->tasks);
88 lock_init(&mutex->lock);
91 __attribute__ ((warn_unused_result)) int mutex_down(struct mutex *mutex, u32 timeout)
93 /* count and list operations are protected by lock */
94 lock(&mutex->lock);
95 list_add_tail(&mutex->tasks, &current->waiting);
97 do {
98 if (!mutex->locked) {
99 mutex->locked = 1;
100 /* success! */
101 current->dont_reschedule = 0;
102 list_del(&current->waiting);
103 unlock(&mutex->lock);
104 return 0;
106 unlock(&mutex->lock);
108 /* if up() is called here, don't reschedule will be set, and
109 * sched_timeout will return */
111 timeout = sched_timeout(timeout);
112 lock(&mutex->lock);
114 } while (timeout > 0);
116 list_del(&current->waiting);
117 unlock(&mutex->lock);
119 return -ETIMEDOUT;
122 __attribute__ ((warn_unused_result)) int mutex_downtry(struct mutex *mutex)
124 /* count and list operations are protected by lock */
125 lock(&mutex->lock);
127 if (!mutex->locked) {
128 mutex->locked = 1;
129 /* success! */
130 unlock(&mutex->lock);
131 return 0;
134 unlock(&mutex->lock);
136 return -ETIMEDOUT;
139 void mutex_up(struct mutex *mutex)
141 struct task *task;
142 int resched = 0;
143 lock(&mutex->lock);
144 if (!list_empty(&mutex->tasks)) {
145 task = list_entry(mutex->tasks.next, struct task, waiting);
146 task->dont_reschedule = 1;
147 task_wake(task);
148 resched = 1;
150 mutex->locked = 0;
151 unlock(&mutex->lock);
153 /* must call scheduler, to get the woken task running */
154 if (resched)
155 arch_sched_next_interrupt(1); /* now, this is ok, since we only schedule it. but it's still some delay that i don't like */