1 /*
2 * Copyright (c) 2013-2023 Ali Mashtizadeh
3 * All rights reserved.
4 */
5
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <string.h>
9
10 #include <sys/kassert.h>
11 #include <sys/kconfig.h>
12 #include <sys/kdebug.h>
13 #include <sys/ktime.h>
14 #include <sys/mp.h>
15 #include <sys/spinlock.h>
16 #include <sys/semaphore.h>
17 #include <sys/thread.h>
18
19 Spinlock semaListLock = { 0, 0, 0, 0, 0, 0, 0, 0, "Semaphore List" };
20 LIST_HEAD(SemaListHead, Semaphore) semaList = LIST_HEAD_INITIALIZER(semaList);
21
22 extern uint64_t ticksPerSecond;
23
24 void
Semaphore_Init(Semaphore * sema,int count,const char * name)25 Semaphore_Init(Semaphore *sema, int count, const char *name)
26 {
27 Spinlock_Init(&sema->lock, name, SPINLOCK_TYPE_NORMAL);
28 sema->count = count;
29
30 strncpy(&sema->name[0], name, SEMAPHORE_NAMELEN);
31 TAILQ_INIT(&sema->waiters);
32
33 Spinlock_Lock(&semaListLock);
34 LIST_INSERT_HEAD(&semaList, sema, semaphoreList);
35 Spinlock_Unlock(&semaListLock);
36 }
37
38 void
Semaphore_Destroy(Semaphore * sema)39 Semaphore_Destroy(Semaphore *sema)
40 {
41 Spinlock_Lock(&semaListLock);
42 LIST_REMOVE(sema, semaphoreList);
43 Spinlock_Unlock(&semaListLock);
44
45 Spinlock_Destroy(&sema->lock);
46 }
47
48 void
Semaphore_Acquire(Semaphore * sema)49 Semaphore_Acquire(Semaphore *sema)
50 {
51 Thread *cur = Sched_Current();
52
53 while (1) {
54 Spinlock_Lock(&sema->lock);
55 if (sema->count > 0) {
56 sema->count -= 1;
57 Spinlock_Unlock(&sema->lock);
58 Thread_Release(cur);
59 return;
60 }
61
62 // Add to sleeper list
63 TAILQ_INSERT_TAIL(&sema->waiters, cur, semaQueue);
64 Sched_SetWaiting(cur);
65
66 Spinlock_Unlock(&sema->lock);
67 Sched_Scheduler();
68 }
69 }
70
71 void
Semaphore_Release(Semaphore * sema)72 Semaphore_Release(Semaphore *sema)
73 {
74 Thread *thr;
75
76 Spinlock_Lock(&sema->lock);
77 sema->count += 1;
78
79 // Wakeup thread
80 thr = TAILQ_FIRST(&sema->waiters);
81 if (thr != NULL) {
82 TAILQ_REMOVE(&sema->waiters, thr, semaQueue);
83 Sched_SetRunnable(thr);
84 }
85 Spinlock_Unlock(&sema->lock);
86 }
87
88 bool
Semaphore_TryAcquire(Semaphore * sema)89 Semaphore_TryAcquire(Semaphore *sema)
90 {
91 Spinlock_Lock(&sema->lock);
92 if (sema->count > 0) {
93 sema->count -= 1;
94 Spinlock_Unlock(&sema->lock);
95 return true;
96 }
97 Spinlock_Unlock(&sema->lock);
98 return false;
99 }
100
101 void
Debug_Semaphores(int argc,const char * argv[])102 Debug_Semaphores(int argc, const char *argv[])
103 {
104 Semaphore *sema;
105
106 Spinlock_Lock(&semaListLock);
107
108 kprintf("%-36s Count\n", "Lock Name");
109 LIST_FOREACH(sema, &semaList, semaphoreList)
110 {
111 Thread *thr;
112 kprintf("%-36s %8d\n", sema->name, sema->count);
113 TAILQ_FOREACH(thr, &sema->waiters, semaQueue) {
114 kprintf("waiting: %d:%d\n", thr->proc->pid, thr->tid);
115 }
116 }
117
118 Spinlock_Unlock(&semaListLock);
119 }
120
121 REGISTER_DBGCMD(semaphores, "Display list of semaphores", Debug_Semaphores);
122
123