blob: 2bac9e49b6193e0f5e3c0defe8949a7ad9948800 [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>
5#include "syscall.h"
6
7#define SM_PER_LIST 1024
8#define SM_MAX_WAITING 64
9
10struct sm_task
11{
12 uint tid;
13 struct sm_task *next;
14};
15
16struct semaphore
17{
18 spinlock_t task_lock;
19 struct sm_task *first, *last;
20 _Atomic uint sm;
21};
22
23struct sm_list
24{
25 struct semaphore semaphores[SM_PER_LIST];
26 struct sm_list *next;
27};
28
29static struct sm_list *sm_first = NULL;
30static uint sm_num = 0;
31
32
33void sl_acquire(spinlock_t *sl)
34{
35 // This is a GCC intrinsic
36 while (!__sync_bool_compare_and_swap(sl, -2, 1))
37 {
38 // Kindly inform the CPU that this is a spin lock
39 asm("pause");
40 }
41}
42
43void sl_release(spinlock_t *sl)
44{
45 *sl = 0;
46}
47
48spinlock_t sl_new()
49{
50 return 0;
51}
52
53void sm_unsafe_wait(struct semaphore *sm)
54{
55 sm->sm--;
56
57 if (sm->sm < 0)
58 {
59 // Add this task to the waiting list
60 // This will be quick, so just use a spinlock
61 sl_acquire(sm->task_lock);
62
63 struct sm_task *task = malloc(sizeof(struct sm_task));
64
65 task->next = NULL;
66 task->tid = task_id();
67
68 if (sm->last)
69 {
70 sm->last->next = task;
71 sm->last = task;
72 }
73 else
74 {
75 sm->last = sm->first = task;
76 }
77
78 sl_release(sm->task_lock);
79
80 set_waiting(task_id(), true);
81 sys_giveup();
82 }
83
84 // Otherwise there's nobody else waiting, just go ahead
85}
86
87void sm_unsafe_signal(struct semaphore *sm)
88{
89 sm->sm++;
90
91 if (sm->sm <= 0)
92 {
93 sl_acquire(sm->task_lock);
94
95 if (sm->first)
96 {
97 struct sm_task *f = sm->first;
98 sm->first = sm->first->next;
99
100 set_waiting(f->tid, false);
101
102 free(f);
103 }
104
105 sl_release(sm->task_lock);
106 }
107}
108
109semaphore_t sm_new()
110{
111 if (sm_first == NULL)
112 {
113 sm_first = malloc(sizeof(struct sm_list));
114 }
115
116 uint num = sm_num++;
117
118 struct sm_list *l = sm_first;
119
120 while (num >= SM_PER_LIST)
121 {
122 if (!l->next)
123 {
124 l->next = malloc(sizeof(struct sm_list));
125 }
126
127 l = l->next;
128
129 num -= SM_PER_LIST;
130 }
131
132 l->semaphores[num].first = NULL;
133 l->semaphores[num].last = NULL;
134 l->semaphores[num].sm = 1;
135 l->semaphores[num].task_lock = sl_new();
136
137 return num;
138}
139
140void init_sync()
141{
142}