File I/O

Update:     Updated:

Category:

Tags:


System Calls


  • System Call : kernel mode로 전환해서 OS에게 필요한 작업을 요청

    -> 매우 expensive : 한 번 호출하는데 많은 절차와 시간 요구

    -> 하드웨어에 접근하기 위해서 반드시 수행해야 하는 단계

  • Function Call : mode switch 없이 함수를 호출 (일반적인 user libraries, functions)

image


Steps for System Calls

한 번 시스템 호출하는데 필요한 단계 : 11 steps (= expensive)

image

  1. program pushed arguments, calls library
  2. library sets up trap, calls OS
  3. OS handles system call
  4. Control returns to library
  5. Library returns to user program

-> 순서 : 프로세스가 System call을 호출하면 interrupt가 발생하여 kernel 모드로 진입. 그 후 요청으로 들어온 System call을 수행하고, return-from-trap을 발생시켜서 user 모드로 돌아가 결과를 반환.


Examples of System Calls

시스템 함수는 파일 관리, 프로세스 관리 등의 목적으로 사용된다.

  • File Management 관련 시스템 함수
    • open(2) : 새로운 파일 열기
    • close(2) : 열려 있는 파일 닫기
    • read(2) : 파일 내용 읽어오기 (-> buffer)
    • write(2) : 파일에 내용 작성하기 (<- buffer)
    • lseek(2) : 파일 pointer 이동
    • stat(2) : 파일 정보 가져오기
  • Process Management 관련 시스템 함수
    • fork(2) : 새로운 child process 생성하기
    • execve(2) : 새로우 프로그램 실행하기
    • waitpid(2) : child process가 종료될 때까지 기다리기
    • exit(2) : 프로세스를 종료하고 status를 반환


System Calls for I/O


  • Unix I/O : system-level I/O functions
  • other languages : ANSI C (standard I/O library), C++ (< <, > > 연산자)

UNIX I/O Overview

  • Unix file : sequence of m bytes

    image

  • Unix/Linux는 “everything as file”로 취급
    • I/O device : /dev/tty2
    • kernel : /dev/kmem

    -> 모두 비슷하게 파일로 취급, input과 output 다루는 방식도 동일함

  • Unix I/O (= unbuffered I/O, System-level I/O)

    : 파일과 시스템 장치들을 연결해주는 역할 (kernel)


File Descriptors (= File Handle)

파일을 열 때마다 부여되는 non-negative integer number로, kernel은 파일을 fd로 구분

  • 표준 입출력 File Descriptor (unistd.h에 정의)
    • STDIN_FILENO : 0
    • STDOUT_FILENO : 1
    • STDERR_FILENO : 2 -> magic number보다는 macro를 사용하는 것이 좋다
  • 새로 열린 파일 File Descriptor : 3부터 시작

    ex. fds.c : 파일을 open했을 때 저장되는 file descriptors 확인하는 코드

image

  • File Sharing : 두 개의 독립적인 프로세스가 하나의 i-node table 가르키는 경우

    -> fork를 통해 child 프로세스 생성하면, parent 프로세스의 open file 그대로 상속

image


open(2) : Opening a file

새로운 또는 기존의 파일을 열 때 사용, fcntl.h 헤더에 포함된 시스템 콜 함수

#include <fcntl.h>
int open(const char &pathname, int oflag /*, mode_t mode */);
int openat(int dirfd, const char &pathname, int oflag /*, mode_t mode */));

// return : file descriptor
// return -1 on error
  • 대표적인 oflags : O_RDONLY 읽기전용, O_WRONLY 쓰기전용, O_RDWR 읽기쓰기전용

    O_APPEND : 파일의 끝(EOF)에 write하도록 설정

    O_CREAT : 파일이 없으면 생성, 있으면 open (dir-w,x권한)

    O_EXCL : O_CREAT과 함께 사용, 파일 있으면 error

    O_TRUNC : 파일 크기를 0으로 초기화 (file-w권한)

  • 대표적인 open errors

    EEXIST : O_CREAT와 O_EXCL을 사용할 때, 파일이 있는 경우

    EMFILE : 프로세스가 maximum file descriptor에 도달

    ENOENT : 파일이 존재하지 않는 경우

    EPERM : 특정 permission이 없는 경우

  • 파일 open시 kernel에 저장되는 정보

    File Descriptor table (process-specific): open에서 사용한 flags와 open file table 포인터를 포함

    Open File table (system-wide): 파일의 status flags, access mode, offset, i-node table 포인터를 포함

    i-Node/v-Node table (system-wide): i-node 정보(file type)와 파일의 속성(size, permissions, timestamp)을 포함

image


create(2)

새로운 파일 생성시에 사용, fcntl.h 헤더에 포함된 시스템 콜 함수

#include <fcntl.h>
int create(const char &pathname, mode_t mode);

// return : file descriptor
// return -1 on error

-> same as : open(path, O_CREAT | O_TRUNC | O_WRONLY, mode);

-> write only로만 설정, 다른 모드를 주고 싶으면 close했다가 다시 open해야 함


close(2)

열려있는 파일을 닫을 때 사용, unistd.h 헤더에 포함된 시스템 콜 함수

#include <unistd.h>
int close(int fd);

// return 0
// return -1 on error

-> 사용 가능한 file descriptor 수가 제한적, 사용하지 않는 파일은 close해두는 것이 좋다 !

ex. openex.c : create, open, openerror, createerror, truncate 사용 예제코드

image


read(2)

열려있는 파일 내용을 읽어들일 때 사용, unistd.h 헤더에 포함된 시스템 콜 함수

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t num);
// return : number of bytes read
// return 0 on EOF, return -1 on error 
// 사용 예시 
char buf[512];  // 읽어들일 만큼 buffer 크기 지정 
int fd;
int nbytes;     // ssize_t : signed integer

if ((nbytes = read(fd, buf, sizeof(buf))) < 0)){ // buffer 크기만큼 읽기
		perror("read");
		exit(1);
}
  • current offset부터 읽기 시작, 그리고 읽은 만큼 offset을 증가
  • Short counts (nbytes < sizeof(buf)) : 요청보다 적게 읽은 경우


write(2)

읽어들인 파일 내용을 다시 출력할 때 사용, unistd.h 헤더에 포함된 시스템 콜 함수

#include <unistd.h>
ssize_t write(int fd, void *buf, size_t num);
// return : number of bytes written
// return -1 on error 
// 사용 예시 
char buf[512];  // write할 만큼 buffer 크기 지정 
int fd;
int nbytes;     // number of bytes read

if ((nbytes = write(fd, buf, sizeof(buf))) < 0)){ // buffer 크기만큼 쓰기
		perror("write");
		exit(1);
}
  • current offset부터 작성(O_APPEND는 맨 뒤), write한 만큼 offset을 이동
  • Short counts 발생 가능 -> not error !
    • 끝까지 읽어들이기 전에 EOF 발생된 경우
    • 네트워크 소켓에 reading, writing 하는 경우 (buffer 딜레이)
    • signal에 의해 interruption이 발생된 경우
    • 터미널에서 명령을 읽어들이는 경우

ex. stdin에서 읽은 값을 stdout으로 1 byte씩 복사

image

ex. rwex.c : read, write 함수 사용 예제 코드

image

ex. mycopy.c : write program that copies content of file -> 직접 해보기 !


lseek(2)

파일의 위치를 옮겨주는 함수, random access를 가능하게 함

  • Sequential access : 파일을 처음부터 순차적으로 읽어들임, jump 불가능
  • Random access : 파일을 어느 순서로도 읽어들일 수 있음, jump 가능

image

#include <sys/types.h>
#include <fcntl.h>

off_t lseek(int fd, off_t offset, int whence);

// return : new offset
// return -1 on error 
  • file offset : 파일의 pointer 개념

    파일을 처음 열었을 때 0으로 초기화, read, write 한만큼 증가

  • whence options (offset 설정 기준)

    SEEK_SET : 파일의 맨처음을 기준으로

    SEEK_CUR : 현채 파일 위치를 기준으로

    SEEK_END : 파일의 마지막(EOF)을 기준으로

ex. lseek.c : lseek 함수로 offset이 이동하는 과정

image

ex. hole.c : 비어있는 경우, 자동으로 중간이 null character로 채워짐

image

-> 30만큼 lseek로 옮긴 후, write을 한 실행 결과

image


Atomic Operation

프로세스의 순서가 일정하지 않기 때문에, 두 개의 연동된 프로세스를 실행하는 경우 생각했던 것과 다른 결과를 출력할 수 있음. Atomic Operation은 두 프로세스를 한 뭉텅이로 만들어서 인터럽트가 발생하지 않도록 하는 것

ex. parent 프로세스와 child 프로세스가 같은 일을 하는 경우

image

-> atomic operation이 필요한 이유 : reliable한 operation !

-> atomic operation 사용 예시

  • O_APPEND = lseek + write
  • pread, pwrite : lseek + read write
ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
	// returns number of byte read, -1 on error

ssize_t pwrite(int fd, void *buf, size_t nbytes, off_t offset);
	// returns number of byte written, -1 on error


File descriptor duplication : dup(2)

file descriptor 를 복사하는 함수, 다른 file descriptor지만 같은 open file table 참조

dup : 같은 물리적 파일을 연 새로운 file descriptor를 반환
dup2 : newfd가 open된 파일이면 닫은 후, oldfd를 복사

#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);

// return : newfd
// return -1 on error


-> dup을 사용했을 때, 각 테이블 사이의 관계성

image

I/O Redirection

dup2(fd, 1) : 표준 출력을 fd 파일로 redirection

-> 출력 결과를 터미널이 아닌 특정 파일에 저장하고 싶을 때 사용

image

ex. dup2로 복제한 파일들끼리 read

image

ex. dup으로 복제한 파일들끼리 write

image

-> dup을 한 파일끼리는 같은 open file table(offset) 공유


File descriptor control : fcntl()

열려 있는 file descriptor에 대해 특정 command를 수행하는 함수

-> 파일에 대한 정보를 가져오거나 file descriptor 속성을 변경할 수 있음

#include <fcntl.h>
int fcntl(int fd, int cmd, ..);

// return : cmd마다 다름
// return -1 on error
  • command options

    F_DUPFD : file descriptor를 복제

    F_GETFD : file descriptor flags 가져오기

    F_SETFD : file descriptor flags 설정하기

    F_GETFL : file status flags 가져오기

    F_SETFL : file status flags 설정하기

  • dup, dup2 : atomic operation

    dup : fcntl(fd, F_DUPFD, 0);

    dup2 :close(fd2); fcntl(fd, F_DUPFD, fd2);


buffered I/O vs. unbuffered I/O

  • buffered vs. unbuffered 비교

      buffered I/O unbuffered I/O
    functions standard library I/O system-level I/O
    outputs when buffer flushed every time when called
    executing time short time long time (= expensive)
    std streams FILE* type (fd + buffer) int type (fd)
    interrupt signal handler, can exit well optimized, strong
    example ANSI C Linux/Unix Systems
    usages usual programming accessing file meta data, permission


  • Buffering Mechanism : buffer를 통해 system call을 최소화 하는 것 !
    -> 최적화된 buffer size 중요함, 보통 4096으로 사용
    • Fully buffered, Block buffered : 가득 채울 때마다 flush
    • Line buffered : ‘\n’ 마다 flush
    • unbuffered : 아예 사용하지 않는 경우


ex. hello.c : ‘h’ ‘e’ ‘l’ ‘l’ ‘o’ 따로 printf하는 코드

-> 진짜 standard l/O에서 buffer를 사용하는지 확인하기 위함 (sleep)

image





@Advanced Programming in the UNIX environment, Third edition 내용을 참고함



맨 위로 이동하기