[UNIX] session
POSIX 1.1에서 도입한 세션(session)이라는 개념에 대한 소개
프로세스 그룹
- 모든 프로세스는 pid를 가지며 하나의 프로세스 그룹에 속한다
- 프로세스 그룹은 한 개 이상의 프로세스로 구성된 집합이고 pgid를 가진다
- 프로세스 그룹은 주로 같은 작업을 하는 프로세스들의 집합이고 같은 터미널로부터 신호를 받는다
- shell pipeline(
|
)을 통해 프로세스 그룹을 만들 수 있다proc1 | proc2 & proc3 | proc4 | proc5
- proc1, proc2가 하나의 프로세스 그룹을 형성하고 proc3, proc4, proc5가 하나의 프로세스 그룹을 형성한다
- & 기호는 proc1, proc2를 background process group으로 지정한다
#include <unistd.h>
/**
* pid가 0이면 호출한 프로세스의 pgid를 반환한다
* 실패할 경우 -1을 반환한다
*/
pid_t getpgid(pid_t pid)
그룹 리더
- 프로세스 그룹에는 그룹 리더가 존재하는데 pid값이 pgid와 동일한 프로세스가 그룹 리더이다
- 그룹 리더는 프로세스 그룹을 생성한 프로세스이고 그룹 안에 프로세스들을 생성할 수 있다
- 프로세스 그룹 리더가 종료되어도 프로세스 그룹은 여전히 존재할 수 있다
- 프로세스 그룹 내의 모든 프로세스가 종료되어야 그룹이 사라진다
- 프로세스는 자신의 그룹을 변경할 수 있다
세션
- 세션은 하나 이상의 프로세스 그룹의 집합이다
#include <unistd.h>
/**
* 호출한 프로세스가 프로세스 리더이면 실패(-1 반환)
* 그렇지 않은 경우 새 세션을 생성하고 pgid 반환
*/
pid_t setsid(void);
- 위의 함수는 새로운 세션을 생성한다
setsid
호출에 성공한 프로세스는 새로운 세션의 리더인 동시에 새로운 프로세스 그룹의 리더가 된다- 함수 호출에 성공한 시점에 새로운 세션에는 프로세스 그룹이 한 개 있고 그 그룹에 프로세스는 호출 프로세스 한개이다
- 호출 프로세스가 함수 호출 전에 제어 터미널에 연결되어 있었다면 그 제어 터미널과의 연결 관계가 끊어진다
- open한게 자동으로 닫힌다는 뜻인가?
- 프로세스가 그룹 리더가 아님을 보장하는 방법은 fork를 호출한 뒤 부모는 종료하고 자식은 계속 실행하는 것이다
제어 터미널
- 세션에는 하나의 제어 터미널이 연결될 수 있다(없을 수도 있다)
- 제어 터미널과 연결을 확립한 세션 리더를 제어 프로세스라고 한다
- 세션의 프로세스 그룹은 background group, foreground group으로 분류할 수 있다
- foreground 그룹은 한 개, background group은 하나 이상 있을 수 있다
- 세션에 제어 터미널이 있으면 그 세션에는 반드시 하나의 foreground process 그룹이 있다
- 터미널에서 interrupt key(e.g. ctrl-c)를 입력하면 foreground group의 모든 프로세스에게 signal이 전달된다
/dev/tty
- 표준 입출력 리다이렉션 여부에 관계없이 입출력 대상이 터미널이 되도록 보장하는 방법은
/dev/tty
device file을 open하는 것이다- 커널은 이 파일을 제어 터미널로 인식한다
- 제어 터미널이 없는 프로세스가
/dev/tty
를 open하려고 시도하면 실패한다
실습
procinfo.c
- cli 인자로 전달받은 프로세스의 그룹 아이디와 세션 아이디를 출력하는 프로그램
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
if (argc == 1)
return 1;
pid_t tpid = atoi(argv[1]);
printf("[%s] pid: %d pgid: %d sid: %d\n",
argv[0], tpid, getpgid(tpid), getsid(tpid));
return 0;
}
amplify.c
- 표준입력에서 읽은 문자열을 표준 출력과 제어 터미널에 여러 번 출력하는 프로그램
amplify < input.txt > output.txt
와 같이 실행(stdin, stdout 리다이렉션)하더라도 터미널에 문자열을 출력하는 것이 보장된다
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void printn2stdout(const unsigned char str[], int n)
{
for (int i = 0; i < n; i++)
printf("%s\n", str);
}
void print2control_terminal(const unsigned char str[])
{
int tfd;
tfd = open("/dev/tty", O_WRONLY);
if (tfd < 0)
return;
unsigned char buffer[7*128];
memset(buffer, '\0', 7*128);
snprintf(buffer, sizeof(buffer),
"\033[31m%s\033[0m\n"
"\033[33m%s\033[0m\n"
"\033[33m%s\033[0m\n"
"\033[32m%s\033[0m\n"
"\033[34m%s\033[0m\n"
"\033[36m%s\033[0m\n"
"\033[35m%s\033[0m\n",
str, str, str, str, str, str, str);
write(tfd, buffer, 7*128);
close(tfd);
}
int main(int argc, const char *argv[])
{
int n = 7;
if (argc == 2)
n = atoi(argv[1]);
unsigned char str[128];
memset(str, '\0', 128);
fgets(str, sizeof(str), stdin);
if (str[strlen(str) - 1] == '\n')
str[strlen(str) - 1] = '\0';
print2control_terminal(str);
printn2stdout(str, n);
return 0;
}