POSIX (Portable Operating System Interface)

POSIX는 유닉스 계열 운영체제의 공통 인터페이스 계약을 정리한 표준입니다. 이 문서는 POSIX의 역사, Issue 8 문서 구조, 시스템 인터페이스(System Interfaces)와 셸·유틸리티(Shell and Utilities)의 범위, Linux와 GNU 확장의 차이, 커널 개발자가 실제로 부딪히는 이식성 문제를 한 문서에서 연결해 설명합니다.

최신 기준: 현재 공개 최신 기준은 POSIX.1-2024 / IEEE Std 1003.1-2024이며, Issue 8 다운로드 안내에서 개인용 HTML 묶음을 받을 수 있습니다. 이 문서는 최신 공개판을 기준으로 설명하고, Linux 고유 확장과 표준 범위를 분리해서 다룹니다.
전제 조건: 시스템 콜(System Call), 프로세스(Process), VFS 문서를 먼저 읽으세요. POSIX는 커널 내부 구현 자체가 아니라 사용자 공간(User Space)과 커널이 맞춰야 하는 계약을 설명하므로, 실제 호출 경로와 파일 시맨틱을 먼저 알고 읽어야 표준 문구가 어떻게 코드로 내려오는지 이해하기 쉽습니다.
일상 비유: 이 개념은 전기 콘센트 규격서와 비슷합니다. 규격서가 벽 안의 배선 구현을 직접 강제하지는 않지만 플러그 모양, 전압 범위, 안전 조건을 정해 서로 다른 제품이 함께 동작하게 만들듯이, POSIX도 커널 내부 구현보다 인터페이스 계약을 정의합니다.

핵심 요약

  • POSIX — 운영체제 인터페이스와 셸·유틸리티 동작 계약을 정의하는 표준 계열입니다.
  • Issue 8 — 현재 공개 최신판이며 IEEE Std 1003.1-2024와 The Open Group Base Specifications Issue 8이 기술적으로 같은 문서입니다.
  • 표준 범위 — 시스템 콜만이 아니라 라이브러리 함수, 헤더, 셸 문법, 유틸리티까지 포함합니다.
  • Linux 확장 — epoll, io_uring, pidfd, signalfd, eventfd처럼 유용하지만 POSIX 밖에 있는 Linux 전용 인터페이스가 많습니다.
  • 이식성 — 커널 개발자도 사용자 공간 도구, 테스트 코드, 빌드 스크립트를 쓸 때 POSIX 경계를 이해해야 불필요한 GNU/Linux 종속성을 줄일 수 있습니다.

단계별 이해

  1. 표준의 위치 파악
    POSIX는 커널 소스가 아니라 사용자 프로그램과 운영체제 사이의 계약 문서라는 점부터 잡습니다.
  2. 문서 구조 익히기
    XBD, XSH, XCU, XRAT 네 덩어리로 나뉜다는 사실을 알면 필요한 조항을 훨씬 빨리 찾을 수 있습니다.
  3. 표준과 구현 분리
    open() 같은 이름이 표준 인터페이스인지, glibc 래퍼인지, Linux 시스템 콜인지 구분합니다.
  4. Feature Test Macro 설정
    #define _POSIX_C_SOURCE 200809L을 소스 맨 위에 두면 GNU 확장을 차단하고 POSIX 범위만 노출합니다. _GNU_SOURCE를 쓰면 반대로 모든 GNU/Linux 확장이 열립니다. 둘을 혼용하면 이식성 경계가 흐려집니다.
  5. 실전 적용
    poll()epoll, sigaction()signalfd처럼 POSIX 경로와 Linux 전용 경로를 코드에서 명시적으로 분리하면 버그 재현 범위를 좁히기 쉬워집니다.

개요

POSIXPortable Operating System Interface의 약자이며, 서로 다른 유닉스 계열 시스템이 공통된 인터페이스를 제공하도록 정리한 표준 집합입니다. 이름만 보면 시스템 콜 표준처럼 느껴지지만, 실제 범위는 그보다 훨씬 넓습니다. 함수(Function), 헤더(Header), 시그널(Signal), 파일 시맨틱(File Semantics), 스레드(Thread), 셸 문법, 표준 유틸리티, 빌드 도구의 최소 동작까지 함께 다룹니다.

리눅스 커널 개발자에게 POSIX가 중요한 이유는 두 가지입니다. 첫째, 커널은 사용자 공간이 기대하는 파일·프로세스·시그널 시맨틱을 구현해야 합니다. 둘째, 커널 개발 과정에서 쓰는 테스트 프로그램, 재현 코드, 셸 스크립트, 이식성 있는 도구는 POSIX 계약 위에서 움직입니다. 따라서 POSIX를 모르면 커널 내부는 알아도 사용자 공간 기대치와 어긋난 설계를 하기 쉽습니다.

질문POSIX가 답하는 범위POSIX가 직접 답하지 않는 범위
파일 열기open(), read(), write(), 권한 비트, 에러 코드, 파일 시간 갱신 규약VFS 내부 자료구조, 페이지 캐시(Page Cache) 알고리즘, ext4 저널 구현
프로세스 생성fork(), exec*, wait*, 프로세스 속성 상속 규약task_struct 레이아웃, 스케줄러(Scheduler) 큐 구조
시그널 처리sigaction(), 시그널 마스크, 기본 동작, 비동기 인터럽트(Interrupt) 계약Linux 시그널 전달 구현 상세, 태스크(Task) 웨이크업 내부 경로
셸 스크립트POSIX sh 문법, 유틸리티 옵션과 종료 코드Bash 배열, [[ ]], GNU Coreutils 확장 옵션
이벤트 처리poll(), select(), pselect()epoll, io_uring, eventfd, pidfd
중요한 구분: POSIX 호환 인터페이스를 많이 구현했다고 해서 모든 Linux 시스템이 자동으로 POSIX 인증 시스템이 되는 것은 아닙니다. 표준 문서, 구현체, 배포판 정책, 인증 절차는 서로 다른 층위입니다. 이 문서에서는 "Linux가 POSIX 시맨틱을 참고하고 많이 구현한다"는 수준과 "정식 인증 제품"을 엄격히 구분합니다.
POSIX가 다루는 계약과 Linux가 구현하는 계층 응용 프로그램 테스트 코드, 빌드 스크립트, 데몬, 도구 POSIX 계약 층 함수, 헤더, 셸, 유틸리티, 에러 시맨틱 libc / 런타임 glibc, musl, 셸, 표준 유틸리티 구현 Linux 시스템 콜 경계 open, read, fork, execve, clock_gettime 일부는 POSIX, 일부는 Linux 전용 커널 내부 구현 VFS, 스케줄러, 신호 전달, 파일시스템, 타이머 표준은 결과를 규정하고 내부 구조는 강제하지 않음 핵심: POSIX는 "무엇을 보장해야 하는가"를 정의하고 Linux는 "어떻게 구현할 것인가"를 선택합니다.
그림 1. POSIX는 응용 프로그램과 구현체 사이의 계약을 규정하고, Linux 커널 내부 자료구조나 알고리즘 자체를 표준화하지는 않습니다.

역사와 표준 계보

POSIX는 여러 유닉스 계열 시스템 사이의 인터페이스 차이를 줄이기 위해 등장했습니다. 오늘날 개발자가 보는 온라인 문서는 The Open Group이 게시하지만, 표준 자체는 IEEE와 The Open Group이 함께 관리하며, 실제 기술 작업은 Austin Group이 주도합니다.

시기핵심 사건커널 개발자 관점의 의미
1980년대 후반유닉스 벤더별 API 차이가 커짐이식성 있는 도구와 응용 프로그램 작성 비용이 커짐
1990년초기 POSIX.1 계열 정립프로세스, 파일, 시그널 등 공통 OS 인터페이스 기준이 생김
2001년 이후POSIX, Single UNIX Specification, ISO 문서군이 점점 통합표준 참조점이 여러 갈래에서 하나로 수렴
2017년IEEE Std 1003.1-2017많은 문서와 교재가 아직 이 판본을 기본으로 인용
2024년IEEE Std 1003.1-2024 / The Open Group Base Specifications Issue 8현재 최신 공개판. 최신 링크와 설명은 이 판본 기준으로 잡는 것이 안전

Issue 8 rationale는 POSIX.1-2024가 Issue 8과 기술적으로 동일하며, Austin Group이 IEEE, The Open Group, ISO/IEC 협업 구조 안에서 작업했다는 점을 명확히 밝힙니다. 실무에서는 "POSIX", "Issue 8", "SUSv5"가 문맥에 따라 함께 언급될 수 있지만, 완전히 같은 범위로 느슨하게 써버리면 문서 참조가 흐려집니다.

POSIX 표준 계보와 현재 참조점 유닉스 벤더별 API System V, BSD, 상용 유닉스 POSIX 계열 표준화 공통 인터페이스 정리 Austin Group IEEE + The Open Group + ISO/IEC Issue 8 POSIX.1-2024 SUS Version 5 계열 Linux 개발자가 실무에서 참조하는 위치 온라인 표준 문서 + glibc/musl 문서 + man-pages + 커널 문서를 함께 읽어 실제 동작을 확인
그림 2. 오늘날 실무에서는 POSIX를 단독으로 읽기보다 Austin Group이 관리하는 최신 표준 문서와 Linux 구현 문서를 함께 봐야 정확한 판단이 됩니다.

Issue 8 문서 구조와 읽는 법

POSIX 문서는 처음 보면 방대해 보이지만, 실제로는 네 덩어리만 익히면 됩니다. 대부분의 커널 개발자는 함수 하나를 찾다가 문서 전체에 압도되는데, 먼저 "어느 권(volume)에 있는가"를 분리하면 탐색 비용이 크게 줄어듭니다.

의미무엇을 찾을 때 보는가대표 링크
XBDBase Definitions용어 정의, 공통 개념, 헤더, 파일 접근 규칙, 에러 번호, 옵션 이름Base Definitions
XSHSystem Interfacesopen(), fork(), sigaction(), pthread_*, mq_* 같은 함수 규약System Interfaces
XCUShell and UtilitiesPOSIX sh 문법, make, find, awk, sed, test 같은 유틸리티Shell and Utilities
XRATRationale왜 이런 규칙이 생겼는지, 이전 판본과의 호환성, 모호한 부분의 배경Rationale

커널 개발자에게 특히 중요한 읽기 순서는 다음과 같습니다. 함수 의미가 애매하면 먼저 XSH를 봅니다. 에러 코드나 타입 정의가 헷갈리면 XBD로 올라갑니다. 왜 Linux 구현과 다르게 보이는지 이해가 안 되면 XRAT를 확인합니다. 셸 스크립트 이식성 문제라면 XCU를 봅니다.

문서 읽기 팁: POSIX는 규정 문서이므로 shall, should, may 같은 표현 차이가 중요합니다. shall은 필수, should는 권고, may는 허용을 뜻합니다. 커널 코드 리뷰에서 "표준상 보장"을 말할 때 이 구분을 흐리면 쉽게 과장된 주장이 됩니다.
표현의미실무 해석
shall반드시 보장해야 함호환성 주장에 근거로 써도 되는 강한 규정
should권장좋은 구현 관행이지만 미준수만으로 비호환 단정은 어려움
may허용구현마다 다를 수 있으므로 가정하면 위험
implementation-defined구현이 선택하되 문서화해야 함glibc, musl, 배포판 문서를 같이 봐야 함
unspecified표준이 결과를 정하지 않음동작에 의존하면 이식성 버그가 생기기 쉬움

Feature Test Macro — POSIX 범위 제어

POSIX 함수를 사용하기 전에 반드시 이해해야 하는 것이 기능 테스트 매크로(Feature Test Macro)입니다. 이 매크로는 libc 헤더가 어느 수준의 인터페이스를 노출할지 컴파일러에게 알려줍니다. 매크로를 지정하지 않으면 glibc 기본값은 _DEFAULT_SOURCE로 GNU 확장 상당 부분이 노출되어, 이식성 문제가 있는 코드를 컴파일 오류 없이 작성해버리기 쉽습니다.

매크로노출 범위권장 상황
_POSIX_C_SOURCE 200809LPOSIX.1-2008 (Issue 7) 인터페이스만 노출이식성 있는 도구·테스트 코드 작성 시 기본값
_POSIX_C_SOURCE 202405LPOSIX.1-2024 (Issue 8) 인터페이스만 노출최신 표준 함수(ppoll, getentropy 등) 사용 시
_XOPEN_SOURCE 700POSIX + X/Open (XSI) 확장 포함XSI 옵션 인터페이스가 필요할 때
_GNU_SOURCEPOSIX + GNU 확장 + Linux 전용 전부 노출Linux 전용 코드. 이식성 버그가 숨기 쉬움
_DEFAULT_SOURCEglibc 기본값 (GNU + POSIX 혼합)매크로 미지정 시 glibc의 기본 동작
소스 코드 #define _POSIX_C_SOURCE 200809L 소스 코드 #define _GNU_SOURCE (GNU/Linux 확장 포함) libc 헤더 <unistd.h> <fcntl.h> … POSIX 심볼 XSI/GNU 확장 심볼 Linux 전용 심볼 _POSIX_C_SOURCE POSIX 심볼만 보임 _GNU_SOURCE 모든 심볼 노출
Feature Test Macro가 libc 헤더의 심볼 노출 범위를 제어하는 원리
/* 이식성을 최우선으로 할 때 — POSIX.1-2008 범위만 사용 */
#define _POSIX_C_SOURCE 200809L
#include <unistd.h>
#include <fcntl.h>

/* epoll_create1()은 POSIX 범위 밖 → 이 설정에서는 선언이 보이지 않음 */

/* Linux 전용 API까지 허용할 때 — GNU/Linux 특화 코드에서만 사용 */
#define _GNU_SOURCE
#include <sys/epoll.h>
/* epoll_create1(), signalfd(), eventfd() 등 모두 보임 */
혼용 금지: _GNU_SOURCE_POSIX_C_SOURCE를 같은 파일에 함께 정의하면 glibc는 _GNU_SOURCE를 우선하므로 POSIX 제한 효과가 사라집니다. 의도를 명확히 하려면 하나만 사용하십시오.

핵심 시스템 인터페이스

커널 개발자 입장에서 POSIX의 중심은 결국 시스템 인터페이스입니다. 다만 "시스템 인터페이스"가 곧 "시스템 콜"은 아닙니다. 어떤 함수는 libc 래퍼가 직접 시스템 콜에 연결되고, 어떤 함수는 사용자 공간에서 조합되며, 어떤 함수는 스레드 라이브러리와 커널 기능이 함께 구현합니다.

주제대표 POSIX 인터페이스Linux 구현에서 주의할 점관련 문서
프로세스fork(), execve(), waitpid()fork()는 POSIX 계약이고 실제 구현은 clone 계열을 활용프로세스, 시스템 콜
파일 I/Oopen(), read(), write(), fsync()표준 파일 시맨틱과 ext4/XFS 실제 보장 범위를 구분해야 함VFS, ext4, XFS
시그널sigaction(), sigprocmask(), sigsuspend()비동기 안전(async-signal-safe) 제약은 설계 실수의 흔한 원인시그널 처리
IPCpipe(), mq_open(), shm_open(), sem_open()System V IPC와 POSIX IPC는 자원 모델과 API가 다름IPC, shmem / tmpfs
스레드pthread_create(), pthread_mutex_lock()사용자 API는 POSIX지만 실제 구현은 NPTL과 futex에 크게 의존커널 스레드(Kernel Thread), Futex
시간clock_gettime(), nanosleep(), timer_create()vDSO 경량 경로와 hrtimer 기반 커널 구현을 함께 봐야 함ktime / Clock, 타이머(Timer)
네트워크소켓(Socket) API, poll(), select()epollio_uring은 Linux 확장이므로 별도 분리 표기 필요네트워크 스택(Network Stack), io_uring 네트워킹

예를 들어 pthread_mutex_lock()은 POSIX 인터페이스이지만 Linux 커널 안에 동일 이름의 시스템 콜이 있는 것은 아닙니다. 반대로 epoll_wait()는 Linux에서 실무적으로 매우 중요하지만 POSIX 표준 함수는 아닙니다. 따라서 커널 문서나 코드 예제에서 "POSIX API"와 "Linux syscall"을 같은 말처럼 쓰면 설명이 무너집니다.

#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static volatile sig_atomic_t stop;

static void on_sigint(int sig)
{
    (void)sig;
    stop = 1;
}

int main(void)
{
    struct sigaction sa;
    int fd;
    char buf[64];
    ssize_t nr;

    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = on_sigint;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGINT, &sa, 0);

    fd = open("posix-demo.txt", O_RDONLY);
    if (fd < 0) {
        perror("open");
        return 1;
    }

    nr = read(fd, buf, sizeof(buf) - 1);
    if (nr >= 0) {
        buf[nr] = '\0';
        write(STDOUT_FILENO, buf, nr);
    }

    close(fd);
    return stop ? 130 : 0;
}
코드 설명
  • 1행_POSIX_C_SOURCE는 어느 판본 수준의 POSIX 인터페이스를 노출할지 libc에 알리는 기능 매크로(Macro)입니다. GNU 확장 노출 범위를 줄일 때 유용합니다.
  • 11-16행시그널 핸들러(Handler)는 최소한의 상태 변경만 수행합니다. 비동기 안전 제약을 어기지 않기 위한 전형적 패턴입니다.
  • 23-25행sigaction()은 POSIX 표준 시그널 인터페이스의 핵심이며, Linux에서도 전통적인 signal()보다 이 경로가 기준입니다.
  • 27-35행open(), read(), write(), close()는 가장 대표적인 POSIX 파일 인터페이스입니다. 커널 내부에서는 VFS와 파일시스템 구현체가 이 계약을 만족시킵니다.
실무 포인트: 재현용 테스트 프로그램은 먼저 POSIX 범위 안에서 최소 사례를 작성하고, 문제가 Linux 확장에만 나타나는지 별도로 분리하세요. 이렇게 하면 버그 리포트가 "표준 시맨틱 위반"인지 "Linux 전용 기능 상호작용"인지 더 빨리 가려집니다.

파일 디스크립터(File Descriptor)와 I/O 모델

POSIX I/O의 핵심은 파일 디스크립터(File Descriptor, FD)입니다. FD는 프로세스가 열린 파일·파이프·소켓·파일시스템(Filesystem) 디바이스를 참조하는 음수가 아닌 정수입니다. POSIX는 FD의 의미, 상속 규칙, 에러 시맨틱을 규정하지만 커널 내부 자료구조는 강제하지 않습니다.

프로세스 FD 테이블 fd 0 (stdin) fd 1 (stdout) fd 2 (stderr) fd 3 (open 반환) fd 4 … (미사용) 열린 파일 기술자 (Open File Description) 파일 오프셋 O_RDONLY / O_WRONLY / … O_APPEND / O_NONBLOCK 참조 카운트 (dup/fork로 공유 가능) inode 파일 메타데이터 퍼미션(Permission), 크기, 블록 (커널 내부 — POSIX 미규정) POSIX 규정 POSIX 규정 커널 내부 구현
FD 테이블 → 열린 파일 기술자 → inode 계층. FD와 열린 파일 기술자는 POSIX가 정의하고, inode와 그 내부는 커널 구현 영역입니다.

POSIX FD vs. stdio 스트림

C 표준 라이브러리의 FILE * 스트림(stdio)과 POSIX FD는 다른 수준의 인터페이스입니다. stdio는 내부적으로 POSIX FD를 사용하지만 버퍼(Buffer) 계층을 추가합니다.

특성POSIX FDstdio (FILE *)
인터페이스open / read / write / closefopen / fread / fwrite / fclose
버퍼링(Buffering)없음 (커널 페이지 캐시만 적용)사용자 공간(User Space) 내부 버퍼 있음
표준POSIX XSHISO C (POSIX도 포함)
FD 번호 접근직접 사용fileno(fp)로 꺼낼 수 있음
시그널 인터럽트 처리EINTR 재시도 필요내부적으로 처리하는 경우도 있음
주 사용처커널 인터페이스, 소켓, 저수준 I/O텍스트 처리, 이식성 높은 파일 작업

POSIX 에러 모델 — errno

POSIX 함수가 실패하면 일반적으로 -1을 반환하고 errno에 에러 코드를 설정합니다. errno는 스레드 로컬 변수이므로 멀티스레드 환경에서도 각 스레드가 독립적으로 확인합니다.

#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
    int fd = open("/nonexistent", O_RDONLY);
    if (fd == -1) {
        /* errno는 open() 직후에 즉시 읽어야 합니다.
         * 다른 함수 호출 사이에 errno가 덮어써질 수 있습니다. */
        int saved_errno = errno;
        fprintf(stderr, "open 실패: %s (errno=%d)\n",
                strerror(saved_errno), saved_errno);
        return 1;
    }
    close(fd);
    return 0;
}
코드 설명
  • open() == -1POSIX 관행: 실패 시 -1 반환. fd >= 0이어야 유효한 FD입니다.
  • saved_errnoerrno는 다음 함수 호출에서 덮어써지므로 즉시 복사해 두는 것이 올바른 패턴입니다.
  • strerror()errno 값을 사람이 읽을 수 있는 문자열로 변환합니다. 멀티스레드 환경에서는 strerror_r()을 사용하십시오.
async-signal-safe 제약: 시그널 핸들러 안에서는 비동기 안전(async-signal-safe) 함수만 호출할 수 있습니다. printf(), malloc(), strerror()는 재진입(Re-entrant)이 불가능해 시그널 핸들러에서 호출하면 교착 상태(Deadlock)나 데이터 손상이 생길 수 있습니다. 시그널 핸들러에서 안전한 대표적인 함수는 write(), _exit(), sig_atomic_t 전역 플래그 설정입니다. 전체 목록은 POSIX XSH Signal Actions 참조.

셸·유틸리티·빌드 도구

POSIX는 C API만 다루지 않습니다. 셸 명령어 언어와 표준 유틸리티도 큰 비중을 차지합니다. 커널 개발 환경에서 이 부분이 중요한 이유는 빌드 스크립트, 테스트 스크립트, initramfs 초기화 스크립트, 패키징 도구가 예상보다 자주 /bin/sh 이식성 문제를 일으키기 때문입니다.

영역POSIX가 정의하는 것Linux 현장에서 흔한 확장관련 문서
POSIX sh 문법, 리디렉션, 파이프, 확장 최소 집합Bash 배열, [[ ]], 프로세스 치환, localBash 셸 스크립팅, BusyBox
빌드make의 기본 규칙과 동작GNU Make 함수, 패턴 규칙 확장, 병렬 기능GNU Make, 빌드 시스템(Build System)
텍스트 처리sed, awk, grep, find, xargsGNU 전용 옵션, BusyBox 축약 구현, BSD 차이정규표현식, diff & patch
# POSIX sh 호환 예시: /bin/sh에서 동작하는 형태
set -eu

file="${1:-Makefile}"
if [ ! -r "$file" ]; then
    printf '읽을 수 없는 파일: %s\n' "$file" >&2
    exit 1
fi

case "$file" in
    *.c|*.h) printf 'C 계열 파일: %s\n' "$file" ;;
    *)       printf '기타 파일: %s\n' "$file" ;;
esac

count=0
for line in $(wc -l < "$file"); do
    count="$line"
done
printf '줄 수: %s\n' "$count"

위 스크립트는 Bash에서는 너무 평범해 보이지만, 핵심은 Bash 전용 문법에 기대지 않는다는 점입니다. 커널 트리의 많은 보조 스크립트는 이 수준의 보수성을 전제로 작성됩니다. /bin/sh가 bash가 아닐 수 있다는 사실을 기준으로 보면, POSIX 셸 문법이 왜 여전히 중요한지 바로 이해됩니다.

Linux와 POSIX의 차이

Linux는 POSIX를 많이 구현하지만 POSIX 그 자체는 아닙니다. 또한 실무에서는 POSIX 코어, XSI 옵션, GNU 확장, Linux 전용 API가 겹쳐 쓰입니다. 이 층을 분리하지 않으면 문서 설명도, 코드 리뷰도, 버그 재현도 모두 흐려집니다.

분류예시의미
POSIX 코어open(), read(), fork(), sigaction(), POSIX sh이식성 기준선으로 삼기 좋은 공통 인터페이스
XSI / 옵션 영역ucontext 계열 일부, X/Open 계열 기능, 특정 유틸리티 옵션구현 옵션 또는 추가 프로파일이라 모든 시스템에서 당연하다고 보면 위험
GNU 확장getline(), strdupa(), GNU Make 함수, Coreutils 장옵션GNU 환경에서는 흔하지만 다른 libc나 BSD 계열에서 깨질 수 있음
Linux 전용epoll, eventfd, signalfd, io_uring, pidfd, openat2강력하지만 문서와 코드에서 명시적으로 Linux 전용이라고 드러내야 함
POSIX 코어, GNU 확장, Linux 전용 API의 관계 POSIX 코어 open, read, write, fork, exec, sigaction pthread, poll, clock_gettime, POSIX sh make, sed, awk, find의 공통 부분 GNU 확장 getline, get_current_dir_name Bash 확장, GNU Make 함수, Coreutils 옵션 Linux 전용 epoll, eventfd, signalfd, timerfd, pidfd io_uring, openat2, memfd_create, clone3 커널 신기능을 빠르게 노출하지만 이식성은 낮음 이식성 최우선 기준선
그림 3. 표준 범위와 확장 범위를 문서에서 명확히 구분해야, 기능 설명과 이식성 기대치가 함께 맞습니다.

대표적인 예로 ioctl()은 POSIX에서 구체적 시맨틱을 강하게 규정한 인터페이스가 아닙니다. 반면 open()read()는 규정이 비교적 강합니다. 또 epoll은 Linux에서 사실상 표준처럼 쓰이지만 POSIX poll()의 대체 확장으로 이해해야 합니다. 문서에서 이런 층을 명시하지 않으면 독자가 "휴대 가능한 계약"과 "Linux 최적화 인터페이스"를 섞어 받아들이게 됩니다.

이식성 실전 예제

이식성은 거창한 목표가 아니라, 문제가 생겼을 때 범위를 좁히기 쉽게 만드는 작업입니다. 커널 개발자 입장에서는 테스트 코드와 보조 스크립트만 POSIX 중심으로 작성해도 재현 환경이 훨씬 넓어집니다.

상황휴대성 높은 선택Linux 전용 선택권장 전략
이벤트 대기poll(), pselect()epoll, io_uring기준 경로는 POSIX로 두고, 성능 경로를 Linux 전용으로 분리
타이머clock_gettime(), timer_create()timerfd기본 시맨틱 설명은 POSIX, 이벤트 루프(Event Loop) 최적화는 Linux 별도 문단
파일 공유shm_open(), mmap()memfd_create()표준 경로와 익명 메모리 파일 확장을 문서에서 분리
프로세스 제어fork(), waitpid()pidfd_open(), clone3()재현용 예제는 POSIX 우선, 관리 자동화는 Linux 확장 허용
셸 스크립트POSIX sh 문법Bash 확장/bin/sh 대상인지 명확히 선언
/* Linux 확장 대신 POSIX 우선 경로를 잡는 예시 */
#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <unistd.h>

int wait_for_input(int fd, int timeout_ms)
{
    struct pollfd pfd;

    pfd.fd = fd;
    pfd.events = POLLIN;
    pfd.revents = 0;

    for (;;) {
        int ret = poll(&pfd, 1, timeout_ms);
        if (ret >= 0)
            return ret;
        if (errno != EINTR)
            return -1;
    }
}

이 코드는 Linux에서 epoll보다 느릴 수 있지만, 인터페이스 계약은 단순하고 넓게 호환됩니다. 커널 버그 재현이나 최소 예제에서는 이런 코드가 훨씬 가치가 큽니다. 반대로 고성능 서버 경로에서는 Linux 전용 API를 적극 써도 되지만, 그 사실을 문서와 코드 주석에서 숨기지 말아야 합니다.

자주 틀리는 지점

오해왜 틀렸는가올바른 관점
"POSIX 함수는 전부 시스템 콜이다"많은 함수는 libc 조합 또는 스레드 라이브러리와 커널 기능의 결합입니다표준 인터페이스, libc 구현, Linux syscall을 분리해서 말해야 합니다
"Linux에서 되니까 POSIX일 것이다"Linux는 강력한 전용 API를 많이 제공합니다pidfd, epoll, io_uring 같은 확장은 별도로 표시합니다
"rename()만 하면 영속성이 보장된다"표준은 저널 구현이나 저장 장치 flush를 그렇게 단순하게 보장하지 않습니다파일시스템 문맥과 fsync() 요구를 함께 설명해야 합니다
"EAGAIN과 EWOULDBLOCK은 항상 같은 값이다"Linux에서는 같지만 POSIX는 다를 수 있음을 허용합니다이식성 있는 코드는 둘 다 검사합니다
"POSIX sh는 Bash의 부분집합이니 아무 Bash 문법이나 써도 된다"[[ ]], 배열, 프로세스 치환은 POSIX가 아닙니다/bin/sh 대상이면 POSIX 문법만 사용합니다
"POSIX는 Linux 커널 내부 자료구조까지 정한다"표준은 결과와 인터페이스 계약을 정의합니다구현 알고리즘과 자료구조는 커널 설계 선택입니다
문서 작성 기준: 앞으로 이 사이트에서 어떤 인터페이스를 설명할 때 POSIX 표준, GNU 확장, Linux 전용 중 어디에 속하는지 먼저 밝히면 독자의 기대치를 정확히 맞출 수 있습니다. 커널 문서에서 이 층 분리를 해두면 성능 최적화 설명과 이식성 설명이 서로 충돌하지 않습니다.

POSIX.1-2024 (Issue 8) 핵심 변경 요약

IEEE Std 1003.1-2024 / The Open Group Base Specifications Issue 8은 2024년 6월 14일에 공식 발행되었습니다. 직전 버전인 Issue 7 (POSIX.1-2008, 2017년 수정판 포함)과 비교해 약 7년 만의 메이저 갱신이며, 이 7년 동안 glibc/musl/Linux syscall 생태계에 관습적으로 정착된 다수의 API가 표준에 편입되었습니다.

한 줄 요약: ppoll(), pthread_mutex_clocklock(), strlcpy/strlcat, getentropy(), memset_explicit() 등 과거 GNU/BSD 확장이던 함수들이 표준 함수가 되었고, 언어 바인딩 기준이 C11 → C17로 갱신되었습니다.

문서 구조와 공개 방식

표준화된 주요 신규 인터페이스

함수/유틸이전 출처Issue 8 의미
ppoll()Linux/glibc 확장시그널 마스크와 함께 타임아웃 poll 표준화
pthread_mutex_clocklock() / pthread_cond_clockwait()glibc 2.30+ GNU 확장CLOCK_MONOTONIC 기반 락 대기 표준화
strlcpy() / strlcat()OpenBSD 유래길이 안전 문자열 복사가 표준 — 커널 문자열 관용 그대로
getentropy()OpenBSD/glibc 확장/dev/urandom 수준 엔트로피를 표준 인터페이스로 제공
memset_explicit()C23 유래컴파일러가 제거할 수 없는 시큐어 zero-fill
posix_getdents()없음(신규)이식성 있는 디렉터리 엔트리 열거 — Linux getdents64의 표준판
futex_* 계열 (제한적)Linux 전용경량 동기화 프리미티브의 표준 플래그 일부 반영
SCCS 관련 유틸리티Issue 7까지 남아있던 레거시Issue 8에서 삭제
gettimeofday(), asctime/ctime지원Issue 8에서 obsolescent로 강등 — clock_gettime(), strftime() 사용 권장

C 언어 정합성 갱신

셸 · 유틸리티 주요 변경

2026 시점 Linux와 POSIX의 간극

기능Linux 제공POSIX 상태
io_uring5.1+ 완전 구현표준 미편입 — 차기 Issue 후보
pidfd_*5.3+ 완비미편입 — 프로세스 핸들 추상화 논의 중
epoll, inotify, signalfd, timerfd표준 Linux미편입 — POSIX는 poll/sigwaitinfo로 커버
statx()4.11+미편입 — stat() 계열 유지
clone3()5.3+미편입
mseal()6.10+ 신규미편입 — 메모리 보호 분야에서 표준화 논의
이식성 작성 원칙: 2026 시점에서 POSIX-portable 코드를 목표로 한다면, Linux 전용 API(io_uring, epoll 등)는 feature-test 매크로 __linux__ 블록 안에 두고, poll()/pthread 기반 대안을 동일 인터페이스로 제공하는 것이 현실적입니다. 반대로 "이식성 필요 없음"이 명확한 커널 tools/ 코드라면 Issue 8 준수보단 Linux native API가 항상 더 빠르고 풍부합니다.

참고자료

다음 학습:
  • 시스템 콜 — POSIX 인터페이스가 Linux syscall 경계와 어떻게 연결되는지 상세히 봅니다.
  • VFS — POSIX 파일 시맨틱이 커널 내부에서 어떤 구조로 구현되는지 확인합니다.
  • Bash 셸 스크립팅 — POSIX sh와 Bash 확장의 실제 차이를 실전 코드로 비교합니다.