작업제어는 단일한 로그인 세션에서 사용자가 여러개의 프로세스 그룹들(또는 작업들) 사이에서 제어를 옮기는 것을 허용하는 프로토콜을 적용한다. 작업제어 기능은 대부분의 프로그램에서 자동적으로 적당하게 수행되고, 작업제어에 대한 특별한 어떤 것을 할 필요가 없다. 그래서 당신이 쉘이나 로그인 프로그램을 만들지 않는다면 이 장에 있는 것들을 무시할 수 있다.
당신이 이 장에 나와있는 것들을 이해하기 위해서는 시그널 핸들링(21장 [Signal Handling] 참조)과 프로세스 생성(23.2절 [Process Creation Concepts] 참조) 과 연관된 개념에 친숙해질 필요가 있다.
대화형(interactive) 쉘의 기본적인 목적은 사용자 터미널로부터 명령문을 읽고 그 명령문에의해 지정된 프로그램을 실행하도록 프로세스들을 만드는 것이다. 그것은 fork( 23.4절 [Creadting a Process] 참조.)와 exec ( 23.5절 [Executing a File] 참조.)함수를 사용해서 할 수 있다.
단일한 명령문은 단지 한 개의 프로세스를 실행시키지만_종종 한 개의 명령문도 여러개의 프로세스들을 사용한다. 만일 당신이 쉘 커맨드에서 `|'을 사용한다면 당신은 명시적으로 그들 프로세스안에 여러개의 프로그램들을 요청한것이다. 그러나 만일 당신이 한 개의 프로그램을 실행시킬지라도, 그것이 내부적으로는 여러개의 프로세스들을 사용할 수 있다. 예를들어, `cc -c foo.c'와 같은 단일한 컴파일 명령문은, 전형적으로 네 개의 프로세스들을 사용한다. 만일 당신이 make를 실행한다면, 그 작업은 분리된 프로세스 안에서 다른 프로그램을 실행하는 것이다.
단일한 명령문에 소속되어 있는 프로세스들은 프로세스 그룹이나 작업(job)이라고 불린다. 당신은 동시에 그들 모든 프로세스들을 작동시킬 수 있다. 예를들어, C-c를 타이핑하면 전면 프로세스 그룹에 있는 모든 프로세스가 종료되도록 시그널 SIGINT를 보낸다. 세션은 프로세스들의 좀 큰 그룹이라고 할 수 있다. 일반적으로 단일한 로그인에 있는 모든 프로세스들은 같은 세션에 속한다.
모든 프로세스는 프로세스 그룹에 속한다. 어떤 프로세스가 만들어질 때, 그것은 부모 프로세스와 같은 프로세스 그룹과 세션의 멤버가 된다. 당신은 setpid 함수를 사용해서 다른 프로세스 그룹으로 소속을 바꿀 수 있는데, 그때 그 프로세스 그룹은 같은 세션에 소속된 프로세스 그룹이다.
다른 세션에 프로세스를 소속시키는 유일한 방법은 setsid 함수를 사용해서, 새로운 세션이나, 또는 세션 리더의 처음 프로세스를 만드는 것이다. 새로운 프로세스 그룹에 세션리더를 소속시키면, 당신은 다시 프로세스 그룹의 외부로 그것을 다시 옮길 수 없다.
보통, 새로운 세션들은 시스템 로그인 프로그램에 의해 만들어지고 세션 리더는 사용자의 로그인 쉘을 실행시키는 프로세스이다. 작업제어를 지원하는 쉘은 어떤 시간에 어떤 작업이 터미널을 사용할 수 있도록 제어를 조정해야만 한다. 그렇지않다면 여러개의 작업들이 동시에 터미널로부터 입력을 받아들이려 시도할것이고, 어떤 프로세스가 사용자가 타입한 입력을 받을 것인지가 혼란하게 될 수도 있다. 이것을 방지하기 위해서, 쉘은 이 장에 설명된 프로토콜을 사용해서 터미널 드라이버와 협력해야만 한다.
쉘은 한 번에 오직 한 프로세스 그룹에게만 터미널을 제어하는 제한없는 권한을 줄 수 있다. 이처럼 터미널을 제어하고 있는 프로세스 그룹을 전면 작업(foreground job)이라고 부른다. 터미널을 억세스 하지 않고 실행중인, 쉘에 의해 처리되고 있는 다른 프로세스 그룹들은 배경작업(background job)이라고 불린다.
만일 배경 작업이 터미널을 제어하여 터미널로부터 읽거나 쓰거나 할 필요가 있다면, 그것은 터미널 드라이버에 의해 멈추어진다. 사용자는 SUSP문자( 12.4.9절 [Special Characters] 참조)를 입력함으로써 전면 작업을 멈출 수 있고 프로그램은 SIGSTOP시그널을 보냄으로써 어떤 작업을 멈출 수 있다. 작업들이 멈추었을 때 쉘은 그들에 대하여 사용자에게 알릴 책임이 있고, 멈추어진 작업에 대해서 계속 진행할 것인지에 대한 여부를 사용자에게 선택하도록 허용하기 위한 메카니즘의 제공과 전면 작업과 배경 작업사이의 작업전환도 쉘에게 책임이 있다. 제어중인 터미널에 입/출력 하는것에 대한 자세한 정보는 24.4절 [Access to the Terminal] 참조.
모든 운영체제가 작업제어를 지원하는 것은 아니다. GNU 시스템은 작업제어를 지원하지만, 만일 다른 시스템에서 GNU 라이브러리를 사용한다고해도 그 시스템에서 작업제어를 지원하지 않을 수 도 있다. 당신은 시스템이 작업제어를 지원하는지에 대한 여부를 시험하기 위해서 컴파일할 때 _POSIX_JOB_CONTROL 매크로를 사용할 수 있다. 27.2절[System Options] 참조.
만일 작업제어가 지원되지 않으면, 한 세션만다 오직 한 개의 프로세스 그룹만 존재하고 그 프로세스 그룹은 항상 전면 작업으로써 행동한다. 부가적인 프로세스 그룹을 만드는 함수에는 에러코드 ENOSYS를 사용해서 간단히 실패했음을 알린다.
다양한 작업제어 시그널(21.2.5절 [Job Control Signals] 참조.)들을 대표하고 있는 매크로들은 작업제어가 지원되지 않는다고 할지라도 정의되어 있다. 그렇지만, 작업제어를 지원하지 않는 시스템에서 그 시그널들을 결코 발생되지 않고, 에러를 보고하거나 아무것도 하지않는 등의 시그널에 대한 행동을 정하거나 시험하거나 보내려고 시도하지 않는다.
프로세스의 속성들중 하나는 그 프로세스가 제어중인 터미널이다. fork를 사용해서 만들어진 자식 프로세스는 그들의 부모 프로세스로부터 제어중인 터미널을 상속받는다. 이와같은 방법으로, 한 세션안에 있는 모든 프로세스들은 세션 리더(session leader)로부터 제어중인 터미널을 상속받는다. 터미널의 제어권을 가진 세션리더를 터미널의제어중인 프로세스(controlling process)라고 불린다.
당신이 로그인할 때 시스템이 당신을 위해서 그 일을 하기 때문에, 당신은 세션에 터미널 제어권을 할당하는 정확한 메카니즘에 대해서는 걱정할 필요가 없다. 개별적인 프로세스가 새로운 세션의 리더가 되기위해서 setsid를 호출할 때, 그 프로세스는 제어중인 터미널로부터 단절된다.
터미널을 제어하고 있는 전면작업안의 프로세스들은 터미널에 대한 제한 없는 억세스 권한을 가진다; 배경프로세스들은 권한을 가지지 않는다. 이 절에서는 배경작업에 있는 프로세스가 터미널을 제어하려 시도할 때 어떤 일이 발생하는지에 대해서 자세히 설명하고 있다.
배경작업에 있는 프로세스가 전면작업이 제어하고 있는 터미널로부터 읽으려 시도할 때, 프로세스 그룹은 SIGTTIN 시그널을 받는다. 이것은 그룹안에 있는 모든 프로세스들의 동작을 멈추게 하는 원인이 된다(그 시그널이 처리되지 않거나 그들 스스로 멈추게 하지 않는다면). 그렇지만 읽기를 시도한 프로세스가 이 시그널을 무시하거나 블록한다면, 대신에 EIO 에러를 얻게 될 것이다.
유사하게, 배경작업에 있는 프로세스가 전면작업에서 제어하고 있는 터미널에 출력을 시도한다면, 그것에 대응된 디폴트 동작은 프로세스 그룹에게 SIGTTOU 시그널을 보내는 것이다. 그렇지만, 그 동작은 지역 모드 플래그(local modes flags)(12.4.7절 [Local Modes] 참조.)의 TOSTOP 비트에 의해서 갱신된다. 만일 이 비트가 설정되지 않는다면(이것이 디폴트이다.), 전면 작업에 의해 제어중인 터미널에 배경작업이 출력을 시도하는 것에는 시그널을 보내지 않고 항상 허가된다. 또한 출력을 시도하는 프로세스에 의해 SIGTTOU 시그널이 무시되거나 블록된다면 이때도 출력은 허가된다.
프로그램에서 할 수 있는 터미널 명령들의 대부분은 입력이나 출력을 위한 것이다. 기본적인 입력과 출력 함수에 대한 정보는 8.2절 [I/O Primitives] 참조.
터미널 제어중이던 프로세스가 종료되면, 그 터미널은 해제되고 새로운 세션에 의해서 다시 제어될 수 있다.(실제로, 다른 사용자가 터미널 상에서 로그인 할 수 있다.) 이것은 만일 예전의 세션에 있는 어떤 프로세스가 그 터미널을 계속 사용하려고 시도한다면 문제가 발생할 수 있다.
그러한 문제들을 막기위해서, 세션리더가 종료된 후에도 계속 실행되고 있는 프로세스 그룹들은 고아가된 프로세스 그룹으로써 표시된다. 고아 프로세스 그룹(orphand process group) 안에 소속된 프로세스들은 터미널에 읽거나 쓰기를 할 수 없다. 만일 그렇게 하려 시도한다면 EIO 에러를 얻게 될 것이다.
어떤 프로세스 그룹이 고아가 되었을 때, 그 프로세스들은 SIGHUP 시그널을 받는다. 보통, 이것은 프로세스를 종료시키는 원인이 된다. 그렇지만, 만일 프로그램이 이 시그널을 무시하거나 시그널을 위한 핸들러를 만들었다면(21장 [Signal Handling] 참조.), 터미널을 제어중이던 프로세스가 종료되었다고 하더라도 실행중이던 고아 프로세스들은 계속 그 작업을 수행할 수 있다; 그렇지만 더 이상은 터미널의 억세스를 시도할 수 없다.
이 절은 쉘이 작업 제어를 수행하기 위해서는 무엇을 해야만 하는지, 그 개념이 포함된 간단한 예제 프로그램을 통해서 설명하고 있다.
24.6.2절 [Initializing the Shell]
24.6.4절 [Foreground and Background]
24.6.5절 [Stoppend and Terminated Jobs]
24.6.6 [Continuing Stopped Jobs]
24.6.7 [Missing Pieces] : 쉘의 다른 부분들에 대해서 설명하고 있다.
이 장에 포함된 모든 예제 프로그램들은 간단한 쉘 프로그램의 일부분이다. 이 절은 이 예제에서 사용되고 있는 데이터 구조체와 유틸리티 함수들을 설명하고 있다.
간단한 쉘은 주로 두 개의 데이터 구조체를 다룬다. job 타입(type)은 파이프(pipes)로 서로 연결된 서브프로세스들의 집합인 작업에 대한 정보를 포함한다. process 타입(type)은 단일한 서브프로세스에 대한 정보를 저장하고 있다. 다음은 적절한 데이터 구조체 선언들이다.
일반적으로 작업제어를 수행하는 쉘 프로그램이 시작될 때, 그 쉘이 이미 자신의 작업제어를 수행하고 있는 다른 쉘로부터 호출되었을 경우에는 주의를 해야만 한다. 서브쉘(subshell)에서 작업제어가 가능하게 되기전에 우선 부모 쉘에 의해서 전면에 놓여져야만 한다. 그것은 getpgrp로 초기 프로세스 그룹 ID를 얻고, 현재 터미널을 제어하고 있는 전면작업의 프로세스 그룹 ID와 그것을 비교해서 한다( tcgetpgrp함수를 사용해서 추출될 수 있다. )
만일 그 서브쉘이 전면 작업으로써 실행되고 있지 않다면, 그것은 그 자신의 프로세스 그룹에 SIGTTIN 시그널을 보냄으로써 스스로 멈춰야만 한다. 그것은 전면에 그 자신을 제멋대로 놓을수 없다; 사용자가 부모 쉘에게 이것을 시키도록 기다려야만 한다. 만일 그 서브쉘이 계속된다면, 검사를 반복하고 만일 그것이 여전히 전면에 있지 않다면 다시 스스로 멈춘다.
일단 서브쉘이 부모 쉘에 의해서 전면에 놓이게되면, 서브쉘은 자신의 작업 제어가 가능하게 된다. 자신소유의 프로세스 그룹안에 그 자신이 놓이도록 setpgid를 호출하고, 그다음 전면에 이 프로세스 그룹이 놓이도록 tcsetpgrp를 호출함으로써 이러한 일을 한다.
쉘이 작업제어가 가능하게 되었을 때, 작업제어를 멈추도록 하는 모든 시그널에 대해서 무시하도록 그 자체에서 설정하기 때문에 그 자체는 우연히 멈추게 되지 않는다. 당신은 모든 멈춤 시그널들을 SIG_IGN 으로 설정하여 이러한 일을 할 수 있다.
비-대화식으로 실행되는 서브쉘은 작업제어가 지원되지도 않고 지원될 수도 없다. 그것은 그자체가 쉘인 프로세스 그룹안에 만든 모든 프로세스가 존재해야만 한다; 이것은 비-대화실 쉘과 부모 쉘에 의해 단일한 작업으로 취급되는 자식 프로세스를 허용한다. 이것은 작업제어를 사용하지 않지만 그것을 하는 쉘을 만들기 위해서는 기억해야만 한다.
다음은 이러한 모든 것을 어떻게 하는지 보여주는 예제 쉘을 위한 초기 코드이다.
일단 쉘이 터미널을 제어하여서 작업제어를 수행하는 책임을 갖게 되면, 쉘은 사용자에의해 입력된 명령문에 응답하여 작업을 개시할 수 있다. 프로세스 그룹에서 프로세스들을 만들기 위해서는, 23.2절 [Process Creation Concepts] 에 설명된 fork 와 exec를 사용한다. 그곳에는 여러개의 자식 프로세스들이 이미 존재하고 있기 때문에, 그 일을 하기는 좀 많이 복잡하고 당신은 올바른 순서로 프로세스를 만들도록 주의를 해야만 한다. 그렇지 않다면, 고약한 경쟁상황(race condition)이 발생될 것이다.
당신은 프로세스들 사이의 부모-자식 관계를 어떻게 구성할것인지에 대해서 두가지를 선택할 수 있다. 프로세스 그룹안에 있는 모든 프로세스들을 쉘 프로세스의 자식 프로세스로 만들거나, 또는 그룹에 있는 한 개의 프로세스를 그 그룹에 있는 다른 모든 프로세스들의 조상이 되도록 만들수 있다. 이 장에 설명된 예제 쉘 프로그램은 첫 번째가 좀 간단하게 때문에 첫 번째를 사용한다.
만들어진 각각의 프로세스는, setpid를 호출하여 새로운 프로세스 그룹에 그 자신을 넣어야만 한다; 24.7.2절 [Process Group Functions] 참조. 새로운 그룹에 있는 첫 번째 프로세스는 그 프로세스 그룹의 리더가 되고 그 프로세스 ID가 그 그룹을 위한 프로세스 그룹 ID가 된다.
쉘은 새로운 프로세스 그룹으로 각각의 자식 프로세스들을 넣기 위해서 setpgid를 호출한다. 이것은 타이밍 문제가 내포되어 있다; 각각의 자식 프로세스는 새로운 프로그램이 실행되기 전에 프로세스 그룹에 들어가야만 하고, 쉘은 실행을 계속하기 전에 그룹이 가지고 있는 모든 자식 프로세스에 의존한다. 만일 자식 프로세스와 쉘이 모두 setpgid를 호출한다면, 이것은 프로세스가 먼저 그 일을 처리하도록 해서 아무런 문제가 발생되지 않을 것이다.
만일 전면 작업으로 어떤 작업이 진행되고 있다면, 새로운 프로세스 그룹을 tcsetpgrp를 사용해서 터미널을 제어하고 있는 전면으로 넣을 필요가 있다. 다시, 이것은 경쟁 상황을 피하기 위해서 각각의 자식 프로세스 뿐만아니라, 쉘에 의해서도 수행된다. 각 자식 프로세스의 다음 일은 시그널동작을 재설정하는 일이다.
초기화 하는동안, 쉘 프로세스는 작업제어 시그널들을 무시하도록 그 자신을 설정한다; 24.6.2절 [Initializing the Shell] 참조. 그 결과로, 그것이 만든 어떤 자식 프로세스도 또한 상속으로 인해서 그러한 시그널들을 무시하게 된다. 이것에 만족하지 못하면, 각각의 자식 프로세스는 그것이 만들어진 후에 SIG-DFL을 사용해서 그 시그널의 원래 동작으로 되돌려 설정할 수 있다.
쉘이 이러한 관습을 따르기 때문에, 응용 프로그램은 그들이 부모 프로세스로부터 시그널의 처리에 대한 것을 정확히 상속받는다고 가정 할 수 있다. 그러나 모든 응용프로그램은 멈춤 시그널들의 처리에 간섭할 수 없다. SUSP 문자의 일반적인 해석이 불가능하게 만든 응용프로그램은 사용자가 작업을 멈추게 하기 위해서 다른 메카니즘을 제공한다. 사용자가 이 메카니즘을 호출할 때, 그 프로그램은 단지 프로세스 그 자체가 아니라, 그 프로세스의 프로세스 그룹에게 SIGTSTP 시그널을 보낸다. 21.6.2절 [Signaling Another Process] 참조.
마침내, 각각의 자식 프로세스는 보통의 방법으로 exec를 호출하여야 한다. 이것은 표준 입/출력 채널들의 리다이렉션이 처리되는 지점이다. 8.8절 [Duplicating Descriptors] 를 참조하여 이것을 어떻게 하는지 보아라. 다음은 프로그램을 개시하기 위한, 대화식 쉘 프로그램에 있는 함수이다. 그 함수는 쉘에 의해서 자식 프로세스가 만들어진 후에 즉시 자식 프로세스에 의해서 실행되고 결코 리턴하지 않는다.
만일 쉘이 대화식으로 실행되지 않으면, 이 함수는 프로세스 그룹이나 시그널로 아무일도 하지 않는다. 작업제어를 수행하지 않는 쉘은 그 자체가 쉘인 프로세스 그룹안에 모든 서브프로세스들이 존재해야만 한다.
다음은 실제로 완전한 작업을 시작하는 함수이다. 자식 프로세스가 만들어진 후에, 이 함수는 전면이나 배경으로 새로이 만들어진 작업을 넣기위해서 어떤 다른 함수를 호출한다; 그것은 24.6.4절 [Foreground and Background] 에 설명되어 있다.
이제 전면(foreground)에 있는 작업을 시작할 때 쉘에 의해서 행해져야만 하는 동작은 무엇이며, 배경작업이 시작될 때 해야만 되는 것과 무엇이 어떻게 다른지 알아보자. 전면작업이 시작될 때, 쉘은 첫 번째로 tcsetpgrp를 호출해서 그 전면작업에 터미널 제어권을 줘야만 한다. 그리고나서, 쉘은 프로세스 그룹안에 있는 프로세스들이 종료되거나 멈출때까지 기다려야한다. 이것에 대한 상세한 내용은 24.6.5절 [Stopped and Terminated Jobs] 를 참조하라.
그룹안에 있는 모든 프로세스들이 수행됐거나 멈추었을 때, 쉘은 다시 tcsetpgrp를 호출해서 자신의 프로세스 그룹을 위해서 터미널 제어권을 되찾는다. 배경작업으로부터의 입/출력이나 사용자에의해 입력된 SUSP 문자가 원인이 된 멈춤 시그널이 프로세스 그룹에게 보내어지면, 보통, 작업안에 있는 모든 프로세스들이 함께 멈춘다.
전면작업이 터미널을 이상한 상황으로 만들었을지도 모르므로, 쉘은 계속하기전에 자신이 저장해놓았던 터미널 모드들을 반환하여야한다. 작업이 완전히 멈춘경우에, 쉘은 일단 현재 터미널 모드들을 저장하고, 그래서 만일 그 작업이 나중에 다시 계속된다면 그들을 반환할 수 있다. 터미널 모드들을 다루는 함수들은 tcgetattr 과 tcsetattr이 있다; 그들은 12.4절 [Terminal Modes] 를 참조하라. 다음은 위에 설명된 일들을 하는 예제 쉘을 함수이다.
전면 프로세스가 시작될 때, 쉘은 작업에 있는 모든 프로세스들이 멈추거나 종료될때까지 블록해야만 한다. 그것은 waitpid 함수를 호출함으로써 이루어진다; 23.6절 [Process Completion] 참조. 프로세스가 종료된것뿐만 아니라 멈춤 또한 보고하도록 WUNTRACED 옵션을 사용하라. 쉘은 배경작업이 멈추었거나 종료된 작업들을 사용자에게 보고하도록 배경작업들의 상황을 체크해야만 한다; 이것은 WNOHANG 옵션을 사용해서 waitpid 함수를 호출함으로써할 수 있다. 작업이 멈추었거나 종료되었음을 체크하는것과 같은 코드문을 넣는 좋은 위치는 새로운 명령문을 읽으려(prompting) 하기 전이다.
쉘은 SIGCHLD 시그널을 처리하는 핸들러를 만듦으로써 자식 프로세스를 위한 유용한 상황정보를 비동기적으로 통지받을 수 있다. 21장 [Signal Handling] 참조.
예제 쉘 프로그램의 경우에는, SIGCHLD 시그널은 보통 무시된다. 쉘이 조작하고 있는 전역 데이터 구조체를 재진입하는 문제를 피하기 위함이다. 그러나 쉘이 그들 데이터 구조체를 사용하지 않는 어떤 시간동안에는 _예를들어, 터미널에서 입력을 기다리는 때와 같은_SIGCHLD 시그널을 처리하는 핸들러는 가능하다. 동기적으로 상황들을 체크하는데 사용되는 같은 함수는 (이 경우, do_job_notification) 이 핸들러로부터 호출될 수 있다.
다음은 작업의 상황들을 체크하고 사용자에게 정보를 보고하는 것을 취급하는 예제 쉘 프로그램의 일부분이다.
쉘은 프로세스 그룹에게 SIGCONT 시그널을 보냄으로써 멈추어진 작업을 계속하게 할 수 있다. 만일 작업이 전면에서 계속 실행되어야하면, 쉘은 일단 tcsetpgrp 를 호출해서 터미널 제어권을 그 작업에게 부여하고, 저장된 터미널 설정을 반환한다. 전면에서 작업이 재개된 후에, 쉘은 그 작업이 마치 전면에서 시작된것처럼, 그 작업이 멈추거나 종료되기를 기다린다.
예제 쉘 프로그램에서 새로이 만들어진 작업과 재개된 작업들에 대한 처리는 put_job_in_foreground 와 put_job_in_background 한쌍의 함수로 이루어진다. 그들 함수에 대한 정의는 24.6.4절 [Foreground and Background] 에 나와있다. 멈추었던 작업을 재개할 때, cont 인수에 주어진 0이 아닌값은 SIGCONT 시그널을 보내고 적당한 터미널 모드를 반환함을 확실하게 한다.
다음은 재개되어 실행되고 있는 작업에 대해서 쉘이 내부적으로 보유하고 있던 정보를 갱신하는 함수이다.
이장에 포함된 예제 쉘을 위한 여분의 코드는 전체 쉘 프로그램을 위한 일부분이다. 하지만, 어떻게 작업과 프로그램 데이터 구조체들이 할당되고 초기화되는지에 대해서는 전혀 얘기하지 않았다. 대부분의 실제 쉘은 명령문; 변수들; 약어, 대입, 그리고 파일이름의 패턴 매칭등을 위한 것을 제공하는, 복잡한 사용자 인터페이스로 되어있다. 이곳에 설명된 이 모든 것은 복잡함과는 거리가 멀다! 대신에, 우리는 어떻게 코아 프로세스를 생성을 하는지를 보여주고 그와 같은 쉘에서 어떤 작업제어 함수들이 호출될 수 있는지에 대해서 관심을 두었다. 다음은 우리가 표현했던 주요 엔트리 포인트를 요약한 테이블이다.
void init_shell (void)
void init_sh
void launch_job (job *j, int foreground)
void do_job_notification (void)
void continue_job (job *j, int foreground)
이 절은 작업제어와 연관된 함수들을 자세하게 설명하고 있다.
당신은 제어중인 터미널을 개방하기 위해서 사용할 수 있는 파일이름을 얻기 위해서 ctermid 함수를 사용할 수 있다. GNU 라이브러리에서는, 항상 같은 문자열이 리턴된다: "/dev/tty". 그것은 현재 프로세스의 제어 중인 터미널(만일 그것이 한 개라면)을 참조하기위한 "이상한" 특별파일 이름이다. ctermid 함수는 헤더파일 `stdio.h'에 선언되어 있다.
함수 : char * ctermid (char *string)
매크로 : int L_ctermid
또한 12.1절 [Is It a Terminal] 에 있는 isatty 와 ttyname 함수를 참조하라.
다음은 프로세스 그룹을 다루기 위한 함수를 설명하고 있다. 당신의 프로그램에서 그들 함수들을 사용하기 위해서는 헤더파일 `sys/types.h' 와 `unistd.h'를 포함해야만 한다.
함수 : pid_t setsid (void)
EPERM
POSIX.1 함수 : pid_t getpgrp (void)
BSD 함수 : pid_t getpgrp (pid_t pid)
함수 : int setpgid (pid_t pid, pid_t pgid)
EACCES : pid라는 이름을 가진 자식 프로세스가 만들어진 후에 exec 함수를 통해서 실행되었다.
EINVAL : pgid의 값이 유용하지 않다.
ENOSYS : 시스템이 작업제어를 지원하지 않는다.
EPERM
ESRCH
함수 : int setpgrp(pid_t pid, pid_t pgid)
다음은 터미널의 전면프로세스 그룹을 알아내거나 설정하기 위한 함수들이다. 당신은 그들 함수들을 당신의 어플리케이션에서 사용하기 위해서는 헤더파일 `sys/types.h'와 `unistd.h'를 인클루드해야만 한다. 그들 함수들이 터미널 디바이스를 정하도록 파일 기술자 인수를 정한다고 하더라도, 전면작업은 터미널 파일 그자체와 연관되어 있고 특별히 개방된 파일 기술자가 아니다.
함수 : pid_t tcgetpgrp(int filedes)
EBADF : filedes 인수가 유용한 파일 기술자가 아니다.
ENOSYS : 시스템이 작업제어를 지원하지 않는다.
ENOTTY : filedes 인수와 연관된 터미널 파일이 호출한 프로세스가 제어중인 터미널이 아니다.
함수 : tcsetpgrp(int filedes, pid_t pgid)
EBADF : filedes 인수가 유용한 파일 기술자가 아니다.
EINVAL : pgid 인수가 유용하지 않다.
ENOSYS : 시스템이 작업제어를 지원하지 않는다.
ENOTTY : filedes는 호출한 프로세스가 제어하고 있는 터미널이 아니다.
EPERM : pgid 는 호출한 프로세스와 같은 세션에 있는 프로세스 그룹이 아니다.
목차 이전 : 23. 프로세스 다음 : 25. 사용자와 그룹