제 12 장고급입출력 Nov 2007 숙대창병모 1
Contents 1. Nonblocking I/O 2. Record Locking 3. Memory Mapped I/O Nov 2007 숙대창병모 2
12.1 Nonblocking I/O Nov 2007 숙대창병모 3
Nonblocking I/O Blocking I/O I/O 작업완료를기다리며영원히리턴안할수있다 (block forever) 예 ) getchar(): 엔터키를입력할때까지영원히기다린다 Nonblocking I/O I/O 작업이당장완료될수없으면바로에러를리턴한다 예 ) 이미입력된키가있으면그값을리턴하고, 아니면기다리지않고즉시에러를리턴한다 Nov 2007 숙대창병모 4
Slow system calls Slow system calls which can block forever Reads from pipes, terminals, network, if data isn't present Writes to above if they don't handle reading promptly Opens of files block until some condition occurs Open of a terminal device attached to a modem Open of a FIFO for writing only when there is no other process for reading the FIFO Reads and writes of files that have mandatory record locking enabled Certain ioctl operations Some of IPC functions Nov 2007 숙대창병모 5
Nonblocking I/O 설정방법 open() 으로파일을열때 O_NONBLOCK 플래그 open("a.out",o_rdonly O_NONBLOCK); open file에 fcntl() 로 O_NONBLOCK 플래그설정 int flag; flag = fcntl(fd, F_GETFL, 0); flag = O_NONBLOCK; fcntl(fd, F_SETFL, flag); O_NONBLOCK 플래그설정취소 int flag; flag = fcntl(fd, F_GETFL, 0); flag &= ~O_NONBLOCK; fcntl(fd, F_SETFL, flag); Nov 2007 숙대창병모 6
예제 : nonblockw.cc #include <fcntl.h> void set_fl(int fd, int flags) { int val; if ( (val = fcntl(fd, F_GETFL, 0)) < 0) perror("fcntl F_GETFL error"); val = flags; /* turn on flags */ if (fcntl(fd, F_SETFL, val) < 0) perror("fcntl F_SETFL error"); void clr_fl(int fd, int flags) { int val; if ( (val = fcntl(fd, F_GETFL, 0)) < 0) perror("fcntl F_GETFL error"); val &= ~flags; /* turn flags off */ if (fcntl(fd, F_SETFL, val) < 0) perror("fcntl F_SETFL error"); Nov 2007 숙대창병모 7
예제 : nonblockw.cc #include <sys/types.h> yp /* nonblockw.c */ #include <errno.h> #include <fcntl.h> char buf[100000]; int main(void) { int ntowrite, nwrite; char *ptr; ntowrite = read(stdin_fileno, buf, sizeof(buf)); fprintf(stderr, "read %d bytes n", ntowrite); set_fl(stdout_fileno, O_NONBLOCK); /* set nonblocking */ for (ptr = buf; ntowrite > 0; ) { errno = 0; nwrite = write(stdout_fileno, ptr, ntowrite); fprintf(stderr, "nwrite = %d, errno = %d n", nwrite, errno); if (nwrite > 0) { ptr += nwrite; ntowrite -= nwrite; clr_fl(stdout_fileno, O_NONBLOCK); /* clear nonblocking */ exit(0); Nov 2007 숙대창병모 8
12.2 Record locking Nov 2007 숙대창병모 9
Record Locking 필요한이유 하나의파일에두프로세스가동시에쓴다면어떤내용은덮어쓰여질수있다 방법 쓰여지는내용이파일의뒤에덧붙여지는것이라면 open() 에서 O_APPEND 모드로열면된다 한프로세스가파일의영역을읽거나수정할때다른프로세스의접근을제한하기위해서그영역에 lock 을걸어야한다 Nov 2007 숙대창병모 10
Lock 사이의호환성 Request for read lock Request for write lock Region No locks OK OK currently has One or more read locks OK denied One write lock denied denied Types of Locks F_RDLCK : Shared Read Lock F_WRLCK : Exclusive Write Lock Nov 2007 숙대창병모 11
fcntl() #include <sys/types.h> #include <unistd.h> #include <fcntl.h> int fcntl(int filedes, int cmd, struct flock *flockptr); returns : depends on cmd if OK, -1 on error cmd : F_GETLK, F_SETLK, F_SETLKW struct flock { short l_type; /* F_RDLCK, F_WRLCK, F_UNLCK */ off_t l_start; /* 로킹영역의시작지점 */ short l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_len; /* 로킹영역의길이 (0이면파일끝까지 ) */ pid_t l_pid; /* 프로세스의 PID */ ; Nov 2007 숙대창병모 12
fcntl() F_GETLK flockptr 에설정한 lock을걸수있는지, 즉이미 lock 이걸려있는지검사 걸수없다면이미걸려있는 lock 정보 flockptr 가채워짐 걸수있다면 flockptr 의 l_type 만 F_UNLCK으로변경됨 F_SETLK and l_type == F_RDLCK or F_WRLCK flockptr 에설정한 lock 을건다 실패하면즉시 -1 을리턴한다 (errno = EACCESS or EAGAIN) Nov 2007 숙대창병모 13
fcntl() F_SETLK and l_type == F_UNLCK flockptr 에설정한 lock 을해제한다 F_SETLKW F_SETLK 의 blocking version 프로세스는 lock 이가능할때까지 sleep 상태가된다 This sleep is interrupted if a signal is caught Nov 2007 숙대창병모 14
예 :report.c #include <fcntl.h> #include <errno.h> #include "emp.h #define MAX 10 int main(argc, argv) int argc; char *argv[]; { struct flock lock; struct emp record; int fd, open(), fcntl(), sum=0, try=0; if ((fd=open(argv[1], O_RDONLY))== -1) { perror(argv[1]); exit(1); lock.l_type = F_RDLCK; lock.l_whence = 0; lock.l_start = 0L; lock.l_len = 0L; while (fcntl(fd,f_setlk, &lock) == -1) { if (errno == EAGAIN) { if (try++ < MAX) { sleep(1); continue; Nov 2007 숙대창병모 15
예 :report.c printf("%s busy -- try later n", argv[1]); exit(2); perror(argv[1]); exit(3); sum = 0; while (read(fd, (char *) & record, sizeof(record)) >0) { printf("employee: %s, Salary: %d n", record.name, record.salary); sum += record.salary; printf(" ntotal salary: %d= n", sum); lock.l_type = F_UNLCK; fcntl(fd, F_SETLK, &lock); close(fd); Nov 2007 숙대창병모 16
예 : update.c #include <fcntl.h> main(argc, argv) int argc; char *argv[]; { struct t flock lock; struct emp record; #include "emp.h" int fd, open(), pid, getpid(), recnum; long position; if ((fd=open(argv[1], O_RDWR))== -1) { perror(argv[1]); exit(1); pid = getpid(); for(;;) { printf(" n Enter record number; "); scanf("%d", &recnum); if (recnum <0) break; position = recnum * sizeof(record); Nov 2007 숙대창병모 17
예 : update.c lock.l_type = F_WRLCK; lock.l_whence = 0; lock.l_start = position; lock.l_len = sizeof(record); if (fcntl(fd,f_setlkw, &lock) == -1) { perror(argv[1]); exit(2); lseek(fd, position,0); if (read(fd, (char *) & record, sizeof(record)) == 0) { printf("record %d not found n", recnum); lock.l_type = F_UNLCK; fcntl(fd, F_SETLK, &lock); continue; printf("employee: %s, salray: %d n", record.name, record.salary); record.pid = pid; printf("enter new salary: "); scanf("%d", &record.salary); Nov 2007 숙대창병모 18
예 : update.c lseek(fd, position, ii 0); write(fd, (char *) &record, sizeof(record)); lock.l_type = F_UNLCK; fcntl(fd, F_SETLK, &lock); close(fd); Nov 2007 숙대창병모 19
Lock 요청및해제 #include <sys/types.h> #include <fcntl.h> int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len) { struct flock lock; lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */ lock.l_start = offset; /* byte offset, relative to l_whence */ lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */ lock.l_len = len; /* #bytes (0 means to EOF) */ return( fcntl(fd, cmd, &lock) ); Nov 2007 숙대창병모 20
Lock 요청및해제 #define read_lock(fd, offset, whence, len) lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len) #define readw_lock(fd, offset, whence, len) lock_reg(fd, F_SETLKW, F_RDLCK, offset, whence, len) #define write_lock(fd, offset, whence, len) lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len) #define writew_lock(fd, offset, whence, len) lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, len) #define un_lock(fd, offset, whence, len) lock_reg(fd, F_SETLK, F_UNLCK, offset, whence, len) Nov 2007 숙대창병모 21
Lock 시험예 #include <sys/types.h> #include <fcntl.h> pid_t lock_test(int fd, int type, off_t offset, int whence, off_t len) { struct flock lock; lock.l_type l = type; /* F_RDLCK or F_WRLCK */ lock.l_start = offset; /* byte offset, relative to l_whence */ lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */ lock.l_len len = len; /* #bytes (0 means to EOF) */ if (fcntl(fd, F_GETLK, &lock) < 0) perror("fcntl error"); if (lock.l_type == F_UNLCK) return(0); /* false, region is not locked by another proc */ return(lock.l_pid) pid); /* true, return pid of lock owner */ Nov 2007 숙대창병모 22
Lock 상속및해제 Lock 해제 프로세스가종료하면그프로세스가설정한모든 lock 은해제된다 fd 가닫히면이와관련된모든 lock 은해제된다. 다음과같은경우들에도모든 lock 은해제된다 fd1 = open("a", ); read_lock(fd1, ); fd2 = dup(fd1); close(fd2) fd1 = open("a", ); read_lock(fd1, ); fd2 = open("a", ); close(fd2) Nov 2007 숙대창병모 23
Lock 상속및해제 fork() 에의한자식프로세스에게 lock 은상속되지않는다 exec() 의경우에는상속된다 Nov 2007 숙대창병모 24
커널구현 fd1 = open("a", ); write_lock(fd1, 0, ); /* parent write locks byte 0 */ if (fork() > 0) { /* parent */ fd2 = dup(fd1); fd3 = open("a", ); pause(); close(fd3); /* is the write lock released? */ else { /* child */ read_lock(fd1, ); /* child read locks byte 1 */ pause(); 위실행결과는다음슬라이드와같음 lock 은 file descriptor 가아니고 file 에연관되어있다 따라서 fd1, fd2, fd3 중어느것이라도 close 하면 lock 은해제된다 Nov 2007 숙대창병모 25
커널구현 process pocesstabe table entry file descriptors fd 1: fd flags ptr fd 2: fd 3:.... file table fd status flags current file offset v-node ptr fd status flags current file offset v-node ptr i-node table i-node information current file size linked list of locks file descriptors fd 1: fd flags ptr fd 2: fd 3:.... struct flock link flags, etc starting offset length process ID struct flock link flags, etc starting offset length process ID Nov 2007 숙대창병모 26
Advisory vs. Mandatory Locking Advisory Locking lock 을걸수있고검사할수있지만강제되지는않는다 즉 locking 규칙을무시하고읽고쓰기가능 따라서모든프로세스들이자발적으로규칙을준수해야함 Mandatory Locking 커널이 locking 규칙을강제하므로무시하고읽고쓰기불가능 커널이모든입출력호출을감시해야하므로시스템부하증가 설정방법 set-group-id 비트를켜고 group-execute 비트를끔 -rw-r-lr-- 1 lsj 5 Jul 15 12:11 lockfile $ chmod 2644 lockfile Nov 2007 숙대창병모 27
Mandatory Locking Blocking descriptor, tries to Non Blocking descriptor, tries to read write read write Read lock exists on region OK blocks OK EAGAIN Wit Write lock exists on region blocks blocks EAGAIN EAGAIN Nov 2007 숙대창병모 28
예 : file_lock.clock c #include <stdio.h> #include <fcntl.h> int main(int argc, char **argv) { static struct flock lock; int fd, ret; if (argc <2){ fprintf(stderr, " 사용법 : %s 파일 n", argv[0]); exit(1); fd = open(argv[1], O_WRONLY); if(fd == -1) { printf(" 파일열기실패 n"); exit(1); Nov 2007 숙대창병모 29
예 : file_lock.clock c lock.l_type l =F F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len l len =0; lock.l_pid = getpid(); ret = fcntl(fd, F_SETLKW, &lock); if(ret == 0) { // 파일잠금성공하면 while (1) { scanf("%c", " NULL); Nov 2007 숙대창병모 30
12.3 Memory Mapped I/O Nov 2007 숙대창병모 31
Memory Mapped I/O 디스크의파일에메모리주소를부여한다 주소에서읽는것은파일의데이터를읽는다 주소에쓰면파일에저장된다 메모리인것처럼포인터와배열을사용하여파일의데이터를다룰수있게된다 성능향상을기대할수있다 파일 I/O 처럼시스템버퍼와라이브러리버퍼사이에데이터가복사될필요없다 알고리즘단순화 마치메모리처럼배열과포인터사용가능 Nov 2007 숙대창병모 32
예 : memory mapped file high address stack len memory mapped portion of file start addr heap uninitialized data (bss) initialized data low address text file : memory mapped portion of file off len Nov 2007 숙대창병모 33
mmap() #include <sys/types.h> #include <sys/mman.h> caddr_t mmap(caddr_t addr,, size_t len,, int prot,, int flag, int filedes, off_t off); Returns : starting address of mapped region if OK, -1 on error 디스크파일에메모리주소를부여한다 addr : 부여될메모리시작주소 addr 가 NULL 이면시스템이적당한시작주소를선택한다 virtual memory page의배수이어야한다 len : 메모리크기 Nov 2007 숙대창병모 34
mmap() prot : specify the protection of the mapped region. PROT_READ : the region can be read. PROT_WRITE : the region can be written. PROT_EXEC : the region can be executed. PROT_NONE : the region cannot be accessed (not in 43 4.3+BSD). The protection specified for a region has to match the open mode of the file. Nov 2007 숙대창병모 35
mmap() flag : mapped region 의특성 MAP_FIXED 반환주소가 addr 와같아야한다. MAP_FIXED 가지정되지않고 addr 가 0 이아니면, 커널은 addr 를단지힌트로만사용한다. MAP_SHARED 부여된주소에쓰면파일에저장된다 MAP_SHARED 나 MAP_PRIVATE 중의하나가반드시지정되어야한다 MAP_PRIVATE 부여된주소에쓰면파일의복사본이만들어지고 이후부터는복사본을읽고쓰게된다 Nov 2007 숙대창병모 36
예 :memcpy 이용한파일복사 #include <sys/types.h> /* mcopy.c */ #include <sys/stat.h> #include <sys/mman.h> /* mmap() */ #include <fcntl.h> int main(int argc, char *argv[]) { int fdin, fdout; char *src, *dst; struct stat statbuf; if (argc!= 3) err_quit( quit("usage: usage: a.out <fromfile> <tofile>"); if ( (fdin = open(argv[1], O_RDONLY)) < 0) perror("can't open %s for reading", argv[1]); if ( (fdout = open(argv[2], O_RDWR O_CREAT O_TRUNC, FILE_MODE)) MODE))<0) perror("can't creat %s for writing", argv[1]); if (fstat(fdin, &statbuf) < 0) /* need size of input file */ perror("fstat error"); Nov 2007 숙대창병모 37
예 :memcpy 이용한파일복사 /* set size of output file */ if (lseek(fdout, statbuf.st_size - 1, SEEK_SET) == -1) perror("lseek error"); if (write(fdout, "", 1)!= 1) perror("write error"); if ( (src = mmap(0, statbuf.st_size, PROT_READ, MAP_FILE MAP_SHARED, fdin, 0)) == (caddr_t) -1) perror("mmap error for input"); if ( (dst = mmap(0, statbuf.st_size, PROT_READ PROT_WRITE, MAP_FILE MAP_SHARED, fdout, 0)) == (caddr_t) -1) perror("mmap error for output"); memcpy(dst, src, statbuf.st_size); /* does the file copy */ exit(0); Nov 2007 숙대창병모 38