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