Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

정규 ABI

ABI는 애플리케이션 바이너리 인터페이스로, 바이너리 형식으로 데이터를 주고받는 방식에 대한 약속입니다. ABI는 특히 비트와 바이트 수준의 데이터 레이아웃을 다룹니다. 예를 들어 ABI는 정수를 표현하는 방식(빅 엔디언인가, 리틀 엔디언인가?), 문자열을 표현하는 방식(널 종료 문자 시퀀스에 대한 포인터인가, 길이 접두사 방식인가? UTF-8 인코딩인가, UTF-16 인코딩인가?), 그리고 복합 타입을 표현하는 방식(구조체 시작점으로부터 각 필드의 오프셋)을 정의할 수 있습니다.

컴포넌트 모델은 모든 컴포넌트가 따르는 ABI인 정규 ABI를 정의합니다. 이를 통해 컴포넌트가 서로 다른 언어로 빌드되었더라도 혼동 없이 서로 통신할 수 있음이 보장됩니다. 내부적으로 C 컴포넌트는 Rust 컴포넌트와 상당히 다른 방식으로 문자열을 표현할 수 있지만, 정규 ABI는 두 컴포넌트가 그 사이의 경계를 넘어 문자열을 전달할 수 있는 형식을 제공합니다.

정규 ABI가 무엇인지에 대한 보다 공식적인 정의는 정규 ABI 설명서를 참고하십시오.

네이티브 비동기 확장

WASI 0.3은 async func, stream<T>, future<T>를 정규 ABI 프리미티브로 추가했습니다. 기존 규칙은 모든 인터페이스 호출이 동기적으로 반환된다고 가정했기 때문에, 이를 지원하려면 ABI 자체를 확장해야 했습니다. 이 절에서는 이러한 확장이 무엇인지 개략적으로 설명합니다. 전체 명세는 업스트림 동시성 설명서와 정규 ABI 설명서를 참고하십시오.

비동기 함수 ABI

async로 선언된 WIT 함수는 기존의 (동기) 시그니처에 더해 논블로킹 코어 함수 시그니처를 갖습니다. 두 시그니처 모두 계속 사용할 수 있으므로, 어느 쪽도 상대방의 호출 규약을 채택할 필요 없이 동기 호출자가 비동기 피호출자를 호출하고 비동기 호출자가 동기 피호출자를 호출할 수 있습니다.

동기 로어링(WIT 수준 시그니처를 실제 코어 Wasm 함수 매개변수 및 결과로 매핑하는 것)에서 매개변수와 반환 값은 들어맞는 경우 평탄한(flat) 코어 Wasm 타입으로 전달되고, 그렇지 않은 경우 선형 메모리 포인터(매개변수에는 입력 포인터(in-pointer), 결과에는 출력 포인터(out-pointer))를 통해 전달됩니다. 비동기 로어링은 실제 함수 반환 값으로 i32 상태 코드를 추가합니다. 논리적 반환 값은 호출이 완료되면 호출자가 제공한 출력 포인터에 기록됩니다. 상태 코드의 하위 비트는 다음 세 가지 경우를 구분합니다.

  • 호출이 아직 매개변수 읽기를 시작하지 않았습니다.
  • 호출이 매개변수를 읽었지만 아직 결과를 쓰지 않았습니다.
  • 호출이 반환되었으며, 매개변수 메모리와 결과 메모리가 모두 소비되었습니다.

런타임은 진행 중인 각 비동기 호출을 서브태스크(subtask)로 표현합니다. 호출자는 단일 서브태스크를 기다리거나 대기 가능 집합(waitable set)에 속한 서브태스크 중 어느 하나를 기다릴 수 있습니다. 해당 대기 내장 함수는 아래에 나열되어 있습니다. 런타임이 완료를 알리면 호출자는 실행을 재개하고 결과를 소비할 수 있습니다.

경계를 넘나드는 스트림과 퓨처

stream<T>와 future<T>는 리소스가 아니라 정규 ABI 값입니다. 전송 수준에서 각 끝은 컴포넌트별 핸들 테이블에 대한 정수 인덱스로 표현되며(리소스가 사용하는 것과 동일한 일반적인 메커니즘), 값과 리소스의 구분은 인코딩이 아니라 아래의 소유권 규칙에서 드러납니다. 각각에는 읽기 가능 끝과 쓰기 가능 끝이라는 두 개의 끝이 있습니다. 소유권 규칙은 간단합니다.

  • 새로운 stream.new 또는 future.new 내장 함수를 통해 스트림이나 퓨처를 생성한 컴포넌트는 두 끝을 모두 받습니다.
  • 다른 컴포넌트나 호스트로부터 스트림이나 퓨처를 받은 컴포넌트는 읽기 가능 끝의 고유한 소유권을 얻습니다.
  • 스트림이나 퓨처를 경계 너머로 전달하는 컴포넌트는 읽기 가능한 끝의 소유권을 이전합니다.

쓰기 가능한 끝은 고정되어 있습니다. 즉, 스트림이나 퓨처를 생성한 컴포넌트에 남아 있으며 경계 너머로 이전할 수 없습니다.

코어 Wasm 코드는 선형 메모리 버퍼를 전달하여 stream.read 내장 함수로 스트림에서 읽고 stream.write로 스트림에 씁니다. 이러한 내장 함수는 완료 기반입니다. 즉, 호출은 값을 즉시 버퍼로 복사하거나 버퍼에서 복사해 오며, 그렇지 않으면 작업이 동시에 계속 진행됨을 나타내는 “blocked” 센티널 값을 반환합니다. 퓨처는 이와 유사한 future.read와 future.write를 사용합니다.

이는 OS 수준의 완료 기반 I/O(Linux의 io_uring, Windows의 Overlapped I/O)와 같은 형태이며, 이 때문에 바인딩 생성기는 별도의 연결 작업 없이 스트림과 퓨처를 호스트 언어의 기존 동시성 기본 요소에 매핑할 수 있습니다.

기타 내장 함수

비동기 지원은 다음과 같은 여러 정규 ABI 내장 함수를 추가로 제공합니다.

  • task.return은 비동기 함수의 익스포트 측에서 결과를 전달하는 데 사용됩니다.
  • task.cancel은 진행 중인 서브태스크를 취소하는 데 사용됩니다.
  • Waitable-set 프리미티브는 진행 중인 여러 서브태스크를 기다리거나 그중 하나를 선택하는 데 사용됩니다(비동기 호출 결과를 소비하는 데 쓰이는 메커니즘입니다).

전체 목록은 정규 ABI 설명서에 있으며, 동시성 설명서에서는 설계 근거와 더 넓은 동시성 모델을 다룹니다.


원문 © 2023 The Bytecode Alliance Contributors · WebAssembly Components Documentation · CC BY 4.0
Yeokja 한국어 번역·편집 · Anthropic 사의 claude-sonnet-5 모델을 활용하여 번역되었으며 학습을 모두 비허용한 상태로 작업하였습니다 · 이 번역은 원문을 수정한 문서이며 CC BY 4.0으로 제공합니다.