23.11.29 최초 작성
SMP (Symmetric Multiprocessing)
: 여러 cpu가 프로세스를 동시에 실행하기 때문에 발생
Preemptive Scheduling
: 선점 스케줄링 실행 도중 sleep
상태의 프로세스가 사용하던 공간을 수정할 경우
Interrupt
: 실행하던 작업을 멈추고 인터럽트 핸들러를 수행 시 임계 영역 접근 시 발생
누군가 스핀락 획득 시 해제할 때 까지 계속 기다림(busy wait
)
cpu 아키텍처에 의존적(Armv8 : 디버그 컨피그 : CONFIG_DEBUG_SPINLOCK
)
spin_lock()
, spin_unlock()
: 스핀락 획득 / 해제하는 함수
spin_lock_irq()
, spin_unlock_irq()
: 스핀락을 걸 때 로컬 인터럽트 비활성화/활성화 하는 함수
spin_lock_irqsave()
, spin_unlock_irqsave()
: 위 함수에서 인터럽트 상태 활성화 / 비활성화 확인하는 기능 추가
// /source/include/linux/spinlock_types.h
typedef struct spinlock {
union {
struct raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC //디버그와 관련한 구조체
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct {
u8 __padding[LOCK_PADSIZE];
struct lockdep_map dep_map;
};
#endif
};
} spinlock_t;
qspinlock()
: 최대 2개의 cpu까지 스핀락을 획득할 수 있으며 3번째 부터 관련 msc_lock
에 정보를 저장함typedef struct qspinlock {
union {
atomic_t val;
/*
* By using the whole 2nd least significant byte for the
* pending bit, we can allow better optimization of the lock
* acquisition for the pending bit holder.
*/
#ifdef __LITTLE_ENDIAN
struct {
u8 locked;
u8 pending;
};
struct {
u16 locked_pending;
u16 tail;
};
#else
struct {
u16 tail;
u16 locked_pending;
};
struct {
u8 reserved[2];
u8 pending;
u8 locked;
};
#endif
};
} arch_spinlock_t;
queued_spin_lock()
, queued_spin_unlock()
: qspinlock
을 획득 / 해제하는 함수static __always_inline void queued_spin_lock(struct qspinlock *lock)
{
int val = 0;
if (likely(atomic_try_cmpxchg_acquire(&lock->val, &val, _Q_LOCKED_VAL)))
return;
queued_spin_lock_slowpath(lock, val);
}
static __always_inline void queued_spin_unlock(struct qspinlock *lock)
{
/*
* unlock() needs release semantics:
*/
smp_store_release(&lock->locked, 0);
}
mutex
: 뮤텍스를 활용하려는 프로세스의 태스크 디스크립터 정보 저장하는 구조체// /source/include/linux/mutex.h
struct mutex {
atomic_long_t owner; // 뮤텍스를 획득한 프로세스의 태스크 디스크립터 주소
raw_spinlock_t wait_lock;
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
struct optimistic_spin_queue osq; /* Spinner MCS lock */
#endif
struct list_head wait_list; // 뮤텍스 기다리는 프로세스 정보
#ifdef CONFIG_DEBUG_MUTEXES // 디버깅 모드 시 활성화
void *magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC // 디버깅 모드 시 활성화
struct lockdep_map dep_map;
#endif
};
fastpath
: 다른 프로세스가 뮤텍스 획득하지 않은 상태에서 바로 획득하는 루틴slowpath
: 다른 프로세스가 뮤텍스를 획득한 상태에서 실행되는 루틴/source/kernel/locking/mutex.c
mutex_lock()
: 뮤텍스 획득하는 함수
(획득 시 : fastpath
, 획득하지 못할 시 : slowpath
)
__mutex_trylock_fast()
: fastpath
실행하는 함수
__mutex_lock_slowpath()
: slowpath
실행하는 함수
(__mutex_lock_common()
호출)
- __mutex_lock_common() : 프로세스가 깨어날 조건을 설정하고 schedule_preempt_disable()을 통해 sleep 상태로 들어감
mutex_unlock()
: 뮤텍스 획득하는 함수
(fastpath
해제 시 : __mutex_trylock_fast()
slowpath
해제 시 : __mutex_unlock_slowpath()
)
__mutex_trylock_fast()
: current 프로세스(curr
)와 뮤텍스의 owner 비교해 같으면 해제
__mutex_unlock_slowpath()
: wait_list
의 프로세스 중 하나를 가져와 sleep
상태 해제
순차성 베리어