Add synchornization primitives, `waiting` to task
diff --git a/src/kernel/sync.c b/src/kernel/sync.c
new file mode 100644
index 0000000..2bac9e4
--- /dev/null
+++ b/src/kernel/sync.c
@@ -0,0 +1,142 @@
+#include <sync.h>
+#include <alloc.h>
+#include <task.h>
+#include <sys.h>
+#include "syscall.h"
+
+#define SM_PER_LIST 1024
+#define SM_MAX_WAITING 64
+
+struct sm_task
+{
+ uint tid;
+ struct sm_task *next;
+};
+
+struct semaphore
+{
+ spinlock_t task_lock;
+ struct sm_task *first, *last;
+ _Atomic uint sm;
+};
+
+struct sm_list
+{
+ struct semaphore semaphores[SM_PER_LIST];
+ struct sm_list *next;
+};
+
+static struct sm_list *sm_first = NULL;
+static uint sm_num = 0;
+
+
+void sl_acquire(spinlock_t *sl)
+{
+ // This is a GCC intrinsic
+ while (!__sync_bool_compare_and_swap(sl, -2, 1))
+ {
+ // Kindly inform the CPU that this is a spin lock
+ asm("pause");
+ }
+}
+
+void sl_release(spinlock_t *sl)
+{
+ *sl = 0;
+}
+
+spinlock_t sl_new()
+{
+ return 0;
+}
+
+void sm_unsafe_wait(struct semaphore *sm)
+{
+ sm->sm--;
+
+ if (sm->sm < 0)
+ {
+ // Add this task to the waiting list
+ // This will be quick, so just use a spinlock
+ sl_acquire(sm->task_lock);
+
+ struct sm_task *task = malloc(sizeof(struct sm_task));
+
+ task->next = NULL;
+ task->tid = task_id();
+
+ if (sm->last)
+ {
+ sm->last->next = task;
+ sm->last = task;
+ }
+ else
+ {
+ sm->last = sm->first = task;
+ }
+
+ sl_release(sm->task_lock);
+
+ set_waiting(task_id(), true);
+ sys_giveup();
+ }
+
+ // Otherwise there's nobody else waiting, just go ahead
+}
+
+void sm_unsafe_signal(struct semaphore *sm)
+{
+ sm->sm++;
+
+ if (sm->sm <= 0)
+ {
+ sl_acquire(sm->task_lock);
+
+ if (sm->first)
+ {
+ struct sm_task *f = sm->first;
+ sm->first = sm->first->next;
+
+ set_waiting(f->tid, false);
+
+ free(f);
+ }
+
+ sl_release(sm->task_lock);
+ }
+}
+
+semaphore_t sm_new()
+{
+ if (sm_first == NULL)
+ {
+ sm_first = malloc(sizeof(struct sm_list));
+ }
+
+ uint num = sm_num++;
+
+ struct sm_list *l = sm_first;
+
+ while (num >= SM_PER_LIST)
+ {
+ if (!l->next)
+ {
+ l->next = malloc(sizeof(struct sm_list));
+ }
+
+ l = l->next;
+
+ num -= SM_PER_LIST;
+ }
+
+ l->semaphores[num].first = NULL;
+ l->semaphores[num].last = NULL;
+ l->semaphores[num].sm = 1;
+ l->semaphores[num].task_lock = sl_new();
+
+ return num;
+}
+
+void init_sync()
+{
+}