File descriptor
- Regular files
- Special files
- Character devices (e.g., Keyboard)
- Block devices
- Pipes
- Sockets
우리가 평소에 다루던 진짜 file들은 Regular file들이고, Character devices나 pipe와 같은 file들을 Special file들이라 부른다. 그리고 Multiplexed I/O는 special file들에 유용하게 쓰인다.
A signle process cannot reasonably block on more than one file descriptor at the same time
- if a read() system call is issued, and there is not yet any data, the process will block, no longer able to service the other file descriptors
read()같은 경우, 만약 read()하고자 하는 file에 데이터가 하나도 없다면, 그 프로세스는 block되는데, 다른 file descriptor가 사용가능하더라도 block된다.
I/O Multiplexing
- Allows us to simultaneously monitor multiple file descriptors to see if I/O is possible on any of them
I/O Multiplexing은 여러 file descriptors들의 I/O작업의 가능성을 동시에 모니터링하는 것을 말한다.
다음은 I/O Multiplexing의 과정이다:
- Tell me when any of these file descriptors are ready for I/O
- Sleep until one or more file descriptors are ready
- Woken up: What is ready?
- Handle all file descriptors ready for I/O, without blocking
- Go back to step 1, and start over
Select
- int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
- Blocks until the given file descriptors are ready to perform I/O, or until an optionally specified timeout has elapsed
- File descriptors listed in the readfds set are watched to see if data is available for reading
- File descriptors listed in the writefds set are watched to see if a write operation will complete without blocking
- File descriptors listed in the exceptfds set are watched to see if an exception has occurred
- n
- Equal to the value of the highest-valued file decriptor in any set, plus one
- 우리가 관심이 있는 fd의 최대값의 + 1 을 입력으로 넣는다.
- timeout
- Can be specified either as NULL, in which case select() blocks indefinitely, or as a pointer to a timeval structure
- Linux modifies this parameter automatically, setting the values to the time remaing
- 리눅스는 timeout구조체를 자동적으로 수정하는데, timeout까지 남은 시간으로 계속 수정한다.
- Return value
- -1 indicates that an error occurred
- if errno == EINTR, the call was interrupted by a signal handler
- 0 means that the call timed out before any file descriptor became ready
- Total number of file descriptors marked as ready in all three returned sets
- -1 indicates that an error occurred
FD Macros
- FD_CLR(int fd, fd_set *set)
- Removes a file descriptor from a given set
- FD_ISSET(int fd, fd_set *set)
- Tests whether a file descriptor is part of a given set
- 일반적으로 select를 한 후에 사용한다.
- FD_SET(int fd, fd_set *set)
- Adds a file descriptor to a given set
- 일반적으로 select를 하기 전에 사용한다.
- FD_ZERO(fd_set *set)
- Removes all file descriptors from the specified set
- fd_set을 초기화하기 위해 사용한다.
pselect
- int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask)
- timeout
- Uses the timespec structure, not the timeval structure
- Is not modified by pselect()
- select()와 달리 timeout값이 계속해서 변경되지 않는다.
- sigmask
- Specifies a set of signals to be unmasked while the call is blocked
- pselect()가 blocked되어있는 상태에서 특정한 signal에 의해 interrupt되는 것을 방지하기 위함이다.
poll() and epoll() ...
Example1
int main(void)
{
fd_set readfds;
int ret;
/* Wait on stdin for input */
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
/* All right, now block! */
ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, NULL);
if(ret == -1){
perror("select");
return 1;
}
if(FD_ISSET(STDIN_FILENO, &readfds)){
char buf[BUF_LEN+1]
int len;
/* guaranteed to not block */
len = read(STDIN_FILENO, buf, BUF_LEN);
if(len == -1){
perror("read");
return 1;
}
if(len){
buf[len] = '\0';
printf("read: %s\n", buf);
}
return 0;
}
printf("This should not happend!\n");
return 1;
}
+ STDIN이 keyboard를 통해 들어온다면 select의 block이 풀리게 되고, readfds에 들어있는 fd는 STDIN밖에 없었기 때문에 FD_ISSET(STDIN_FILENO, ...) 는 반드시 true가 된다.
Example 2
int main(void)
{
fd_set readfds, writefds;
int ret, fd;
/* Wait on stdin for input */
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(STDIN_FILENO, &readfds);
FD_SET(STDOUT_FILENO, &writefds);
/*
STDIN_FILENO: 0
STDOUT_FILENO: 1
*/
/* All right, now block! */
ret = select(STDOUT_FILENO + 1, &readfds, &writefds, NULL, NULL);
if(ret == -1){
perror("select");
return 1;
}
for(fd = 0; fd<STDOUT_FILENO + 1; fd++){
printf("fd %d: %s%s\n", fd,
FD_ISSET(fd, &readfds) ? "R" : "",
FD_ISSET(fd, &writefds) ? "W" : "");
return 1;
}
+ STDOUT은 항상 ready to I/O이기 때문에, 출력해주는 것은 항상 준비되어있기 때문에, select에서 block되지 않고 바로 넘어가게된다. 그렇기 때문에 select에서 marked된 fd는 STDOUT_FILENO이기 때문에 FD_ISSET(..., &readfds)는 false가 되고, FD_ISSET(..., &writefds)는 true가 된다.
+ STDIN은 keyboard에 무엇인가가 들어가야 ready가 되기 때문에 select하면 바로 넘어가지 않고 block된다
Example 3
int main(void)
{
int pipefd1[2], pipefd2[2];
pid_t cpid[2] = {-1, -1};
if(pipe(pipefd1) == -1){
perror("pipe1");
exit(EXIT_FAILURE);
}
if(pipe(pipefd2) == -1){
perror("pipe2");
exit(EXIT_FAILURE);
}
cpid[0] = fork();
if(cpid[0] == -1){
perror("fork1");
exit(EXIT_FAILURE);
}
if(cpid[0] != 0){
cpid[1] = fork();
if(cpid[1] == -1){
perror("fork2");
exit(EXIT_FAILURE);
}
}
if(cpid[0] == 0){
char buf = 'K';
close(pipefd1[0]); close(pipefd2[0]); close(pipefd2[1]);
write(pipefd1[1], &buf, 1);
close(pipefd1[1]);
exit(EXIT_SUCCESS);
}
else if(cpid[1] == 0){
char buf = 'U';
close(pipefd1[0]); close(pipefd1[1]); close(pipefd2[0]);
write(pipefd2[1], &buf, 1);
close(pipefd2[1]);
exit(EXIT_SUCCESS);
}
else{
fd_set fdlist, templist;
int fdmax;
char buf;
close(pipefd1[1]); close(pipefd2[1]);
FD_ZERO(&fdlist);
FD_SET(pipefd1[0], &fdlist);
FD_SET(piprfd2[0], &fdlist);
fdmax = (pipefd1[0] > pipefd2[0]) ? pipefd1[0] : pipefd2[0];
templist = fdlist;
while(select(fdmax + 1, &templist, NULL, NULL, NULL)){
if(FD_ISSET(pipefd1[0], &templist))
if(read(pipefd1[0], &buf, 1) > 0)
printf("%c\n", buf);
if(FD_ISSET(pipefd2[0], &templist))
if(read(pipefd2[0], &buf, 1) > 0)
printf("%c\n", buf);
if(waitpid(-1, NULL, WNOHANG) == -1) break;
templist = fdlist;
}
close(pipefd1[0]); close(pipefd2[0]);
exit(EXIT_SUCCESS);
}
}
'[학교 수업] > [학교 수업] 시스템 프로그래밍' 카테고리의 다른 글
[시스템 프로그래밍] I/O Redirection (1) | 2024.11.28 |
---|---|
[시스템 프로그래밍] Memory Mapped I/O (1) | 2024.11.24 |
[시스템 프로그래밍] File Offset (0) | 2024.11.14 |
[시스템 프로그래밍] File I/O (0) | 2024.11.13 |
[시스템 프로그래밍] Miscellaneous Thread Topics (1) | 2024.11.12 |