워커를 관리하고 저장하는 자료구조는 worker 구조체입니다. 이번 절에서는 worker 구조체의 세부 필드를 분석하겠습니다.
worker 구조체 분석
다음은 worker 구조체의 선언부입니다.
https://elixir.bootlin.com/linux/v4.19.30/source/kernel/workqueue_internal.h
1 struct worker {
2 union {
3 struct list_head entry;
4 struct hlist_node hentry;
5 };
6 struct work_struct *current_work;
7 work_func_t current_func;
8 struct pool_workqueue *current_pwq;
9 bool desc_valid;
10 struct list_head scheduled;
11
12 struct task_struct *task;
13 struct worker_pool *pool;
14
15 struct list_head node;
16 unsigned long last_active;
17 unsigned int flags;
18 int id;
19
20 char desc[WORKER_DESC_LEN];
21
22 struct workqueue_struct *rescue_wq;
23};
각 구조체의 세부 필드를 살펴봅시다.
struct work_struct *current_work
work_struct 구조체로 현재 실행하려는 워크를 저장하는 필드입니다.
work_func_t current_func
실행하려는 워크 핸들러의 주소를 저장하는 필드입니다.
그런데 워크 구조체와 워크 핸들러는 커널의 어느 코드에서 worker 구조체 필드에 저장될까요? 워크 구조체와 워크 핸들러는 process_one_work() 함수에서 앞의 current_work와 current_func 필드에 각각 저장됩니다.
https://github.com/raspberrypi/linux/blob/rpi-4.19.y/kernel/workqueue.c
static void process_one_work(struct worker *worker, struct work_struct *work)
{
...
worker->current_work = work;
worker->current_func = work->func;
worker->current_pwq = pwq;
이어서 다른 필드를 분석하겠습니다.
struct task_struct *task
워커 스레드의 태스크 디스크립터 주소입니다.
struct worker_pool *pool
워커를 관리하는 워커 풀 주소를 저장하는 필드입니다.
struct list_head node
워커풀에 등록된 연결 리스트입니다.
워커와 워커 스레드는 어떤 관계일까?
워커 스레드는 커널 스레드의 한 종류로서 워크를 실행하는 프로세스입니다. 워커 스레드의 스레드 핸들 함수는 worker_thread()입니다.
커널 스레드가 무슨 일을 하는지 알려면 해당 커널 스레드 핸들 함수를 분석해야 합니다. 처음 커널 스레드를 분석할 때는 먼저 스레드 핸들 함수를 분석해야 합니다. 이를 통해 스레드를 어떤 과정으로 실행 및 제어하는지 알 수 있습니다.
워커는 워커 스레드를 표현하는 자료구조이며, worker 구조체입니다. 워커 스레드와 워커는 비슷한 개념으로 볼 필요가 있습니다.
워커 스레드를 생성하기 위해서는 우선 워커를 생성해야 합니다. 워커는 워커 스레드를 담은 그릇(container)과 비슷한 역할을 수행합니다. 만약 “워커를 해제했다”라고 하면 “해당 워커 스레드를 해제했다”와 같은 뜻입니다.
워커 스레드 구조체인 worker 구조체의 주요 플래그를 살펴봤으니 워커 스레드를 누가 언제 생성하는지 살펴보겠습니다.
# Reference: For more information on 'Linux Kernel';
디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 1
디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 2

최근 덧글