CS350 COS
COS
Loading...
Searching...
No Matches
spinlock.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022-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
17#include <machine/atomic.h>
18#include <machine/amd64.h>
19#include <machine/amd64op.h>
20
22 0, 0, 0, 0, 0, 0, 0,
24 "SPINLOCK LIST",
25};
26LIST_HEAD(LockListHead, Spinlock) lockList = LIST_HEAD_INITIALIZER(lockList);
27
28TAILQ_HEAD(LockStack, Spinlock) lockStack[MAX_CPUS];
29
31
32void
34{
35 int c;
36
37 for (c = 0; c < MAX_CPUS; c++) {
38 TAILQ_INIT(&lockStack[c]);
39 }
40}
41
42void
43Spinlock_Init(Spinlock *lock, const char *name, uint64_t type)
44{
45 lock->lock = 0;
46 lock->cpu = 0;
47 lock->count = 0;
48 lock->rCount = 0;
49 lock->lockTime = 0;
50 lock->waitTime = 0;
51 lock->type = type;
52
53 strncpy(&lock->name[0], name, SPINLOCK_NAMELEN);
54
56 LIST_INSERT_HEAD(&lockList, lock, lockList);
58}
59
60void
62{
64 LIST_REMOVE(lock, lockList);
66}
67
74void
76{
77 uint64_t startTSC;
79
80 startTSC = Time_GetTSC();
81 while (atomic_swap_uint64(&lock->lock, 1) == 1)
82 {
83 if (lock->type == SPINLOCK_TYPE_RECURSIVE && lock->cpu == CPU()) {
84 break;
85 }
86 if ((Time_GetTSC() - startTSC) / ticksPerSecond > 1) {
87 kprintf("Spinlock_Lock(%s): waiting for over a second!\n", lock->name);
88 breakpoint();
89 }
90 }
91 lock->waitTime += Time_GetTSC() - startTSC;
92
93 lock->cpu = CPU();
94 lock->count++;
95
96 lock->rCount++;
97 if (lock->rCount == 1)
98 lock->lockedTSC = Time_GetTSC();
99
100 TAILQ_INSERT_TAIL(&lockStack[CPU()], lock, lockStack);
101}
102
108void
110{
111 ASSERT(lock->cpu == CPU());
112
113 TAILQ_REMOVE(&lockStack[CPU()], lock, lockStack);
114
115 lock->rCount--;
116 if (lock->rCount == 0) {
117 lock->cpu = 0;
118 lock->lockTime += Time_GetTSC() - lock->lockedTSC;
119 atomic_set_uint64(&lock->lock, 0);
120 }
121
123}
124
125bool
127{
128 return (lock->cpu == CPU()) && (lock->lock == 1);
129}
130
131void
132Debug_Spinlocks(int argc, const char *argv[])
133{
134 Spinlock *lock;
135
137
138 kprintf("%-36s Locked CPU Count WaitTime LockTime\n", "Lock Name");
139 LIST_FOREACH(lock, &lockList, lockList)
140 {
141 kprintf("%-36s %6llu %3llu %8llu %12llu %12llu\n", lock->name,
142 lock->lock, lock->cpu, lock->count,
143 lock->waitTime, lock->lockTime);
144 }
145
147}
148
149REGISTER_DBGCMD(spinlocks, "Display list of spinlocks", Debug_Spinlocks);
150
151void
152Debug_LockStack(int argc, const char *argv[])
153{
154 int c = CPU();
155 Spinlock *lock;
156
157 kprintf("Lock Stack:\n");
158 TAILQ_FOREACH(lock, &lockStack[c], lockStack) {
159 kprintf(" %s\n", lock->name);
160 }
161}
162
163REGISTER_DBGCMD(lockstack, "Display stack of held spinlocks", Debug_LockStack);
164
static INLINE void breakpoint()
Definition: amd64op.h:29
static INLINE uint64_t atomic_swap_uint64(volatile uint64_t *dst, uint64_t newval)
Definition: atomic.h:15
static void atomic_set_uint64(volatile uint64_t *dst, uint64_t newval)
Definition: atomic.h:24
#define __NO_LOCK_ANALYSIS
Definition: cdefs.h:31
void Critical_Exit()
Definition: critical.c:35
void Critical_Enter()
Definition: critical.c:28
#define CPU
Definition: mp.h:7
#define ASSERT(_x)
Definition: kassert.h:8
int kprintf(const char *fmt,...)
Definition: printf.c:210
#define MAX_CPUS
Definition: kconfig.h:8
#define REGISTER_DBGCMD(_NAME, _DESC, _FUNC)
Definition: kdebug.h:11
uint64_t ticksPerSecond
Definition: ktime.c:17
uint32_t type
Definition: multiboot.h:8
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:557
#define TAILQ_INIT(head)
Definition: queue.h:597
#define TAILQ_HEAD(name, type)
Definition: queue.h:491
#define LIST_REMOVE(elm, field)
Definition: queue.h:465
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:641
#define LIST_HEAD_INITIALIZER(head)
Definition: queue.h:368
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:659
#define LIST_FOREACH(var, head, field)
Definition: queue.h:410
#define LIST_INSERT_HEAD(head, elm, field)
Definition: queue.h:451
#define LIST_HEAD(name, type)
Definition: queue.h:363
void Debug_Spinlocks(int argc, const char *argv[])
Definition: spinlock.c:132
bool Spinlock_IsHeld(Spinlock *lock)
Definition: spinlock.c:126
void Spinlock_Destroy(Spinlock *lock)
Definition: spinlock.c:61
Spinlock lockListLock
Definition: spinlock.c:21
void Spinlock_Unlock(Spinlock *lock) __NO_LOCK_ANALYSIS
Definition: spinlock.c:109
void Debug_LockStack(int argc, const char *argv[])
Definition: spinlock.c:152
void Spinlock_Init(Spinlock *lock, const char *name, uint64_t type)
Definition: spinlock.c:43
void Spinlock_Lock(Spinlock *lock) __NO_LOCK_ANALYSIS
Definition: spinlock.c:75
#define SPINLOCK_TYPE_NORMAL
Definition: spinlock.h:12
void Spinlock_EarlyInit()
#define SPINLOCK_TYPE_RECURSIVE
Definition: spinlock.h:13
#define SPINLOCK_NAMELEN
Definition: spinlock.h:10
char * strncpy(char *to, const char *from, size_t len)
Definition: string.c:34
uint64_t type
Definition: spinlock.h:24
uint64_t cpu
Definition: spinlock.h:18
uint64_t count
Definition: spinlock.h:19
uint64_t rCount
Definition: spinlock.h:20
volatile uint64_t lock
Definition: spinlock.h:17
uint64_t lockTime
Definition: spinlock.h:21
uint64_t waitTime
Definition: spinlock.h:22
char name[SPINLOCK_NAMELEN]
Definition: spinlock.h:25
uint64_t Time_GetTSC()
Definition: time.c:13
unsigned long uint64_t
Definition: types.h:13