Linux System Calls
File descriptor I/O ->리눅스는 posix interface를 따른다.
• open(); close(); creat(), read(); write();
• seek(); // random access
• fcntl(); // for file/record locking
Process control
Thread programming
IPC
Signal handling
Memory management
Synchronization
Time management
Network socket API (TCP, UDP)
System Calls & Library Calls for File I/O
System Calls for File descriptor I/O
• open(); close(); creat(), read(); write();
• seek(); // random access • fcntl(); // for file/record locking
Library Calls for File I/O
• fopen(); freopen(); fclose(); fread(); fwrite();
• fgetc(), fgetchar(); fputc, putchar(); …
• fseek(), fprintf(); fscanf();.
System Calls vs. Library Calls
커널영역 유저영역으로 나뉘어짐.
System Calls
- OS에서 제공하는 함수 그대로임.
- kernel code로 들어가는 진입점
- documented in section 2 of the linux manual(e.g. write(2) or man 2 write)
library call 안에는 system call이 있는 것
Library Calls - 유저레벨 라이브러리
- transfers to user code which performs the desired functions.
- documented in section 3 of the linux manual(e.g. printf(3))
- API(application programming interface)라고도 불린다
- 쓰는 이유? 바로 system call 로 불러서 OS 에서 제공하는 기능보다 더 효율적인 기능을 라이브러리화 해서 제공
Library
A set of compiled object functions for reuse
• e.g. Graphic Lib., Mathematical Lib., etc.
• 리눅스에, 일반적으로 “/lib” 나 “/usr/lib” 에 위치함.
• 필요한 function(obj) 만 유저 프로그램에 link됨
Compile & Linking (review)
Library의 종류
• Shared library (*.so, *.dll)
– 오직 하나의 copy of the function이 메모리에 있다. the function은 여러개의 프로세스들 사이에서 공유 됨.
(memory saving)
– function의 주소는 런타임내에 해결됨.(called dynamic linking or binding)
– A symbol table for the dynamic linking 은 memory에 있음. (memory overhead).
– 서버시스템에서 유용함.
• Static library (*.a)
- 실행파일에다가 코드를 임베딩시키는 방식
– 필요한 function들은 각 binary 프로그램에 추가되어(link되어) 있음.
– 그래서 여러개의 같은 copies of a function이 메모리에 있다.
(overhead)
– 임베디드 시스템에서 유용함.
shared library일 때
-> 라이브러리 파일을 메모리에 상주시켜놓고 필요한 프로그램마다 공유시킨다
실행파일은 link로 가져온다.(Dynamic linking 시스템)
라이브러리는 실행이 안되더라도 떠있어야함.(메모리를 점유하게 됨)
static library일 때
-> 실제 개발되는 각각의 프로그램(실행파일)에 라이브러리 파일이 들어감.
그러다 보니 실행파일 크기 자체는 커질 수 있음.
하지만 필요한 부분만 들어가서 메모리를 효율적으로 쓸 수 있음.(실행도 더 빠를 수 있음)
Standard I/O Library
<stdio.h>
• Standard I/O Library의 기호와 API를 정의하는 헤더 파일. (usually for console and files)
• fopen fclose fread fwrite fflush fgetc 등이 있음
FILE* 포인터 형태로 넘겨받아서 대상이 되는 파일에 대해 I/O를 수행할 수 있음.
File I/O with the standard I/O library
• I/O devices are mapped to special files
– 리눅스 시스템에서는 특별히 파일 포인터 3개를 제공
-> Console terminal: stdin(표준입력), stdout(표준출력), stderr(표준에러)
– 콘솔파일은 자동으로 런타임에 열릴 것임. will be automatically open at run-time.
FILE object in C
I/O stream object created by standard I/O library
• 포인터 FILE* 에 의해 접근됨.
• 파일 스트림 포인터는 열린 파일을 지정하는데 사용됨
• 파일포인터는 열린 파일의 여러 시스템 정보를 가지고 있음.
stdin, stdout, stderr
• 콘솔의 3개의 instance를 위한 파일 스트림 포인터
• 이미 shell에 의해 열리고, 사용자 프로그램으로 상속됨.
File descriptor
I/O를 위한 OS system call
• file descriptors 사용 (NOT FILE*)
• 열린파일에 대한 a file descriptor는 정수
• descriptors 0,1,2 는 stdin, stdout, stderr에 할당됨.
• 유저의 열린 파일에 대해서, file descriptors 는 3부터 오름차순으로 할당됨.
– 일반적으로 사용자는 최대 1024개의 파일을 열 수 있다.
표준 I/O 라이브러리 함수는 최종적으로 적절한 system call을 호출함
• printf, fprintf, puts, ..... -> call write()
왜 표준 I/O 라이브러리를 쓸까?
• 단순한 시스템 호출보다 더 편리
• formatting이 되어있음, library buffering, ..
File stream & File Descriptor
대상이 되는 파일은 하나지만 유저레벨에서는 이걸 system call로 쓸건지 library call로 쓸건지 두가지 사용 측면이 있음
file stream pointer로 받았으면 file descriptor로 바꿔서 system call을 바로 불러서 사용할 수도 있고
file descriptor를 file stream pointer로 바꿔서 library I/O를 이용해 동작할 수도 있음.
file stream은 file descriptor와 일대일 mapping이 된다.
따라서 우리는 다음과 같은 함수로 각각의 counterpart 정보를 얻을 수 있다.
• 열린 FILE stream에 대해 file descriptor (number)를 반환
• 열려 있는 파일의 file descriptor를 사용하여 FILE 스트림을 만들고 반환
Library buffering
library call와 system call 의 차이점은 버퍼링에 대한 것임.
버퍼란?
읽고쓰기를 할때 완충이 되는 역할을 하는 영역. 데이터를 임시 저장할 수 있는 메모리 공간.
버퍼에 데이터를 모아서 한번에 처리(write 등)하기 위함.
Library buffering
• 라이브러리에 의한 유저 레벨 버퍼링 (i.e. user program)
• system calls의 수를 줄인다. e.g. “DEL” key processing in keyboard input
Full buffering
버퍼의 크기를 잡아놓고(디스크 블록 몇 개쯤) 프로그램의 효율을 높임
I/O에 해당하는 크기만큼 버퍼를 가짐
fflush를 이용해서 버퍼를 가득 안채우고 데이터를 뺌
• lib-level buffer for disk blocks (multiple KBs)
• significantly reduce system calls.
• For synchronization with the kernel , fflush() can be used.
-> 버퍼링 개념에서 많이 모아서 한꺼번에 내보낼수록 성능은 좋아짐. I/O 횟수가 줄어드니까!
하지만 문제점이라면 유저레벨에서 데이터를 쌓아두면(버퍼시간이 길어질수록) 정전 시에 데이터를 잃어버릴 우려가 있음.
Line buffering
• console I/O할 때 주로 사용
• 실제적인 I/O는 “newline” (enter) 가 나타날 때 일어남
• getchar() problem
– enter 입력되기 전까지 character가 전달 안됨.
Unbuffering
• library buffer 를 사용하지 않음. 데이터를 한 character 쓰자마자 OS 레벨에 데이터를 전송.
• system call로 직접적으로 전달됨.
• 정전 시에 안전함
-> 빈번한 유저레벨과 시스템 사이의 IO 횟수가 발생한다면 프로세스 입장에서는 안좋음 -> 성능 저하 우려
file stream 중에 특별한 게 3가지 있다고 했었음.
각각 어떤 버퍼가 적용되어 있는가?
Linux library buffering
• stderr: always unbuffering
• stddin / stdout: always line buffering
• anything else: always full buffering (by default)
근데 버퍼링을 지정할 수 있음
Set Buffering Type
setbuf 함수를 이용
따로 버퍼를 지정해주지 않으면 full buffering임.
setvbuf는 버퍼링의 타입을 지정해줄 수 있음.
여기까지는 유저레벨에서 라이브러리가 하는 버퍼링
Kernel Buffering
OS 의 kernel 에서도 버퍼나 캐시 정책을 써서 데이터 모아서 한번에 처리하도록 함.
Kernel buffering
• 커널에 의한 소프트웨어 캐싱
• page cache 페이지 캐시 (buffer cache 버퍼 캐시): disk I/Os를 줄이기 위함
e.g. 빈번히 사용되는 disk block들은 커널 메모리에 저장됨 (page cache 페이지 캐시)
• disk로 부터 읽을 때 – try page cache first, if fail do the disk I/O.
• disk에 쓸 때 – write the bytes into the cache, sync to the disk later. (called “delayed write”)
fflush
가득 차지 않았을 때에도 버퍼링 된 데이터를 쓰게 해주는 것(내려보내는 것)
• 커널로 라이브러리 버퍼 내용을 flush out 함. (synchronization)
• 버퍼링 때문에, printf (…) 은 실제적인 output을 보장하지 않는다.(why?)
• 따라서 디버깅을 위해서, 다음과 같은 코드 작성
printf(“something”);
fflush(stdout);
for block device I/O (e.g. disk)
• in block device, a transfer unit b/w disk and kernel is in KBs
• fflush() 는 contents를 “lib. buffer” 에서 “page cache”로 !
• 따라서 disk synchronization(동기화)를 원한다면, sync() 사용
파일을 닫으면, fflush() 이 자동으로 끝난다.
I/O buffering & Sync
라이브러리 버퍼는 유저레벨에 있고
커널 레벨에는 버퍼 캐시 혹은 페이지 캐시라고 불리는 버퍼가 존재함
kernel buffer cache 에 있는 건 주기적으로 disk로 내려감.
하지만 이걸 완전히 보장해주고 싶으면 유저레벨에서 fsync() 나 sync() 를 불러주면 동기화 시켜서 데이터를 무조건 disk로 내려보냄.
File Open
파일을 open 하는 함수이다
r : 읽기만 가능
w : write 위해 파일길이를 0으로 줄이거나 파일을 생성함
a : append mode(EOF), 쓰기 전용. 파일이 없는 경우 생성됨.
r+ : read/write
w+ : read&write 위해 파일길이를 0으로 줄이거나 파일을 생성함
a+ : read/append mode(EOF). 파일이 없는 경우 생성됨.
열린 파일의 수는 제한이 있다.(system configuration에 의해)
File Reopen
열려있는 파일을 재오픈 하고 싶을 때
• first, close a file linked to the input stream (3rd arg)
• and open a file with a given filename by reusing the old stream
• NOTE: the original file descriptor is also reused! Example
freopen("myfile.txt", "w", stdout);
printf("This sentence is redirected to a file.");
fclose(stdout);
• guess what will happen in this code!
File Close
When a process exits normally, all files are automatically closed.
If a process is terminated without closing a file,
• cannot check some errors that are reported by the fclose().
• file data in the library buffer might be lost
File I/O functions
Character Input
getc 는 매크로로 만들어져 있는 함수
fgetc는 함수가 라이브러리 형태로 구현되어 있다
getchar는 콘솔의 입력을 받을 때 사용
getc(stdin) = getchar()
Character Output
File I/O example
Line I/O example (1)
Array I/O example
Struct I/O example
File copy with Full buffering
File Offset
모든 열린 파일들은 파일에서 다음으로 접근할 위치를 가리키는 a (r/w) offset 를 가진다.
• 파일이 reading/writing 을 위해 열렸을 때, the offset 은 파일의 시작점에 세팅됨.
• 파일이 appending 을 위해 열렸을 때, the offset 은 파일의 끝점에 세팅됨
• reading/writing 할 동안, the offset 은 자동으로 증가
File Access Methods
Sequential access
• sequential access by following the r/w offset
Random access
• fseek() 라이브러리 함수를 호출함으로써 원하는 접근 위치로 offset을 이동시킨다.
– or by lseek() system call,
• mainly used for record processing.
cf. Keyed access
• Access a record of a DB by a key,
• A internal index tree of a DB is necessary.
R/W offset related functions
SEEK options
• SEEK_SET: new r/w offset = offset 파일의 시작위치
• SEEK_CUR: new r/w offset = current_offset + offset 현재위치
• SEEK_END: new r/w offset = EOF + offset 마지막위치
Random access example
I/O Types
Unformatted I/O (Binary I/O)
메모리에 써있는 형태 그대로를 씀
• I/O in binary format (memory representation).
integer : 4 byte, signed two’s complement.
float: 4 bytes, “sign + exp(8-bit) + mantissa(23-bit)”.
double: 8 bytes, “sign + exp(11-bit) + mantissa(52-bit)”.
• a user’s viewer program must be supported.
Formatted I/O
특별한 형태로 포매팅해서 IO를 함
• output: integer, float, double -> output in an ASCII string
• input: ASCII string input -> integer, float, double (scan conversion)
• e.g. %5d: integer to decimal ASCII string (5 digits)
%f: 12.43
• file contents can be seen by “cat file”.
Formatted Output
Formatted Input
Formatted I/O example
File error check
파일에 어떤 에러가 났는지
File error check example
EOF check example
Error handling
특정 파일에 여러 에러가 발생할 수 있는데
strerror 는 해당 에러 메세지를 string 형태로 반환하고
perror 는 가장 최근의 에러 메세지를 출력한다.
Error Handling:
• meaningful return values
• errno variable – must include