OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2014 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2014 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 'use strict'; | 7 'use strict'; |
8 | 8 |
9 /** | 9 /** |
10 * PipeServer manages a set of anonymous pipes. | 10 * PipeServer manages a set of anonymous pipes. |
11 */ | 11 */ |
12 function PipeServer() { | 12 function PipeServer() { |
13 // Start id for anonymous pipes. | 13 // Start id for anonymous pipes. |
14 this.anonymousPipeId = 1; | 14 this.anonymousPipeId = 1; |
15 | 15 |
16 // Status of anonymous pipes. | 16 // Status of anonymous pipes. |
17 this.anonymousPipes = {}; | 17 this.anonymousPipes = {}; |
18 } | 18 } |
19 | 19 |
20 /** | 20 /** |
21 * Pipe error. | 21 * Pipe error. |
22 * @type {number} | 22 * @type {number} |
23 */ | 23 */ |
24 PipeServer.prototype.EPIPE = 32; | 24 PipeServer.prototype.EPIPE = 32; |
25 | 25 |
26 /** | 26 /** |
| 27 * EAGAIN / EWOULDBLOCK. |
| 28 * @type {number} |
| 29 */ |
| 30 PipeServer.prototype.EAGAIN = 11; |
| 31 |
| 32 /** |
27 * Handle an anonymous pipe creation call. | 33 * Handle an anonymous pipe creation call. |
28 */ | 34 */ |
29 PipeServer.prototype.handleMessageAPipe = function(msg, reply, src) { | 35 PipeServer.prototype.handleMessageAPipe = function(msg, reply, src) { |
30 var id = this.anonymousPipeId++; | 36 var id = this.anonymousPipeId++; |
31 this.anonymousPipes[id] = { | 37 this.anonymousPipes[id] = { |
32 readers: {}, | 38 readers: {}, |
33 writers: {}, | 39 writers: {}, |
34 readsPending: [], | 40 readsPending: [], |
35 writesPending: [], | 41 writesPending: [], |
36 }; | 42 }; |
(...skipping 19 matching lines...) Expand all Loading... |
56 count: this.EPIPE, | 62 count: this.EPIPE, |
57 }); | 63 }); |
58 return; | 64 return; |
59 } | 65 } |
60 var pipe = this.anonymousPipes[id]; | 66 var pipe = this.anonymousPipes[id]; |
61 while (data.byteLength > 0 && pipe.readsPending.length > 0) { | 67 while (data.byteLength > 0 && pipe.readsPending.length > 0) { |
62 var item = pipe.readsPending.shift(); | 68 var item = pipe.readsPending.shift(); |
63 var part = data.slice(0, item.count); | 69 var part = data.slice(0, item.count); |
64 item.reply({ | 70 item.reply({ |
65 data: part, | 71 data: part, |
| 72 error: 0, |
66 }); | 73 }); |
67 data = data.slice(part.byteLength); | 74 data = data.slice(part.byteLength); |
68 } | 75 } |
69 if (data.byteLength === 0) { | 76 if (data.byteLength === 0) { |
70 reply({ | 77 reply({ |
71 count: dataInitialSize, | 78 count: dataInitialSize, |
72 }); | 79 }); |
73 } else { | 80 } else { |
74 if (Object.keys(pipe.readers).length > 0) { | 81 if (Object.keys(pipe.readers).length > 0) { |
75 // TODO(bradnelson): consider limiting slack on buffer here. | 82 // TODO(bradnelson): consider limiting slack on buffer here. |
(...skipping 20 matching lines...) Expand all Loading... |
96 } | 103 } |
97 }; | 104 }; |
98 | 105 |
99 /** | 106 /** |
100 * Handle an anonymous pipe read call. | 107 * Handle an anonymous pipe read call. |
101 */ | 108 */ |
102 PipeServer.prototype.handleMessageAPipeRead = function( | 109 PipeServer.prototype.handleMessageAPipeRead = function( |
103 msg, reply, src) { | 110 msg, reply, src) { |
104 var id = msg.pipe_id; | 111 var id = msg.pipe_id; |
105 var count = msg.count; | 112 var count = msg.count; |
| 113 var nonblock = msg.nonblock; |
106 if (count === 0 || | 114 if (count === 0 || |
107 !(id in this.anonymousPipes && | 115 !(id in this.anonymousPipes && |
108 src.pid in this.anonymousPipes[id].readers)) { | 116 src.pid in this.anonymousPipes[id].readers)) { |
109 reply({ | 117 reply({ |
110 data: new ArrayBuffer(0), | 118 data: new ArrayBuffer(0), |
| 119 error: 0, |
111 }); | 120 }); |
112 return; | 121 return; |
113 } | 122 } |
114 var pipe = this.anonymousPipes[id]; | 123 var pipe = this.anonymousPipes[id]; |
115 if (pipe.writesPending.length > 0) { | 124 if (pipe.writesPending.length > 0) { |
116 var item = pipe.writesPending.shift(); | 125 var item = pipe.writesPending.shift(); |
117 if (item.data.byteLength > count) { | 126 if (item.data.byteLength > count) { |
118 var part = item.data.slice(0, count); | 127 var part = item.data.slice(0, count); |
119 reply({ | 128 reply({ |
120 data: part, | 129 data: part, |
| 130 error: 0, |
121 }); | 131 }); |
122 item.data = item.data.slice(part.byteLength); | 132 item.data = item.data.slice(part.byteLength); |
123 pipe.writesPending.unshift(item); | 133 pipe.writesPending.unshift(item); |
124 } else { | 134 } else { |
125 reply({ | 135 reply({ |
126 data: item.data, | 136 data: item.data, |
| 137 error: 0, |
127 }); | 138 }); |
128 if (!item.replied) { | 139 if (!item.replied) { |
129 item.reply({ | 140 item.reply({ |
130 count: item.dataInitialSize, | 141 count: item.dataInitialSize, |
131 }); | 142 }); |
132 } | 143 } |
133 } | 144 } |
134 } else { | 145 } else { |
135 if (Object.keys(pipe.writers).length > 0) { | 146 if (Object.keys(pipe.writers).length > 0) { |
136 pipe.readsPending.push({ | 147 if (nonblock !== 0) { |
137 count: count, | 148 reply({ |
138 reply: reply, | 149 error: this.EAGAIN, |
139 pid: src.pid, | 150 }); |
140 }); | 151 } else { |
| 152 pipe.readsPending.push({ |
| 153 count: count, |
| 154 reply: reply, |
| 155 pid: src.pid, |
| 156 }); |
| 157 } |
141 } else { | 158 } else { |
142 reply({ | 159 reply({ |
143 data: new ArrayBuffer(0), | 160 data: new ArrayBuffer(0), |
| 161 error: 0, |
144 }); | 162 }); |
145 } | 163 } |
146 } | 164 } |
147 }; | 165 }; |
148 | 166 |
149 /** | 167 /** |
150 * Close handle to an anonymous pipe for a process. | 168 * Close handle to an anonymous pipe for a process. |
151 */ | 169 */ |
152 PipeServer.prototype.closeAPipe = function(pid, pipeId, writer) { | 170 PipeServer.prototype.closeAPipe = function(pid, pipeId, writer) { |
153 if (pipeId in this.anonymousPipes) { | 171 if (pipeId in this.anonymousPipes) { |
154 var pipe = this.anonymousPipes[pipeId]; | 172 var pipe = this.anonymousPipes[pipeId]; |
155 if (writer) { | 173 if (writer) { |
156 delete pipe.writers[pid]; | 174 delete pipe.writers[pid]; |
157 } else { | 175 } else { |
158 delete pipe.readers[pid]; | 176 delete pipe.readers[pid]; |
159 } | 177 } |
160 if (Object.keys(pipe.writers).length === 0 && | 178 if (Object.keys(pipe.writers).length === 0 && |
161 Object.keys(pipe.readers).length === 0) { | 179 Object.keys(pipe.readers).length === 0) { |
162 delete this.anonymousPipes[pipeId]; | 180 delete this.anonymousPipes[pipeId]; |
163 } else if (Object.keys(pipe.writers).length === 0) { | 181 } else if (Object.keys(pipe.writers).length === 0) { |
164 for (var i = 0; i < pipe.readsPending.length; i++) { | 182 for (var i = 0; i < pipe.readsPending.length; i++) { |
165 var item = pipe.readsPending[i]; | 183 var item = pipe.readsPending[i]; |
166 item.reply({ | 184 item.reply({ |
167 data: new ArrayBuffer(0), | 185 data: new ArrayBuffer(0), |
| 186 error: 0, |
168 }); | 187 }); |
169 } | 188 } |
170 pipe.readsPending = []; | 189 pipe.readsPending = []; |
171 } else if (Object.keys(pipe.readers).length === 0) { | 190 } else if (Object.keys(pipe.readers).length === 0) { |
172 for (var i = 0; i < pipe.writesPending.length; i++) { | 191 for (var i = 0; i < pipe.writesPending.length; i++) { |
173 var item = pipe.writesPending[i]; | 192 var item = pipe.writesPending[i]; |
174 item.reply({ | 193 item.reply({ |
175 count: this.EPIPE, | 194 count: this.EPIPE, |
176 }); | 195 }); |
177 } | 196 } |
178 pipe.writesPending = []; | 197 pipe.writesPending = []; |
179 } | 198 } |
180 } | 199 } |
181 }; | 200 }; |
182 | 201 |
183 /** | 202 /** |
184 * Handle an anonymous pipe close call. | 203 * Handle an anonymous pipe close call. |
185 */ | 204 */ |
186 PipeServer.prototype.handleMessageAPipeClose = function( | 205 PipeServer.prototype.handleMessageAPipeClose = function( |
187 msg, reply, src) { | 206 msg, reply, src) { |
188 this.closeAPipe(src.pid, msg.pipe_id, msg.writer); | 207 this.closeAPipe(src.pid, msg.pipe_id, msg.writer); |
189 reply({ | 208 reply({ |
190 result: 0, | 209 result: 0, |
191 }); | 210 }); |
192 }; | 211 }; |
193 | 212 |
194 | 213 |
195 /** | 214 /** |
196 * Add spawned pipe entries. | 215 * Add spawned pipe entries. |
| 216 * @pid {Object} Numeric process for which to add pipes. |
197 * @params {Object} Dictionary of environment variables passed to process. | 217 * @params {Object} Dictionary of environment variables passed to process. |
| 218 * @returns {boolean} True if stdin is routed. |
198 */ | 219 */ |
199 PipeServer.prototype.addProcessPipes = function(pid, params) { | 220 PipeServer.prototype.addProcessPipes = function(pid, params) { |
| 221 var routeStdin = false; |
200 var fdCount = 0; | 222 var fdCount = 0; |
201 for (;;fdCount++) { | 223 for (;;fdCount++) { |
202 var entry = 'NACL_SPAWN_FD_SETUP_' + fdCount; | 224 var entry = 'NACL_SPAWN_FD_SETUP_' + fdCount; |
203 if (!(entry in params)) | 225 if (!(entry in params)) |
204 break; | 226 break; |
205 // Pull out a a pipe spec of the form: | 227 // Pull out a a pipe spec of the form: |
206 // pipe:<fd number>:<pipe-id>:<is-writer> | 228 // pipe:<fd number>:<pipe-id>:<is-writer> |
207 var m = params[entry].match(/pipe:([0-9]+):([0-9]+):([0-9]+)/); | 229 var m = params[entry].match(/pipe:([0-9]+):([0-9]+):([0-9]+)/); |
208 if (m) { | 230 if (m) { |
209 var fd = parseInt(m[1]); | 231 var fd = parseInt(m[1]); |
210 var id = parseInt(m[2]); | 232 var id = parseInt(m[2]); |
211 var isWriter = parseInt(m[3]); | 233 var isWriter = parseInt(m[3]); |
| 234 if (fd === 0) { |
| 235 routeStdin = true; |
| 236 } |
212 if (id in this.anonymousPipes) { | 237 if (id in this.anonymousPipes) { |
213 var pipe = this.anonymousPipes[id]; | 238 var pipe = this.anonymousPipes[id]; |
214 if (isWriter) { | 239 if (isWriter) { |
215 pipe.writers[pid] = null; | 240 pipe.writers[pid] = null; |
216 } else { | 241 } else { |
217 pipe.readers[pid] = null; | 242 pipe.readers[pid] = null; |
218 } | 243 } |
219 } | 244 } |
220 } | 245 } |
221 } | 246 } |
| 247 return routeStdin; |
222 }; | 248 }; |
223 | 249 |
224 | 250 |
225 /** | 251 /** |
226 * Add spawned pipe entries. | 252 * Add spawned pipe entries. |
227 * @params {Object} Dictionary of environment variables passed to process. | 253 * @params {Object} Dictionary of environment variables passed to process. |
228 */ | 254 */ |
229 PipeServer.prototype.deleteProcess = function(pid) { | 255 PipeServer.prototype.deleteProcess = function(pid) { |
230 for (var pipeId in this.anonymousPipes) { | 256 for (var pipeId in this.anonymousPipes) { |
231 var pipe = this.anonymousPipes[pipeId]; | 257 var pipe = this.anonymousPipes[pipeId]; |
232 if (pid in pipe.readers) { | 258 if (pid in pipe.readers) { |
233 this.closeAPipe(pid, pipeId, false); | 259 this.closeAPipe(pid, pipeId, false); |
234 } | 260 } |
235 if (pid in pipe.writers) { | 261 if (pid in pipe.writers) { |
236 this.closeAPipe(pid, pipeId, true); | 262 this.closeAPipe(pid, pipeId, true); |
237 } | 263 } |
238 } | 264 } |
239 }; | 265 }; |
OLD | NEW |