blob: 4b210ca5e72d4285a52f933fae07b93f3348f729 [file] [log] [blame]
swissChili52a03d82021-07-18 15:22:14 -07001#include <sync.h>
2#include <alloc.h>
3#include <task.h>
4#include <sys.h>
swissChili4749d022021-07-19 12:33:06 -07005#include <log.h>
swissChili52a03d82021-07-18 15:22:14 -07006
7#define SM_PER_LIST 1024
swissChili52a03d82021-07-18 15:22:14 -07008
9struct sm_task
10{
11 uint tid;
12 struct sm_task *next;
13};
14
15struct semaphore
16{
17 spinlock_t task_lock;
18 struct sm_task *first, *last;
19 _Atomic uint sm;
20};
21
22struct sm_list
23{
24 struct semaphore semaphores[SM_PER_LIST];
25 struct sm_list *next;
26};
27
28static struct sm_list *sm_first = NULL;
29static uint sm_num = 0;
30
31
32void sl_acquire(spinlock_t *sl)
33{
34 // This is a GCC intrinsic
35 while (!__sync_bool_compare_and_swap(sl, -2, 1))
36 {
37 // Kindly inform the CPU that this is a spin lock
38 asm("pause");
39 }
40}
41
42void sl_release(spinlock_t *sl)
43{
44 *sl = 0;
45}
46
47spinlock_t sl_new()
48{
49 return 0;
50}
51
swissChili4749d022021-07-19 12:33:06 -070052static struct semaphore *sm_from_id(semaphore_t sm)
53{
54 struct sm_list *first = sm_first;
55
56 while (sm >= SM_PER_LIST)
57 {
58 first = first->next;
59 sm -= SM_PER_LIST;
60 }
61
62 return &first->semaphores[sm];
63}
64
65static void sm_unsafe_wait(struct semaphore *sm)
swissChili52a03d82021-07-18 15:22:14 -070066{
67 sm->sm--;
68
69 if (sm->sm < 0)
70 {
71 // Add this task to the waiting list
72 // This will be quick, so just use a spinlock
swissChili36ed5d72021-07-23 14:56:36 -070073 sl_acquire(&sm->task_lock);
swissChili52a03d82021-07-18 15:22:14 -070074
swissChili4749d022021-07-19 12:33:06 -070075 kprintf(INFO "Semaphore waiting\n");
76
swissChili52a03d82021-07-18 15:22:14 -070077 struct sm_task *task = malloc(sizeof(struct sm_task));
78
79 task->next = NULL;
swissChili36ed5d72021-07-23 14:56:36 -070080 task->tid = get_task_id();
swissChili52a03d82021-07-18 15:22:14 -070081
82 if (sm->last)
83 {
84 sm->last->next = task;
85 sm->last = task;
86 }
87 else
88 {
89 sm->last = sm->first = task;
90 }
91
swissChili36ed5d72021-07-23 14:56:36 -070092 sl_release(&sm->task_lock);
swissChili52a03d82021-07-18 15:22:14 -070093
swissChili36ed5d72021-07-23 14:56:36 -070094 set_waiting(get_task_id(), true);
swissChili52a03d82021-07-18 15:22:14 -070095 sys_giveup();
96 }
97
98 // Otherwise there's nobody else waiting, just go ahead
99}
100
swissChili4749d022021-07-19 12:33:06 -0700101static void sm_unsafe_signal(struct semaphore *sm)
swissChili52a03d82021-07-18 15:22:14 -0700102{
103 sm->sm++;
104
105 if (sm->sm <= 0)
106 {
swissChili36ed5d72021-07-23 14:56:36 -0700107 sl_acquire(&sm->task_lock);
swissChili52a03d82021-07-18 15:22:14 -0700108
109 if (sm->first)
110 {
111 struct sm_task *f = sm->first;
112 sm->first = sm->first->next;
113
114 set_waiting(f->tid, false);
115
116 free(f);
117 }
118
swissChili36ed5d72021-07-23 14:56:36 -0700119 sl_release(&sm->task_lock);
swissChili52a03d82021-07-18 15:22:14 -0700120 }
121}
122
123semaphore_t sm_new()
124{
125 if (sm_first == NULL)
126 {
127 sm_first = malloc(sizeof(struct sm_list));
128 }
129
130 uint num = sm_num++;
131
132 struct sm_list *l = sm_first;
133
134 while (num >= SM_PER_LIST)
135 {
136 if (!l->next)
137 {
138 l->next = malloc(sizeof(struct sm_list));
139 }
140
141 l = l->next;
142
143 num -= SM_PER_LIST;
144 }
145
146 l->semaphores[num].first = NULL;
147 l->semaphores[num].last = NULL;
148 l->semaphores[num].sm = 1;
149 l->semaphores[num].task_lock = sl_new();
150
151 return num;
152}
153
swissChili4749d022021-07-19 12:33:06 -0700154void sm_wait(semaphore_t sm)
155{
156 sm_unsafe_wait(sm_from_id(sm));
157}
158
159void sm_signal(semaphore_t sm)
160{
161 sm_unsafe_signal(sm_from_id(sm));
162}
163
164
165
swissChili52a03d82021-07-18 15:22:14 -0700166void init_sync()
167{
168}