DragonOS/kernel/process/spinlock.h

169 lines
4.4 KiB
C
Raw Normal View History

2022-04-07 09:46:09 +00:00
/**
* @file spinlock.h
* @author fslongjin (longjin@RinGoTek.cn)
* @brief
* @version 0.1
* @date 2022-04-07
*
* @copyright Copyright (c) 2022
*
*/
2022-04-12 13:30:07 +00:00
#pragma once
2022-04-13 03:14:49 +00:00
#include <common/glib.h>
#include <process/preempt.h>
2022-04-07 09:46:09 +00:00
/**
* @brief
*
*/
typedef struct
{
__volatile__ char lock; // 1:unlocked 0:locked
} spinlock_t;
/**
* @brief
2022-04-13 03:14:49 +00:00
*
* @param lock
2022-04-07 09:46:09 +00:00
*/
void spin_init(spinlock_t *lock)
{
lock->lock = 1;
}
/**
* @brief
*
* @param lock
*/
void spin_lock(spinlock_t *lock)
{
__asm__ __volatile__("1: \n\t"
2022-04-13 03:14:49 +00:00
"lock decq %0 \n\t" // 尝试-1
"jns 3f \n\t" // 加锁成功跳转到步骤3
"2: \n\t" // 加锁失败,稍后再试
2022-04-07 09:46:09 +00:00
"pause \n\t"
"cmpq $0, %0 \n\t"
2022-04-13 03:14:49 +00:00
"jle 2b \n\t" // 若锁被占用,则继续重试
"jmp 1b \n\t" // 尝试加锁
2022-04-07 09:46:09 +00:00
"3:"
: "=m"(lock->lock)::"memory");
preempt_disable();
2022-04-07 09:46:09 +00:00
}
2022-07-11 10:40:23 +00:00
/**
* @brief
*
* @param lock
*/
2022-04-13 03:14:49 +00:00
void spin_unlock(spinlock_t *lock)
2022-04-07 09:46:09 +00:00
{
preempt_enable();
2022-04-07 09:46:09 +00:00
__asm__ __volatile__("movq $1, %0 \n\t"
2022-04-13 03:14:49 +00:00
: "=m"(lock->lock)::"memory");
}
2022-07-11 10:40:23 +00:00
/**
* @brief
*
* @warning
*/
void spin_lock_no_preempt(spinlock_t *lock)
{
__asm__ __volatile__("1: \n\t"
"lock decq %0 \n\t" // 尝试-1
"jns 3f \n\t" // 加锁成功跳转到步骤3
"2: \n\t" // 加锁失败,稍后再试
"pause \n\t"
"cmpq $0, %0 \n\t"
"jle 2b \n\t" // 若锁被占用,则继续重试
"jmp 1b \n\t" // 尝试加锁
"3:"
: "=m"(lock->lock)::"memory");
}
/**
* @brief
*
* @warning
*/
void spin_unlock_no_preempt(spinlock_t * lock)
{
__asm__ __volatile__("movq $1, %0 \n\t"
: "=m"(lock->lock)::"memory");
}
2022-04-13 03:14:49 +00:00
/**
* @brief
*
* @param lock
* @return long 10
*/
long spin_trylock(spinlock_t *lock)
{
uint64_t tmp_val = 0;
preempt_disable();
// 交换tmp_val和lock的值若tmp_val==1则证明加锁成功
asm volatile("lock xchgq %0, %1 \n\t" // 确保只有1个进程能得到锁
: "=q"(tmp_val), "=m"(lock->lock)
: "0"(0)
: "memory");
if (!tmp_val)
preempt_enable();
return tmp_val;
}
// 保存当前rflags的值到变量x内并关闭中断
#define local_irq_save(x) __asm__ __volatile__("pushfq ; popq %0 ; cli" \
: "=g"(x)::"memory")
// 恢复先前保存的rflags的值x
#define local_irq_restore(x) __asm__ __volatile__("pushq %0 ; popfq" ::"g"(x) \
: "memory")
#define local_irq_disable() cli();
#define local_irq_enable() sti();
/**
* @brief
*
*/
#define spin_lock_irqsave(lock, flags) \
do \
{ \
local_irq_save(flags); \
spin_lock(lock); \
} while (0)
/**
* @brief rflags以及中断状态并解锁自旋锁
*
*/
#define spin_unlock_irqrestore(lock, flags) \
do \
{ \
spin_unlock(lock); \
local_irq_restore(flags); \
} while (0)
/**
* @brief
*
*/
#define spin_lock_irq(lock) \
do \
{ \
local_irq_disable(); \
spin_lock(lock); \
} while (0)
/**
* @brief
*
*/
#define spin_unlock_irq(lock) \
do \
{ \
spin_unlock(lock); \
local_irq_enable(); \
} while (0)