대체 I/O 모델

EEEFFEE·2023년 11월 17일

System Programming

목록 보기
15/19

23.11.17 최초 작성

1. 파일 locking

  • 여러 프로세스가 파일을 갱신할 때 동시에 갱신할 시 데이터가 손상될 수 있음
  • 이를 위해 Mutex, Semaphore와 같이 lock을 해줘야 함
  • 같은 프로그램을 중복되지 않고 실행하도록 할 때 사용

1.1 파일 전체 잠금

  • flock : 파일의 사용을 막는 함수

#include <sys/file.h>

int flock(int fd, int operation);

///
fd : 파일 디스크립터
operation : 동작 지정
	LOCK_SH :공유 (읽기) 잠금을 적용 (LOCK_SH를 적용한 다른 프로세스만 접근 가능)
	LOCK_EX : 배타적 (쓰기) 잠금을 적용 (다른 프로세스 접근 불가)
	LOCK_NB : 잠금 시 차단하지 마십시오. 이 값은 LOCK_SH 또는 LOCK_EX로 논리적으로 OR 연산될 수 있음
	LOCK_UN : 잠금 해제

Return
(0 : Success, -1 : Fail)

  • flock의 경우 파일 전체를 잠가 파일의 다른 영역을 다룰때 필요없는 동작을 하게 됨

ex) 예제

  • t_flock : flock 동작을 구현

#include <sys/file.h>
#include <fcntl.h>
#include "curr_time.h"                  /* Declaration of currTime() */
#include "tlpi_hdr.h"

int
main(int argc, char *argv[])
{
    int fd, lock;
    const char *lname;

    if (argc < 3 || strcmp(argv[1], "--help") == 0 ||
            strchr("sx", argv[2][0]) == NULL)
        usageErr("%s file lock [sleep-time]\n"
                 "    'lock' is 's' (shared) or 'x' (exclusive)\n"
                 "        optionally followed by 'n' (nonblocking)\n"
                 "    'sleep-time' specifies time to hold lock\n", argv[0]);

    lock = (argv[2][0] == 's') ? LOCK_SH : LOCK_EX;
    if (argv[2][1] == 'n')
        lock |= LOCK_NB;

    fd = open(argv[1], O_RDONLY);               /* Open file to be locked */
    if (fd == -1)
        errExit("open");

    lname = (lock & LOCK_SH) ? "LOCK_SH" : "LOCK_EX";

    printf("PID %ld: requesting %s at %s\n", (long) getpid(), lname,
            currTime("%T"));

    if (flock(fd, lock) == -1) {
        if (errno == EWOULDBLOCK)
            fatal("PID %ld: already locked - bye!", (long) getpid());
        else
            errExit("flock (PID=%ld)", (long) getpid());
    }

    printf("PID %ld: granted    %s at %s\n", (long) getpid(), lname,
            currTime("%T"));

    sleep((argc > 3) ? getInt(argv[3], GN_NONNEG, "sleep-time") : 10);

    printf("PID %ld: releasing  %s at %s\n", (long) getpid(), lname,
            currTime("%T"));
    if (flock(fd, LOCK_UN) == -1)
        errExit("flock");

    exit(EXIT_SUCCESS);
}


1.2 파일 일부 잠금

  • fcntl : 파일의 일부 영역에 다른 프로세스가 접근하지 못하도록 막음



///

Return
(0 : Success, -1 : Fail)

2. epoll

  • 1개의 프로세스에 1개의 파일 디스크립터로 I/O를 수행 → 만약 프로세스가 파일 사용 시 다른 파일에 접근을 못함 (blocking)
  • epoll은 하나의 프로세스가 여러 파일 디스크립터로 I/O를 수행

ex) 예제

  • epoll_input.c : epoll이 작동하는 방식을 나타내는 코드

#include <sys/epoll.h>
#include <fcntl.h>
#include "tlpi_hdr.h"

#define MAX_BUF     1000        /* Maximum bytes fetched by a single read() */
#define MAX_EVENTS     5        /* Maximum number of events to be returned from
                                   a single epoll_wait() call */

int
main(int argc, char *argv[])
{
    int epfd, ready, fd, s, j, numOpenFds;
    struct epoll_event ev;
    struct epoll_event evlist[MAX_EVENTS];
    char buf[MAX_BUF];

    if (argc < 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s file...\n", argv[0]);

    epfd = epoll_create(argc - 1);
    if (epfd == -1)
        errExit("epoll_create");

    /* Open each file on command line, and add it to the "interest
       list" for the epoll instance */

    for (j = 1; j < argc; j++) {
        fd = open(argv[j], O_RDONLY);
        if (fd == -1)
            errExit("open");
        printf("Opened \"%s\" on fd %d\n", argv[j], fd);

        ev.events = EPOLLIN;            /* Only interested in input events */
        ev.data.fd = fd;
        if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
            errExit("epoll_ctl");
    }

    numOpenFds = argc - 1;

    while (numOpenFds > 0) {

        /* Fetch up to MAX_EVENTS items from the ready list of the
           epoll instance */

        printf("About to epoll_wait()\n");
        ready = epoll_wait(epfd, evlist, MAX_EVENTS, -1);
        if (ready == -1) {
            if (errno == EINTR)
                continue;               /* Restart if interrupted by signal */
            else
                errExit("epoll_wait");
        }

        printf("Ready: %d\n", ready);

        /* Deal with returned list of events */

        for (j = 0; j < ready; j++) {
            printf("  fd=%d; events: %s%s%s\n", evlist[j].data.fd,
                    (evlist[j].events & EPOLLIN)  ? "EPOLLIN "  : "",
                    (evlist[j].events & EPOLLHUP) ? "EPOLLHUP " : "",
                    (evlist[j].events & EPOLLERR) ? "EPOLLERR " : "");

            if (evlist[j].events & EPOLLIN) {
                s = read(evlist[j].data.fd, buf, MAX_BUF);
                if (s == -1)
                    errExit("read");
                printf("    read %d bytes: %.*s\n", s, s, buf);

            } else if (evlist[j].events & (EPOLLHUP | EPOLLERR)) {

                /* After the epoll_wait(), EPOLLIN and EPOLLHUP may both have
                   been set. But we'll only get here, and thus close the file
                   descriptor, if EPOLLIN was not set. This ensures that all
                   outstanding input (possibly more than MAX_BUF bytes) is
                   consumed (by further loop iterations) before the file
                   descriptor is closed. */

                printf("    closing fd %d\n", evlist[j].data.fd);
                if (close(evlist[j].data.fd) == -1)
                    errExit("close");
                numOpenFds--;
            }
        }
    }

    printf("All file descriptors closed; bye\n");
    exit(EXIT_SUCCESS);
}

3. /proc

  • 현재 실행되고 있는 프로세스에 대한 정보가 있는 디렉토리
/proc/1 : pid 1번에 대한 정보
/proc/cpuinfo : 프로세서의 정보
/proc/devices : 현재 커널에 설정되어 있는 정보
/proc/dma : 현재 사용중인 dma 채널
/proc/filesystems : 현재 파일시스템 정보
/proc/interrupts : 현재 인터럽트 정보

0개의 댓글