- 객체 지향 디자인 패턴은 C 언어로 작성된 커널에서도 다형성과 모듈성을 구현해 유연한 시스템 설계를 가능하게 함
- vtable(가상 함수 테이블)을 사용해 장치와 서비스의 인터페이스를 표준화, 런타임 동적 변경으로 다양한 동작 지원
- 커널 서비스와 스케줄러는 vtable을 통해 시작, 중지, 재시작 같은 일관된 인터페이스를 제공하며 구현 세부 사항을 캡슐화
- 커널 모듈과의 결합으로 동적 드라이버 로딩을 지원, 재컴파일 없이 시스템 확장 가능
- 이 접근법은 유연성과 실험적 자유를 제공하지만, 복잡한 구문과 명시적 객체 전달로 인한 번잡함이 단점으로 작용
OS 개발에서의 자유와 객체 지향 패턴
- 자신만의 OS 개발은 협업이나 실제 응용의 제약 없이 자유로운 실험 가능
- 보안 취약점, 코드 유지보수, 릴리스 부담에서 자유로움
- 이는 OS 개발의 매력으로, 비표준 프로그래밍 패턴 탐구 가능
- LWN 기사 “Object-oriented design patterns in the kernel”에서 Linux 커널이 C로 객체 지향 원칙을 구현한 사례 소개
- 함수 포인터를 포함한 구조체로 다형성 구현
- 캡슐화, 모듈성, 확장성을 통해 저수준 커널에서도 객체 지향 이점 활용
vtable의 기본 개념
- vtable은 함수 포인터를 포함한 구조체로, 객체의 인터페이스 정의
- 예: 장치 동작을 위한 구조체
struct device_ops { void (*start)(void); void (*stop)(void); }; struct device { const char *name; const struct device_ops *ops; };
- 예: 장치 동작을 위한 구조체
- 서로 다른 장치(예:
netdev,disk)가 동일한 API를 사용, 구현은 다름netdev.ops->start()는 네트워크 장치,disk.ops->start()는 디스크 장치 동작 호출
- 런타임 변경: vtable을 동적으로 교체해 호출자 코드 변경 없이 동작 변경
- 적절한 동기화로 깔끔한 동적 동작 진화 제공
OS에서의 적용 사례
서비스 관리
- 커널 서비스(네트워킹 매니저, 워커 풀, 윈도우 서버 등)를 일관된 인터페이스로 관리
- 서비스 구조체:
struct service_ops { void (*start)(void); void (*stop)(void); void (*restart)(void); }; struct service { pid_t pid; const struct service_ops *ops; };
- 서비스 구조체:
- 각 서비스는 고유한 동작을 구현하되, 터미널에서 시작/중지/재시작을 표준화된 방식으로 실행
- 코드와 서비스 간 결합도 감소, 관리 간소화
스케줄러
- 스케줄러는 라운드 로빈, 최단 작업 우선, FIFO, 우선순위 스케줄링 등 다양한 전략 지원
- 인터페이스는
yield,block,add,next로 단순화 - vtable로 정의해 런타임에 스케줄링 정책 교체 가능
- 커널 나머지 부분 수정 없이 전체 정책 변경 가능
- 인터페이스는
파일 추상화
- Linux의 file_operations 구조체는 “모든 것이 파일” 철학 구현
- 예: https://elixir.bootlin.com/linux/v6.15/source/include/linux/fs.h
struct file_operations { struct module *owner; loff_t (*llseek)(struct file *, loff_t, int); ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); ... };
- 예: https://elixir.bootlin.com/linux/v6.15/source/include/linux/fs.h
- 소켓, 장치, 텍스트 파일 모두 동일한 read/write 인터페이스 제공
- 사용자 공간 코드는 구현 세부 사항을 알 필요 없이 일관된 방식으로 동작
커널 모듈과의 결합
- 커널 모듈은 vtable 교체로 동적 드라이버나 훅 로딩 지원
- Linux 모듈처럼, 재컴파일이나 재부팅 없이 커널 확장 가능
- 새로운 기능 추가 시 기존 구조체의 vtable만 업데이트
단점
- 구문 복잡성:
object->ops->start(object)처럼 객체를 명시적으로 전달해야 함- C++의 암묵적 전달에 비해 번잡함
- 함수 시그니처도 장황:
static void object_start(struct object* this) { this->id = ... }
- 장점: 명시적 전달로 함수의 의존성 명확, 객체와 동작 간 결합 투명
- 커널 코드에서 복잡성과 명확성 간의 적절한 tradeoff
시사점
- vtable은 유연성을 유지하며 복잡성을 줄이는 간단한 방법 제공
- 런타임 동작 교체, 일관된 인터페이스 유지, 새로운 기능 추가 용이
- C 언어로 객체 지향 설계를 구현하는 새로운 방식 제공, OS 개발의 실험적 재미 강조
- 추가 자료: xine 프로젝트(https://xine.sourceforge.net/hackersguide#id324430)는 vtable로 비공개 변수 관리 방법 소개
- OS 개발은 창의적 실험의 장으로, 객체 지향 패턴이 저수준 시스템에서도 강력한 도구임을 증명