-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathintro.html
280 lines (248 loc) · 27.6 KB
/
intro.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="Lukasz A. Bartnik" />
<meta name="date" content="2017-01-02" />
<title>Introduction to Sub-Processes in R</title>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
</style>
<link href="data:text/css;charset=utf-8,body%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0Amargin%3A%201em%20auto%3B%0Amax%2Dwidth%3A%20700px%3B%0Aoverflow%3A%20visible%3B%0Apadding%2Dleft%3A%202em%3B%0Apadding%2Dright%3A%202em%3B%0Afont%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0Afont%2Dsize%3A%2014px%3B%0Aline%2Dheight%3A%201%2E35%3B%0A%7D%0A%23header%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%23TOC%20%7B%0Aclear%3A%20both%3B%0Amargin%3A%200%200%2010px%2010px%3B%0Apadding%3A%204px%3B%0Awidth%3A%20400px%3B%0Aborder%3A%201px%20solid%20%23CCCCCC%3B%0Aborder%2Dradius%3A%205px%3B%0Abackground%2Dcolor%3A%20%23f6f6f6%3B%0Afont%2Dsize%3A%2013px%3B%0Aline%2Dheight%3A%201%2E3%3B%0A%7D%0A%23TOC%20%2Etoctitle%20%7B%0Afont%2Dweight%3A%20bold%3B%0Afont%2Dsize%3A%2015px%3B%0Amargin%2Dleft%3A%205px%3B%0A%7D%0A%23TOC%20ul%20%7B%0Apadding%2Dleft%3A%2040px%3B%0Amargin%2Dleft%3A%20%2D1%2E5em%3B%0Amargin%2Dtop%3A%205px%3B%0Amargin%2Dbottom%3A%205px%3B%0A%7D%0A%23TOC%20ul%20ul%20%7B%0Amargin%2Dleft%3A%20%2D2em%3B%0A%7D%0A%23TOC%20li%20%7B%0Aline%2Dheight%3A%2016px%3B%0A%7D%0Atable%20%7B%0Amargin%3A%201em%20auto%3B%0Aborder%2Dwidth%3A%201px%3B%0Aborder%2Dcolor%3A%20%23DDDDDD%3B%0Aborder%2Dstyle%3A%20outset%3B%0Aborder%2Dcollapse%3A%20collapse%3B%0A%7D%0Atable%20th%20%7B%0Aborder%2Dwidth%3A%202px%3B%0Apadding%3A%205px%3B%0Aborder%2Dstyle%3A%20inset%3B%0A%7D%0Atable%20td%20%7B%0Aborder%2Dwidth%3A%201px%3B%0Aborder%2Dstyle%3A%20inset%3B%0Aline%2Dheight%3A%2018px%3B%0Apadding%3A%205px%205px%3B%0A%7D%0Atable%2C%20table%20th%2C%20table%20td%20%7B%0Aborder%2Dleft%2Dstyle%3A%20none%3B%0Aborder%2Dright%2Dstyle%3A%20none%3B%0A%7D%0Atable%20thead%2C%20table%20tr%2Eeven%20%7B%0Abackground%2Dcolor%3A%20%23f7f7f7%3B%0A%7D%0Ap%20%7B%0Amargin%3A%200%2E5em%200%3B%0A%7D%0Ablockquote%20%7B%0Abackground%2Dcolor%3A%20%23f6f6f6%3B%0Apadding%3A%200%2E25em%200%2E75em%3B%0A%7D%0Ahr%20%7B%0Aborder%2Dstyle%3A%20solid%3B%0Aborder%3A%20none%3B%0Aborder%2Dtop%3A%201px%20solid%20%23777%3B%0Amargin%3A%2028px%200%3B%0A%7D%0Adl%20%7B%0Amargin%2Dleft%3A%200%3B%0A%7D%0Adl%20dd%20%7B%0Amargin%2Dbottom%3A%2013px%3B%0Amargin%2Dleft%3A%2013px%3B%0A%7D%0Adl%20dt%20%7B%0Afont%2Dweight%3A%20bold%3B%0A%7D%0Aul%20%7B%0Amargin%2Dtop%3A%200%3B%0A%7D%0Aul%20li%20%7B%0Alist%2Dstyle%3A%20circle%20outside%3B%0A%7D%0Aul%20ul%20%7B%0Amargin%2Dbottom%3A%200%3B%0A%7D%0Apre%2C%20code%20%7B%0Abackground%2Dcolor%3A%20%23f7f7f7%3B%0Aborder%2Dradius%3A%203px%3B%0Acolor%3A%20%23333%3B%0Awhite%2Dspace%3A%20pre%2Dwrap%3B%20%0A%7D%0Apre%20%7B%0Aborder%2Dradius%3A%203px%3B%0Amargin%3A%205px%200px%2010px%200px%3B%0Apadding%3A%2010px%3B%0A%7D%0Apre%3Anot%28%5Bclass%5D%29%20%7B%0Abackground%2Dcolor%3A%20%23f7f7f7%3B%0A%7D%0Acode%20%7B%0Afont%2Dfamily%3A%20Consolas%2C%20Monaco%2C%20%27Courier%20New%27%2C%20monospace%3B%0Afont%2Dsize%3A%2085%25%3B%0A%7D%0Ap%20%3E%20code%2C%20li%20%3E%20code%20%7B%0Apadding%3A%202px%200px%3B%0A%7D%0Adiv%2Efigure%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0Aimg%20%7B%0Abackground%2Dcolor%3A%20%23FFFFFF%3B%0Apadding%3A%202px%3B%0Aborder%3A%201px%20solid%20%23DDDDDD%3B%0Aborder%2Dradius%3A%203px%3B%0Aborder%3A%201px%20solid%20%23CCCCCC%3B%0Amargin%3A%200%205px%3B%0A%7D%0Ah1%20%7B%0Amargin%2Dtop%3A%200%3B%0Afont%2Dsize%3A%2035px%3B%0Aline%2Dheight%3A%2040px%3B%0A%7D%0Ah2%20%7B%0Aborder%2Dbottom%3A%204px%20solid%20%23f7f7f7%3B%0Apadding%2Dtop%3A%2010px%3B%0Apadding%2Dbottom%3A%202px%3B%0Afont%2Dsize%3A%20145%25%3B%0A%7D%0Ah3%20%7B%0Aborder%2Dbottom%3A%202px%20solid%20%23f7f7f7%3B%0Apadding%2Dtop%3A%2010px%3B%0Afont%2Dsize%3A%20120%25%3B%0A%7D%0Ah4%20%7B%0Aborder%2Dbottom%3A%201px%20solid%20%23f7f7f7%3B%0Amargin%2Dleft%3A%208px%3B%0Afont%2Dsize%3A%20105%25%3B%0A%7D%0Ah5%2C%20h6%20%7B%0Aborder%2Dbottom%3A%201px%20solid%20%23ccc%3B%0Afont%2Dsize%3A%20105%25%3B%0A%7D%0Aa%20%7B%0Acolor%3A%20%230033dd%3B%0Atext%2Ddecoration%3A%20none%3B%0A%7D%0Aa%3Ahover%20%7B%0Acolor%3A%20%236666ff%3B%20%7D%0Aa%3Avisited%20%7B%0Acolor%3A%20%23800080%3B%20%7D%0Aa%3Avisited%3Ahover%20%7B%0Acolor%3A%20%23BB00BB%3B%20%7D%0Aa%5Bhref%5E%3D%22http%3A%22%5D%20%7B%0Atext%2Ddecoration%3A%20underline%3B%20%7D%0Aa%5Bhref%5E%3D%22https%3A%22%5D%20%7B%0Atext%2Ddecoration%3A%20underline%3B%20%7D%0A%0Acode%20%3E%20span%2Ekw%20%7B%20color%3A%20%23555%3B%20font%2Dweight%3A%20bold%3B%20%7D%20%0Acode%20%3E%20span%2Edt%20%7B%20color%3A%20%23902000%3B%20%7D%20%0Acode%20%3E%20span%2Edv%20%7B%20color%3A%20%2340a070%3B%20%7D%20%0Acode%20%3E%20span%2Ebn%20%7B%20color%3A%20%23d14%3B%20%7D%20%0Acode%20%3E%20span%2Efl%20%7B%20color%3A%20%23d14%3B%20%7D%20%0Acode%20%3E%20span%2Ech%20%7B%20color%3A%20%23d14%3B%20%7D%20%0Acode%20%3E%20span%2Est%20%7B%20color%3A%20%23d14%3B%20%7D%20%0Acode%20%3E%20span%2Eco%20%7B%20color%3A%20%23888888%3B%20font%2Dstyle%3A%20italic%3B%20%7D%20%0Acode%20%3E%20span%2Eot%20%7B%20color%3A%20%23007020%3B%20%7D%20%0Acode%20%3E%20span%2Eal%20%7B%20color%3A%20%23ff0000%3B%20font%2Dweight%3A%20bold%3B%20%7D%20%0Acode%20%3E%20span%2Efu%20%7B%20color%3A%20%23900%3B%20font%2Dweight%3A%20bold%3B%20%7D%20%20code%20%3E%20span%2Eer%20%7B%20color%3A%20%23a61717%3B%20background%2Dcolor%3A%20%23e3d2d2%3B%20%7D%20%0A" rel="stylesheet" type="text/css" />
</head>
<body>
<h1 class="title toc-ignore">Introduction to Sub-Processes in R</h1>
<h4 class="author"><em>Lukasz A. Bartnik</em></h4>
<h4 class="date"><em>2017-01-02</em></h4>
<div id="introduction" class="section level2">
<h2>Introduction</h2>
<p>Since R is not really a systems-programming language<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a> some facilities present in other such languages (e.g. C/C++, Python) haven’t been yet brought to R. One of such features is process management which is understood here as the capability to create, interact with and control the lifetime of child processes.</p>
<p>The R package <code>subprocess</code> aims at filling this gap by providing the few basic operations to carry out the aforementioned tasks. The <code>spawn_subprocess()</code> function starts a new child process and returns a handle which can be later used in <code>process_read()</code> and <code>process_write()</code> to send and receive data or in <code>process_wait()</code> or <code>process_terminate()</code> to stop the such a process.</p>
<p>The R <code>subprocess</code> package has been designed after the exemplary Python package which goes by the same. Its documentation can be found <a href="https://docs.python.org/3/library/subprocess.html">here</a> and numerous examples of how it can be used can be found on the Web.</p>
<p>The R <code>subprocess</code> package has been implemented for both <strong>Linux</strong> and <strong>Windows</strong> but since the author doesn’t have access to a <strong>MacOS</strong> machine the extent to which it is compatible with <strong>MacOS</strong> is unknown to him.</p>
</div>
<div id="design-and-implementation" class="section level2">
<h2>Design and Implementation</h2>
<p>The main concept in the package is the <strong>handle</strong> which holds process identifiers and an <strong>external pointer</strong> object which in turn is a handle to a low-level data structure holding various system-level parameters of the running sub-process.</p>
<p>A child process, once started, runs until it exits on its own or until its killed. Its current state as well as its exit status can be obtained by dedicated API.</p>
<p>Communication with the child process can be carried out over the three standard streams: the standard input, standard output and standard error output. These streams are intercepted on the child process’ side and redirected into three anonymous pipes whose other ends are held by the parent process and can be accessed through the process <strong>handle</strong>.</p>
<p>In <strong>Linux</strong> these are regular pipes created with the <code>pipe()</code> system call and opened in the <strong>non-blocking</strong> mode. All communication takes place on request and follows the usual OS rules (e.g. the sub-process will sleep if its output buffer gets filled).</p>
<p>In <strong>Windows</strong> these pipes are created with the <code>CreatePipe()</code> call and opened in the <strong>blocking</strong> mode. <strong>Windows</strong> does not support <strong>non-blocking</strong> (<strong>overlapped</strong> in <strong>Windows</strong>-speak) mode for anonymous pipes. For that reason each stream has an accompanying reader thread. Reader threads are separated from R interpreter, do not exchange memory with the R interpreter and will not break the single-thread assumption under which R operates.</p>
</div>
<div id="introduction-to-examples" class="section level2">
<h2>Introduction to Examples</h2>
<p>Before we move on to examples, let’s define a few helper functions that abstract out the underlying operating system. We will use them throughout this vignette.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">is_windows <-<span class="st"> </span>function () (<span class="kw">tolower</span>(.Platform$OS.type) ==<span class="st"> "windows"</span>)
R_binary <-<span class="st"> </span>function () {
R_exe <-<span class="st"> </span><span class="kw">ifelse</span> (<span class="kw">is_windows</span>(), <span class="st">"R.exe"</span>, <span class="st">"R"</span>)
<span class="kw">return</span>(<span class="kw">file.path</span>(<span class="kw">R.home</span>(<span class="st">"bin"</span>), R_exe))
}</code></pre></div>
<p>Just for the record, vignette has been built in Linux.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">ifelse</span>(<span class="kw">is_windows</span>(), <span class="st">"Windows"</span>, <span class="st">"Linux"</span>)
<span class="co">#> [1] "Linux"</span></code></pre></div>
<p>Now we can load the package and move on to the next section.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">library</span>(subprocess)</code></pre></div>
</div>
<div id="example-controlling-chlid-r-process" class="section level2">
<h2>Example: controlling chlid R process</h2>
<p>In this example we spawn a new R process, send a few commands to its standard input and read the responses from its standard output. First, let’s spawn the child process (and give it a moment to complete the start-up sequence<a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a>):</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">handle <-<span class="st"> </span><span class="kw">spawn_process</span>(<span class="kw">R_binary</span>(), <span class="kw">c</span>(<span class="st">'--no-save'</span>))
<span class="kw">Sys.sleep</span>(<span class="dv">1</span>)</code></pre></div>
<p>Let’s see the description of the child process:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">print</span>(handle)
<span class="co">#> Process Handle</span>
<span class="co">#> command : /usr/lib/R/bin/R --no-save</span>
<span class="co">#> system id : 11382</span>
<span class="co">#> state : running</span></code></pre></div>
<p>And now let’s see what we can find it the child’s output:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">process_read</span>(handle, PIPE_STDOUT, <span class="dt">timeout =</span> <span class="dv">1000</span>)
<span class="co">#> [1] "" </span>
<span class="co">#> [2] "R version 3.3.2 (2016-10-31) -- \"Sincere Pumpkin Patch\"" </span>
<span class="co">#> [3] "Copyright (C) 2016 The R Foundation for Statistical Computing"</span>
<span class="co">#> [4] "Platform: x86_64-pc-linux-gnu (64-bit)" </span>
<span class="co">#> [5] "" </span>
<span class="co">#> [6] "R is free software and comes with ABSOLUTELY NO WARRANTY." </span>
<span class="co">#> [7] "You are welcome to redistribute it under certain conditions." </span>
<span class="co">#> [8] "Type 'license()' or 'licence()' for distribution details." </span>
<span class="co">#> [9] "" </span>
<span class="co">#> [10] " Natural language support but running in an English locale" </span>
<span class="co">#> [11] "" </span>
<span class="co">#> [12] "R is a collaborative project with many contributors." </span>
<span class="co">#> [13] "Type 'contributors()' for more information and" </span>
<span class="co">#> [14] "'citation()' on how to cite R or R packages in publications." </span>
<span class="co">#> [15] "" </span>
<span class="co">#> [16] "Type 'demo()' for some demos, 'help()' for on-line help, or" </span>
<span class="co">#> [17] "'help.start()' for an HTML browser interface to help." </span>
<span class="co">#> [18] "Type 'q()' to quit R." </span>
<span class="co">#> [19] "" </span>
<span class="co">#> [20] "> "</span>
<span class="kw">process_read</span>(handle, PIPE_STDERR)
<span class="co">#> character(0)</span></code></pre></div>
<p>The first number in the output is the value returned by <code>process_write</code> which is the number of characters written to standard input of the child process. The final <code>character(0)</code> is the output read from the standard error stream.</p>
<p>Next, we create a new variable in child’s session. Please notice the new-line character at the end of the command. It triggers the child process to process its input.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">process_write</span>(handle, <span class="st">'n <- 10</span><span class="ch">\n</span><span class="st">'</span>)
<span class="co">#> [1] 8</span>
<span class="kw">process_read</span>(handle, PIPE_STDOUT, <span class="dt">timeout =</span> <span class="dv">1000</span>)
<span class="co">#> [1] "n <- 10" "> "</span>
<span class="kw">process_read</span>(handle, PIPE_STDERR)
<span class="co">#> character(0)</span></code></pre></div>
<p>Now it’s time to use this variable in a function call:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">process_write</span>(handle, <span class="st">'rnorm(n)</span><span class="ch">\n</span><span class="st">'</span>)
<span class="co">#> [1] 9</span>
<span class="kw">process_read</span>(handle, PIPE_STDOUT, <span class="dt">timeout =</span> <span class="dv">1000</span>)
<span class="co">#> [1] "rnorm(n)" </span>
<span class="co">#> [2] " [1] 2.39239740 0.95520346 0.96145834 -0.28637014 0.01075136 -0.26330992"</span>
<span class="co">#> [3] " [7] -0.41293419 0.04698814 0.85471492 -0.67604254" </span>
<span class="co">#> [4] "> "</span>
<span class="kw">process_read</span>(handle, PIPE_STDERR)
<span class="co">#> character(0)</span></code></pre></div>
<p>Finally, we exit the child process:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">process_write</span>(handle, <span class="st">'q(save = "no")</span><span class="ch">\n</span><span class="st">'</span>)
<span class="co">#> [1] 15</span>
<span class="kw">process_read</span>(handle, PIPE_STDOUT, <span class="dt">timeout =</span> <span class="dv">1000</span>)
<span class="co">#> [1] "q(save = \"no\")"</span>
<span class="kw">process_read</span>(handle, PIPE_STDERR)
<span class="co">#> character(0)</span></code></pre></div>
<p>The last thing is making sure that the child process is no longer alive:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">process_state</span>(handle)
<span class="co">#> [1] "exited"</span>
<span class="kw">process_return_code</span>(handle)
<span class="co">#> [1] 0</span></code></pre></div>
<p>Of course there is little value in running a child R process since there are multiple other tools that let you do that, like <code>parallel</code>, <code>Rserve</code> and <code>opencpu</code> to name just a few. However, it’s quite easy to imagine how running a remote shell in this manner enables new ways of interacting with the environment. Consider running a local shell:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">shell_binary <-<span class="st"> </span>function () {
<span class="kw">ifelse</span> (<span class="kw">tolower</span>(.Platform$OS.type) ==<span class="st"> "windows"</span>,
<span class="st">"C:/Windows/System32/cmd.exe"</span>, <span class="st">"/bin/sh"</span>)
}
handle <-<span class="st"> </span><span class="kw">spawn_process</span>(<span class="kw">shell_binary</span>())
<span class="kw">print</span>(handle)
<span class="co">#> Process Handle</span>
<span class="co">#> command : /bin/dash </span>
<span class="co">#> system id : 11389</span>
<span class="co">#> state : running</span></code></pre></div>
<p>Now we can interact with the shell sub-process. We send a request to list the current directory, then give it a moment to process the command and produce the output (and maybe finish its start-up, too). Finally, we check its output streams.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">process_write</span>(handle, <span class="st">"ls</span><span class="ch">\n</span><span class="st">"</span>)
<span class="co">#> [1] 3</span>
<span class="kw">Sys.sleep</span>(<span class="dv">1</span>)
<span class="kw">process_read</span>(handle, PIPE_STDOUT)
<span class="co">#> [1] "intro.Rmd"</span>
<span class="kw">process_read</span>(handle, PIPE_STDERR)
<span class="co">#> character(0)</span></code></pre></div>
</div>
<div id="advanced-techniques" class="section level2">
<h2>Advanced techniques</h2>
<div id="terminating-a-child-process" class="section level3">
<h3>Terminating a child process</h3>
<p>If the child process needs to be terminated one can choose to:</p>
<ul>
<li>send a command on the standard input with <code>process_write()</code></li>
<li>send the termination signal, <code>SIGTERM</code> (<strong>Linux</strong>, <strong>Windows</strong>)</li>
<li>send the kill signal, <code>SIGKILL</code> (<strong>Linux</strong> only)</li>
</ul>
<p>Assume the child R process is hung and there is no way to stop it gracefully. <code>process_wait(handle, 1000)</code> waits for 1 second (1000 milliseconds) for the child process to exit. It then returns <code>NA</code> and <code>process_terminate()</code> gives <code>R</code> a chance to exit graceully. Finally, <code>process_kill()</code> forces it to exit.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">sub_command <-<span class="st"> "library(subprocess);subprocess:::signal(15,'ignore');Sys.sleep(1000)"</span>
handle <-<span class="st"> </span><span class="kw">spawn_process</span>(<span class="kw">R_binary</span>(), <span class="kw">c</span>(<span class="st">'--slave'</span>, <span class="st">'-e'</span>, sub_command))
<span class="kw">Sys.sleep</span>(<span class="dv">1</span>)
<span class="co"># process is hung</span>
<span class="kw">process_wait</span>(handle, <span class="dv">1000</span>)
<span class="co">#> [1] 1</span>
<span class="kw">process_state</span>(handle)
<span class="co">#> [1] "exited"</span>
<span class="co"># ask nicely to exit; will be ignored in Linux but not in Windows</span>
<span class="kw">process_terminate</span>(handle)
<span class="co">#> [1] TRUE</span>
<span class="kw">process_wait</span>(handle, <span class="dv">1000</span>)
<span class="co">#> [1] 1</span>
<span class="kw">process_state</span>(handle)
<span class="co">#> [1] "exited"</span>
<span class="co"># forced exit; in Windows the same as the previous call to process_terminate()</span>
<span class="kw">process_kill</span>(handle)
<span class="co">#> [1] TRUE</span>
<span class="kw">process_wait</span>(handle, <span class="dv">1000</span>)
<span class="co">#> [1] 1</span>
<span class="kw">process_state</span>(handle)
<span class="co">#> [1] "exited"</span></code></pre></div>
<p>We see that the child process remains running until it receives the <code>SIGKILL</code> signal<a href="#fn3" class="footnoteRef" id="fnref3"><sup>3</sup></a>. The final return code (exit status) is the number of the signal that caused the child process to exit<a href="#fn4" class="footnoteRef" id="fnref4"><sup>4</sup></a>.</p>
</div>
<div id="sending-a-signal-to-the-child-process" class="section level3">
<h3>Sending a signal to the child process</h3>
<p>The last topic we want to cover here is sending an arbitrary<a href="#fn5" class="footnoteRef" id="fnref5"><sup>5</sup></a> signal to the child process. Signals can be listed by looking at the <code>signals</code> variable present in the package. It is constructed automatically when the package is loaded and its value on <strong>Linux</strong> is different than on <strong>Windows</strong>. In the example below we see the first three elements of the <strong>Linux</strong> list of signals.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">length</span>(signals)
<span class="co">#> [1] 19</span>
signals[<span class="dv">1</span>:<span class="dv">3</span>]
<span class="co">#> $SIGHUP</span>
<span class="co">#> [1] 1</span>
<span class="co">#> </span>
<span class="co">#> $SIGINT</span>
<span class="co">#> [1] 2</span>
<span class="co">#> </span>
<span class="co">#> $SIGQUIT</span>
<span class="co">#> [1] 3</span></code></pre></div>
<p>All possible signal identifiers are supported directly from the <code>subprocess</code> package. Signals not supported on the current platform are set to <code>NA</code> and the rest have their OS-specific numbers as their values.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">ls</span>(<span class="dt">pattern =</span> <span class="st">'SIG'</span>, <span class="dt">envir =</span> <span class="kw">asNamespace</span>(<span class="st">'subprocess'</span>))
<span class="co">#> [1] "SIGABRT" "SIGALRM" "SIGCHLD" "SIGCONT" "SIGFPE" "SIGHUP" "SIGILL" </span>
<span class="co">#> [8] "SIGINT" "SIGKILL" "SIGPIPE" "SIGQUIT" "SIGSEGV" "SIGSTOP" "SIGTERM"</span>
<span class="co">#> [15] "SIGTSTP" "SIGTTIN" "SIGTTOU" "SIGUSR1" "SIGUSR2"</span></code></pre></div>
<p>Now we can create a new child process and send an arbitrary using its handle.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">handle <-<span class="st"> </span><span class="kw">spawn_process</span>(R_binary, <span class="st">'--slave'</span>)
<span class="kw">process_send_signal</span>(handle, SIGUSR1)</code></pre></div>
</div>
</div>
<div class="footnotes">
<hr />
<ol>
<li id="fn1"><p>“By systems programming I mean writing code that directly uses hardware resources, has serious resource constraints, or closely interacts with code that does.” Bjarne Stroustrup, “The C++ Programming Language”<a href="#fnref1">↩</a></p></li>
<li id="fn2"><p>Depending on the system load, R can take a few seconds to start and be ready for input. This is true also for other processes. Thus, you will see <code>Sys.sleep()</code> following <code>spawn_process()</code> in almost every example in this vignette.<a href="#fnref2">↩</a></p></li>
<li id="fn3"><p>The <code>.Call("C_signal")</code> in our example is a call to a hidden C function that <code>subprocess</code> provides mainly for the purposes of this example.<a href="#fnref3">↩</a></p></li>
<li id="fn4"><p>See the <code>waitpid()</code> manual page, e.g. <a href="https://linux.die.net/man/2/waitpid">here</a>.<a href="#fnref4">↩</a></p></li>
<li id="fn5"><p>The list of signals supported in <strong>Windows</strong> is much shorter than the list of signals supported in <strong>Linux</strong> and contains the following three signals: <code>SIGTERM</code>, <code>CTRL_C_EVENT</code> and <code>CTRL_BREAK_EVENT</code>.<a href="#fnref5">↩</a></p></li>
</ol>
</div>
<!-- dynamically load mathjax for compatibility with self-contained -->
<script>
(function () {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
document.getElementsByTagName("head")[0].appendChild(script);
})();
</script>
</body>
</html>