Chromium Code Reviews| 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. |
| 197 * @params {Object} Dictionary of environment variables passed to process. | 216 * @params {Object} Dictionary of environment variables passed to process. |
|
Pete Williamson
2016/02/29 20:53:47
nit: With two input variables, I expect to see two
bradnelson
2016/03/03 18:04:02
No by all means. And you have js readability too :
| |
| 217 * @returns {boolean} True if stdin is routed. | |
| 198 */ | 218 */ |
| 199 PipeServer.prototype.addProcessPipes = function(pid, params) { | 219 PipeServer.prototype.addProcessPipes = function(pid, params) { |
| 220 var routeStdin = false; | |
| 200 var fdCount = 0; | 221 var fdCount = 0; |
| 201 for (;;fdCount++) { | 222 for (;;fdCount++) { |
| 202 var entry = 'NACL_SPAWN_FD_SETUP_' + fdCount; | 223 var entry = 'NACL_SPAWN_FD_SETUP_' + fdCount; |
| 203 if (!(entry in params)) | 224 if (!(entry in params)) |
| 204 break; | 225 break; |
| 205 // Pull out a a pipe spec of the form: | 226 // Pull out a a pipe spec of the form: |
| 206 // pipe:<fd number>:<pipe-id>:<is-writer> | 227 // pipe:<fd number>:<pipe-id>:<is-writer> |
| 207 var m = params[entry].match(/pipe:([0-9]+):([0-9]+):([0-9]+)/); | 228 var m = params[entry].match(/pipe:([0-9]+):([0-9]+):([0-9]+)/); |
| 208 if (m) { | 229 if (m) { |
| 209 var fd = parseInt(m[1]); | 230 var fd = parseInt(m[1]); |
| 210 var id = parseInt(m[2]); | 231 var id = parseInt(m[2]); |
| 211 var isWriter = parseInt(m[3]); | 232 var isWriter = parseInt(m[3]); |
| 233 if (fd === 0) { | |
| 234 routeStdin = true; | |
| 235 } | |
| 212 if (id in this.anonymousPipes) { | 236 if (id in this.anonymousPipes) { |
| 213 var pipe = this.anonymousPipes[id]; | 237 var pipe = this.anonymousPipes[id]; |
| 214 if (isWriter) { | 238 if (isWriter) { |
| 215 pipe.writers[pid] = null; | 239 pipe.writers[pid] = null; |
| 216 } else { | 240 } else { |
| 217 pipe.readers[pid] = null; | 241 pipe.readers[pid] = null; |
| 218 } | 242 } |
| 219 } | 243 } |
| 220 } | 244 } |
| 221 } | 245 } |
| 246 return routeStdin; | |
| 222 }; | 247 }; |
| 223 | 248 |
| 224 | 249 |
| 225 /** | 250 /** |
| 226 * Add spawned pipe entries. | 251 * Add spawned pipe entries. |
| 227 * @params {Object} Dictionary of environment variables passed to process. | 252 * @params {Object} Dictionary of environment variables passed to process. |
| 228 */ | 253 */ |
| 229 PipeServer.prototype.deleteProcess = function(pid) { | 254 PipeServer.prototype.deleteProcess = function(pid) { |
| 230 for (var pipeId in this.anonymousPipes) { | 255 for (var pipeId in this.anonymousPipes) { |
| 231 var pipe = this.anonymousPipes[pipeId]; | 256 var pipe = this.anonymousPipes[pipeId]; |
| 232 if (pid in pipe.readers) { | 257 if (pid in pipe.readers) { |
| 233 this.closeAPipe(pid, pipeId, false); | 258 this.closeAPipe(pid, pipeId, false); |
| 234 } | 259 } |
| 235 if (pid in pipe.writers) { | 260 if (pid in pipe.writers) { |
| 236 this.closeAPipe(pid, pipeId, true); | 261 this.closeAPipe(pid, pipeId, true); |
| 237 } | 262 } |
| 238 } | 263 } |
| 239 }; | 264 }; |
| OLD | NEW |