metal-cos/sys/kern/spinlock.c

101 lines
2.1 KiB
C

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/kassert.h>
#include <sys/kconfig.h>
#include <sys/kdebug.h>
#include <sys/ktime.h>
#include <sys/mp.h>
#include <sys/spinlock.h>
#include <machine/atomic.h>
Spinlock lockListLock = { 0, 0, 0, 0, 0, 0, "SPINLOCK LIST" };
LIST_HEAD(LockListHead, Spinlock) lockList = LIST_HEAD_INITIALIZER(lockList);
extern uint64_t ticksPerSecond;
void
Spinlock_Init(Spinlock *lock, const char *name)
{
lock->lock = 0;
lock->cpu = 0;
lock->count = 0;
lock->lockTime = 0;
lock->waitTime = 0;
strncpy(&lock->name[0], name, SPINLOCK_NAMELEN);
Spinlock_Lock(&lockListLock);
LIST_INSERT_HEAD(&lockList, lock, lockList);
Spinlock_Unlock(&lockListLock);
}
void
Spinlock_Destroy(Spinlock *lock)
{
Spinlock_Lock(&lockListLock);
LIST_REMOVE(lock, lockList);
Spinlock_Unlock(&lockListLock);
}
void
Spinlock_Lock(Spinlock *lock)
{
uint64_t startTSC;
Critical_Enter();
startTSC = Time_GetTSC();
while (atomic_swap_uint64(&lock->lock, 1) == 1)
{
if ((Time_GetTSC() - startTSC) / ticksPerSecond > 1) {
kprintf("Spinlock_Lock(%s): waiting for over a second!\n", lock->name);
}
}
lock->waitTime += Time_GetTSC() - startTSC;
lock->cpu = CPU();
lock->count++;
lock->lockedTSC = Time_GetTSC();
}
void
Spinlock_Unlock(Spinlock *lock)
{
lock->cpu = 0;
lock->lockTime += Time_GetTSC() - lock->lockedTSC;
atomic_set_uint64(&lock->lock, 0);
Critical_Exit();
}
bool
Spinlock_IsHeld(Spinlock *lock)
{
return (lock->cpu == CPU()) && (lock->lock == 1);
}
void
Debug_Spinlocks(int argc, const char *argv[])
{
Spinlock *lock;
Spinlock_Lock(&lockListLock);
kprintf("%-36s Locked CPU Count WaitTime LockTime\n", "Lock Name");
LIST_FOREACH(lock, &lockList, lockList)
{
kprintf("%-36s %6llu %3llu %8llu %12llu %12llu\n", lock->name,
lock->lock, lock->cpu, lock->count,
lock->waitTime, lock->lockTime);
}
Spinlock_Unlock(&lockListLock);
}
REGISTER_DBGCMD(spinlocks, "Display list of spinlocks", Debug_Spinlocks);