1. Redirection을 구현

 

Redirection(in) 구현 부

 

Main() 함수에서 자식 프로세스 exec을 수행하기 전에 “<”가 있는지 확인후

 

있을 경우 dup2함수를 이용하여 redirection 기능을 수행하도록 구현 하였습니다.

 

그리고 마지막 for문을 이용하여 이전 커맨드벡터에서 떙겨주었습니다

 

( 리다이렉션 명령어가 들어있던 부분)

 

 Redirection(out) 구현 부

 

마찬가지로 main()함수에서 자식프로세스가 exec을 하기 전에 redir_out함수로 들어가서

 

“>” 명령어가 있는지를 확인하고 있다면 dup2함수를 이용하여 redirection을 수행후

 

마지막 for문을 이용하여 커멘드벡터를 떙겨주었습니다.

 

( 리다이렉션 명령어가 들어있던 부분)

 

2. 파이프 처리 기능

 

받은 커맨드문장(cmdvector) 에서 파이프가 있는지 와 커맨드문장의 어느 위치에 파이프가

 

있는지를 확인합니다.

 

만약 파이프 명령어가 없다면 바로 리턴 합니다.(리턴 값 1)

 

그리고 for문을 통해서 파이프 명령어(“|”) 앞, 뒤 명령어들을 나눠줍니다.

 

그리고 파이프를 생성하여 줍니다.

 

그리고 첫 번째 받은 명령어를 리다이렉션을 이용하여 출력을 돌려줍니다.

 

그리고 함수 내에서 자식을 생성한 후 자식은 두번째 명령어를 실행하는데

 

dup함수와 리 다이렉션을 이용하여 입력을 첫 번째 명령어(cmdpipe1)로부터

 

입력을 받도록 리다이렉션을 합니다.그리고 결과의 출력이 표준출력이 아닌 파이프를

 

통해서 나가도록 파이프출력으로 내보내도록 dup함수를 통해 설정합니다.

 

그 후 exec을 실행합니다.

 

부모 프로세스는 3번째 명령어(cmdpipe3)를 수행합니다.

 

이 프로세는 입력을 파이프를 통해서 입력받도록 dup함수를 이용하여 설정해주고

 

그리고 출력을 redirection을 통하여 조절해줍니다.

 

1) SIGCHLD 로 자식 프로세스 wait() 시 프로세스가 온전하게 수행되도록 구현.

 

 

위와 같이 SIGCHLD 처리를 하여 기존의 백그라운드 수행 후 좀비 프로세스가 생기는 문제 해결.

 

2) ^C(SIGINT), ^\(SIGQUIT) 사용 시 쉘이 종료되지 않도록, foreground 프로세스 실행 시 SIGINT를 받으면 프로세스가 

 

끝나도록 구현.

위와 같이 ^C(SIGINT), ^\(SIGQUIT) 를 쉘 프로세스에서는 이 시그널을 받으면 핸들러로 돌려서 동료되지 않게끔

 

설정하였습니다.

 

그리고 위와같이 쉘프로세스가 아닌 foreground에서 돌아가는 프로세스들은 ^C(SIGINT), ^|(SIGQUIT)

 

이 시그널들을 받으면 정상적으로 종료가 되어야 하기 때문에 exec을 하기전에 위 시그널 들을

 

SIG_DFL 처리 하였습니다. 백그라운드로 수행되고 있는 프로그램들은 종료가 되면 안되므로

 

foreground 프로세스일 경우에만 SIG_DFL을 하고 exec을 하도록 하였습니다.

'학부생 공부 > unix' 카테고리의 다른 글

쉘 구현 (Redirection, 파이프(pipes))  (6) 2020.03.03
파이프(pipes) -1  (0) 2019.11.13
쉘 구현하기 . (백그라운드 실행)  (0) 2019.11.06

- 파이프 란 ?

 # 간단하게 말하자면 한 프로세스의 출력이 다른 프로세스의 입력으로 들어가서

    두개의 프로세스가 inter-communication 을 하는 것이다.

 # FIFO basis

 # half duplex ( full duplex를 굳이 하자면 가능 하기는 하지만 이를 권고)

    (보내는 쪽은 보내기만, 받는 쪽은 받기만)

 # 공통 부모인 프로세스나 친척들 끼리 파이프를 사용가능 (parent-child뿐만 아니라 child-child도 가능(공통조상에서        파이프를 열였을 경우))

 # 공통조상이 아닌 프로세스들 끼리 파이프와 같은 기능을 사용하고 싶을 때는 FIFO 를 이용

 #  #include<iostream>

     int pipe(int filedes[2]);

 # 프로세스가 파이프를 통해 read를 하려고 하는 경우

     -1. pipe is not empty : read를 하고 즉시 리턴 한다. (리턴값은 읽은 데이터의 바이트 수)

     -2. pipe is empty : read가 block된다. ( write를 통해서 들어올 때까지 기다림)

 # 프로세스가 파이프를 통해 write를 하려고 하는 경우

     -1. pipe is not full : 즉시 write하고 리턴한다.

     -2. pipe is full : 빈(여유)공간이 만들어 질때 까지 block(기다림)

 # 파이프의 한쪽이 closed(닫힌경우)

     -1 . (write 가 닫혔을 때) read의 경우 데이터 파일을 다 읽고 나면 0을 리턴한다.

     -2 . (read 가 닫혔을 때) write의 경우 write를 해도 read할 프로세스가 없다.

          커널이 SIGPIPE라는 시그널을 보낸다.(write를 실행한 프로세스에게)

                (default 값은 죽는것.)

          시그널을 무시하거나 잡아서(catch) 핸들러를 수행하거나 할경우 -1을 리턴하고

          errno을 EPIPE로 셋팅한다.

 

myshell 을 구현을 하는 중이다.

표준 입력으로 마지막에 &를 입력해주면 이는 프로세스를 백그라운드로 실행시켜 주라는 뜻이다.

나의 쉘에서도 역시 이를 같은 기능을 해주도록 구현을 해야한다.

처음 든 생각은 나의 쉘 프로세스는 여전히 동작 하여야 하므로 종료가 되어서는 안되고

즉 나의 쉘 프로세스는 계속 나의 일을 하고 백그라운드로 실행을 시킬 프로세스는 

알아서 실행 되도록 해야 한다.

맨 처음 든 직관적인 생각 자식을 만든후 그 자식이 다시 자식 프로세스를 만든후

인수를 전달해서 그 프로세스(손자) 에서 수행하도록 하고 부모 프로세스는 먼저 종료를 한다.

조부모(myshell) 프로세스는 부모 프로세스가 종료를 하면 wait로 받아줄 것이고 

while문을 통해 myshell에서 여전히 작업을 할 수 있게 되고 손자 프로세스는 따로 돌 수 있는 것이다.

문제는 이렇게 부모프로세스가 먼저 죽어버리면 손자프로세스가 수행이 끝난 후

종료를 했을 때 wait를 해줄 부모 프로세스가 없다는 것이 문제이다.

즉 손자프로세스는 부모 프로세스가 죽는 순간 고아 프로세스가 되었다가

수행이 끝나면 좀비 프로세스가 된다.

그리고 좀비 프로세스가 되면 init 프로세스가 이를 입양해서 wait를 시켜준다

하지만 wait 는 systemcall이고 이는 자원이 많이 소모 되는 일이므로

바로 wait를 시켜주지 않고 주기적으로 wait를 시켜준다.

이론상은 이랬는데 코드를 짜고 수행중에 문제가 있다.

 

코드를 짜고 수행을 시켰을 때 예를 들어 sleep 10 & 라는 명령어를 입력했을 때

 

손자 프로세스에서 sleep이 수행되게 되고

10초가 지나면 (예를 들면 11초??) <- 종료 되었으나 init이 wait 시켜주지 않은 상황

가 되었을때 ps를 하면 sleep프로세스가 <defunct> 상태로 보여야 하는데 

여러번 ps를 입력 해보아도 그 상태인 것을 잡아 내지 못했다.

 

한가지 가설은 init 이 system call은 시스템 자원을 많이 드는 일 이므로 주기적으로 (가끔가다)

한번씩 wait 를 해준다고 했는데 이것이 사실 컴퓨터 입장에서는 매우 긴 시간이지만

인간인 우리 입장에서는 굉장히 짧은 시간이라 우리가 그 순간을 명령어를 통해서 확인하기는 굉장히 

어려운 것인가?? 라는 생각을 했고

 

init이 wait해주는 주기적인 시간이 대략 어느정도 됩니까? 라고 질문 했는데

그건 시스템 마다 설정되어 있는 값이 다르다 라고 말해주셔서 ..... 여전히 해결이 되지 않은 상태이다.

 

일단 그래도 표면상으로는 백그라운드로 실행 시켜주는 역할을 충실히 하고 있는 것 같다.

 

이에 해당되는 이유는 찾으면 업데이트 하도록 하겠습니다..

 

## 수정

INIT프로세스는 고아 프로세스상태에서 입양을 하는것 같습니다 그래서 좀비프로세스가 나타나지 않는 것 처럼 보이는 것 같습니다.

-> 손자를 만들어서 좀비프로세스가 눈에 띄지 않게 하는 방향이 아닌 SIGCHILD를 이용하여

    좀비 프로세스가 생기지 않도록 수정 하였습니다.

 

 

+ Recent posts