Linux 6.18 completion·wait queue API

wait queue와 completion: 기다림보다 먼저 정할 것

깨우는 신호, 기다리는 조건, 결과 데이터, 객체 수명을 분리해 비동기 코드를 읽습니다.

wake_up은 결과 데이터를 대신 저장하지 않습니다

wait queue는 조건이 참이 될 때까지 task가 기다릴 수 있게 합니다. 생산자는 공유 상태를 먼저 바꾸고 적절히 알리며, 소비자는 깨어난 뒤에도 조건을 확인합니다. “깨웠다”는 사실만을 데이터로 삼으면 대기 등록 전후의 경쟁이나 여러 소비자가 있을 때 결과를 잃기 쉽습니다.

공유 상태를 이용하는 대기의 개념
  1. 생산자

    동기화 규칙에 맞춰 결과와 준비 상태를 갱신합니다.

    wait queue에 상태 변화를 알립니다.

  2. 기다리는 task

    대기 등록과 조건 확인을 API 규칙에 맞춰 수행합니다.

    조건이 참이면 데이터를 사용할 단계로 갑니다.

  3. 결과 소비

    lock·메모리 순서·소유권 규칙에 맞춰 데이터를 읽고 처리합니다.

화살표는 상태 공개와 알림의 관계입니다. wake_up 호출 순간 소비자가 즉시 CPU를 얻는다는 뜻은 아닙니다.

volatile만 붙여 이 과정을 동기화할 수는 없습니다. 데이터 경쟁·메모리 순서·다중 소비자 처리는 lock이나 적절한 atomic·barrier 규칙을 포함해 설계해야 합니다. wait_event와 wake_up API

completion은 완료 상태를 보존합니다

작업이 먼저 끝나도 기다릴 수 있는 이유

1. 객체 초기화

init_completion() 또는 선언 매크로로 완료 객체를 준비합니다. worker와 waiter가 같은 객체를 사용하고 그 객체가 둘보다 오래 살아 있어야 합니다.

2. 작업 시작

worker에게 처리를 요청합니다. waiter가 wait 함수를 호출하기 전에 worker가 끝날 수도 있습니다. 이 순서 자체는 completion에서 잃어버린 알림이 되는 이유가 아닙니다.

3. 완료 기록

worker가 결과를 준비하고 complete()를 호출합니다. completion은 완료 상태를 기록하므로 아직 waiter가 잠들지 않았어도 이후 wait가 이를 소비할 수 있습니다.

4. 대기 종료

wait가 완료를 얻으면 다음 처리로 갑니다. timeout·signal로 돌아온 경우는 실제 작업 완료와 구분하고, 아직 실행 중인 worker가 접근할 객체를 반환하지 않아야 합니다.

단계는 가능한 실행 순서의 한 예입니다. worker와 waiter는 동시에 진행할 수 있고, complete가 wait보다 먼저 오는 경우도 유효합니다.

completion의 완료 상태와 수명

반환형과 반환값을 정확하게 읽습니다

API반환값의 의미
wait_for_completion()반환값이 없습니다. 완료를 기다리는 동안 잠들 수 있습니다.
wait_for_completion_timeout()0은 timeout, 양수는 완료에 따른 남은 jiffies이며, 완료로 반환할 때에는 최소 1입니다.
wait_for_completion_interruptible_timeout()long을 반환합니다. 0은 timeout, 양수는 완료, 음수는 signal에 따른 중단을 나타냅니다.
try_wait_for_completion()기다리지 않고 완료 하나를 얻을 수 있는지 시도합니다. 성공하면 완료 하나를 소비하고 true, 얻지 못하면 false를 반환합니다.
completion_done()완료 상태가 있는지 관찰합니다. “waiter가 없는가”를 조사하는 API가 아니며 관찰 직후 상태가 달라질 수 있습니다.

interruptible은 하드웨어 interrupt를 모두 끈다는 뜻이 아닙니다. 대기 중 signal에 의해 돌아올 수 있는 task 상태를 말합니다. 함수 반환형을 unsigned로 바꿔 음수 오류를 큰 양수로 읽지 않아야 합니다. 6.18.37 API 선언 완료 처리 구현

timeout은 작업 취소가 아닙니다

ret = wait_for_completion_interruptible_timeout(&job->done, limit);
if (ret <= 0) {
    /* 실제 작업을 취소하거나, 종료를 확인하거나, 수명을 연장합니다. */
    /* 이 지점에서 무조건 free(job) 하면 안 됩니다. */
}

설명용 코드입니다. limit는 jiffies 단위로 준비한 대기 시간이며 ret는 long입니다. 실제 cancel API와 동기화는 작업 종류에 따라 다릅니다. 시간 제한이 지났는데 worker가 뒤늦게 complete(&job->done)를 호출하면, 이미 해제한 job에 접근하는 use-after-free가 될 수 있습니다.

재사용할 때필요한 확인
reinit_completion()앞선 waiter·complete 호출과 동시에 재초기화하지 않도록 제어해야 합니다.
complete_all() 이후다음 작업을 시작하기 전에 이전 작업의 모든 사용자와 완료 상태를 정리해야 합니다.
stack에 놓은 completion함수가 반환한 뒤 producer가 접근하지 않는다는 보장이 있어야 합니다.