→ "한 페이지는
VM_UNINIT
,VM_ANON
,VM_FILE
라는 세 가지 종류 중 하나입니다. 하나의 페이지는swap in
,swap out
, 그리고 페이지 삭제같은 여러 동작을 수행하게 됩니다.
페이지의 타입별로 이러한 동작을 하기 위해 요구되는 단계와 작업들이 다릅니다. 즉,VM_ANON
페이지와VM_FILE
페이지는 서로 다른 destroy 함수를 호출합니다. 이를 위해 switch-case 구문을 활용해서 각 케이스에 맞는 함수를 사용하는 방법이 하나 있습니다.
우리는 이 문제를 해결하는 방법으로 객체 지향 프로그래밍의 컨셉인 “클래스 상속”을 소개하려고 합니다.
실제로 C 언어에서는 클래스와 상속이라는 개념은 없지만, 우리는 이 개념을 이해하기 위해 함수 포인터를 사용할 것입니다. 이 방법은 리눅스같은 실제 운영체제 코드에서 사용되는 방법과 유사합니다."
PintOS Project 3주차 과정 중 재미있는 내용이 있어서 간단하게 글을 작성해보려고 한다. 💡
요지는 pintOS의 VM 부분에서 page 객체를 사용할 때 절차 지향 언어인 C언어를 사용해서 객체 지향 언어의 상속(inheritance) 개념을 사용하는 것이다.
구분 | 절차 지향 프로그래밍 (Procedural Programming) | 객체 지향 프로그래밍 (Object-Oriented Programming) |
---|---|---|
중심 요소 | 함수와 명령어 | 객체와 클래스 |
데이터 접근 | 변수와 함수로 접근 | 캡슐화를 통해 데이터 접근 제어 |
재사용성 | 함수 단위로 재사용 | 클래스와 객체 단위로 재사용 |
유지보수성 | 코드가 복잡해지면 유지 보수의 어려움 | 클래스 구조를 통해 유지보수 용이 |
모델링 | 절차적 문제 해결 방식 | 현실 세계의 객체를 모델링 하기 적합 |
1. 클래스 (Class)
객체를 정의하기 위한 청사진(Template) 또는 설계도.
- 그림에서
onAnimal
이 최상위 클래스onAnimal
클래스는 모든 동물들이 공통으로 가지는 속성 (brain = true
,legs=0
)과 동작(메서드가 있다면)을 정의.
2. 인스턴스 (Instance)
클래스를 기반으로 생성된 실제 객체
- ex)
oHuman
,oDog
,oCat
등은 각각oAnimal
클래스로부터 생성된 인스턴스들- 각 인스턴스는 기본적으로 클래스의 속성과 메서드를 공유하지만, 고유한 값을 가질 수도 있음.
- ex)
oHuman
의legs=2
,oDogs
의fleas = 8
3. 상속 (Inheritance)
기존 클래스의 속성과 메서드를 다른 클래스가 물려받는 OOP의 핵심 기능.
- 그림에서
oHuman
과oPet
은oAnimal
을 상속받아brain
과legs
속성을 공유.oDog
와oCat
은oPet
을 상속 받아,legs=4
를 공유하지만 각자의 고유 속성 (ex.fleas
)을 추가적으로 정의
/* vm/vm.h */
struct page {
const struct page_operations *operations;
void *va; /* Address in terms of user space */
struct frame *frame; /* Back reference for frame */
/* Per-type data are binded into the union.
* Each function automatically detects the current union */
union {
struct uninit_page uninit;
struct anon_page anon;
struct file_page file;
#ifdef EFILESYS
struct page_cache page_cache;
#endif
};
};
vm/vm.h
에 위와 같이 struct page
가 정의되어 있다.
재미있는 점은, union
구조체를 사용해서 해당 page의 상태에 따라 요소를 달리 갖는데, 이 때 해당 상태에 따라 사용하는 '함수'까지 바꿀 수 있다는 것이다.
/* vm/vm.h */
struct page_operations {
bool (*swap_in)(struct page *, void *);
bool (*swap_out)(struct page *);
void (*destroy)(struct page *);
enum vm_type type;
};
struct page
구조체 안에는 위와 같이 struct page_operations
라는 구조체가 정의되어 있다.
안에는 swap_in()
, swap_out()
, destroy()
각 함수에 대한 포인터가 정의되어 있다.
uninit.c
의 uninit_ops
/* vm/uninit.c */
static const struct page_operations uninit_ops = {
.swap_in = uninit_initialize,
.swap_out = NULL,
.destroy = uninit_destroy,
.type = VM_UNINIT,
};
anon.c
의 anon_ops
/* vm/anon.c */
static const struct page_operations anon_ops = {
.swap_in = anon_swap_in,
.swap_out = anon_swap_out,
.destroy = anon_destroy,
.type = VM_ANON,
};
file.c
의 file_ops
/* vm/file.c */
static const struct page_operations file_ops = {
.swap_in = file_backed_swap_in,
.swap_out = file_backed_swap_out,
.destroy = file_backed_destroy,
.type = VM_FILE,
};
추천글: https://velog.io/@gomjellie/C%EC%9D%98-%EA%B0%9D%EC%B2%B4
It Seems Like... 🤔
// Page.java
public class Page {
private PageOperations operations;
private Object va; // Address in terms of user space
private Frame frame; // Back reference for frame
// Union-like structure for different page types
private UninitPage uninit;
private AnonPage anon;
private FilePage file;
private PageCache pageCache; // Optional, for EFILESYS
public Page(PageOperations operations, Object va, Frame frame) {
this.operations = operations;
this.va = va;
this.frame = frame;
}
// Getters and setters
public PageOperations getOperations() {
return operations;
}
public void setOperations(PageOperations operations) {
this.operations = operations;
}
// Other getters and setters for uninit, anon, file, and pageCache
}
// PageOperations.java
public interface PageOperations {
boolean swapIn(Page page, Object aux); // Corresponds to swap_in
boolean swapOut(Page page); // Corresponds to swap_out
void destroy(Page page); // Corresponds to destroy
VMType getType(); // Corresponds to type
}
// UninitOps.java
public class UninitOps implements PageOperations {
@Override
public boolean swapIn(Page page, Object aux) {
return Uninit.initialize(page, aux); // Assuming Uninit.initialize is a method
}
@Override
public boolean swapOut(Page page) {
return false; // NULL equivalent in C
}
@Override
public void destroy(Page page) {
Uninit.destroy(page); // Assuming Uninit.destroy is a method
}
@Override
public VMType getType() {
return VMType.VM_UNINIT;
}
}
// AnonOps.java
public class AnonOps implements PageOperations {
@Override
public boolean swapIn(Page page, Object aux) {
return Anon.swapIn(page, aux); // Assuming Anon.swapIn is a method
}
@Override
public boolean swapOut(Page page) {
return Anon.swapOut(page); // Assuming Anon.swapOut is a method
}
@Override
public void destroy(Page page) {
Anon.destroy(page); // Assuming Anon.destroy is a method
}
@Override
public VMType getType() {
return VMType.VM_ANON;
}
}
// FileOps.java
public class FileOps implements PageOperations {
@Override
public boolean swapIn(Page page, Object aux) {
return FileBacked.swapIn(page, aux); // Assuming FileBacked.swapIn is a method
}
@Override
public boolean swapOut(Page page) {
return FileBacked.swapOut(page); // Assuming FileBacked.swapOut is a method
}
@Override
public void destroy(Page page) {
FileBacked.destroy(page); // Assuming FileBacked.destroy is a method
}
@Override
public VMType getType() {
return VMType.VM_FILE;
}
}
주요 사용 사례:
- 파일 시스템 (VFS: Virtual File System)
https://www.kernel.org/doc/html/latest/filesystems/vfs.html
https://www.kernel.org/doc/html/latest/filesystems/api-summary.html#c.file- 장치 드라이버 모델
- 네트워크 프로토콜 스택
struct file_operations {
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
int (*open)(struct inode *, struct file *);
int (*release)(struct inode *, struct file *);
...
};
struct file {
const struct file_operations *f_op;
void *private_data;
...
};
file_operations
구조체는 File System 관리를 위한 함수들의 테이블로 역할하고, 이를 상속 받아 하위 함수들로 동작한다.union
자료형에 대해서
학과 시절
'H/W가 지금처럼 발전하기 이전에, 메모리 용량 문제를 해결하기 위한 방법 중 하나로 주로 사용되었고, 태생적으로 단편화 문제를 갖고있기 때문에 H/W가 고도로 발전한 현재에는 굳이 잘 사용하지 않는 자료형이다.'
라고 배웠었다.
→ 'C언어에서 구조체 안에
union
변수를 정의 해 다형성을 흉내내는 설계를 할 수 있구나'
→ 학과에서도 안가르쳐주는, 하위 자료형을 가지고 또 새로운 고차원적인 구조를 만드는 방법에 대해 학습할 수 있었다.
JAVA와 같은 객체 지향 프로그래밍 언어도 '문법적으로는 다르지만, 내부적으로 상속이나 다형성 등 개념을 구현하는데에 있어서는 우리가 위에서 작성한 C코드처럼 결국 메모리 참조를 기반으로 이루어지겠구나!' 라는 것을 몸으로 체감할 수 있었다.
→ 단, C언어에서는 우리가 직접 주소를 다루었다면, JAVA에서는 JVM(JAVA Virtual Machine)이 메모리 관리를 자동화 해주는 등의 차이는 있다.
Linux와 같이 실제 상용화 되고 있는 운영체제 같은 경우에도 위와 같은 구조를 사용하고 있다!
→ '현실 세계에서 기능하는 어떤 서비스의 일부 형식을 내가 배우고 있구나.' 하는 자각에서 오는 즐거움을 느낄 수 있었다.
- [WIL] PintOS 프로젝트와 함께 알아보는: Interrupt Frame, TCB, PCB
https://velog.io/@takealittletime/WIL-PintOS-프로젝트와-함께-알아보는-Interrupt-Frame-TCB-PCB
PintOS Project Official GitBook
https://casys-kaist.github.io/pintos-kaist/project3/vm_management.html
나무위키::절차 지향 프로그래밍
https://namu.wiki/w/%EC%A0%88%EC%B0%A8%EC%A0%81%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D?
나무위키::객체 지향 프로그래밍
https://namu.wiki/w/%EA%B0%9D%EC%B2%B4%20%EC%A7%80%ED%96%A5%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D
객체지향 vs 절차지향 프로그래밍
https://blog.naver.com/pcs9569/221564276991
객체지향 프로그래밍에 대한 이해
https://velog.io/@gparkkii/oop00
객체지향 프로그래밍이란?
https://jongminfire.dev/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80