워크큐란?
워크큐는 인터럽트 후반부를 처리하는 기법으로 쓰인다.
다른 인러텁트 후반부 처리 기법이랑 다른점이라면 워크큐는 프로세스 레벨에서 인터럽트 후반부를 처리한다.
워크큐에는 워크, 워크스레드, 워커 풀, 풀워크큐로 이루어져있다.
워크란?
워크는 워크큐의 실행단위다.
자료구조는 아래와 같다.
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
data : 워크 실행상태를 나타낸다
entry : 워크 연결리스트 노드 변수 (list_head는 다음을 참고)
func : 실행할 함수
아래 두 매크로로 워크를 초기화 할 수 있다.
- INIT_WORK()
- DECLARE_WORK()
INIT_WORK()는 실행중에 워크가 동적으로 초기화 되는 것이고,
DECLARE_WORK()는 컴파일이 될때 전역변수로 초기화 해준다.
워크 자료구조의 data가 진짜 골때리는데, 초기값은 WORK_STRUCT_NO_POOL(0xFFFF_FFE0)인데, 이건 워크풀에 아직 들어 있지 않다. 라는 뜻이고
WORK_OFFQ_POOL_SHIFT = WORK_OFFQ_FLAG_BASE + WORK_OFFQ_FLAG_BITS = 4 + 1
WORK_OFFQ_LEFT = BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT
WORK_OFFQ_FLAG_BITS = WORK_OFFQ_LEFT <= 31 ? WORK_OFFQ_LEFT : 31
WORK_OFFQ_POOL_NONE = (1 << WORK_OFFQ_POOL_BITS) - 1
WORK_STRUCT_NO_POOL = WORK_OFFQ_POOL_NONE << WORK_OFFQ_POOL_SHIFT
이렇게 결정된다;;
워크를 워크큐에 큐잉하기
초기화한 워크는 워크큐에 큐잉해야 사용할 수 있다.
아래 함수로 워크를 워크큐에 큐잉할수 있다.
- schedule_work(struct work_struct *work)
- queue_work(struct workqueue_struct *wq, struct work_struct *work)
- queue_work_on(int cpu, struct workqueue_struct *wq, struct work_struct *work)
사실 이 함수들은 같은 매커니즘으로 움직인다.
schedule_work는 system_wq (시스템 워크큐)로 queue_work를 호출하고,
queue_work는 WORK_CPU_UNBOUND를 인자로 넣어서 queue_work_on을 실행한다.
WORK_CPU_UNBOUND는 https://lwn.net/Articles/731052/에 나와있다. 아마도.. 아무 cpu나 쓰시오 같은 의미인듯.
static inline bool schedule_work(struct work_struct *work)
{
return queue_work(system_wq, work);
}
static inline bool queue_work(struct workqueue_struct *wq,
struct work_struct *work)
{
return queue_work_on(WORK_CPU_UNBOUND, wq, work);
}
bool queue_work_on(int cpu, struct workqueue_struct *wq,
struct work_struct *work)
{
bool ret = false;
unsigned long flags;
local_irq_save(flags);
if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
__queue_work(cpu, wq, work);
ret = true;
}
local_irq_restore(flags);
return ret;
}
'디버깅을 통해 배우는 리눅스 커널의 구조' 카테고리의 다른 글
계획 수정과 2권 시작! (0) | 2022.07.16 |
---|---|
스터디 계획(4주차) (0) | 2022.07.02 |
리눅스 커널 스터디 결산 (3주차) (0) | 2022.07.02 |
태스크릿 Tasklet (0) | 2022.07.02 |
ksoftirqd 스레드 (0) | 2022.07.02 |