33
44
55# ' Start a new child process.
6- # '
6+ # '
77# ' @description
88# ' In Linux, the usual combination of `fork()` and `exec()`
99# ' is used to spawn a new child process. Standard streams are redirected
1010# ' over regular unnamed `pipe`s.
11- # '
11+ # '
1212# ' In Windows a new process is spawned with `CreateProcess()` and
1313# ' streams are redirected over unnamed pipes obtained with
1414# ' `CreatePipe()`. However, because non-blocking (*overlapped*
1515# ' in Windows-speak) read/write is not supported for unnamed pipes,
1616# ' two reader threads are created for each new child process. These
1717# ' threads never touch memory allocated by R and thus they will not
1818# ' interfere with R interpreter's memory management (garbage collection).
19- # '
20- # '
19+ # '
20+ # '
2121# ' @details
2222# ' `command` is always prepended to `arguments` so that the
2323# ' child process can correcty recognize the name of its executable
2424# ' via its `argv` vector. This is done automatically by
2525# ' `spawn_process`.
26- # '
26+ # '
2727# ' `environment` can be passed as a `character` vector whose
2828# ' elements take the form `"NAME=VALUE"`, a named `character`
2929# ' vector or a named `list`.
30- # '
30+ # '
3131# ' `workdir` is the path to the directory where the new process is
3232# ' ought to be started. `NULL` and `""` mean that working
3333# ' directory is inherited from the parent.
34- # '
34+ # '
3535# ' @section Termination:
36- # '
36+ # '
3737# ' The `termination_mode` specifies what should happen when
3838# ' `process_terminate()` or `process_kill()` is called on a
3939# ' subprocess. If it is set to `TERMINATION_GROUP`, then the
4040# ' termination signal is sent to the parent and all its descendants
4141# ' (sub-processes). If termination mode is set to
4242# ' `TERMINATION_CHILD_ONLY`, only the child process spawned
4343# ' directly from the R session receives the signal.
44- # '
44+ # '
4545# ' In Windows this is implemented with the job API, namely
4646# ' `CreateJobObject()`, `AssignProcessToJobObject()` and
4747# ' `TerminateJobObject()`. In Linux, the child calls `setsid()`
4848# ' after `fork()` but before `execve()`, and `kill()` is
4949# ' called with the negate process id.
50- # '
50+ # '
5151# ' @param command Path to the executable.
5252# ' @param arguments Optional arguments for the program.
5353# ' @param environment Optional environment.
5858# ' @return `spawn_process()` returns an object of the
5959# ' *process handle* class.
6060# ' @rdname spawn_process
61- # '
61+ # '
6262# ' @format `TERMINATION_GROUP` and `TERMINATION_CHILD_ONLY`
6363# ' are single `character` values.
64- # '
64+ # '
6565# ' @export
6666spawn_process <- function (command , arguments = character (), environment = character (),
6767 workdir = " " , termination_mode = TERMINATION_GROUP )
@@ -76,7 +76,7 @@ spawn_process <- function (command, arguments = character(), environment = chara
7676 }
7777 environment <- paste(names(environment ), as.character(environment ), sep = ' =' )
7878 }
79-
79+
8080 if (! (is.null(workdir ) || identical(workdir , " " ))){
8181 workdir <- normalizePath(workdir , mustWork = TRUE )
8282 }
@@ -92,7 +92,7 @@ spawn_process <- function (command, arguments = character(), environment = chara
9292
9393# ' @param x Object to be printed or tested.
9494# ' @param ... Other parameters passed to the `print` method.
95- # '
95+ # '
9696# ' @export
9797# ' @rdname spawn_process
9898print.process_handle <- function (x , ... )
@@ -101,14 +101,14 @@ print.process_handle <- function (x, ...)
101101 cat(' command : ' , x $ command , ' ' , paste(x $ arguments , collapse = ' ' ), ' \n ' , sep = ' ' )
102102 cat(' system id : ' , as.integer(x $ c_handle ), ' \n ' , sep = ' ' )
103103 cat(' state : ' , process_state(x ), ' \n ' , sep = ' ' )
104-
104+
105105 invisible (x )
106106}
107107
108108
109109# ' @description `is_process_handle()` verifies that an object is a
110110# ' valid *process handle* as returned by `spawn_process()`.
111- # '
111+ # '
112112# ' @export
113113# ' @rdname spawn_process
114114is_process_handle <- function (x )
@@ -118,37 +118,37 @@ is_process_handle <- function (x)
118118
119119
120120# ' Terminating a Child Process.
121- # '
121+ # '
122122# ' @description
123- # '
123+ # '
124124# ' These functions give access to the state of the child process and to
125125# ' its exit status (return code).
126- # '
126+ # '
127127# ' The `timeout` parameter can take one of three values:
128128# ' \itemize{
129129# ' \item `0` which means no timeout
130130# ' \item `-1` which means "wait until there is data to read"
131131# ' \item a positive integer, which is the actual timeout in milliseconds
132132# ' }
133- # '
133+ # '
134134# ' @details `process_wait()` checks the state of the child process
135135# ' by invoking the system call `waitpid()` or
136136# ' `WaitForSingleObject()`.
137- # '
137+ # '
138138# ' @param handle Process handle obtained from `spawn_process`.
139139# ' @param timeout Optional timeout in milliseconds.
140- # '
140+ # '
141141# ' @return `process_wait()` returns an `integer` exit code
142142# ' of the child process or `NA` if the child process has not exited
143143# ' yet. The same value can be accessed by `process_return_code()`.
144- # '
144+ # '
145145# ' @name terminating
146146# ' @rdname terminating
147147# ' @export
148- # '
148+ # '
149149# ' @seealso [spawn_process()], [process_read()]
150150# ' [signals()]
151- # '
151+ # '
152152process_wait <- function (handle , timeout = TIMEOUT_INFINITE )
153153{
154154 stopifnot(is_process_handle(handle ))
@@ -160,10 +160,10 @@ process_wait <- function (handle, timeout = TIMEOUT_INFINITE)
160160# ' `process_wait()` with no timeout and returns one of these
161161# ' values: `"not-started"`. `"running"`, `"exited"`,
162162# ' `"terminated"`.
163- # '
163+ # '
164164# ' @rdname terminating
165165# ' @export
166- # '
166+ # '
167167process_state <- function (handle )
168168{
169169 stopifnot(is_process_handle(handle ))
@@ -174,17 +174,34 @@ process_state <- function (handle)
174174# ' @details `process_return_code()` gives access to the value
175175# ' returned also by `process_wait()`. It does not invoke
176176# ' `process_wait()` behind the scenes.
177- # '
177+ # '
178178# ' @rdname terminating
179179# ' @export
180- # '
180+ # '
181181process_return_code <- function (handle )
182182{
183183 stopifnot(is_process_handle(handle ))
184184 .Call(" C_process_return_code" , handle $ c_handle )
185185}
186186
187187
188+ # ' Check if process with a given id exists.
189+ # '
190+ # ' @param x A process handle returned by [spawn_process] or a OS-level process id.
191+ # ' @return `TRUE` if process exists, `FALSE` otherwise.
192+ # '
193+ # ' @export
194+ # '
195+ process_exists <- function (x )
196+ {
197+ if (is_process_handle(x )) {
198+ x <- x $ c_handle
199+ }
200+
201+ isTRUE(.Call(" C_process_exists" , as.integer(x )))
202+ }
203+
204+
188205# ' @description `TIMEOUT_INFINITE` denotes an "infinite" timeout
189206# ' (that is, wait until response is available) when waiting for an
190207# ' operation to complete.
@@ -197,7 +214,7 @@ TIMEOUT_INFINITE <- -1L
197214# ' @description `TIMEOUT_IMMEDIATE` denotes an "immediate" timeout
198215# ' (in other words, no timeout) when waiting for an operation to
199216# ' complete.
200- # '
217+ # '
201218# ' @rdname terminating
202219# ' @export
203220TIMEOUT_IMMEDIATE <- 0L
@@ -206,7 +223,7 @@ TIMEOUT_IMMEDIATE <- 0L
206223# ' @description `TERMINATION_GROUP`: `process_terminate(handle)`
207224# ' and `process_kill(handle)` deliver the signal to the child
208225# ' process pointed to by `handle` and all of its descendants.
209- # '
226+ # '
210227# ' @rdname spawn_process
211228# ' @export
212229TERMINATION_GROUP <- " group"
@@ -216,7 +233,7 @@ TERMINATION_GROUP <- "group"
216233# ' `process_terminate(handle)` and `process_kill(handle)`
217234# ' deliver the signal only to the child process pointed to by
218235# ' `handle` but to none of its descendants.
219- # '
236+ # '
220237# ' @rdname spawn_process
221238# ' @export
222239TERMINATION_CHILD_ONLY <- " child_only"
0 commit comments