Add options to set the child process group id or session for Unix. This fixes part of #307.

db4
Doug Coleman 2011-10-29 02:47:10 -07:00
parent dc0a921866
commit eb7fd4a69b
6 changed files with 85 additions and 19 deletions

View File

@ -35,6 +35,15 @@ $nl
{ "a file stream or a socket - the stream is connected to the given Factor stream, which cannot be used again from within Factor and must be closed after the process has been started" } { "a file stream or a socket - the stream is connected to the given Factor stream, which cannot be used again from within Factor and must be closed after the process has been started" }
} ; } ;
ARTICLE: "io.launcher.group" "Setting process groups"
"The process group of a child process can be controlled by setting the " { $snippet "group" } " slot of a " { $link process } " tuple:"
{ $list
{ $link +same-group+ }
{ $link +new-group+ }
{ $link +new-session+ }
}
"The default value is " { $link +same-group+ } ", which denotes that the child process should be part of the process group of the parent process. The " { $link +new-group+ } " option creates a new process group, while the " { $link +new-session+ } " creates a new session." ;
ARTICLE: "io.launcher.priority" "Setting process priority" ARTICLE: "io.launcher.priority" "Setting process priority"
"The priority of the child process can be set by storing one of the below symbols in the " { $snippet "priority" } " slot of a " { $link process } " tuple:" "The priority of the child process can be set by storing one of the below symbols in the " { $snippet "priority" } " slot of a " { $link process } " tuple:"
{ $list { $list
@ -126,7 +135,7 @@ HELP: kill-process
{ $description "Kills a running process. Does nothing if the process has already exited." } ; { $description "Kills a running process. Does nothing if the process has already exited." } ;
HELP: kill-process* HELP: kill-process*
{ $values { "handle" "a process handle" } } { $values { "process" "process" } }
{ $contract "Kills a running process." } { $contract "Kills a running process." }
{ $notes "User code should call " { $link kill-process } " instead." } ; { $notes "User code should call " { $link kill-process } " instead." } ;
@ -282,6 +291,7 @@ ARTICLE: "io.launcher" "Operating system processes"
"io.launcher.detached" "io.launcher.detached"
"io.launcher.environment" "io.launcher.environment"
"io.launcher.redirection" "io.launcher.redirection"
"io.launcher.group"
"io.launcher.priority" "io.launcher.priority"
"io.launcher.timeouts" "io.launcher.timeouts"
} ; } ;

View File

@ -21,6 +21,7 @@ stdout
stderr stderr
priority priority
group
timeout timeout
@ -47,10 +48,15 @@ SYMBOL: +high-priority+
SYMBOL: +highest-priority+ SYMBOL: +highest-priority+
SYMBOL: +realtime-priority+ SYMBOL: +realtime-priority+
SYMBOL: +same-group+
SYMBOL: +new-group+
SYMBOL: +new-session+
: <process> ( -- process ) : <process> ( -- process )
process new process new
H{ } clone >>environment H{ } clone >>environment
+append-environment+ >>environment-mode ; +append-environment+ >>environment-mode
+same-group+ >>group ;
: process-started? ( process -- ? ) : process-started? ( process -- ? )
dup handle>> swap status>> or ; dup handle>> swap status>> or ;
@ -158,12 +164,12 @@ M: process-failed error.
: try-process ( desc -- ) : try-process ( desc -- )
run-process wait-for-success ; run-process wait-for-success ;
HOOK: kill-process* io-backend ( handle -- ) HOOK: kill-process* io-backend ( process -- )
: kill-process ( process -- ) : kill-process ( process -- )
t >>killed t >>killed
[ pipe>> [ dispose ] when* ] [ pipe>> [ dispose ] when* ]
[ handle>> [ kill-process* ] when* ] bi ; [ dup handle>> [ kill-process* ] [ drop ] if ] bi ;
M: process timeout timeout>> ; M: process timeout timeout>> ;

View File

@ -4,8 +4,8 @@ io.pathnames tools.test io.launcher arrays io namespaces
continuations math io.encodings.binary io.encodings.ascii continuations math io.encodings.binary io.encodings.ascii
accessors kernel sequences io.encodings.utf8 destructors accessors kernel sequences io.encodings.utf8 destructors
io.streams.duplex locals concurrency.promises threads io.streams.duplex locals concurrency.promises threads
unix.process calendar unix unix.process debugger.unix unix.process calendar unix debugger.unix io.timeouts
io.timeouts io.launcher.unix ; io.launcher.unix ;
[ ] [ [ ] [
[ "launcher-test-1" temp-file delete-file ] ignore-errors [ "launcher-test-1" temp-file delete-file ] ignore-errors
@ -158,7 +158,7 @@ io.timeouts io.launcher.unix ;
[ p fulfill ] [ wait-for-process s fulfill ] bi [ p fulfill ] [ wait-for-process s fulfill ] bi
] in-thread ] in-thread
p 1 seconds ?promise-timeout handle>> kill-process* p 1 seconds ?promise-timeout kill-process*
s 3 seconds ?promise-timeout 0 = s 3 seconds ?promise-timeout 0 =
] ]
] unit-test ] unit-test
@ -181,3 +181,36 @@ io.timeouts io.launcher.unix ;
[ wait-for-process ] [ wait-for-process ]
tri tri
] unit-test ] unit-test
! Test priority
[ 0 ] [
<process>
{ "bash" "-c" "sleep 2&" } >>command
+low-priority+ >>priority
run-process status>>
] unit-test
! Check that processes launched with the group option kill their children (or not)
! This test should leave two sleeps running for 30 seconds.
[
<process> { "bash" "-c" "sleep 30& sleep 30" } >>command
+same-group+ >>group
500 milliseconds >>timeout
run-process
] [ process-was-killed? ] must-fail-with
! This test should kill the sleep after 500ms.
[
<process> { "bash" "-c" "sleep 30& sleep 30" } >>command
+new-group+ >>group
500 milliseconds >>timeout
run-process
] [ process-was-killed? ] must-fail-with
! This test should kill the sleep after 500ms.
[
<process> { "bash" "-c" "sleep 30& sleep 30" } >>command
+new-session+ >>group
500 milliseconds >>timeout
run-process
] [ process-was-killed? ] must-fail-with

View File

@ -14,16 +14,23 @@ IN: io.launcher.unix
: assoc>env ( assoc -- env ) : assoc>env ( assoc -- env )
[ "=" glue ] { } assoc>map ; [ "=" glue ] { } assoc>map ;
: setup-process-group ( process -- process )
dup group>> {
{ +same-group+ [ ] }
{ +new-group+ [ 0 0 setpgid io-error ] }
{ +new-session+ [ setsid io-error ] }
} case ;
: setup-priority ( process -- process ) : setup-priority ( process -- process )
dup priority>> [ dup priority>> [
H{ {
{ +lowest-priority+ 20 } { +lowest-priority+ [ 20 ] }
{ +low-priority+ 10 } { +low-priority+ [ 10 ] }
{ +normal-priority+ 0 } { +normal-priority+ [ 0 ] }
{ +high-priority+ -10 } { +high-priority+ [ -10 ] }
{ +highest-priority+ -20 } { +highest-priority+ [ -20 ] }
{ +realtime-priority+ -20 } { +realtime-priority+ [ -20 ] }
} at set-priority } case set-priority
] when* ; ] when* ;
: reset-fd ( fd -- ) : reset-fd ( fd -- )
@ -69,6 +76,7 @@ IN: io.launcher.unix
] when ; ] when ;
: spawn-process ( process -- * ) : spawn-process ( process -- * )
[ setup-process-group ] [ 2drop 249 _exit ] recover
[ setup-priority ] [ 2drop 250 _exit ] recover [ setup-priority ] [ 2drop 250 _exit ] recover
[ setup-redirection ] [ 2drop 251 _exit ] recover [ setup-redirection ] [ 2drop 251 _exit ] recover
[ current-directory get absolute-path cd ] [ 2drop 252 _exit ] recover [ current-directory get absolute-path cd ] [ 2drop 252 _exit ] recover
@ -82,8 +90,12 @@ M: unix current-process-handle ( -- handle ) getpid ;
M: unix run-process* ( process -- pid ) M: unix run-process* ( process -- pid )
[ spawn-process ] curry [ ] with-fork ; [ spawn-process ] curry [ ] with-fork ;
M: unix kill-process* ( pid -- ) M: unix kill-process* ( process -- )
SIGTERM kill io-error ; [ handle>> SIGTERM ] [ group>> ] bi {
{ +same-group+ [ kill ] }
{ +new-group+ [ killpg ] }
{ +new-session+ [ killpg ] }
} case io-error ;
: find-process ( handle -- process ) : find-process ( handle -- process )
processes get swap [ nip swap handle>> = ] curry processes get swap [ nip swap handle>> = ] curry

View File

@ -143,8 +143,8 @@ M: launch-error error.
"Launch descriptor:" print nl "Launch descriptor:" print nl
process>> . ; process>> . ;
M: windows kill-process* ( handle -- ) M: windows kill-process* ( process -- )
hProcess>> 255 TerminateProcess win32-error=0/f ; handle>> hProcess>> 255 TerminateProcess win32-error=0/f ;
: dispose-process ( process-information -- ) : dispose-process ( process-information -- )
#! From MSDN: "Handles in PROCESS_INFORMATION must be closed #! From MSDN: "Handles in PROCESS_INFORMATION must be closed

View File

@ -80,6 +80,8 @@ FUNCTION: int getaddrinfo ( c-string hostname, c-string servname, addrinfo* hint
FUNCTION: c-string getcwd ( c-string buf, size_t size ) ; FUNCTION: c-string getcwd ( c-string buf, size_t size ) ;
FUNCTION: pid_t getpid ; FUNCTION: pid_t getpid ;
FUNCTION: int getdtablesize ; FUNCTION: int getdtablesize ;
FUNCTION: pid_t getpgrp ;
FUNCTION: pid_t getpgid ( pid_t pid ) ;
FUNCTION: gid_t getegid ; FUNCTION: gid_t getegid ;
FUNCTION: uid_t geteuid ; FUNCTION: uid_t geteuid ;
FUNCTION: gid_t getgid ; FUNCTION: gid_t getgid ;
@ -88,6 +90,7 @@ FUNCTION: c-string getenv ( c-string name ) ;
FUNCTION: int getgrgid_r ( gid_t gid, group* grp, c-string buffer, size_t bufsize, group** result ) ; FUNCTION: int getgrgid_r ( gid_t gid, group* grp, c-string buffer, size_t bufsize, group** result ) ;
FUNCTION: int getgrnam_r ( c-string name, group* grp, c-string buffer, size_t bufsize, group** result ) ; FUNCTION: int getgrnam_r ( c-string name, group* grp, c-string buffer, size_t bufsize, group** result ) ;
FUNCTION: passwd* getpwent ( ) ; FUNCTION: passwd* getpwent ( ) ;
FUNCTION: int killpg ( pid_t pgrp, int sig ) ;
FUNCTION: void setpwent ( ) ; FUNCTION: void setpwent ( ) ;
FUNCTION: void setpassent ( int stayopen ) ; FUNCTION: void setpassent ( int stayopen ) ;
FUNCTION: passwd* getpwuid ( uid_t uid ) ; FUNCTION: passwd* getpwuid ( uid_t uid ) ;
@ -153,8 +156,10 @@ FUNCTION: int setegid ( gid_t egid ) ;
FUNCTION: int seteuid ( uid_t euid ) ; FUNCTION: int seteuid ( uid_t euid ) ;
FUNCTION: int setgid ( gid_t gid ) ; FUNCTION: int setgid ( gid_t gid ) ;
FUNCTION: int setgroups ( int ngroups, gid_t* gidset ) ; FUNCTION: int setgroups ( int ngroups, gid_t* gidset ) ;
FUNCTION: int setpgid ( pid_t pid, pid_t gid ) ;
FUNCTION: int setregid ( gid_t rgid, gid_t egid ) ; FUNCTION: int setregid ( gid_t rgid, gid_t egid ) ;
FUNCTION: int setreuid ( uid_t ruid, uid_t euid ) ; FUNCTION: int setreuid ( uid_t ruid, uid_t euid ) ;
FUNCTION: pid_t setsid ( ) ;
FUNCTION: int setsockopt ( int s, int level, int optname, void* optval, socklen_t optlen ) ; FUNCTION: int setsockopt ( int s, int level, int optname, void* optval, socklen_t optlen ) ;
FUNCTION: int setuid ( uid_t uid ) ; FUNCTION: int setuid ( uid_t uid ) ;
FUNCTION: int socket ( int domain, int type, int protocol ) ; FUNCTION: int socket ( int domain, int type, int protocol ) ;