상세 컨텐츠

본문 제목

UNIX - process attributes, Process groups and process group-ids, Sessions, The current working & root directory, Changing User IDs and Group IDs, Process priorities

Computer Science/UNIX

by 2021. 10. 18. 21:08

본문

반응형

Process Attributes

process-id

#include <unistd.h>

pid_t getpid(void);
// Returns: process ID of calling process

pid_t getppid(void);
// Returns: parent process ID of calling process

uid_t getuid(void);
// Returns: real user ID of calling process

uid_t geteuid(void);
// Returns: effective user ID of calling process

gid_t getgid(void);
// Returns: real group ID of calling process

gid_t getegid(void);
// Returns: effective group ID of calling process

 

process id를 가져오는 방법에는 위와 같은 방법들이 있다. 

getpid로 process id를

getppid로 parent process id를

getuid로 real user id를

geteuid로 effective user id를

getgid로 real group id를 

getegid로 effective group id를 구할 수 있다.

Process ID 0 & 1

process id 0은 swapper로 프로세스 스케줄링을 담당한다.

process id 1은 init process로 모든 프로세스의 부모로 작용한다.

Process groups and process group-ids

process group은 동일한 작업을 하는데 연관된 process들의 group이다. 

process group id는 process id와 유사하다.

양의 정수로 이루어진 pid_t 자료형이다.

process user id는 사용자 차원에서의 id를 말하지만 group id는 프로세스 차원에서의 id이므로 성격이 다르다. 

process group의 프로세스 중 하나가 process group leader가 된다.

group leader는 pid(process id)가 pgid(process group id)와 같다.

 

이와 관련된 system call은 다음과 같다

#include <unistd.h>

pid_t getpgrp(void);
// Returns: process group ID of calling process

pid_t getpgid(pid_t pid);	/* getpgid(0) == getpgrp() */
// Returns: process group ID if OK, -1 on error

getpgrp는 해당 system call을 호출하는 process의 group id를 반환한다.

getpgid는 매개변수로 전달한 pid에 해당하는 process의 group id를 반환한다. 

만약 getpgid의 매개변수로 0을 전달하면, getpgrp와 같은 역할을 한다. 

 

다음과 같은 방법으로 프로세스의 각종 id들을 볼 수 있다. 

[root@localhost root]# ps -o "pid ppid pgrp session tpgid comm" | cat
  PID  PPID  PGRP  SESS TPGID COMMAND
10617 10606 10617 10617 10692 bash
10692 10617 10692 10617 10692 ps
10693 10617 10692 10617 10692 cat
[root@localhost root]#

 위 결과를 보면 ps와 cat의 ppid가 bash의 pid와 같은 것으로 보아 ps와 cat명령어의 parent는 bash임을 알 수 있다. 

또한 ps와 cat의 pgrp(process group id)가 같은 것으로 보아 같은 group임을 확인할 수 있고, ps의 pgrp와 pid가 같은 것으로 보아 ps가 group leader임을 알 수 있다. 

Changing process group

fork로 child를 생성하면 pid는 다르겠지만 그외 pgid와 같은 값들은 그대로 상속받는다. 하지만 child는 스스로 pgid를 바꾸어 parent process로부터 독립할 수 있다. 다음과 같은 명령어를 이용해서 말이다.

#include <unistd.h>

int setpgid(pid_t pid, pid_t pgid);
// Returns: 0 if OK, -1 on error

setpgid는 pid에 해당하는 process의 group id를 pgid로 변경하는 역할을 한다.

 

매개변수 pid와 pgid의 값의 관계가 다음과 같이 상황에 따라 다르다.

pid==pgid the process specified by pid becomes a process group leader
해당 pid를 가진 프로세스의 pid로 group id가 생성되므로 생성된 pgid group의 leader가 된다.
pid==0 the process ID of the caller is used
setpgid를 호출하는 프로세스 자신의 process id를 pgid로 변경
pgid==0 the process ID specified by pid is used as the process group ID
setpgid를 호출하는 프로세스의 process id를 해당 pid를 가진 프로세스의 group id로 설정
즉 새로운 group를 생성하고, 생성한 해당 group의 leader는 setpgid를 호출한 프로세스이다.

process group ID를 변경하는 것은 오직 자기 자신이나 자신의 child의 group ID만 가능하다. 

하지만, parent가 child의 group ID를 바꿀 수 없는 경우가 있는데, fork를 통해 생성된 child process가 exec를 통해 변경된 이후에는 parent가 group id를 변경할 수 없게 된다. 

Sessions and session-ids

session은 process group보다 큰 차원의 group이다. session안에 여러 process group이 존재하는 형태이다.session의 역할을 알아보자. 터미널에서 가장 처음으로 shell process가 실행되고, 명령어를 입력하면 명령어에 해당하는 process가 생성되어 실행한다. 생성되는 각종 process들은 모두 shell안에서 생성된 것이고, 이 shell은 터미널에 고정되어있다. 

 터미널을 controlling terminal이라고 하고 이 터미널과 shell은 긴밀하게 연결되어있다. 명령어를 실행할 때 &연산자를 통해 background로 실행할 수도 있어 foreground와 process group이 구분된다. 이 group들은 모두 같은 session안에서 실행되는 process들이다. session안에서 foreground로 실행되는 group은 실행되는 동안 shell이 wait되므로 한 개밖에 없지만, background로 실행되는 group은 여러 개 있을 수 있다. 

getsid

#include <unistd.h>

pid_t getsid(pid_t pid);
// Returns: session leader's process group ID if OK, -1 on error

터미널에서 로그인 후 가장 먼저 shell 프로세스가 실행된다. shell안에 session이 존재하고 같은 session안에 존재하는 모든 process들의 표준 입력(keyboard)과 표준 출력(terminal display)은 같다. 

 

controlling terminal에 생성된 shell에 pid가 있고, 해당 shell안에 존재하는 session의 session id가 있다. shell을 포함하고 있는 group이 있고 group id가 있을 것이다. 해당 group안에 여러 process들이 있으므로 여러 pid가 존재할 것이다. shell을 포함한 해당 group에서 group id 즉 pgid의 값은 shell의 pid과 같을 것이고, shell은 해당 group의 group leader이다. 또한 shell은 session leader이므로 shell의 pid와 session id(sid)가 같다. 따라서 shell의 pid = pgid = sid이다. 

 

getsid 함수의 매개변수 pid값이 0일 경우, 호출한 프로세스 자신의 session id를 반환한다.

Daemon process

daemon process는 controlling terminal을 가지고 있지 않는 프로세스를 daemon process라고 한다. 

즉 이 경우에는 child의 session id를 변경함으로써 같은 controlling terminal session으로부터 독립시키는 것이다. 

 

shell에서 exit를 통해 session을 종료하면 shell이 session leader이므로 해당 session에 포함된 group의 process들은 모두 죽는다. 하지만 daemon process는 독립된 session을 가지고 있으므로 죽지 않지만, controlling terminal의 I/O(입출력 장치)를 공유하지 않는다.

Daemon process에는 ftpd, telentd, cron과 같은 것들이 있다. 

setsid

#include <unistd.h>

pid_t setsid(void);
// Returns: process group ID if OK, -1 on error

setsid를 이용해서 프로세스 스스로의 session id를 변경시키면, daemon process가 되면서 다음과 같은 일들이 벌어진다.

  • 자신의 pid로 새로운 session을 생성하고 해당 프로세스가 sesison leader가 된다.
  • 해당 프로세스의 pid로 group id가 생성되므로 해당 프로세스가 group leader가 된다.
  • 해당 프로세스는 controlling terminal을 갖지 않게 된다. 

example

(예시 파트)

처음에 shell이 생성되면 해당 shell의 pid(100)와 shell이 속한 group의 pgid(100)는 같다. 그리고 shell의 sid(100) 또한 shell의 pid와 같다. 

shell이 fork를 통해 child(101, 102)를 만들면 pid는 다르지만 pgid는 같으므로 같은 group에 속한 프로세스가 생성된다.

 

parent가 setpgid system call을 통해 child process의 pgid(103)를 child의 pid와 같게 설정하면, child가 독립된 group을 이루어 해당 child(103)가 group leader인 새 group이 생성된다. 

child(103)가 fork를 통해 또 다른 child를 생성하면 pid(104,105)는 다르지만 pgid(103)은 같은 group의 process들이 생성된다.

 

만약 pid=105인 child가 setgid system call( setpgid( 0,0 ) )을 통해 스스로의 group id를 자신의 pid(105)로 설정하면, pgid=105인 또 다른 group이 생성되어 pid=105인 프로세스가 독립 group을 형성하게 된다. 

 

pid=105인 프로세스가 fork를 통해 pid=107인 child process를 생성하고, pid=107인 프로세스가 setsid system call( setsid() )을 통해 스스로의 session id를 독립시키면, sid=107인 session이 독립되고, 동시에 pgid=107인 group으로 독립되면서 pid=pgid=sid=107으로 프로세스가 독립된다.

 

sid=107인 session의 프로세스들은 controlling terminal과는 단절되며 daemon process가 된다. 

 

The current working  & root directory

chroot

#include <unistd.h>

int chroot(const char *path);
// Return: 0 if OK, -1 on error

chroot는 current root directory를 변경한다. 

 

다음 예시 코드를 보자

int main() {
    int pid;

    if (chroot("/home/mydir") != 0){	/* ‘/’ == ‘/home/mydir’ */
        perror("chroot");
        exit(0);
    }

    if (execl("/bin/bash","bash", NULL) == -1) /* ‘/home/mydir/bin/bash’ */
    	perror("error");
}

/home/mydir를 root directory로 지정하면 /bin/bash경로가 절대경로 /home/mydir/bin/bash 경로와 같은 의미가 된다. 

Changing User IDs and Group IDs

setuid, setgid

#include <unistd.h>

int setuid(uid_t uid);
int setgid(gid_t gid);
// Both return: 0 if OK, -1 on error

setuid, setgid와 같은 방법으로 user id나 group id를 변경할 수 있다.

File size limits: ulmit

#include <ulimit.h>

long ulimit(int cmd, [long newlimit]);
// Return: the value of the requested limit if OK, -1 on error

write system call로 생성할 수 있는 file size의 limit를 변경할 수 있다.

Process priorities: nice

cpu점유율에 있어서 process의 priority가 존재하는데, 0이 가장 우선순위가 높고, 숫자가 클수록 priority가 낮다. 

 

어떤 process로 작업을 진행하는데 우선순위가 높지는 않지만 중간에 다른 사용자로 인하여 종료되서는 안되는 상황이라고 하였을 때, 다음과 같이 실행할 수 있다.

$ nohup nice.cc program.c 2<err &
$ exit

 program이라는 프로그램을 실행한다. '2>err'은 error message 출력을 err이라는 파일에 출력한다.

nice를 통해 process priority를 낮춘다. nohup은 프로그램을 종료시키는 kill signal을 차단시켜준다. 

반응형

관련글 더보기