File Table in Operating System
- In-kernel per-process list of open files → process의 PCB에 존재하는 open file table입니다. 즉, process마다 존재하는 file table입니다.
- Indexed via nonnegative integers known as file descriptors (fds) → file table의 index로 fd가 표현되기 때문에 음수가 아닌 정수로 표현됩니다.
- Each entry in the list contains information an open file
- inode
- File offset → 파일 내부에 존재하는 I/O 작업의 pointer
- Access modes → 접근 권한
File descriptor
- C int type
- File descriptors start at 0 → index value
- Each Linux process has a maximum number of files that it may open
- By default, the maximum is 1,024, but it can be configured as high as 1,048,576 → 동시에 열 수 있는 file의 개수는 기본 1,024개이지만, 설정을 통해 늘릴 수 있습니다.
- 0: stdin (C library: STDIN_FILENO)
- 1: stdout (C library: STDOUT_FILENO)
- 2: stderr (C library: STDERR_FILENO)
- 위 세개의 fd는 따로 open()하지 않아도 process생성시 반드시 생기는 fd입니다.
- Each Linux process has a maximum number of files that it may open
- Can reference more than just regular files
- E.g., device files, pipes, directories, and sockets
Opening Files
- int open(const char *name, int flags)
- int open(const char *name, int flags, mode_t mode)
Map the file to a file descriptor
- Subsequent operations (reading, writing, and so on) take the file descriptor as their primary argument
flags
- Must be one of O_RDONLY, O_WRONLY, or O_RDWR → access mode를 반드시 설정해야합니다.
- Can be bitwise-ORed with one or more of the following values
- O_APPEND → file내용을 override하지 않고 뒤에서부터 I/O작업을 수행한다
- O_CREAT → 없으면 만들고, 있으면 가져오기
- O_EXCL → 없으면 만들고, 있으면 error
- O_SYNC
- O_TRUNC → 아에 새로쓰기
mode
- Required if O_CREAT is given → O_CREAT이 있는 경우 필요한 변수입니다.
- Provides the permissions of the newly created file → 파일 자체의 권한 설정, 파일 자체의 권한과 access권한이 충돌하면 error가 발생한다.
- S_IRWXU, S_IRUSR, S_IWUSR, S_IXUSR
- S_IRWXG, S_IRGRP, S_IWGRP , S_IXGRP
- S_IRWXO, S_IROTH, S_IWOTH , S_IXOTH
- On error, return -1, and set errno to an appropriate error value
int creat(const char* name, mode_t mode)
- Identical to open(file, O_WRONLY|O_CREAT|O_TRUNC, mode)
- On error, return -1, and set errno to an appropriate error value
Reading Files
- ssize_t read(int fd, void *buf, size_t len)
- Reads up to len bytes into buf from the current file offset of the file referenced by fd
- The file offset is advanced by the number of bytes read from fd → read를 할때는 읽은 바이트 수만큼 file offset이 이동합니다. 따라서 다시 read하면 마지막 fild offset부터 이어서 읽기 시작합니다.
- On success, the number of bytes written into buf is returned
- Can return a positive nonzero value less than len
- Less tan len bytes may have been available → len만큼의 data가 file에 없는 경우
- A signal interrupted the read midway → 읽고 있는 도중에 signal에 의해 interrupt되는 경우
- Returns 0 to indicate end-of-file (EOF)
- File offset has advanced past the last valid offset
- Can return a positive nonzero value less than len
- On error, the call returns -1
- If terminated by a signam before any bytes are read,
- errno == EINTR
- 하나도 읽지 못한 상태에서 signal에 의해 interrupt를 당한다면 -1을 리턴합니다. 하지만 이때 -1만을 가지고는 signal에 의해 error가 발생한 것인지, 아니면 다른 원인으로 인해 error가 발생한 것인지를 모르기 때문에, errno를 확인해야합니다.
Reading all the bytes
ssize_t ret;
while(len != 0 && (ret = read(fd, buf, len)) != 0)
{
if(ret == -1)
if(errno == EINTR)
continue;
// read()를 기다리는 상태에서 signal에 의해 interrupt를 당하면 다시 read()를 수행한다.
perror("read");
break;
}
len -= ret;
buf += ret;
// 중간에 read()가 끊겨도 끝까지 읽을 수 있게 while()처리
// len과 buf도 이에 맞게 수정
}
Size Limits
- The Maximum value of a size_t: SIZE_MAX
- The Maximum value of an ssize_t: SSIZE_MAX
읽어들이는 길이는 Limit값을 생각하며 coding해야합니다.
Writing Files
- ssize_t write(int fd, const void* buf, size_t count)
- Writes up to count bytes starting at buf to the current file offset of the file referenced by the file descriptor fd
- On success, the number of bytes written is returned, and the file offset is updated → read()와 마찬가지로 FO가 뒤로 밀린다.
- For regular files, writte() is guaranteed to perform the entire requested write, unless an error occurs
- For regular files, you do not need to perform writes in a loop → 그렇기 때문에 while문을 돌면서 write()을 할 필요는 없다.
- For regular files, writte() is guaranteed to perform the entire requested write, unless an error occurs
- On error, -1 is returned
Delayed writes
- Linux kernel simply copies the data into a kernel buffer (page cache) → Disk에 바로 쓰지 않고, memory 상에 임시로 써놓고, 여유가 있을때 OS가 한 번에 Disk로 옮긴다 (flush)
- No guarantee that the data has been written out to its intended destination
- Later, in the background, the kernel gathers up all of the "dirty" buffers, sorts them optimally, and writes them out to disk
Synchronized I/O
- int fsync(int fd)
- Ensures that all dirty data associated with the file mapped by the file descriptor fd is written back to disk
- Returns 0 on success and -1 on failure
- memory (page cache) 에 있는 값을 Disk로 flush하는 코드로 많이 사용한다면 성능이 떨어지지만 안정성을 오른다는 특징을 지님.
- ex. ctrl+s
Closing Files
- int close(int fd)
- Unmaps the open file descriptor fd, and disassociates the process from the file
- Return 0 on success and -1 on error
- Closing a file has no bearing on when the file is flushed to disk → close()했다고 해서 page cache에 있는 값들이 Disk로 flush된다고 보장할 수는 없다.
Example
code
int main(void)
{
char str[BUF_SIZE], rbuf[BUF_SIZE];
size_t len;
ssize_t ret;
int fd;
char *bufp = rbuf;
printf("Input: ");
if(fgets(str, BUF_SIZE, stdin) == NULL){
perror("fgets");
exit(1);
}
len = strlen(str);
if(fork() == 0){
fd = open("file1.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
if(fd < 0){
perror("open");
exit(1);
}
if(write(fd, str, len) < 0){
perror("write");
close(fd);
exit(1);
}
}
else{
wait(NULL);
fd = open("file1.txt", O_RDONLY);
if(fd < 0){
perror("open");
exit(1);
}
while(len){
ret = read(fd, bufp, len);
if(ret < 0){
if(errno == EINTR)
continue;
perror("read");
close(fd);
exit(1);
}
len -= ret;
bufp += ret;
}
*bufp = '\0';
printf("Output: %s\n", rbuf);
}
close(fd);
return 0;
}
'[학교 수업] > [학교 수업] 시스템 프로그래밍' 카테고리의 다른 글
[시스템 프로그래밍] Multiplexed I/O (0) | 2024.11.24 |
---|---|
[시스템 프로그래밍] File Offset (0) | 2024.11.14 |
[시스템 프로그래밍] Miscellaneous Thread Topics (1) | 2024.11.12 |
[시스템 프로그래밍] Thread Synchronization (0) | 2024.10.31 |
[시스템 프로그래밍] Threads (2) | 2024.10.30 |