Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: build_tools/naclprocess.js

Issue 1436283002: Add support for jslint and cleanup core JavaScript files (Closed) Base URL: https://chromium.googlesource.com/external/naclports.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Makefile ('k') | build_tools/naclterm.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 /* jshint evil: true */ 7 /* jshint evil: true */
8 /* globals PipeServer */ 8 /* globals PipeServer */
9 9
10 'use strict'; 10 'use strict';
(...skipping 19 matching lines...) Expand all
30 mountPoint: undefined, 30 mountPoint: undefined,
31 31
32 // Mount is available 32 // Mount is available
33 available: false, 33 available: false,
34 34
35 // Mount has been mounted 35 // Mount has been mounted
36 mounted: false 36 mounted: false
37 }; 37 };
38 38
39 /** 39 /**
40 * This creates a popup that runs a NaCl process inside.
41 *
42 * @param {Object} process The NaCl process to be run.
43 * @param {number} width
44 * @param {number} height
45 * @param {string} title
46 */
47 function GraphicalPopup(process, width, height, title) {
48 this.process = process || null;
49 this.width = width || GraphicalPopup.DEFAULT_WIDTH;
50 this.height = height || GraphicalPopup.DEFAULT_HEIGHT;
51 this.title = title || '';
52 this.win = null;
53 this.onClosed = null;
54 }
55
56 /**
57 * The default width of the popup.
58 * @type {number}
59 */
60 GraphicalPopup.DEFAULT_WIDTH = 600;
61
62 /**
63 * The default height of the popup.
64 * @type {number}
65 */
66 GraphicalPopup.DEFAULT_HEIGHT = 400;
67
68 /**
69 * The (empty) HTML file to which the NaCl module is added.
70 * @const
71 */
72 GraphicalPopup.HTML_FILE = 'graphical.html';
73
74 /**
75 * Focus the window in which this code is run.
76 */
77 GraphicalPopup.focusCurrentWindow = function () {
78 chrome.app.window.current().focus();
79 };
80
81 /**
82 * This callback is called when the popup is closed.
83 * @callback closedCallback
84 */
85
86 /**
87 * Set a function to be called as a callback when the popup is closed.
88 * @param {closedCallback} listener
89 */
90 GraphicalPopup.prototype.setClosedListener = function (listener) {
91 if (this.win) {
92 throw new Error("Cannot set closed listener after creating window.");
93 }
94 this.onClosed = listener;
95 };
96
97 /**
98 * Create the window.
99 */
100 GraphicalPopup.prototype.create = function () {
101 var self = this;
102 chrome.app.window.create('graphical.html', {
103 'bounds': {
104 'width': self.width,
105 'height': self.height
106 },
107 }, function (win) {
108 var process = self.process;
109 var popup = win.contentWindow;
110
111 self.win = process.window = win;
112
113 popup.document.title = self.title;
114
115 popup.addEventListener('load', function () {
116 process.style.position = 'absolute';
117 process.style.top = '0';
118 process.style.left = '0';
119 process.style.width = '100%';
120 process.style.height = '100%';
121 popup.document.body.appendChild(process);
122 });
123
124 popup.focused = true;
125 popup.addEventListener('focus', function () {
126 this.focused = true;
127 });
128 popup.addEventListener('blur', function () {
129 this.focused = false;
130 });
131
132 if (self.onClosed) {
133 win.onClosed.addListener(self.onClosed);
134 }
135 });
136 };
137
138 /**
139 * Close the popup.
140 */
141 GraphicalPopup.prototype.destroy = function () {
142 if (this.win.contentWindow.focused) {
143 GraphicalPopup.focusCurrentWindow();
144 }
145 if (this.onClosed) {
146 this.win.onClosed.removeListener(this.onClosed);
147 }
148 this.win.close();
149
150 this.process = null;
151 this.win = null;
152 };
153
154
155 /**
40 * NaClProcessManager provides a framework for NaCl executables to run within a 156 * NaClProcessManager provides a framework for NaCl executables to run within a
41 * web-based terminal. 157 * web-based terminal.
42 */ 158 */
43 function NaClProcessManager() { 159 function NaClProcessManager() {
44 var self = this; 160 var self = this;
45 self.onError = function() {}; 161 self.onError = null;
46 self.onStdout = function() {}; 162 self.onStdout = null;
47 self.onRootProgress = function() {}; 163 self.onRootProgress = null;
48 self.onRootLoad = function() {}; 164 self.onRootLoad = null;
49 165
50 // The process which gets the input from the user. 166 // The process which gets the input from the user.
51 self.foregroundProcess = null; 167 self.foregroundProcess = null;
52 168
53 // Process group information keyed by PGID. The value is an object consisting 169 // Process group information keyed by PGID. The value is an object consisting
54 // of the fields: { 170 // of the fields: {
55 // sid: the session ID of the process group 171 // sid: the session ID of the process group
56 // processes: an object keyed by the PIDs of processes in this group, used 172 // processes: an object keyed by the PIDs of processes in this group, used
57 // as a set 173 // as a set
58 // } 174 // }
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 /** 382 /**
267 * Handles an architecture gotten event. 383 * Handles an architecture gotten event.
268 * @callback naclArchCallback 384 * @callback naclArchCallback
269 */ 385 */
270 386
271 /** 387 /**
272 * Called to get the nacl architectgure. 388 * Called to get the nacl architectgure.
273 * @param {naclArchCallback} callback. 389 * @param {naclArchCallback} callback.
274 */ 390 */
275 function getNaClArch(callback) { 391 function getNaClArch(callback) {
276 if (getNaClArch.naclArch_ === undefined) { 392 if (getNaClArch.naclArch === undefined) {
277 if (chrome && chrome.runtime && chrome.runtime.getPlatformInfo) { 393 if (chrome && chrome.runtime && chrome.runtime.getPlatformInfo) {
278 chrome.runtime.getPlatformInfo(function(platformInfo) { 394 chrome.runtime.getPlatformInfo(function (platformInfo) {
279 getNaClArch.naclArch_ = { 395 getNaClArch.naclArch = {
280 'x86-32': 'i686', 396 'x86-32': 'i686',
281 'x86-64': 'x86_64', 397 'x86-64': 'x86_64',
282 'arm': 'arm', 398 'arm': 'arm',
283 }[platformInfo.nacl_arch] || platformInfo.nacl_arch; 399 }[platformInfo.nacl_arch] || platformInfo.nacl_arch;
284 callback(getNaClArch.naclArch_); 400 callback(getNaClArch.naclArch);
285 }); 401 });
286 return; 402 return;
287 } else {
288 getNaClArch.naclArch_ = null;
289 } 403 }
404 getNaClArch.naclArch = null;
290 } 405 }
291 setTimeout(function() { 406 setTimeout(function () {
292 callback(getNaClArch.naclArch_); 407 callback(getNaClArch.naclArch);
293 }, 0); 408 }, 0);
294 } 409 }
295 410
296 /** 411 /**
297 * Handles a stdout event. 412 * Handles a stdout event.
298 * @callback stdoutCallback 413 * @callback stdoutCallback
299 * @param {string} msg The string sent to stdout. 414 * @param {string} msg The string sent to stdout.
300 */ 415 */
301 416
302 /** 417 /**
303 * Listen for stdout from the spawned processes. 418 * Listen for stdout from the spawned processes.
304 * @param {stdoutCallback} callback The callback to be called on a stdout write. 419 * @param {stdoutCallback} callback The callback to be called on a stdout write.
305 */ 420 */
306 NaClProcessManager.prototype.setStdoutListener = function(callback) { 421 NaClProcessManager.prototype.setStdoutListener = function (callback) {
307 this.onStdout = callback; 422 this.onStdout = callback;
308 }; 423 };
309 424
310 /** 425 /**
311 * Handles an error event. 426 * Handles an error event.
312 * @callback errorCallback 427 * @callback errorCallback
313 * @param {string} cmd The name of the process with the error. 428 * @param {string} cmd The name of the process with the error.
314 * @param {string} err The error message. 429 * @param {string} err The error message.
315 */ 430 */
316 431
317 /** 432 /**
318 * Listen for errors from the spawned processes. 433 * Listen for errors from the spawned processes.
319 * @param {errorCallback} callback The callback to be called on error. 434 * @param {errorCallback} callback The callback to be called on error.
320 */ 435 */
321 NaClProcessManager.prototype.setErrorListener = function(callback) { 436 NaClProcessManager.prototype.setErrorListener = function (callback) {
322 this.onError = callback; 437 this.onError = callback;
323 }; 438 };
324 439
325 /** 440 /**
326 * Handles a progress event from the root process. 441 * Handles a progress event from the root process.
327 * @callback rootProgressCallback 442 * @callback rootProgressCallback
328 * @param {string} url The URL that is being loaded. 443 * @param {string} url The URL that is being loaded.
329 * @param {boolean} lengthComputable Is our progress quantitatively measurable? 444 * @param {boolean} lengthComputable Is our progress quantitatively measurable?
330 * @param {number} loaded The number of bytes that have been loaded. 445 * @param {number} loaded The number of bytes that have been loaded.
331 * @param {number} total The total number of bytes to be loaded. 446 * @param {number} total The total number of bytes to be loaded.
332 */ 447 */
333 448
334 /** 449 /**
335 * Listen for a progress event from the root process. 450 * Listen for a progress event from the root process.
336 * @param {rootProgressCallback} callback The callback to be called on progress. 451 * @param {rootProgressCallback} callback The callback to be called on progress.
337 */ 452 */
338 NaClProcessManager.prototype.setRootProgressListener = function(callback) { 453 NaClProcessManager.prototype.setRootProgressListener = function (callback) {
339 this.onRootProgress = callback; 454 this.onRootProgress = callback;
340 }; 455 };
341 456
342 /** 457 /**
343 * Handles a load event from the root process. 458 * Handles a load event from the root process.
344 * @callback rootLoadCallback 459 * @callback rootLoadCallback
345 */ 460 */
346 461
347 /** 462 /**
348 * Listen for a load event from the root process. 463 * Listen for a load event from the root process.
349 * @param {rootLoadCallback} callback The callback to be called on load. 464 * @param {rootLoadCallback} callback The callback to be called on load.
350 */ 465 */
351 NaClProcessManager.prototype.setRootLoadListener = function(callback) { 466 NaClProcessManager.prototype.setRootLoadListener = function (callback) {
352 this.onRootLoad = callback; 467 this.onRootLoad = callback;
353 }; 468 };
354 469
355 /** 470 /**
356 * Is the given process the root process of this process manager? A root 471 * Is the given process the root process of this process manager? A root
357 * process is the one created by NaClProcessManager and not spawned by 472 * process is the one created by NaClProcessManager and not spawned by
358 * another process. 473 * another process.
359 * @param {HTMLObjectElement} process The element about which one is inquiring. 474 * @param {HTMLObjectElement} process The element about which one is inquiring.
360 */ 475 */
361 NaClProcessManager.prototype.isRootProcess = function(process) { 476 NaClProcessManager.prototype.isRootProcess = function (process) {
362 return !process.parent; 477 return !process.parent;
363 }; 478 };
364 479
365 /** 480 /**
366 * Broadcast message from javascript to all the processes. 481 * Broadcast message from javascript to all the processes.
367 * @message the message to be broadcasted 482 * @message the message to be broadcasted
368 * @callback callback to be stashed away and called when 483 * @callback callback to be stashed away and called when
369 * a process responds with a mount status update 484 * a process responds with a mount status update
370 */ 485 */
371 NaClProcessManager.prototype.broadcastMessage = function(message, callback) { 486 NaClProcessManager.prototype.broadcastMessage = function (message, callback) {
372 this.mountUpdateCallback = callback; 487 this.mountUpdateCallback = callback;
373 for (var p in this.processes) { 488 Object.keys(this.processes).forEach(function (key) {
374 this.processes[p].domElement.postMessage(message); 489 this.processes[key].domElement.postMessage(message);
375 } 490 });
376 }; 491 };
377 492
378 /** 493 /**
379 * Sync Mount status every time a mount/unmount message 494 * Sync Mount status every time a mount/unmount message
380 * is recieved from a process. 495 * is recieved from a process.
381 */ 496 */
382 NaClProcessManager.prototype.syncMountStatus_ = function() { 497 NaClProcessManager.prototype.syncMountStatus_ = function () {
383 var result = true; 498 var result = true;
384 499
385 if (g_mount.available) { 500 if (g_mount.available) {
386 for (var p in this.processes) { 501 Object.keys(this.processes).forEach(function (p) {
387 result = (result && this.processes[p].mounted); 502 result = (result && this.processes[p].mounted);
388 } 503 });
389 } else { 504 } else {
390 result = false; 505 result = false;
391 for (var p in this.processes) { 506 Object.keys(this.processes).forEach(function (p) {
392 result = (result || this.processes[p].mounted); 507 result = (result || this.processes[p].mounted);
393 } 508 });
394 } 509 }
395 510
396 g_mount.mounted = result; 511 g_mount.mounted = result;
397 if (this.mountUpdateCallback !== null) { 512 if (this.mountUpdateCallback !== null) {
398 this.mountUpdateCallback(); 513 this.mountUpdateCallback();
399 } 514 }
400 return result; 515 return result;
401 }; 516 };
402 517
403 /** 518 /**
404 * Makes the path in a NMF entry to fully specified path. 519 * Makes the path in a NMF entry to fully specified path.
405 * @private 520 * @private
406 */ 521 */
407 NaClProcessManager.prototype.adjustNmfEntry_ = function(entry) { 522 NaClProcessManager.prototype.adjustNmfEntry_ = function (entry) {
408 for (var arch in entry) { 523 Object.keys(entry).forEach(function (arch) {
409 var path; 524 var path;
410 if (arch === 'portable') { 525 if (arch === 'portable') {
411 if (entry[arch]['pnacl-translate'] === undefined || 526 if (entry[arch]['pnacl-translate'] === undefined ||
412 entry[arch]['pnacl-translate']['url'] === undefined) { 527 entry[arch]['pnacl-translate'].url === undefined) {
413 return; 528 return;
414 } 529 }
415 path = entry[arch]['pnacl-translate']['url']; 530 path = entry[arch]['pnacl-translate'].url;
416 } else { 531 } else {
417 if (entry[arch]['url'] === undefined) { 532 if (entry[arch].url === undefined) {
418 return; 533 return;
419 } 534 }
420 path = entry[arch]['url']; 535 path = entry[arch].url;
421 } 536 }
422 537
423 // Convert 'path' from the NaCl VFS into an HTML5 filesystem: URL 538 // Convert 'path' from the NaCl VFS into an HTML5 filesystem: URL
424 var tmpMountPoint = '/tmp/'; 539 var tmpMountPoint = '/tmp/';
425 var httpMountPoint = '/mnt/http/'; 540 var httpMountPoint = '/mnt/http/';
426 var fsname = '/persistent/'; 541 var fsname = '/persistent/';
427 if (path.indexOf(tmpMountPoint) === 0) { 542 if (path.indexOf(tmpMountPoint) === 0) {
428 // Strip the /tmp/ prefix 543 // Strip the /tmp/ prefix
429 path = path.replace(tmpMountPoint, ''); 544 path = path.replace(tmpMountPoint, '');
430 fsname = '/temporary/'; 545 fsname = '/temporary/';
431 path = 'filesystem:' + location.origin + fsname + path; 546 path = 'filesystem:' + location.origin + fsname + path;
432 } else if (path.indexOf(httpMountPoint) === 0) { 547 } else if (path.indexOf(httpMountPoint) === 0) {
433 path = path.replace(httpMountPoint, ''); 548 path = path.replace(httpMountPoint, '');
434 var base = location.href.match('.*/')[0]; 549 var base = location.href.match('.*/')[0];
435 path = base + path; 550 path = base + path;
436 } else { 551 } else {
437 if (NaClProcessManager.fsroot !== undefined) { 552 if (NaClProcessManager.fsroot !== undefined) {
438 path = NaClProcessManager.fsroot + path; 553 path = NaClProcessManager.fsroot + path;
439 } 554 }
440 path = 'filesystem:' + location.origin + fsname + path; 555 path = 'filesystem:' + location.origin + fsname + path;
441 } 556 }
442 557
443 if (arch === 'portable') { 558 if (arch === 'portable') {
444 entry[arch]['pnacl-translate']['url'] = path; 559 entry[arch]['pnacl-translate'].url = path;
445 } else { 560 } else {
446 entry[arch]['url'] = path; 561 entry[arch].url = path;
447 } 562 }
448 } 563 });
449 }; 564 };
450 565
451 /** 566 /**
452 * Handle messages sent to us from NaCl. 567 * Handle messages sent to us from NaCl.
453 * @private 568 * @private
454 */ 569 */
455 NaClProcessManager.prototype.handleMessage_ = function(e) { 570 NaClProcessManager.prototype.handleMessage_ = function (e) {
456 var msg = e.data; 571 var msg = e.data;
457 var src = e.srcElement; 572 var src = e.srcElement;
458 573
459 // Set handlers for commands. Each handler is passed three arguments: 574 // Set handlers for commands. Each handler is passed three arguments:
460 // msg: the data sent from the NaCl module 575 // msg: the data sent from the NaCl module
461 // reply: a callback to reply to the command 576 // reply: a callback to reply to the command
462 // src: the DOM element from which the message was received 577 // src: the DOM element from which the message was received
463 var handlers = { 578 var handlers = {
464 nacl_spawn: [this, this.handleMessageSpawn_], 579 nacl_spawn: [this, this.handleMessageSpawn_],
465 nacl_wait: [this, this.handleMessageWait_], 580 nacl_wait: [this, this.handleMessageWait_],
466 nacl_getpgid: [this, this.handleMessageGetPGID_], 581 nacl_getpgid: [this, this.handleMessageGetPGID_],
467 nacl_setpgid: [this, this.handleMessageSetPGID_], 582 nacl_setpgid: [this, this.handleMessageSetPGID_],
468 nacl_getsid: [this, this.handleMessageGetSID_], 583 nacl_getsid: [this, this.handleMessageGetSID_],
469 nacl_setsid: [this, this.handleMessageSetSID_], 584 nacl_setsid: [this, this.handleMessageSetSID_],
470 nacl_apipe: [this.pipeServer, this.pipeServer.handleMessageAPipe], 585 nacl_apipe: [this.pipeServer, this.pipeServer.handleMessageAPipe],
471 nacl_apipe_write: [this.pipeServer, 586 nacl_apipe_write: [this.pipeServer,
472 this.pipeServer.handleMessageAPipeWrite], 587 this.pipeServer.handleMessageAPipeWrite],
473 nacl_apipe_read: [this.pipeServer, 588 nacl_apipe_read: [this.pipeServer,
474 this.pipeServer.handleMessageAPipeRead], 589 this.pipeServer.handleMessageAPipeRead],
475 nacl_apipe_close: [this.pipeServer, 590 nacl_apipe_close: [this.pipeServer,
476 this.pipeServer.handleMessageAPipeClose], 591 this.pipeServer.handleMessageAPipeClose],
477 nacl_jseval: [this, this.handleMessageJSEval_], 592 nacl_jseval: [this, this.handleMessageJSEval_],
478 nacl_deadpid: [this, this.handleMessageDeadPid_], 593 nacl_deadpid: [this, this.handleMessageDeadPid_],
479 nacl_mountfs: [this,this.handleMessageMountFs_], 594 nacl_mountfs: [this, this.handleMessageMountFs_],
480 }; 595 };
481 596
482 // TODO(channingh): Once pinned applications support "result" instead of 597 // TODO(channingh): Once pinned applications support "result" instead of
483 // "pid", change calls to reply() to set "result." 598 // "pid", change calls to reply() to set "result."
484 function reply(contents) { 599 function reply(contents) {
485 var message = {}; 600 var message = {};
486 message[msg['id']] = contents; 601 message[msg.id] = contents;
487 // Enable to debug message stream (disabled for speed). 602 // Enable to debug message stream (disabled for speed).
488 // console.log(src.pid + '> reply: ' + JSON.stringify(reply)); 603 // console.log(src.pid + '> reply: ' + JSON.stringify(reply));
489 src.postMessage(message); 604 src.postMessage(message);
490 } 605 }
491 606
492 if (msg['command'] && handlers[msg['command']]) { 607 if (msg.command && handlers[msg.command]) {
493 // Enable to debug message stream (disabled for speed). 608 // Enable to debug message stream (disabled for speed).
494 //console.log(src.pid + '> ' + msg['command'] + ': ' + JSON.stringify(msg)); 609 //console.log(src.pid + '> ' + msg.command + ': ' + JSON.stringify(msg));
495 var handler = handlers[msg['command']]; 610 var handler = handlers[msg.command];
496 handler[1].call(handler[0], msg, reply, src); 611 handler[1].call(handler[0], msg, reply, src);
497 } else if (msg['mount_status'] == 'success') { 612 } else if (msg.mount_status === 'success') {
498 // TODO(gdeepti): Remove monitoring mount status with strings. 613 // TODO(gdeepti): Remove monitoring mount status with strings.
499 this.processes[src.pid].mounted = true; 614 this.processes[src.pid].mounted = true;
500 this.syncMountStatus_(); 615 this.syncMountStatus_();
501 } else if (msg['unmount_status'] == 'success') { 616 } else if (msg.unmount_status === 'success') {
502 this.processes[src.pid].mounted = false; 617 this.processes[src.pid].mounted = false;
503 this.syncMountStatus_(); 618 this.syncMountStatus_();
504 } else if (msg['mount_status'] == 'fail' || msg['unmount_status'] == 'fail') { 619 } else if (msg.mount_status === 'fail' || msg.unmount_status === 'fail') {
505 console.log('mounter_status: ' + JSON.stringify(msg)); 620 console.log('mounter_status: ' + JSON.stringify(msg));
506 } else if (typeof msg == 'string' && 621 } else if (typeof msg === 'string' &&
507 msg.indexOf(NaClProcessManager.prefix) === 0) { 622 msg.indexOf(NaClProcessManager.prefix) === 0) {
508 var out = msg.substring(NaClProcessManager.prefix.length); 623 var out = msg.substring(NaClProcessManager.prefix.length);
509 this.onStdout(out); 624 if (this.onStdout) {
510 } else if (typeof msg == 'string' && 625 this.onStdout(out);
626 }
627 } else if (typeof msg === 'string' &&
511 msg.indexOf('exited') === 0) { 628 msg.indexOf('exited') === 0) {
512 var exitCode = parseInt(msg.split(':', 2)[1]); 629 var exitCode = parseInt(msg.split(':', 2)[1], 10);
513 if (isNaN(exitCode)) 630 if (isNaN(exitCode)) {
514 exitCode = 0; 631 exitCode = 0;
632 }
515 this.exit(exitCode, src); 633 this.exit(exitCode, src);
516 } else { 634 } else {
517 console.log('unexpected message: ' + JSON.stringify(msg)); 635 console.log('unexpected message: ' + JSON.stringify(msg));
518 return; 636 return;
519 } 637 }
520 }; 638 };
521 639
522 /** 640 /**
523 * Handle a nacl_spawn call. 641 * Handle a nacl_spawn call.
524 * @private 642 * @private
525 */ 643 */
526 NaClProcessManager.prototype.handleMessageSpawn_ = function(msg, reply, src) { 644 NaClProcessManager.prototype.handleMessageSpawn_ = function (msg, reply, src) {
527 var self = this; 645 var self = this;
528 var args = msg['args']; 646 var args = msg.args;
529 var envs = msg['envs']; 647 var envs = msg.envs;
530 var cwd = msg['cwd']; 648 var cwd = msg.cwd;
531 var executable = args[0]; 649 var executable = args[0];
532 var nmf = msg['nmf']; 650 var nmf = msg.nmf;
533 if (nmf) { 651 if (nmf) {
534 if (nmf['files']) { 652 if (nmf.files) {
535 for (var key in nmf['files']) 653 Object.keys(nmf.files).forEach(function (key) {
536 self.adjustNmfEntry_(nmf['files'][key]); 654 self.adjustNmfEntry_(nmf.files[key]);
655 });
537 } 656 }
538 self.adjustNmfEntry_(nmf['program']); 657 self.adjustNmfEntry_(nmf.program);
539 var blob = new Blob([JSON.stringify(nmf)], {type: 'text/plain'}); 658 var blob = new Blob([JSON.stringify(nmf)], {type: 'text/plain'});
540 var nmfUrl = window.URL.createObjectURL(blob); 659 var nmfUrl = window.URL.createObjectURL(blob);
541 var naclType = self.checkNaClManifestType_(nmf) || 'nacl'; 660 var naclType = self.checkNaClManifestType(nmf) || 'nacl';
542 self.spawn(nmfUrl, args, envs, cwd, naclType, src, function(pid) { 661 self.spawn(nmfUrl, args, envs, cwd, naclType, src, function (pid) {
543 reply({pid: pid}); 662 reply({pid: pid});
544 }); 663 });
545 } else { 664 } else {
546 if (NaClProcessManager.nmfWhitelist !== undefined && 665 if (NaClProcessManager.nmfWhitelist !== undefined &&
547 NaClProcessManager.nmfWhitelist.indexOf(executable) === -1) { 666 NaClProcessManager.nmfWhitelist.indexOf(executable) === -1) {
548 var replyMsg = { 667 var replyMsg = {
549 pid: -Errno.ENOENT, 668 pid: -Errno.ENOENT,
550 }; 669 };
551 console.log('nacl_spawn(error): ' + executable + ' not in whitelist'); 670 console.log('nacl_spawn(error): ' + executable + ' not in whitelist');
552 reply(replyMsg); 671 reply(replyMsg);
553 return; 672 return;
554 } 673 }
555 nmf = executable + '.nmf'; 674 nmf = executable + '.nmf';
556 self.checkUrlNaClManifestType(nmf, function(naclType) { 675 self.checkUrlNaClManifestType(nmf, function (naclType) {
557 self.spawn(nmf, args, envs, cwd, naclType, src, function(pid) { 676 self.spawn(nmf, args, envs, cwd, naclType, src, function (pid) {
558 reply({pid: pid}); 677 reply({pid: pid});
559 }); 678 });
560 }, function(msg) { 679 }, function (msg) {
561 var replyMsg = {
562 pid: -Errno.ENOENT,
563 };
564 console.log('nacl_spawn(error): ' + msg); 680 console.log('nacl_spawn(error): ' + msg);
565 reply(replyMsg); 681 reply({pid: -Errno.ENOENT});
566 }); 682 });
567 } 683 }
568 }; 684 };
569 685
570 686
571 /** 687 /**
572 * Handle a waitpid call. 688 * Handle a waitpid call.
573 * @private 689 * @private
574 */ 690 */
575 NaClProcessManager.prototype.handleMessageWait_ = function(msg, reply, src) { 691 NaClProcessManager.prototype.handleMessageWait_ = function (msg, reply, src) {
576 this.waitpid(msg['pid'], msg['options'], function(pid, status) { 692 this.waitpid(msg.pid, msg.options, function (pid, status) {
577 reply({ 693 reply({
578 pid: pid, 694 pid: pid,
579 status: status 695 status: status
580 }); 696 });
581 }, src.pid); 697 }, src.pid);
582 }; 698 };
583 699
584 /** 700 /**
585 * Handle a getpgid call. 701 * Handle a getpgid call.
586 * @private 702 * @private
587 */ 703 */
588 NaClProcessManager.prototype.handleMessageGetPGID_ = function(msg, reply, src) { 704 NaClProcessManager.prototype.handleMessageGetPGID_ = function (msg, reply,
705 src) {
589 var pgid; 706 var pgid;
590 var pid = parseInt(msg['pid']) || src.pid; 707 var pid = parseInt(msg.pid, 10) || src.pid;
591 708
592 if (pid < 0) { 709 if (pid < 0) {
593 pgid = -Errno.EINVAL; 710 pgid = -Errno.EINVAL;
594 } else if (!this.processes[pid] || this.processes[pid].exitCode !== null) { 711 } else if (!this.processes[pid] || this.processes[pid].exitCode !== null) {
595 pgid = -Errno.ESRCH; 712 pgid = -Errno.ESRCH;
596 } else { 713 } else {
597 pgid = this.processes[pid].pgid; 714 pgid = this.processes[pid].pgid;
598 } 715 }
599 reply({ 716 reply({
600 pgid: pgid, 717 pgid: pgid,
601 }); 718 });
602 }; 719 };
603 720
604 /** 721 /**
605 * Handle a setpgid call. 722 * Handle a setpgid call.
606 * @private 723 * @private
607 */ 724 */
608 NaClProcessManager.prototype.handleMessageSetPGID_ = function(msg, reply, src) { 725 NaClProcessManager.prototype.handleMessageSetPGID_ = function (msg, reply,
726 src) {
609 var self = this; 727 var self = this;
610 function setpgid() { 728 function setpgid() {
611 var pid = parseInt(msg['pid']) || src.pid; 729 var pid = parseInt(msg.pid, 10) || src.pid;
612 var newPgid = parseInt(msg['pgid']) || pid; 730 var newPgid = parseInt(msg.pgid, 10) || pid;
613 731
614 if (newPgid < 0) { 732 if (newPgid < 0) {
615 return -Errno.EINVAL; 733 return -Errno.EINVAL;
616 } 734 }
617 if (!self.processes[pid] || self.processes[pid].exitCode !== null || 735 if (!self.processes[pid] || self.processes[pid].exitCode !== null ||
618 (src.pid !== pid && src.pid !== self.processes[pid].ppid)) { 736 (src.pid !== pid && src.pid !== self.processes[pid].ppid)) {
619 return -Errno.ESRCH; 737 return -Errno.ESRCH;
620 } 738 }
621 739
622 var oldPgid = self.processes[pid].pgid; 740 var oldPgid = self.processes[pid].pgid;
(...skipping 12 matching lines...) Expand all
635 // calling process. 753 // calling process.
636 if (sid !== callerSid) { 754 if (sid !== callerSid) {
637 return -Errno.EPERM; 755 return -Errno.EPERM;
638 } 756 }
639 757
640 // The target process is a session leader. 758 // The target process is a session leader.
641 if (sid === pid) { 759 if (sid === pid) {
642 return -Errno.EPERM; 760 return -Errno.EPERM;
643 } 761 }
644 762
645 self.deleteProcessFromGroup_(pid); 763 self.deleteProcessFromGroup(pid);
646 if (self.processGroups[newPgid]) { 764 if (self.processGroups[newPgid]) {
647 self.processGroups[newPgid].processes[pid] = true; 765 self.processGroups[newPgid].processes[pid] = true;
648 } else { 766 } else {
649 self.createProcessGroup_(newPgid, sid); 767 self.createProcessGroup(newPgid, sid);
650 } 768 }
651 self.processes[pid].pgid = newPgid; 769 self.processes[pid].pgid = newPgid;
652 return 0; 770 return 0;
653 } 771 }
654 reply({ 772 reply({
655 result: setpgid(), 773 result: setpgid(),
656 }); 774 });
657 }; 775 };
658 776
659 /** 777 /**
660 * Handle a getsid call. 778 * Handle a getsid call.
661 * @private 779 * @private
662 */ 780 */
663 NaClProcessManager.prototype.handleMessageGetSID_ = function(msg, reply, src) { 781 NaClProcessManager.prototype.handleMessageGetSID_ = function (msg, reply, src) {
664 var sid; 782 var sid;
665 var pid = parseInt(msg['pid']) || src.pid; 783 var pid = parseInt(msg.pid, 10) || src.pid;
666 var process = this.processes[pid]; 784 var process = this.processes[pid];
667 785
668 if (!process || process.exitCode !== null) { 786 if (!process || process.exitCode !== null) {
669 sid = -Errno.ESRCH; 787 sid = -Errno.ESRCH;
670 } else { 788 } else {
671 sid = this.processGroups[process.pgid].sid; 789 sid = this.processGroups[process.pgid].sid;
672 } 790 }
673 reply({ 791 reply({
674 sid: sid 792 sid: sid
675 }); 793 });
676 }; 794 };
677 795
678 /** 796 /**
679 * Handle a setsid call. 797 * Handle a setsid call.
680 * @private 798 * @private
681 */ 799 */
682 NaClProcessManager.prototype.handleMessageSetSID_ = function(msg, reply, src) { 800 NaClProcessManager.prototype.handleMessageSetSID_ = function (msg, reply, src) {
683 var pid = src.pid; 801 var pid = src.pid;
684 var sid; 802 var sid;
685 803
686 // Setsid() cannot be called on a group leader. 804 // Setsid() cannot be called on a group leader.
687 if (this.processGroups[pid]) { 805 if (this.processGroups[pid]) {
688 sid = -Errno.EPERM; 806 sid = -Errno.EPERM;
689 } else { 807 } else {
690 this.deleteProcessFromGroup_(pid); 808 this.deleteProcessFromGroup(pid);
691 this.createProcessGroup_(pid, pid); 809 this.createProcessGroup(pid, pid);
692 sid = this.processes[pid].pgid = pid; 810 sid = this.processes[pid].pgid = pid;
693 } 811 }
694 812
695 reply({ 813 reply({
696 sid: sid 814 sid: sid
697 }); 815 });
698 }; 816 };
699 817
700 /** 818 /**
701 * Handle a javascript invocation. 819 * Handle a javascript invocation.
702 * @private 820 * @private
703 */ 821 */
704 NaClProcessManager.prototype.handleMessageJSEval_ = function(msg, reply) { 822 NaClProcessManager.prototype.handleMessageJSEval_ = function (msg, reply) {
705 // Using '' + so that undefined can be emitted as a string. 823 // Using '' + so that undefined can be emitted as a string.
706 reply({result: '' + eval(msg['cmd'])}); 824 reply({result: String(eval(msg.cmd))});
707 }; 825 };
708 826
709 /** 827 /**
710 * Create a process that immediately exits with a given status. 828 * Create a process that immediately exits with a given status.
711 * Used to implement vfork calling _exit. 829 * Used to implement vfork calling _exit.
712 * @private 830 * @private
713 */ 831 */
714 NaClProcessManager.prototype.handleMessageDeadPid_ = function(msg, reply, src) { 832 NaClProcessManager.prototype.handleMessageDeadPid_ = function (msg, reply,
833 src) {
715 var self = this; 834 var self = this;
716 // TODO(bradnelson): Avoid needing to frivolously manipulate the DOM to 835 // TODO(bradnelson): Avoid needing to frivolously manipulate the DOM to
717 // generate a dead pid by separating the process data structure manipulation 836 // generate a dead pid by separating the process data structure manipulation
718 // parts of spawn + exit from the DOM / module ones. 837 // parts of spawn + exit from the DOM / module ones.
719 self.spawn(null, [], [], '/', 'pnacl', src, function(pid, element) { 838 self.spawn(null, [], [], '/', 'pnacl', src, function (pid, element) {
720 self.exit(msg['status'], element); 839 self.exit(msg.status, element);
721 reply({pid: pid}); 840 reply({pid: pid});
722 }); 841 });
723 }; 842 };
724 843
725 /** 844 /**
726 * Handle a mount filesystem call. 845 * Handle a mount filesystem call.
727 */ 846 */
728 NaClProcessManager.prototype.handleMessageMountFs_ = function(msg, reply, src) { 847 NaClProcessManager.prototype.handleMessageMountFs_ = function (msg, reply,
848 src) {
729 if (g_mount.available) { 849 if (g_mount.available) {
730 reply({ 850 reply({
731 filesystem: g_mount.filesystem, 851 filesystem: g_mount.filesystem,
732 fullPath: g_mount.fullPath, 852 fullPath: g_mount.fullPath,
733 available: g_mount.available, 853 available: g_mount.available,
734 mountPoint: g_mount.mountPoint 854 mountPoint: g_mount.mountPoint
735 }); 855 });
736 } else { 856 } else {
737 reply({ 857 reply({
738 available: g_mount.available 858 available: g_mount.available
739 }); 859 });
740 } 860 }
741 }; 861 };
742 862
743 /** 863 /**
744 * Handle progress event from NaCl. 864 * Handle progress event from NaCl.
745 * @private 865 * @private
746 */ 866 */
747 NaClProcessManager.prototype.handleProgress_ = function(e) { 867 NaClProcessManager.prototype.handleProgress_ = function (e) {
748 e.srcElement.moduleResponded = true; 868 e.srcElement.moduleResponded = true;
749 if (this.isRootProcess(e.srcElement)) { 869 if (this.onRootProgress && this.isRootProcess(e.srcElement)) {
750 this.onRootProgress(e.url, e.lengthComputable, e.loaded, e.total); 870 this.onRootProgress(e.url, e.lengthComputable, e.loaded, e.total);
751 } 871 }
752 }; 872 };
753 873
754 /** 874 /**
755 * Handle load event from NaCl. 875 * Handle load event from NaCl.
756 * @private 876 * @private
757 */ 877 */
758 NaClProcessManager.prototype.handleLoad_ = function(e) { 878 NaClProcessManager.prototype.handleLoad_ = function (e) {
759 e.srcElement.moduleResponded = true; 879 e.srcElement.moduleResponded = true;
760 if (this.isRootProcess(e.srcElement)) { 880 if (this.onRootLoad && this.isRootProcess(e.srcElement)) {
761 this.onRootLoad(); 881 this.onRootLoad();
762 } 882 }
763 }; 883 };
764 884
765 /** 885 /**
766 * Handle a timeout around module startup. 886 * Handle a timeout around module startup.
767 * @private 887 * @private
768 */ 888 */
769 NaClProcessManager.prototype.handleStartupTimeout_ = function(src) { 889 NaClProcessManager.prototype.handleStartupTimeout_ = function (src) {
770 if (!src.moduleResponded) { 890 if (!src.moduleResponded) {
771 this.exit(NaClProcessManager.EX_NO_EXEC, src); 891 this.exit(NaClProcessManager.EX_NO_EXEC, src);
772 } 892 }
773 }; 893 };
774 894
775 /** 895 /**
776 * Handle abort event from NaCl. 896 * Handle abort event from NaCl.
777 * @private 897 * @private
778 */ 898 */
779 NaClProcessManager.prototype.handleLoadAbort_ = function(e) { 899 NaClProcessManager.prototype.handleLoadAbort_ = function (e) {
780 e.srcElement.moduleResponded = true; 900 e.srcElement.moduleResponded = true;
781 this.exit(NaClProcessManager.EXIT_CODE_KILL, e.srcElement); 901 this.exit(NaClProcessManager.EXIT_CODE_KILL, e.srcElement);
782 }; 902 };
783 903
784 /** 904 /**
785 * Handle load error event from NaCl. 905 * Handle load error event from NaCl.
786 * @private 906 * @private
787 */ 907 */
788 NaClProcessManager.prototype.handleLoadError_ = function(e) { 908 NaClProcessManager.prototype.handleLoadError_ = function (e) {
789 e.srcElement.moduleResponded = true; 909 e.srcElement.moduleResponded = true;
790 this.onError(e.srcElement.commandName, e.srcElement.lastError); 910 if (this.onError) {
911 this.onError(e.srcElement.commandName, e.srcElement.lastError);
912 }
791 this.exit(NaClProcessManager.EX_NO_EXEC, e.srcElement); 913 this.exit(NaClProcessManager.EX_NO_EXEC, e.srcElement);
792 }; 914 };
793 915
794 /** 916 /**
795 * Handle crash event from NaCl. 917 * Handle crash event from NaCl.
796 * @private 918 * @private
797 */ 919 */
798 NaClProcessManager.prototype.handleCrash_ = function(e) { 920 NaClProcessManager.prototype.handleCrash_ = function (e) {
799 e.srcElement.moduleResponded = true; 921 e.srcElement.moduleResponded = true;
800 this.exit(e.srcElement.exitStatus, e.srcElement); 922 this.exit(e.srcElement.exitStatus, e.srcElement);
801 }; 923 };
802 924
803 /** 925 /**
804 * Create a process group with the given process as the leader and add the 926 * Create a process group with the given process as the leader and add the
805 * group to the table. 927 * group to the table.
806 * @private 928 * @private
807 * @param {number} pid The process that will be the leader. 929 * @param {number} pid The process that will be the leader.
808 * @param {number} sid The session ID of the session to which the process 930 * @param {number} sid The session ID of the session to which the process
809 * group belongs. 931 * group belongs.
810 */ 932 */
811 NaClProcessManager.prototype.createProcessGroup_ = function(pid, sid) { 933 NaClProcessManager.prototype.createProcessGroup = function (pid, sid) {
812 if (this.processGroups[pid] !== undefined) { 934 if (this.processGroups[pid] !== undefined) {
813 throw new Error('createProcessGroup_(): process group already exists'); 935 throw new Error('createProcessGroup(): process group already exists');
814 } 936 }
815 this.processGroups[pid] = { 937 this.processGroups[pid] = {
816 sid: sid, 938 sid: sid,
817 processes: {} 939 processes: {}
818 }; 940 };
819 this.processGroups[pid].processes[pid] = true; 941 this.processGroups[pid].processes[pid] = true;
820 }; 942 };
821 943
822 /** 944 /**
823 * Delete a process from the process group table. If a group has no more 945 * Delete a process from the process group table. If a group has no more
824 * processes, delete the group as well. 946 * processes, delete the group as well.
825 * @private 947 * @private
826 * @param {number} pid The process to be deleted. 948 * @param {number} pid The process to be deleted.
827 */ 949 */
828 NaClProcessManager.prototype.deleteProcessFromGroup_ = function(pid) { 950 NaClProcessManager.prototype.deleteProcessFromGroup = function (pid) {
829 if (this.processes[pid] === undefined) { 951 if (this.processes[pid] === undefined) {
830 throw new Error('deleteProcessFromGroup_(): process does not exist'); 952 throw new Error('deleteProcessFromGroup(): process does not exist');
831 } 953 }
832 var pgid = this.processes[pid].pgid; 954 var pgid = this.processes[pid].pgid;
833 if (this.processGroups[pgid] === undefined || 955 if (this.processGroups[pgid] === undefined ||
834 this.processGroups[pgid].processes[pid] === undefined) { 956 this.processGroups[pgid].processes[pid] === undefined) {
835 throw new Error('deleteProcessFromGroup_(): process group not found'); 957 throw new Error('deleteProcessFromGroup(): process group not found');
836 } 958 }
837 delete this.processGroups[pgid].processes[pid]; 959 delete this.processGroups[pgid].processes[pid];
838 if (Object.keys(this.processGroups[pgid].processes).length === 0) { 960 if (Object.keys(this.processGroups[pgid].processes).length === 0) {
839 delete this.processGroups[pgid]; 961 delete this.processGroups[pgid];
840 } 962 }
841 }; 963 };
842 964
843 /** 965 /**
844 * Remove entries for a process from the process table. 966 * Remove entries for a process from the process table.
845 * @private 967 * @private
846 */ 968 */
847 NaClProcessManager.prototype.deleteProcessEntry_ = function(pid) { 969 NaClProcessManager.prototype.deleteProcessEntry = function (pid) {
848 delete this.processes[pid]; 970 delete this.processes[pid];
849 }; 971 };
850 972
851 /** 973 /**
852 * Exit the command. 974 * Exit the command.
853 * @param {number} code The exit code of the process. 975 * @param {number} code The exit code of the process.
854 * @param {HTMLObjectElement} element The HTML element of the exited process. 976 * @param {HTMLObjectElement} element The HTML element of the exited process.
855 */ 977 */
856 NaClProcessManager.prototype.exit = function(code, element) { 978 NaClProcessManager.prototype.exit = function (code, element) {
857 var pid = element.pid; 979 var pid = element.pid;
858 var ppid = this.processes[pid].ppid; 980 var ppid = this.processes[pid].ppid;
859 var pgid = this.processes[pid].pgid; 981 var pgid = this.processes[pid].pgid;
860 982
861 this.pipeServer.deleteProcess(pid); 983 this.pipeServer.deleteProcess(pid);
862 this.deleteProcessFromGroup_(pid); 984 this.deleteProcessFromGroup(pid);
863 985
864 // Reply to processes waiting on the exited process. 986 // Reply to processes waiting on the exited process.
865 var waitersToCheck = [pid, -1, -pgid];
866 var reaped = false; 987 var reaped = false;
867 var waiters = this.waiters; 988 var waiters = this.waiters;
868 waitersToCheck.forEach(function(currPid) { 989 [pid, -1, -pgid].forEach(function (currPid) {
869 if (waiters[currPid] === undefined) { 990 if (waiters[currPid] === undefined) {
870 return; 991 return;
871 } 992 }
872 var currPidWaiters = waiters[currPid]; 993 waiters[currPid].forEach(function (waiter) {
873 for (var j = 0; j < currPidWaiters.length; j++) {
874 var waiter = currPidWaiters[j];
875 if (waiter.srcPid === ppid) { 994 if (waiter.srcPid === ppid) {
876 waiter.reply(pid, code); 995 waiter.reply(pid, code);
877 reaped = true; 996 reaped = true;
878 } 997 }
879 } 998 });
880 waiters[currPid] = currPidWaiters.filter(function(waiter) { 999 waiters[currPid] = waiters[currPid].filter(function (waiter) {
881 return waiter.srcPid !== ppid; 1000 return waiter.srcPid !== ppid;
882 }); 1001 });
883 if (waiters[currPid].length === 0) { 1002 if (waiters[currPid].length === 0) {
884 delete waiters[currPid]; 1003 delete waiters[currPid];
885 } 1004 }
886 }); 1005 });
887 if (reaped) { 1006 if (reaped) {
888 this.deleteProcessEntry_(pid); 1007 this.deleteProcessEntry(pid);
889 } else { 1008 } else {
890 this.processes[pid].exitCode = code; 1009 this.processes[pid].exitCode = code;
891 } 1010 }
892 1011
893 // Mark as terminated. 1012 // Mark as terminated.
894 element.pid = -1; 1013 element.pid = -1;
895 1014
896 // Clean up HTML elements. 1015 // Clean up HTML elements.
897 if (element.parentNode === document.body) { 1016 if (element.parentNode === document.body) {
898 document.body.removeChild(element); 1017 document.body.removeChild(element);
899 } 1018 }
900 1019
901 if (element.popup) { 1020 if (element.popup) {
902 element.popup.destroy(); 1021 element.popup.destroy();
903 } 1022 }
904 1023
905 var nextForegroundProcess = null; 1024 var nextForegroundProcess = null;
906 if (this.foregroundProcess === element) { 1025 if (this.foregroundProcess === element) {
907 nextForegroundProcess = element.parent; 1026 nextForegroundProcess = element.parent;
908 // When the parent has already finished, give the control to the 1027 // When the parent has already finished, give the control to the
909 // grand parent. 1028 // grand parent.
910 while (nextForegroundProcess && nextForegroundProcess.pid === -1) 1029 while (nextForegroundProcess && nextForegroundProcess.pid === -1) {
911 nextForegroundProcess = nextForegroundProcess.parent; 1030 nextForegroundProcess = nextForegroundProcess.parent;
1031 }
912 1032
913 this.foregroundProcess = nextForegroundProcess; 1033 this.foregroundProcess = nextForegroundProcess;
914 } 1034 }
915 }; 1035 };
916 1036
917 /** 1037 /**
918 * Determines if an object is a nacl or pnacl manifest. 1038 * Determines if an object is a nacl or pnacl manifest.
919 * 1039 *
920 * @param {object} manifest A manifest to examine. 1040 * @param {object} manifest A manifest to examine.
921 * @return {string} 'nacl' or 'pnacl' on success, or null on failure.. 1041 * @return {string} 'nacl' or 'pnacl' on success, or null on failure..
922 */ 1042 */
923 NaClProcessManager.prototype.checkNaClManifestType_ = function(manifest) { 1043 NaClProcessManager.prototype.checkNaClManifestType = function (manifest) {
924 if ('program' in manifest) { 1044 if (manifest.hasOwnProperty('program')) {
925 if ('portable' in manifest.program && 1045 if (manifest.program.hasOwnProperty('portable') &&
926 'pnacl-translate' in manifest.program.portable) { 1046 manifest.program.portable.hasOwnProperty('pnacl-translate')) {
927 return 'pnacl'; 1047 return 'pnacl';
928 } else {
929 return 'nacl';
930 } 1048 }
931 } else { 1049 return 'nacl';
932 return null;
933 } 1050 }
1051 return null;
934 }; 1052 };
935 1053
936 /** 1054 /**
937 * Determines if an url points to a nacl or pnacl manifest. 1055 * Determines if an url points to a nacl or pnacl manifest.
938 * 1056 *
939 * @param {string} url The url to download and parse. 1057 * @param {string} url The url to download and parse.
940 * @callback typeCallback Called with 'nacl' or 'pnacl' on success. 1058 * @callback typeCallback Called with 'nacl' or 'pnacl' on success.
941 * @callback errorCallback Called with error message on failure. 1059 * @callback errorCallback Called with error message on failure.
942 */ 1060 */
943 NaClProcessManager.prototype.checkUrlNaClManifestType = function( 1061 NaClProcessManager.prototype.checkUrlNaClManifestType = function (
944 url, typeCallback, errorCallback) { 1062 url, typeCallback, errorCallback) {
945 var self = this; 1063 var self = this;
946 var request = new XMLHttpRequest(); 1064 var request = new XMLHttpRequest();
947 request.open('GET', url, true); 1065 request.open('GET', url, true);
948 request.onload = function() { 1066 request.onload = function () {
949 var manifest; 1067 var manifest;
950 try { 1068 try {
951 manifest = JSON.parse(request.responseText); 1069 manifest = JSON.parse(request.responseText);
952 } catch(e) { 1070 } catch (e) {
953 errorCallback('NaCl Manifest is not valid JSON at ' + url); 1071 errorCallback('NaCl Manifest is not valid JSON at ' + url);
954 return; 1072 return;
955 } 1073 }
956 var kind = self.checkNaClManifestType_(manifest); 1074 var kind = self.checkNaClManifestType(manifest);
957 if (kind === null) { 1075 if (kind === null) {
958 errorCallback('NaCl Manifest has bad format at ' + url); 1076 errorCallback('NaCl Manifest has bad format at ' + url);
959 } else { 1077 } else {
960 typeCallback(kind); 1078 typeCallback(kind);
961 } 1079 }
962 }; 1080 };
963 request.onerror = function() { 1081 request.onerror = function () {
964 errorCallback('NaCl Manifest is unreachable at ' + url); 1082 errorCallback('NaCl Manifest is unreachable at ' + url);
965 }; 1083 };
966 request.send(); 1084 request.send();
967 }; 1085 };
968 1086
969 /** 1087 /**
970 * Called once a pid / error code is known for a spawned process. 1088 * Called once a pid / error code is known for a spawned process.
971 * @callback spawnCallback 1089 * @callback spawnCallback
972 * @param {pid} pid The pid of the spawned process or error code if negative. 1090 * @param {pid} pid The pid of the spawned process or error code if negative.
973 * @param {HTMLObjectElement} element DOM object corresponding to the spawned 1091 * @param {HTMLObjectElement} element DOM object corresponding to the spawned
(...skipping 10 matching lines...) Expand all
984 * @param {Array.<string>} envs The environment variables that the spawned 1102 * @param {Array.<string>} envs The environment variables that the spawned
985 * process can access. Each entry in the array should be of the format 1103 * process can access. Each entry in the array should be of the format
986 * "VARIABLE_NAME=value". 1104 * "VARIABLE_NAME=value".
987 * @param {string} cwd The current working directory. 1105 * @param {string} cwd The current working directory.
988 * @param {string} naclType 'nacl' or 'pnacl' to select the mime-type. 1106 * @param {string} naclType 'nacl' or 'pnacl' to select the mime-type.
989 * @param {HTMLObjectElement} parent The DOM object that corresponds to 1107 * @param {HTMLObjectElement} parent The DOM object that corresponds to
990 * the process that initiated the spawn. Set to null if there is no such 1108 * the process that initiated the spawn. Set to null if there is no such
991 * process. 1109 * process.
992 * @param {spawnCallback} callback. 1110 * @param {spawnCallback} callback.
993 */ 1111 */
994 NaClProcessManager.prototype.spawn = function( 1112 NaClProcessManager.prototype.spawn = function (
995 nmf, argv, envs, cwd, naclType, parent, callback) { 1113 nmf, argv, envs, cwd, naclType, parent, callback) {
996 var self = this; 1114 var self = this;
997 1115
998 getNaClArch(function(arch) { 1116 getNaClArch(function (arch) {
999 var mimetype = 'application/x-' + naclType; 1117 var mimetype = 'application/x-' + naclType;
1000 if (navigator.mimeTypes[mimetype] === undefined) { 1118 if (navigator.mimeTypes[mimetype] === undefined) {
1001 if (mimetype.indexOf('pnacl') != -1) { 1119 if (mimetype.indexOf('pnacl') !== -1) {
1002 console.log( 1120 console.log(
1003 'Browser does not support PNaCl or PNaCl is disabled.'); 1121 'Browser does not support PNaCl or PNaCl is disabled.'
1122 );
1004 } else { 1123 } else {
1005 console.log( 1124 console.log(
1006 'Browser does not support NaCl or NaCl is disabled.'); 1125 'Browser does not support NaCl or NaCl is disabled.'
1126 );
1007 } 1127 }
1008 callback(-Errno.ENOEXEC); 1128 callback(-Errno.ENOEXEC);
1009 return; 1129 return;
1010 } 1130 }
1011 1131
1012 if (self.ttyWidth === null || self.ttyHeight === null) { 1132 if (self.ttyWidth === null || self.ttyHeight === null) {
1013 console.log('tty size not set! Call onTerminalResize.'); 1133 console.log('tty size not set! Call onTerminalResize.');
1014 callback(-Errno.ENOEXEC); 1134 callback(-Errno.ENOEXEC);
1015 return; 1135 return;
1016 } 1136 }
1017 1137
1018 var fg = document.createElement('object'); 1138 var fg = document.createElement('object');
1019 self.foregroundProcess = fg; 1139 self.foregroundProcess = fg;
1020 1140
1021 fg.pid = self.pid; 1141 fg.pid = self.pid;
1022 ++self.pid; 1142 self.pid += 1;
1023 1143
1024 fg.width = 0; 1144 fg.width = 0;
1025 fg.height = 0; 1145 fg.height = 0;
1026 fg.data = nmf; 1146 fg.data = nmf;
1027 fg.type = mimetype; 1147 fg.type = mimetype;
1028 fg.parent = parent; 1148 fg.parent = parent;
1029 fg.commandName = argv[0]; 1149 fg.commandName = argv[0];
1030 1150
1031 if (nmf !== null) { 1151 if (nmf !== null) {
1032 fg.addEventListener('abort', self.handleLoadAbort_.bind(self)); 1152 fg.addEventListener('abort', self.handleLoadAbort_.bind(self));
1033 fg.addEventListener('crash', self.handleCrash_.bind(self)); 1153 fg.addEventListener('crash', self.handleCrash_.bind(self));
1034 fg.addEventListener('error', self.handleLoadError_.bind(self)); 1154 fg.addEventListener('error', self.handleLoadError_.bind(self));
1035 fg.addEventListener('load', self.handleLoad_.bind(self)); 1155 fg.addEventListener('load', self.handleLoad_.bind(self));
1036 fg.addEventListener('message', self.handleMessage_.bind(self)); 1156 fg.addEventListener('message', self.handleMessage_.bind(self));
1037 fg.addEventListener('progress', self.handleProgress_.bind(self)); 1157 fg.addEventListener('progress', self.handleProgress_.bind(self));
1038 } 1158 }
1039 1159
1040 var pgid = parent ? self.processes[parent.pid].pgid : fg.pid; 1160 var pgid = parent ? self.processes[parent.pid].pgid : fg.pid;
1041 var ppid = parent ? parent.pid : NaClProcessManager.INIT_PID; 1161 var ppid = parent ? parent.pid : NaClProcessManager.INIT_PID;
1042 self.processes[fg.pid] = { 1162 self.processes[fg.pid] = {
1043 domElement: fg, 1163 domElement: fg,
1044 exitCode: null, 1164 exitCode: null,
1045 pgid: pgid, 1165 pgid: pgid,
1046 ppid: ppid, 1166 ppid: ppid,
1047 mounted: false, 1167 mounted: false,
1048 }; 1168 };
1049 if (!parent) { 1169 if (!parent) {
1050 self.createProcessGroup_(fg.pid, fg.pid); 1170 self.createProcessGroup(fg.pid, fg.pid);
1051 } 1171 }
1052 self.processGroups[pgid].processes[fg.pid] = true; 1172 self.processGroups[pgid].processes[fg.pid] = true;
1053 1173
1054 var params = {}; 1174 var params = {};
1055 // Default environment variables (can be overridden by envs) 1175 // Default environment variables (can be overridden by envs)
1056 params['PS_VERBOSITY'] = '2'; 1176 params.PS_VERBOSITY = '2';
1057 params['TERM'] = 'xterm-256color'; 1177 params.TERM = 'xterm-256color';
1058 params['PS_STDIN'] = '/dev/tty'; 1178 params.PS_STDIN = '/dev/tty';
1059 params['PS_STDOUT'] = '/dev/tty'; 1179 params.PS_STDOUT = '/dev/tty';
1060 params['PS_STDERR'] = '/dev/tty'; 1180 params.PS_STDERR = '/dev/tty';
1061 1181
1062 for (var i = 0; i < envs.length; i++) { 1182 envs.forEach(function (env) {
1063 var env = envs[i];
1064 var index = env.indexOf('='); 1183 var index = env.indexOf('=');
1065 if (index < 0) { 1184 if (index < 0) {
1066 console.error('Broken env: ' + env); 1185 console.error('Broken env: ' + env);
1067 continue; 1186 return;
1068 } 1187 }
1069 var key = env.substring(0, index); 1188 var key = env.substring(0, index);
1070 if (key === 'SRC' || key === 'DATA' || key.match(/^ARG\d+$/i)) 1189 if (key === 'SRC' || key === 'DATA' || key.match(/^ARG\d+$/i)) {
1071 continue; 1190 return;
1191 }
1072 params[key] = env.substring(index + 1); 1192 params[key] = env.substring(index + 1);
1073 } 1193 });
1074 1194
1075 // Addition environment variables (these override the incoming env) 1195 // Addition environment variables (these override the incoming env)
1076 params['PS_TTY_PREFIX'] = NaClProcessManager.prefix; 1196 params.PS_TTY_PREFIX = NaClProcessManager.prefix;
1077 params['PS_TTY_RESIZE'] = 'tty_resize'; 1197 params.PS_TTY_RESIZE = 'tty_resize';
1078 params['PS_TTY_COLS'] = self.ttyWidth; 1198 params.PS_TTY_COLS = self.ttyWidth;
1079 params['PS_TTY_ROWS'] = self.ttyHeight; 1199 params.PS_TTY_ROWS = self.ttyHeight;
1080 params['PS_EXIT_MESSAGE'] = 'exited'; 1200 params.PS_EXIT_MESSAGE = 'exited';
1081 params['LOCATION_ORIGIN'] = location.origin; 1201 params.LOCATION_ORIGIN = location.origin;
1082 params['PWD'] = cwd; 1202 params.PWD = cwd;
1083 params['NACL_PROCESS'] = '1'; 1203 params.NACL_PROCESS = '1';
1084 params['NACL_PID'] = fg.pid; 1204 params.NACL_PID = fg.pid;
1085 params['NACL_PPID'] = ppid; 1205 params.NACL_PPID = ppid;
1086 if (NaClProcessManager.fsroot !== undefined) { 1206 if (NaClProcessManager.fsroot !== undefined) {
1087 params['NACL_HTML5_ROOT'] = NaClProcessManager.fsroot; 1207 params.NACL_HTML5_ROOT = NaClProcessManager.fsroot;
1088 } 1208 }
1089 1209
1090 if (chrome && chrome.runtime && chrome.runtime.getPlatformInfo) { 1210 if (chrome && chrome.runtime && chrome.runtime.getPlatformInfo) {
1091 if (arch === null) { 1211 if (arch === null) {
1092 console.log( 1212 console.log(
1093 'Browser does not support NaCl/PNaCl or is disabled.'); 1213 'Browser does not support NaCl/PNaCl or is disabled.'
1214 );
1094 callback(-Errno.ENOEXEC, fg); 1215 callback(-Errno.ENOEXEC, fg);
1095 return; 1216 return;
1096 } 1217 }
1097 params['NACL_ARCH'] = arch; 1218 params.NACL_ARCH = arch;
1098 } 1219 }
1099 1220
1100 function addParam(name, value) { 1221 function addParam(name, value) {
1101 // Don't set a 'type' field as self seems to confuse manifest parsing for 1222 // Don't set a 'type' field as self seems to confuse manifest parsing for
1102 // pnacl. 1223 // pnacl.
1103 if (name.toLowerCase() === 'type') { 1224 if (name.toLowerCase() === 'type') {
1104 return; 1225 return;
1105 } 1226 }
1106 var param = document.createElement('param'); 1227 var param = document.createElement('param');
1107 param.name = name; 1228 param.name = name;
1108 param.value = value; 1229 param.value = value;
1109 fg.appendChild(param); 1230 fg.appendChild(param);
1110 } 1231 }
1111 1232
1112 for (var key in params) { 1233 Object.keys(params).forEach(function (key) {
1113 addParam(key, params[key]); 1234 addParam(key, params[key]);
1114 } 1235 });
1115 1236
1116 // Add ARGV arguments from query parameters. 1237 // Add ARGV arguments from query parameters.
1117 function parseQuery(query) { 1238 function parseQuery(query) {
1118 if (query.charAt(0) === '?') { 1239 if (query.charAt(0) === '?') {
1119 query = query.substring(1); 1240 query = query.substring(1);
1120 } 1241 }
1121 var splitArgs = query.split('&'); 1242 var splitArgs = query.split('&');
1122 var args = {}; 1243 var args = {};
1123 for (var i = 0; i < splitArgs.length; i++) { 1244 splitArgs.forEach(function (value) {
1124 var keyValue = splitArgs[i].split('='); 1245 var keyValue = value.split('=');
1125 args[decodeURIComponent(keyValue[0])] = 1246 args[decodeURIComponent(keyValue[0])] =
1126 decodeURIComponent(keyValue[1]); 1247 decodeURIComponent(keyValue[1]);
1127 } 1248 });
1128 return args; 1249 return args;
1129 } 1250 }
1251
1130 var args = parseQuery(document.location.search); 1252 var args = parseQuery(document.location.search);
1131 for (var argname in args) { 1253 Object.keys(args).forEach(function (argname) {
1132 addParam(argname, args[argname]); 1254 addParam(argname, args[argname]);
1133 } 1255 });
1134 1256
1135 // If the application has set NaClTerm.argv and there were 1257 // If the application has set NaClTerm.argv and there were
1136 // no arguments set in the query parameters then add the default 1258 // no arguments set in the query parameters then add the default
1137 // NaClTerm.argv arguments. 1259 // NaClTerm.argv arguments.
1138 // TODO(bradnelson): Consider dropping this method of passing in parameters. 1260 // TODO(bradnelson): Consider dropping this method of passing in parameters.
1139 if (args['arg0'] === undefined && args['arg1'] === undefined && argv) { 1261 if (args.arg0 === undefined && args.arg1 === undefined && argv) {
1140 var argn = 0; 1262 var argn = 0;
1141 argv.forEach(function(arg) { 1263 argv.forEach(function (arg) {
1142 var argname = 'arg' + argn; 1264 var argname = 'arg' + argn;
1143 addParam(argname, arg); 1265 addParam(argname, arg);
1144 argn = argn + 1; 1266 argn = argn + 1;
1145 }); 1267 });
1146 } 1268 }
1147 1269
1148 self.pipeServer.addProcessPipes(fg.pid, params); 1270 self.pipeServer.addProcessPipes(fg.pid, params);
1149 1271
1150 if (params[NaClProcessManager.ENV_SPAWN_MODE] === 1272 if (params[NaClProcessManager.ENV_SPAWN_MODE] ===
1151 NaClProcessManager.ENV_SPAWN_POPUP_VALUE) { 1273 NaClProcessManager.ENV_SPAWN_POPUP_VALUE) {
1152 var popup = new GraphicalPopup( 1274 var popup = new GraphicalPopup(
1153 fg, 1275 fg,
1154 parseInt(params[NaClProcessManager.ENV_POPUP_WIDTH] || 1276 parseInt(params[NaClProcessManager.ENV_POPUP_WIDTH] ||
1155 NaClProcessManager.POPUP_WIDTH_DEFAULT), 1277 NaClProcessManager.POPUP_WIDTH_DEFAULT, 10),
1156 parseInt(params[NaClProcessManager.ENV_POPUP_HEIGHT] || 1278 parseInt(params[NaClProcessManager.ENV_POPUP_HEIGHT] ||
1157 NaClProcessManager.POPUP_HEIGHT_DEFAULT), 1279 NaClProcessManager.POPUP_HEIGHT_DEFAULT, 10),
1158 argv[0] 1280 argv[0]
1159 ); 1281 );
1160 popup.setClosedListener(function() { 1282 popup.setClosedListener(function () {
1161 self.exit(NaClProcessManager.EXIT_CODE_KILL, popup.process); 1283 self.exit(NaClProcessManager.EXIT_CODE_KILL, popup.process);
1162 GraphicalPopup.focusCurrentWindow(); 1284 GraphicalPopup.focusCurrentWindow();
1163 }); 1285 });
1164 1286
1165 fg.popup = popup; 1287 fg.popup = popup;
1166 1288
1167 popup.create(); 1289 popup.create();
1168 } else { 1290 } else {
1169 if (params[NaClProcessManager.ENV_SPAWN_MODE] === 1291 if (params[NaClProcessManager.ENV_SPAWN_MODE] ===
1170 NaClProcessManager.ENV_SPAWN_EMBED_VALUE) { 1292 NaClProcessManager.ENV_SPAWN_EMBED_VALUE) {
1171 var style = fg.style; 1293 var style = fg.style;
1172 style.position = 'absolute'; 1294 style.position = 'absolute';
1173 style.top = 0; 1295 style.top = 0;
1174 style.left = 0; 1296 style.left = 0;
1175 style.width = params[NaClProcessManager.ENV_EMBED_WIDTH] || 1297 style.width = params[NaClProcessManager.ENV_EMBED_WIDTH] ||
1176 NaClProcessManager.EMBED_WIDTH_DEFAULT; 1298 NaClProcessManager.EMBED_WIDTH_DEFAULT;
1177 style.height = params[NaClProcessManager.ENV_EMBED_HEIGHT] || 1299 style.height = params[NaClProcessManager.ENV_EMBED_HEIGHT] ||
1178 NaClProcessManager.EMBED_HEIGHT_DEFAULT; 1300 NaClProcessManager.EMBED_HEIGHT_DEFAULT;
1179 } 1301 }
1180 document.body.appendChild(fg); 1302 document.body.appendChild(fg);
1181 } 1303 }
1182 1304
1183 // Work around crbug.com/350445 1305 // Work around crbug.com/350445
1184 var junk = fg.offsetTop; 1306 window.junk = fg.offsetTop;
1185 1307
1186 // Set a startup timeout to detect the case when running a module 1308 // Set a startup timeout to detect the case when running a module
1187 // from html5 storage but nacl is not enabled. 1309 // from html5 storage but nacl is not enabled.
1188 fg.moduleResponded = false; 1310 fg.moduleResponded = false;
1189 setTimeout(function() { 1311 setTimeout(function () {
1190 self.handleStartupTimeout_(fg); 1312 self.handleStartupTimeout_(fg);
1191 }, 500); 1313 }, 500);
1192 1314
1193 // yield result. 1315 // yield result.
1194 callback(fg.pid, fg); 1316 callback(fg.pid, fg);
1195 }); 1317 });
1196 }; 1318 };
1197 1319
1198 /** 1320 /**
1199 * Handles the exiting of a process. 1321 * Handles the exiting of a process.
1200 * @callback waitCallback 1322 * @callback waitCallback
1201 * @param {number} pid The PID of the process that exited or an error code on 1323 * @param {number} pid The PID of the process that exited or an error code on
1202 * error. 1324 * error.
1203 * @param {number} status The exit code of the process. 1325 * @param {number} status The exit code of the process.
1204 */ 1326 */
1205 1327
1206 /** 1328 /**
1207 * Waits for the process identified by pid to exit, and call a callback when 1329 * Waits for the process identified by pid to exit, and call a callback when
1208 * finished. 1330 * finished.
1209 * @param {number} pid The process ID of the process. If pid==-1, wait for any 1331 * @param {number} pid The process ID of the process. If pid==-1, wait for any
1210 * child. If pid==0, wait for any child in the caller's process group. If 1332 * child. If pid==0, wait for any child in the caller's process group. If
1211 * pid<-1, wait for any child in the process group with process group 1333 * pid<-1, wait for any child in the process group with process group
1212 * id==|pid|. 1334 * id==|pid|.
1213 * @param {number} options The desired options, ORed together. 1335 * @param {number} options The desired options, ORed together.
1214 * @param {waitCallback} reply The callback to be called when the process has 1336 * @param {waitCallback} reply The callback to be called when the process has
1215 * exited. 1337 * exited.
1216 * @param {number} [srcPid=1] The process PID of the calling process. Assume 1338 * @param {number} [srcPid=1] The process PID of the calling process. Assume
1217 * the init process if omitted. 1339 * the init process if omitted.
1218 */ 1340 */
1219 NaClProcessManager.prototype.waitpid = function(pid, options, reply, srcPid) { 1341 NaClProcessManager.prototype.waitpid = function (pid, options, reply, srcPid) {
1220 var self = this;
1221 if (srcPid === undefined) { 1342 if (srcPid === undefined) {
1222 srcPid = NaClProcessManager.INIT_PID; 1343 srcPid = NaClProcessManager.INIT_PID;
1223 } 1344 }
1224 1345
1225 // The specified process does not exist or is not a child. 1346 // The specified process does not exist or is not a child.
1226 if (pid > 0 && (this.processes[pid] === undefined || 1347 if (pid > 0 && (this.processes[pid] === undefined ||
1227 this.processes[pid].ppid !== srcPid)) { 1348 this.processes[pid].ppid !== srcPid)) {
1228 reply(-Errno.ECHILD, 0); 1349 reply(-Errno.ECHILD, 0);
1229 return; 1350 return;
1230 } 1351 }
1231 1352
1232 // The specified process has already finished. 1353 // The specified process has already finished.
1233 if (pid > 0 && this.processes[pid].exitCode !== null) { 1354 if (pid > 0 && this.processes[pid].exitCode !== null) {
1234 var exitCode = this.processes[pid].exitCode; 1355 var exitCode = this.processes[pid].exitCode;
1235 this.deleteProcessEntry_(pid); 1356 this.deleteProcessEntry(pid);
1236 reply(pid, exitCode); 1357 reply(pid, exitCode);
1237 return; 1358 return;
1238 } 1359 }
1239 1360
1240 // There should be no processes in the init process group. 1361 // There should be no processes in the init process group.
1241 if (pid === 0 && srcPid === NaClProcessManager.INIT_PID) { 1362 if (pid === 0 && srcPid === NaClProcessManager.INIT_PID) {
1242 reply(-Errno.ECHILD, 0); 1363 reply(-Errno.ECHILD, 0);
1243 return; 1364 return;
1244 } 1365 }
1245 1366
1246 // pid = 0 waits for processes in the calling process's group. 1367 // pid = 0 waits for processes in the calling process's group.
1247 if (pid === 0) { 1368 if (pid === 0) {
1248 pid = -this.processes[srcPid].pgid; 1369 pid = -this.processes[srcPid].pgid;
1249 } 1370 }
1250 1371
1251 if (pid < 0) { 1372 if (pid < 0) {
1252 var finishedPid = null; 1373 var finishedPid = null;
1253 for (var processPid in this.processes) { 1374 var that = this;
1254 var process = this.processes[processPid]; 1375 Object.keys(this.processes).some(function (processPid) {
1376 var process = that.processes[processPid];
1255 if (process.exitCode !== null && 1377 if (process.exitCode !== null &&
1256 process.ppid === srcPid && 1378 process.ppid === srcPid &&
1257 (pid === -1 || process.pgid === -pid)) { 1379 (pid === -1 || process.pgid === -pid)) {
1258 finishedPid = parseInt(processPid); 1380 finishedPid = parseInt(processPid, 10);
1259 break; 1381 return true;
1260 } 1382 }
1261 } 1383 return false;
1384 });
1262 1385
1263 if (finishedPid !== null) { 1386 if (finishedPid !== null) {
1264 reply(finishedPid, this.processes[finishedPid].exitCode); 1387 reply(finishedPid, this.processes[finishedPid].exitCode);
1265 this.deleteProcessEntry_(finishedPid); 1388 this.deleteProcessEntry(finishedPid);
1266 return; 1389 return;
1267 } 1390 }
1268 } 1391 }
1269 1392
1270 if ((options & NaClProcessManager.WNOHANG) !== 0) { 1393 if ((options & NaClProcessManager.WNOHANG) !== 0) {
1271 reply(0, 0); 1394 reply(0, 0);
1272 return; 1395 return;
1273 } 1396 }
1274 1397
1275 // Add the waitpid call to the waiter list. 1398 // Add the waitpid call to the waiter list.
1276 if (!this.waiters[pid]) { 1399 if (!this.waiters[pid]) {
1277 this.waiters[pid] = []; 1400 this.waiters[pid] = [];
1278 } 1401 }
1279 this.waiters[pid].push({ 1402 this.waiters[pid].push({
1280 reply: reply, 1403 reply: reply,
1281 options: options, 1404 options: options,
1282 srcPid: srcPid 1405 srcPid: srcPid
1283 }); 1406 });
1284 }; 1407 };
1285 1408
1286 /** 1409 /**
1287 * Update the dimensions of the terminal on terminal resize. 1410 * Update the dimensions of the terminal on terminal resize.
1288 * @param {number} width The width of the terminal. 1411 * @param {number} width The width of the terminal.
1289 * @param {number} height The height of the terminal. 1412 * @param {number} height The height of the terminal.
1290 */ 1413 */
1291 NaClProcessManager.prototype.onTerminalResize = function(width, height) { 1414 NaClProcessManager.prototype.onTerminalResize = function (width, height) {
1292 this.ttyWidth = width; 1415 this.ttyWidth = width;
1293 this.ttyHeight = height; 1416 this.ttyHeight = height;
1294 if (this.foregroundProcess) { 1417 if (this.foregroundProcess) {
1295 this.foregroundProcess.postMessage({'tty_resize': [ width, height ]}); 1418 this.foregroundProcess.postMessage({'tty_resize': [ width, height ]});
1296 } 1419 }
1297 }; 1420 };
1298 1421
1299 /** 1422 /**
1300 * Handle a SIGINT signal. 1423 * Handle a SIGINT signal.
1301 * @returns {boolean} Whether or not the interrupt succeeded. 1424 * @returns {boolean} Whether or not the interrupt succeeded.
1302 */ 1425 */
1303 NaClProcessManager.prototype.sigint = function() { 1426 NaClProcessManager.prototype.sigint = function () {
1304 if (!this.foregroundProcess) 1427 if (!this.foregroundProcess) {
1305 throw new Error(NaClProcessManager.NO_FG_ERROR); 1428 throw new Error(NaClProcessManager.NO_FG_ERROR);
1429 }
1306 1430
1307 // TODO(bradnelson): Change this once we support signals. 1431 // TODO(bradnelson): Change this once we support signals.
1308 // Abort on Control+C, but don't quit bash. 1432 // Abort on Control+C, but don't quit bash.
1309 if (!this.isRootProcess(this.foregroundProcess)) { 1433 if (!this.isRootProcess(this.foregroundProcess)) {
1310 // Only exit if the appropriate environment variable is set. 1434 // Only exit if the appropriate environment variable is set.
1311 var query = 'param[name="' + NaClProcessManager.ENV_ABORT + '"]'; 1435 var query = 'param[name="' + NaClProcessManager.ENV_ABORT + '"]';
1312 var enabledEnv = this.foregroundProcess.querySelector(query); 1436 var enabledEnv = this.foregroundProcess.querySelector(query);
1313 if (enabledEnv && enabledEnv.value === NaClProcessManager.ENV_ABORT_VALUE) { 1437 if (enabledEnv && enabledEnv.value === NaClProcessManager.ENV_ABORT_VALUE) {
1314 this.exit(NaClProcessManager.EXIT_CODE_KILL, this.foregroundProcess); 1438 this.exit(NaClProcessManager.EXIT_CODE_KILL, this.foregroundProcess);
1315 return true; 1439 return true;
1316 } 1440 }
1317 } 1441 }
1318 return false; 1442 return false;
1319 }; 1443 };
1320 1444
1321 /** 1445 /**
1322 * Send standard input to the foreground process. 1446 * Send standard input to the foreground process.
1323 * @param {string} str The string to be sent to as stdin. 1447 * @param {string} str The string to be sent to as stdin.
1324 */ 1448 */
1325 NaClProcessManager.prototype.sendStdinForeground = function(str) { 1449 NaClProcessManager.prototype.sendStdinForeground = function (str) {
1326 if (!this.foregroundProcess) 1450 if (!this.foregroundProcess) {
1327 throw new Error(NaClProcessManager.NO_FG_ERROR); 1451 throw new Error(NaClProcessManager.NO_FG_ERROR);
1452 }
1328 1453
1329 var message = {}; 1454 var message = {};
1330 message[NaClProcessManager.prefix] = str; 1455 message[NaClProcessManager.prefix] = str;
1331 this.foregroundProcess.postMessage(message); 1456 this.foregroundProcess.postMessage(message);
1332 }; 1457 };
1333
1334 /**
1335 * This creates a popup that runs a NaCl process inside.
1336 *
1337 * @param {Object} process The NaCl process to be run.
1338 * @param {number} width
1339 * @param {number} height
1340 * @param {string} title
1341 */
1342 function GraphicalPopup(process, width, height, title) {
1343 this.process = process || null;
1344 this.width = width || GraphicalPopup.DEFAULT_WIDTH;
1345 this.height = height || GraphicalPopup.DEFAULT_HEIGHT;
1346 this.title = title || '';
1347 this.win = null;
1348 this.onClosed = function () {};
1349 }
1350
1351 /**
1352 * The default width of the popup.
1353 * @type {number}
1354 */
1355 GraphicalPopup.DEFAULT_WIDTH = 600;
1356
1357 /**
1358 * The default height of the popup.
1359 * @type {number}
1360 */
1361 GraphicalPopup.DEFAULT_HEIGHT = 400;
1362
1363 /**
1364 * The (empty) HTML file to which the NaCl module is added.
1365 * @const
1366 */
1367 GraphicalPopup.HTML_FILE = 'graphical.html';
1368
1369 /**
1370 * Focus the window in which this code is run.
1371 */
1372 GraphicalPopup.focusCurrentWindow = function() {
1373 chrome.app.window.current().focus();
1374 };
1375
1376 /**
1377 * This callback is called when the popup is closed.
1378 * @callback closedCallback
1379 */
1380
1381 /**
1382 * Set a function to be called as a callback when the popup is closed.
1383 * @param {closedCallback} listener
1384 */
1385 GraphicalPopup.prototype.setClosedListener = function(listener) {
1386 if (this.win) {
1387 throw new Error("Cannot set closed listener after creating window.");
1388 }
1389 this.onClosed = listener;
1390 };
1391
1392 /**
1393 * Create the window.
1394 */
1395 GraphicalPopup.prototype.create = function() {
1396 var self = this;
1397 chrome.app.window.create('graphical.html', {
1398 'bounds': {
1399 'width': self.width,
1400 'height': self.height
1401 },
1402 }, function(win) {
1403 var process = self.process;
1404 var popup = win.contentWindow;
1405
1406 self.win = process.window = win;
1407
1408 popup.document.title = self.title;
1409
1410 popup.addEventListener('load', function() {
1411 process.style.position = 'absolute';
1412 process.style.top = '0';
1413 process.style.left = '0';
1414 process.style.width = '100%';
1415 process.style.height = '100%';
1416 popup.document.body.appendChild(process);
1417 });
1418
1419 popup.focused = true;
1420 popup.addEventListener('focus', function() {
1421 this.focused = true;
1422 });
1423 popup.addEventListener('blur', function() {
1424 this.focused = false;
1425 });
1426
1427 win.onClosed.addListener(self.onClosed);
1428 });
1429 };
1430
1431 /**
1432 * Close the popup.
1433 */
1434 GraphicalPopup.prototype.destroy = function() {
1435 if (this.win.contentWindow.focused) {
1436 GraphicalPopup.focusCurrentWindow();
1437 }
1438 this.win.onClosed.removeListener(this.onClosed);
1439 this.win.close();
1440
1441 this.process = null;
1442 this.win = null;
1443 };
OLDNEW
« no previous file with comments | « Makefile ('k') | build_tools/naclterm.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698