Add options to set the child process group id or session for Unix. This fixes part of #307.
parent
dc0a921866
commit
eb7fd4a69b
|
@ -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"
|
||||||
} ;
|
} ;
|
||||||
|
|
|
@ -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>> ;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ) ;
|
||||||
|
|
Loading…
Reference in New Issue