콘텐츠로 이동

English | 한국어

Core 스펙 목차 | 이전: Message | 다음: Events

Errors

이 장이 정의하는 것 — 공개 result enum, errno와 version 조회의 공개 계약. 자세한 result-errno 대응표는 이 문서의 Result와 errno 대응 절이 다룬다.

1. Errors 개요

zlink Core의 공개 함수는 실패를 두 층으로 알린다. 주된 제어 흐름은 함수 범주별 typed result enum(zlink_*_result_t)으로 반환하고, 더 세밀한 원인은 호출한 thread마다 따로 유지하는 오류 값 — thread-local errno — 으로 남겨 zlink_errno()로 조회하게 한다. 이 문서는 이 오류 ABI 계약, 즉 공개 result enum, errno 상수와 version 조회를 정의한다. 대상 독자는 C API와 bindings 개발자다. 이 문서는 "공개 함수의 typed result와 thread-local errno가 어떤 값으로 대응하며 build version을 어떻게 판별하는가?"에 답한다.

관련 계약의 소유 문서는 다음과 같다.

관련 계약 정의하는 문서
submit 입력 message의 ownership과 socket별 세부 실패 조건 Socket 공통과 각 socket 정식 문서
zlink_socket_set_receive_flow_state()의 함수 선언과 state enum Socket 공통
receive flow state 설정의 결과로 나타나는 동작 DEALER, ROUTER
언어 binding의 함수별 오류 타입 계층 Bindings 스펙

2. Result와 errno의 기본 규칙

공개 함수는 주된 제어 흐름을 zlink_*_result_t로 반환하고 같은 thread의 zlink_errno()에 세부 원인을 기록한다. caller는 result enum으로 분기하고 errno는 log와 더 세밀한 진단에 사용한다. 성공은 항상 숫자 0이며 성공 뒤 errno 값은 지정하지 않는다.

3. 확장 errno 상수

H = ZLINK_HAUSNUMERO = 156384712를 기준으로 공개 errno를 정의한다. POSIX 이름을 platform이 이미 정의하면 OS 값을 유지하고, 정의하지 않았을 때만 아래 fallback 값을 쓴다. EFSM, ENOCOMPATPROTO, ETERM, EMTHREAD는 ZLink 자체 정의다.

이름 값 또는 fallback 의미
ENOTSUP H + 1 지원하지 않는 operation
EPROTONOSUPPORT H + 2 지원하지 않는 protocol
ENOBUFS H + 3 버퍼 용량 부족
ENETDOWN H + 4 network 사용 불가
EADDRINUSE H + 5 주소 사용 중
EADDRNOTAVAIL H + 6 주소 사용 불가
ECONNREFUSED H + 7 연결 거부
EINPROGRESS H + 8 연결 진행 중
ENOTSOCK H + 9 socket이 아닌 대상
EMSGSIZE H + 10 message 크기 초과
EAFNOSUPPORT H + 11 지원하지 않는 address family
ENETUNREACH H + 12 network 도달 불가
ECONNABORTED H + 13 연결 중단
ECONNRESET H + 14 peer가 연결 reset
ENOTCONN H + 15 연결 없음
ETIMEDOUT H + 16 timeout 만료
EHOSTUNREACH H + 17 host 도달 불가
ENETRESET H + 18 network reset
ESTALE H + 19 stale handle
EALREADY H + 20 중복 operation
EDEADLK H + 21 금지한 재진입
ESHUTDOWN H + 22 종료한 socket
EPROTOTYPE H + 23 호환되지 않는 peer type
EOVERFLOW H + 24 정수 또는 sequence 범위 초과
EFSM H + 51 허용하지 않는 state 전이
ENOCOMPATPROTO H + 52 호환되지 않는 protocol
ETERM H + 53 Context 종료
EMTHREAD H + 54 사용 가능한 I/O thread 없음

함수별 result와 errno 대응은 대응표가 정의한다.

4. Result enum

함수 범주마다 하나의 result enum을 사용한다. 이 절은 선언과 범주별 사용 규칙을 담고, 각 값의 errno 대응과 의미는 Result와 errno 대응이 소유한다.

4.1 Submit result

typedef enum zlink_submit_result_t {
  ZLINK_SUBMIT_OK               = 0,
  ZLINK_SUBMIT_BACKPRESSURED    = 1,
  ZLINK_SUBMIT_NOT_CONNECTED    = 2,
  ZLINK_SUBMIT_NOT_FOUND        = 3,
  ZLINK_SUBMIT_TERMINATED       = 4,
  ZLINK_SUBMIT_INVALID_HANDLE   = 5,
  ZLINK_SUBMIT_INVALID_ARGUMENT = 6,
  ZLINK_SUBMIT_NOT_SUPPORTED    = 7,
  ZLINK_SUBMIT_INVALID_STATE    = 8,
  ZLINK_SUBMIT_THREAD_VIOLATION = 9,
  ZLINK_SUBMIT_OUT_OF_MEMORY    = 10,
  ZLINK_SUBMIT_SEQ_EXHAUSTED    = 11,
  ZLINK_SUBMIT_INTERNAL_ERROR   = 12,
  ZLINK_SUBMIT_NOT_ADMITTED     = 13
} zlink_submit_result_t;

BACKPRESSURED, NOT_CONNECTED, NOT_FOUNDNOT_ADMITTED는 정상적인 runtime 제어 흐름이다. NOT_ADMITTED는 target route는 식별했지만 raw socket의 현재 admission 상태가 신규 submit을 거부했다는 뜻이다. Handshake가 완료되지 않은 peer가 여기에 포함된다. 입력 message ownership은 submit owner 문서가 따로 정하며 result 값만으로 추측하지 않는다.

4.2 Request completion result

typedef enum zlink_request_result_t {
  ZLINK_REQUEST_OK               = 0,
  ZLINK_REQUEST_TIMED_OUT        = 101,
  ZLINK_REQUEST_NOT_FOUND        = 102,
  ZLINK_REQUEST_TERMINATED       = 103,
  ZLINK_REQUEST_PROTOCOL_ERROR   = 104,
  ZLINK_REQUEST_INTERNAL_ERROR   = 105,
  ZLINK_REQUEST_REJECTED         = 106,
  ZLINK_REQUEST_CONFLICT         = 107,
  ZLINK_REQUEST_BUSY             = 108,
  ZLINK_REQUEST_NOT_CONNECTED    = 109,
  ZLINK_REQUEST_INVALID_ARGUMENT = 110,
  ZLINK_REQUEST_INVALID_STATE    = 111,
  ZLINK_REQUEST_NOT_SUPPORTED    = 112,
  ZLINK_REQUEST_BACKPRESSURED    = 113
} zlink_request_result_t;

이 enum은 raw socket request operation의 terminal completion에 사용한다. timeout 결과는 ZLINK_REQUEST_TIMED_OUT으로 표현한다. BACKPRESSURED는 request가 outbound admission 전에 capacity 부족으로 실패했음을 뜻한다.

4.3 Receive와 handler result

typedef enum zlink_recv_result_t {
  ZLINK_RECV_OK               = 0,
  ZLINK_RECV_NO_DATA          = 201,
  ZLINK_RECV_BUSY             = 202,
  ZLINK_RECV_TERMINATED       = 203,
  ZLINK_RECV_INVALID_HANDLE   = 204,
  ZLINK_RECV_NOT_SUPPORTED    = 205,
  ZLINK_RECV_INTERNAL_ERROR   = 206,
  ZLINK_RECV_BUFFER_TOO_SMALL = 207,
  ZLINK_RECV_INVALID_STATE    = 208
} zlink_recv_result_t;

typedef enum zlink_handler_result_t {
  ZLINK_HANDLER_OK               = 0,
  ZLINK_HANDLER_INVALID_ARGUMENT = 301,
  ZLINK_HANDLER_BUSY             = 302,
  ZLINK_HANDLER_NOT_SUPPORTED    = 303,
  ZLINK_HANDLER_DEADLOCK         = 304,
  ZLINK_HANDLER_INVALID_HANDLE   = 305,
  ZLINK_HANDLER_INTERNAL_ERROR   = 306
} zlink_handler_result_t;

BUFFER_TOO_SMALL은 caller가 제공한 batch가 첫 complete message를 담지 못하거나 raw SUB/XSUB· XPUB의 topic buffer가 필요한 길이보다 작은 경우다. 길이 0 topic은 capacity 0과 NULL buffer로도 성공한다. Topic receive는 필요한 topic 길이를 반환하고 queue의 topic과 payload를 소비하지 않으므로 caller가 충분한 buffer로 재시도할 수 있다. INVALID_STATE는 stale handle 또는 종료한 receive state에 사용한다.

4.4 Close, bind와 connect result

typedef enum zlink_close_result_t {
  ZLINK_CLOSE_OK             = 0,
  ZLINK_CLOSE_BUSY           = 401,
  ZLINK_CLOSE_SHUTDOWN       = 402,
  ZLINK_CLOSE_INVALID_HANDLE = 403,
  ZLINK_CLOSE_INTERNAL_ERROR = 404
} zlink_close_result_t;

typedef enum zlink_bind_result_t {
  ZLINK_BIND_OK               = 0,
  ZLINK_BIND_INVALID_ARGUMENT = 501,
  ZLINK_BIND_ADDR_IN_USE      = 502,
  ZLINK_BIND_NOT_SUPPORTED    = 503,
  ZLINK_BIND_INVALID_HANDLE   = 504,
  ZLINK_BIND_INTERNAL_ERROR   = 505
} zlink_bind_result_t;

typedef enum zlink_connect_result_t {
  ZLINK_CONNECT_OK               = 0,
  ZLINK_CONNECT_INVALID_ARGUMENT = 601,
  ZLINK_CONNECT_NOT_SUPPORTED    = 602,
  ZLINK_CONNECT_INVALID_HANDLE   = 603,
  ZLINK_CONNECT_INTERNAL_ERROR   = 604,
  ZLINK_CONNECT_NOT_FOUND        = 605,
  ZLINK_CONNECT_CONFLICT         = 606,
  ZLINK_CONNECT_BUSY             = 607,
  ZLINK_CONNECT_AUTH_FAILED      = 608
} zlink_connect_result_t;

Raw connect intent 또는 routing ID 충돌은 CONFLICT, transport peer authentication 불일치는 AUTH_FAILED다.

4.5 Configuration result

typedef enum zlink_config_result_t {
  ZLINK_CONFIG_OK               = 0,
  ZLINK_CONFIG_INVALID_HANDLE   = 701,
  ZLINK_CONFIG_INVALID_ARGUMENT = 702,
  ZLINK_CONFIG_NOT_SUPPORTED    = 703,
  ZLINK_CONFIG_INTERNAL_ERROR   = 704,
  ZLINK_CONFIG_INVALID_STATE    = 705,
  ZLINK_CONFIG_NOT_FOUND        = 706,
  ZLINK_CONFIG_CONFLICT         = 707,
  ZLINK_CONFIG_BUFFER_TOO_SMALL = 708,
  ZLINK_CONFIG_BUSY             = 709
} zlink_config_result_t;

CONFLICT는 중복 이름, 중복 binding과 process-local identity 충돌이다. BUFFER_TOO_SMALL은 query 또는 retain output capacity가 작으며 caller-owned output을 일부 기록하지 않았음을 뜻한다. BUSY는 같은 mutable batch나 configuration object를 동시에 사용한 경우다.

4.6 Receive flow state 설정 결과

zlink_socket_set_receive_flow_state()의 결과는 다음과 같다. 함수 선언과 state enum은 Socket 공통이 소유하고, 결과로 나타나는 동작은 DEALERROUTER가 소유한다.

조건 결과 errno
DEALER 또는 ROUTER handle과 zlink_receive_flow_state_t 범위 안의 state. Socket이 이미 유지하는 state를 다시 설정한 경우를 포함한다 ZLINK_CONFIG_OK 정의하지 않음
Handle이 NULL이거나 socket이 아니거나, close의 teardown이 이미 끝난 handle ZLINK_CONFIG_INVALID_HANDLE 정의하지 않음
zlink_receive_flow_state_t 범위 밖의 state 값 ZLINK_CONFIG_INVALID_ARGUMENT EINVAL
Receive-flow를 지원하지 않는 socket 유형: PAIR, PUB, SUB, XPUB, XSUB, STREAM ZLINK_CONFIG_NOT_SUPPORTED ENOTSUP
동시에 진행한 close가 이 호출보다 먼저 socket admission을 얻음 ZLINK_CONFIG_INVALID_STATE ESHUTDOWN
소유 Context가 종료 중 ZLINK_CONFIG_INTERNAL_ERROR ETERM

현재 상태를 다시 설정하는 호출은 오류가 아니라 성공하는 no-op다. 이 state는 counter가 아니라 절대값이다.

동시에 진행하는 close와 이 호출은 같은 socket admission을 두고 경합하며, 먼저 수락된 쪽만 관측된다. 경합의 두 결과가 모두 정의되어 있다. INVALID_STATE는 handle이 아직 등록된 상태에서 close가 먼저 수락된 경우다. INVALID_HANDLE은 close의 teardown이 이미 끝나 handle이 더 이상 socket으로 확인되지 않는 경우다. 어느 쪽도 state를 일부만 적용하지 않는다.

5. Version과 진단 함수

#define ZLINK_VERSION_MAJOR 0
#define ZLINK_VERSION_MINOR 17
#define ZLINK_VERSION_PATCH 5

#define ZLINK_MAKE_VERSION(major, minor, patch) \
  ((major) * 10000 + (minor) * 100 + (patch))

#define ZLINK_VERSION \
  ZLINK_MAKE_VERSION(ZLINK_VERSION_MAJOR, ZLINK_VERSION_MINOR, ZLINK_VERSION_PATCH)

Core는 SOVERSION 0을 사용한다.

호출 thread의 errno 값을 반환한다.

ZLINK_EXPORT int zlink_errno(void);

공개 함수가 같은 thread에 기록한 세부 원인 errno를 반환한다. 호출 thread의 값만 반환하며, 성공한 호출 뒤의 값은 지정하지 않는다(§2).

반환값: 호출 thread의 현재 errno 값.

스레드 안전성: thread-safe하다. 호출 thread의 값만 반환한다.

참고: zlink_strerror


errno 값에 대한 설명 문자열을 반환한다.

ZLINK_EXPORT const char *zlink_strerror(int errnum);

반환한 pointer는 caller가 해제하거나 수정하지 않는다. EFSM, ENOCOMPATPROTO, ETERM, EMTHREAD, EHOSTUNREACH, ESTALE은 library 내부 상수 문자열을 반환하고, Windows에서는 ENOTSUP, EPROTONOSUPPORT, ENOBUFS, ENETDOWN, EADDRINUSE, EADDRNOTAVAIL, ECONNREFUSED, EINPROGRESS도 내부 상수 문자열이다. 그 밖의 값은 zlink 확장 영역이라도 platform libc strerror 결과를 그대로 가리키므로, pointer가 이후 호출과 locale 변경에도 유효하다고 가정하지 않는다. 반환 문자열을 보관해야 하면 즉시 복사하는 것을 권장한다.

반환값: errnum에 대한 설명 문자열 pointer. 해제·수정 금지, 수명 보장은 위 본문을 따른다.

스레드 안전성: 모든 thread에서 호출할 수 있다.

참고: zlink_errno


링크된 zlink build의 version을 조회한다.

ZLINK_EXPORT void zlink_version(int *major, int *minor, int *patch);

세 output pointer에 각각 major, minor, patch 값을 기록한다. 세 pointer는 모두 non-NULL이어야 하며, 하나라도 NULL을 전달하면 동작이 정의되지 않는다.

반환값: 없음 (void).

스레드 안전성: thread-safe하다.

참고: zlink_errno

Result와 errno 대응

이 절은 ZLink Core raw public API의 result enum과 thread-local errno 대응을 정의한다. Result는 제어 흐름의 기준이고 errno는 같은 실패를 더 세밀하게 설명한다.

1. 공통 우선순위

한 호출에서 여러 실패 조건이 겹치면 argument, handle·lifecycle, target·connection 조회, capacity, transport·internal failure 순서로 하나를 반환한다. 성공한 함수의 errno는 정의하지 않는다.

2. Submit result

Result errno 의미
ZLINK_SUBMIT_OK - 함수가 정한 ownership 전이가 완료됨
ZLINK_SUBMIT_BACKPRESSURED EAGAIN, ETIMEDOUT, ENOBUFS socket queue 또는 reservation capacity 부족
ZLINK_SUBMIT_NOT_CONNECTED ENOTCONN, EHOSTUNREACH target connection 없음
ZLINK_SUBMIT_NOT_FOUND ENOENT raw target 없음
ZLINK_SUBMIT_NOT_ADMITTED EACCES, ECONNREFUSED, EPROTOTYPE handshake, raw routing admission 또는 peer socket type 거부
ZLINK_SUBMIT_TERMINATED ETERM, ESHUTDOWN Context 또는 socket lifecycle 종료
ZLINK_SUBMIT_INVALID_HANDLE EFAULT handle이 NULL이거나 종류가 다름
ZLINK_SUBMIT_INVALID_ARGUMENT EINVAL, EMSGSIZE 잘못된 pointer, count, metadata 또는 flags
ZLINK_SUBMIT_NOT_SUPPORTED ENOTSUP, EOPNOTSUPP handle에서 지원하지 않는 operation
ZLINK_SUBMIT_INVALID_STATE EFSM, EBUSY, ESTALE, EALREADY socket lifecycle 또는 request state 오류
ZLINK_SUBMIT_THREAD_VIOLATION EDEADLK, EPERM, EMTHREAD 금지한 재진입 또는 thread 사용
ZLINK_SUBMIT_OUT_OF_MEMORY ENOMEM 필요한 storage 확보 실패
ZLINK_SUBMIT_SEQ_EXHAUSTED EOVERFLOW, request submit 경로의 EBUSY operation sequence 공간 소진
ZLINK_SUBMIT_INTERNAL_ERROR 보존된 errno 다른 공개 분류가 없는 내부 실패

각 socket 문서가 input ownership과 socket별 세부 조건을 정의한다.

3. Request completion result

Result errno 의미
ZLINK_REQUEST_OK - terminal success
ZLINK_REQUEST_TIMED_OUT ETIMEDOUT operation deadline 만료
ZLINK_REQUEST_NOT_FOUND ENOENT terminal target 부재
ZLINK_REQUEST_TERMINATED ETERM, ESHUTDOWN owner lifecycle 종료
ZLINK_REQUEST_PROTOCOL_ERROR EPROTO, ENOCOMPATPROTO malformed 또는 호환되지 않는 reply
ZLINK_REQUEST_INTERNAL_ERROR 보존된 errno 다른 terminal 분류가 없는 내부 실패
ZLINK_REQUEST_REJECTED EACCES, ECONNREFUSED, ECANCELED, EPROTOTYPE peer, admission 또는 peer socket type 거절
ZLINK_REQUEST_CONFLICT EEXIST, ESTALE request correlation 충돌(EEXIST) 또는 transport pair generation 불일치(ESTALE)
ZLINK_REQUEST_BUSY EBUSY active request lifecycle 존재
ZLINK_REQUEST_NOT_CONNECTED ENOTCONN, EHOSTUNREACH terminal route 단절
ZLINK_REQUEST_INVALID_ARGUMENT EINVAL, EFAULT asynchronous validation 실패
ZLINK_REQUEST_INVALID_STATE EFSM, EALREADY terminal request state 오류
ZLINK_REQUEST_NOT_SUPPORTED ENOTSUP, EOPNOTSUPP operation 미지원
ZLINK_REQUEST_BACKPRESSURED EAGAIN, ENOBUFS non-blocking admission 또는 reservation 실패

Request submit 성공 뒤에는 nonzero completion ID마다 terminal result를 정확히 한 번 zlink_completion_recv()로 전달한다.

4. Receive result

Result errno 의미
ZLINK_RECV_OK - complete record 하나 이상 수신
ZLINK_RECV_NO_DATA EAGAIN, ETIMEDOUT nonblocking 또는 receive timeout에 data 없음
ZLINK_RECV_BUSY EBUSY 다른 receive mode 사용 중
ZLINK_RECV_TERMINATED ETERM Context 종료
ZLINK_RECV_INVALID_HANDLE EFAULT handle 또는 필수 output pointer가 유효하지 않음
ZLINK_RECV_NOT_SUPPORTED ENOTSUP, EOPNOTSUPP handle이 해당 receive를 지원하지 않음
ZLINK_RECV_INTERNAL_ERROR 보존된 errno 다른 공개 분류가 없는 내부 실패
ZLINK_RECV_BUFFER_TOO_SMALL ENOBUFS caller output capacity 부족
ZLINK_RECV_INVALID_STATE EINVAL, ESTALE, ESHUTDOWN receive lifecycle state 오류

Raw subscription과 XPUB의 BUFFER_TOO_SMALL에서는 필요한 topic 길이만 기록하고 queued record와 다른 output을 변경하지 않는다.

5. Handler와 close result

Result errno 의미
ZLINK_HANDLER_INVALID_ARGUMENT EINVAL handler 인자가 잘못됨
ZLINK_HANDLER_BUSY EBUSY 배타적인 handler 상태가 이미 존재함
ZLINK_HANDLER_NOT_SUPPORTED ENOTSUP, EOPNOTSUPP handle에서 handler operation을 지원하지 않음
ZLINK_HANDLER_DEADLOCK EDEADLK 금지한 handler 재진입
ZLINK_HANDLER_INVALID_HANDLE EFAULT handle이 유효하지 않음
ZLINK_HANDLER_INTERNAL_ERROR 보존된 errno 다른 공개 분류가 없는 내부 실패
ZLINK_CLOSE_BUSY EBUSY, EDEADLK active child·API가 존재하거나 같은 handle close가 재진입함
ZLINK_CLOSE_SHUTDOWN ESHUTDOWN 이미 종료된 handle
ZLINK_CLOSE_INVALID_HANDLE EFAULT, ESTALE pointer 또는 opaque value가 유효하지 않음
ZLINK_CLOSE_INTERNAL_ERROR 보존된 errno 다른 공개 분류가 없는 내부 실패

6. Bind와 connect result

Result errno 의미
ZLINK_BIND_INVALID_ARGUMENT EINVAL endpoint가 잘못됨
ZLINK_BIND_ADDR_IN_USE EADDRINUSE endpoint가 이미 사용 중
ZLINK_BIND_NOT_SUPPORTED ENOTSUP, EOPNOTSUPP, EPROTONOSUPPORT transport 미지원
ZLINK_BIND_INVALID_HANDLE EFAULT handle이 유효하지 않음
ZLINK_BIND_INTERNAL_ERROR 보존된 errno 다른 공개 분류가 없는 bind 실패
ZLINK_CONNECT_INVALID_ARGUMENT EINVAL endpoint 또는 expected RID가 잘못됨
ZLINK_CONNECT_NOT_SUPPORTED ENOTSUP, EOPNOTSUPP, EPROTONOSUPPORT transport 또는 operation 미지원
ZLINK_CONNECT_INVALID_HANDLE EFAULT handle이 유효하지 않음
ZLINK_CONNECT_INTERNAL_ERROR 보존된 errno 다른 공개 분류가 없는 connect 실패
ZLINK_CONNECT_NOT_FOUND ENOENT connection intent가 없음
ZLINK_CONNECT_CONFLICT EEXIST, ESTALE, EADDRINUSE routing ID, endpoint 또는 connection lifecycle 충돌
ZLINK_CONNECT_BUSY EBUSY, ESHUTDOWN lifecycle이 변경을 허용하지 않음
ZLINK_CONNECT_AUTH_FAILED EACCES transport peer 인증 실패

7. Configuration result

Result errno 의미
ZLINK_CONFIG_INVALID_HANDLE EFAULT handle 또는 output pointer가 유효하지 않음
ZLINK_CONFIG_INVALID_ARGUMENT EINVAL, EMSGSIZE option, size, name 또는 value가 잘못됨
ZLINK_CONFIG_NOT_SUPPORTED ENOTSUP, EOPNOTSUPP handle과 option 조합 미지원
ZLINK_CONFIG_INTERNAL_ERROR 보존된 errno 다른 공개 분류가 없는 내부 실패
ZLINK_CONFIG_INVALID_STATE EBUSY, ESTALE, EALREADY, ESHUTDOWN, ENOTCONN, ETIMEDOUT, EPROTO socket lifecycle 또는 terminal state가 변경을 거부함
ZLINK_CONFIG_NOT_FOUND ENOENT local query target 없음
ZLINK_CONFIG_CONFLICT EEXIST 중복 identity, endpoint 또는 등록 값
ZLINK_CONFIG_BUFFER_TOO_SMALL ENOBUFS caller output capacity 부족, partial output 없음
ZLINK_CONFIG_BUSY EBUSY 같은 mutable object를 동시에 사용함

내부 구조

이 절의 계약 소유 — result·errno의 공개 계약은 이 문서의 Result와 errno 대응 절과 검증 요구 절이 소유한다. 이 절은 Core가 API 경계에서 안정적인 공개 result를 노출하면서 내부적으로는 어떻게 상세한 오류를 유지하는지 설명한다.

Layers

  • 내부 실행 경로는 계속 int errno를 사용한다.
  • 공개 C API는 함수 반환 실패를 함수 범주별 8개 typed result enum으로 정규화한다. 정확한 enum은 함수 범주에 따라 달라진다. completion record의 SEND 상태에는 이와 별도인 zlink_send_complete_result_t(ZLINK_SEND_ADMITTED = 0, ZLINK_SEND_TERMINAL = 202)를 쓴다.
  • zlink_submit_result_t — send / publish / request submit / reply submit
  • zlink_request_result_t — request completion record
  • zlink_recv_result_t — recv / subscribe / monitor recv / timer recv
  • zlink_handler_result_t — handler operation
  • zlink_close_result_t — close / destroy
  • zlink_bind_result_t — bind
  • zlink_connect_result_t — connect / disconnect / unbind
  • zlink_config_result_t — option set/get, snapshot, poller mutation, message lifecycle, timer config
  • 0이 아닌 result enum 값은 family별 번호 대역(1-13, 101-113, 201-208, 301-306, 401-404, 501-505, 601-608, 701-709)을 사용해 서로 겹치지 않는다. 단 zlink_send_complete_result_tZLINK_SEND_TERMINAL(202)은 ZLINK_RECV_BUSY(202)와 같은 숫자이므로, 0이 아닌 int 값만으로 출처를 식별하려면 그 값이 함수 반환값인지 completion record의 send_result인지를 함께 알아야 한다.
  • 정식 enum 목록은 위의 Result와 errno 대응 절을 참조한다.
  • Request completion queue는 내부 errno를 from_errno 정규화를 거쳐 zlink_request_result_t로 전달하며, 이 completion channel은 계약상 zlink_request_result_t로 정규화되어 있다.

코드는 세 파일을 중심으로 구성된다.

내부 errno를 유지하는 이유

Core는 여전히 errno로 실패를 알리는 OS와 protocol 코드와 상호작용한다. 이 상세 channel을 유지해야 구현 내부에서 정보를 잃지 않는다.

공개 caller는 그 정도의 세부 정보가 필요하지 않다. caller에게 필요한 것은 안정적인 result 분류다. 그래서 정규화는 공개 경계에서만 일어난다.

구현 규칙

Core와 benchmark/test helper 코드 내부에서 공개 result enum은 boolean이 아니라 이름이 있는 result code로 다뤄야 한다.

  • rc == ZLINK_*_OK 또는 rc != ZLINK_*_OK를 사용한다.
  • if (!zlink_bind(...))같은 boolean 스타일 검사를 작성하지 않는다.

이 규칙이 중요한 이유는 모든 공개 result enum이 성공을 0으로 사용하기 때문이다. boolean 스타일은 성공과 실패를 조용히 뒤집을 수 있으며, 이는 정확히 typed-result 정책이 막으려는 종류의 버그다.

Submit 정규화

Send, request submit과 reply submit은 하나의 공개 result 타입인 zlink_submit_result_t(14개 값: OK, BACKPRESSURED, NOT_CONNECTED, NOT_FOUND, NOT_ADMITTED, TERMINATED, INVALID_HANDLE, INVALID_ARGUMENT, NOT_SUPPORTED, INVALID_STATE, THREAD_VIOLATION, OUT_OF_MEMORY, SEQ_EXHAUSTED, INTERNAL_ERROR)을 공유한다.

정규화 helper는 core/src/api/message/submit_result_internal.hpp에 있다. 이 helper는 내부 submit errno catalog를 공개 submit result로 대응시킨다.

Request completion 정규화

Request completion은 별도의 공개 result 타입인 zlink_request_result_t(14개 값: OK, TIMED_OUT, NOT_FOUND, TERMINATED, PROTOCOL_ERROR, INTERNAL_ERROR, REJECTED, CONFLICT, BUSY, NOT_CONNECTED, INVALID_ARGUMENT, INVALID_STATE, NOT_SUPPORTED, BACKPRESSURED)을 사용한다.

정규화 helper는 core/src/api/message/request_result_internal.hpp에 있다. 이 helper는 completion errno 값을 공개 completion result 계약으로 대응시킨다.

Binding 표면

언어 bindings는 이 8개 범주 구조를 함수별 8개 exception/error subclass(예: SubmitException / BindException / RecvException ...)로 그대로 물려받는다. method signature를 보면 어떤 실패 범주가 발생할 수 있는지 알 수 있다. 정식 binding 규칙은 bindings/doc/spec/README.md(Per-Function Error Type Hierarchy)를, 전체 enum 목록은 위의 Result와 errno 대응 절을 참조한다.

zlink_errno()는 주로 INTERNAL_ERROR의 세부 정보 접근자로 존재한다(그리고 여러 원인을 아직 하나로 묶은 몇몇 거친 bucket을 위해서도 존재한다). 공개 result enum이 이미 자기 설명적이면 (예: BACKPRESSURED, NOT_FOUND, TIMED_OUT), caller는 zlink_errno()를 참고할 필요가 없다.

구현 및 contract test 검증 요구

공개 표면(각 공개 함수의 result 반환값, zlink_completion_recv()의 completion result, zlink_errno(), zlink_strerror(), zlink_version())만으로 다음을 확인한다. 각 항목은 unit test 하나로 이어진다.

공통 규약 - 모든 공개 result enum의 성공 값은 숫자 0이다. - 공개 함수가 실패하면 같은 thread의 zlink_errno()Result와 errno 대응에서 그 result 행에 적힌 errno 중 하나를 반환한다. - 한 호출에서 여러 실패 조건이 겹치면 argument, handle·lifecycle, target·connection 조회, capacity, transport·internal failure 순서로 result 하나만 반환한다. - 성공한 호출 뒤의 zlink_errno() 값은 지정하지 않는다 — test는 성공 뒤 errno 값을 검증하지 않는다. - zlink_errno()는 호출 thread의 값만 반환한다 — 다른 thread에서 실패한 호출이 이 thread의 zlink_errno() 값을 바꾸지 않는다.

확장 errno 상수 - platform에 POSIX 정의가 없어도 ESTALE, EALREADY, EDEADLK, ESHUTDOWN, EPROTOTYPEEOVERFLOW는 모든 지원 platform에서 §3ZLINK_HAUSNUMERO 기반 공개 값으로 관찰된다.

Submit과 request completion - ROUTER가 DEALER RID로 typed request를 보내면 ZLINK_SUBMIT_NOT_ADMITTEDEPROTOTYPE이다. - Completion ID sequence가 소진되면 submit은 ZLINK_SUBMIT_SEQ_EXHAUSTEDEOVERFLOW, ID 0을 반환한다. - Request submit이 성공하면 nonzero ID마다 terminal result(zlink_request_result_t)가 정확히 한 번 REQUEST completion으로 전달된다. - Peer가 유효한 error reply의 첫 4 byte part로 Request completion result의 errno를 보내면 zlink_completion_recv()는 같은 행의 zlink_request_result_t를 받고, 표에 없는 nonzero errno이면 ZLINK_REQUEST_INTERNAL_ERROR를 받는다.

Receive - SUB·XPUB receive에서 topic buffer가 필요한 길이보다 작으면 ZLINK_RECV_BUFFER_TOO_SMALL+ENOBUFS이며 필요한 길이만 기록하고 queued record와 다른 output은 변경하지 않는다. 길이 0 topic은 capacity 0·NULL buffer로 성공한다.

Receive flow state - zlink_socket_set_receive_flow_state()§4.6의 각 조건에서 그 행의 result와 errno를 반환한다. - DEALER는 별도 Completion lane 없이도 zlink_socket_set_receive_flow_state()를 지원하며 유효한 상태에 ZLINK_CONFIG_OK를 반환한다. PAIR·PUB·SUB·XPUB·XSUB·STREAM은 socket type이 receive-flow 대상이 아니므로 ZLINK_CONFIG_NOT_SUPPORTEDENOTSUP을 반환한다. - Socket이 이미 유지하는 state를 다시 설정하면 ZLINK_CONFIG_OK로 성공하는 no-op다. - 동시에 진행하는 close와 경합하면 ZLINK_CONFIG_INVALID_STATE(ESHUTDOWN) 또는 ZLINK_CONFIG_INVALID_HANDLE 중 하나만 관측되고, 어느 쪽도 state를 일부만 적용하지 않는다.

Version과 진단 함수 - zlink_version()은 세 non-NULL output pointer에 major, minor, patch 값을 기록한다. NULL 전달은 미정의다. - zlink_strerror()는 모든 thread에서 호출할 수 있고 zlink 확장 errno에 대해 non-NULL 설명 문자열을 반환한다. caller는 pointer를 해제·수정하지 않으며, 문자열을 보관해야 하면 즉시 복사한다. - zlink_errno()zlink_version()은 여러 thread에서 동시에 호출해도 안전하다.

Core 스펙 목차 | 이전: Message | 다음: Events