| Index: native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
|
| diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
|
| index acb6bc67247f8561e58a58b54c2235080cebb125..534e53a28dac1605d6bea6ee82a1a8ff026d6163 100644
|
| --- a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
|
| +++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
|
| @@ -6,8 +6,11 @@
|
|
|
| #include <assert.h>
|
| #include <errno.h>
|
| +#include <signal.h>
|
| #include <stdio.h>
|
| #include <string.h>
|
| +#include <sys/ioctl.h>
|
| +#include <unistd.h>
|
|
|
| #include <algorithm>
|
|
|
| @@ -24,10 +27,17 @@
|
| #define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL)
|
| #define IS_ICANON CHECK_LFLAG(termios_, ICANON)
|
|
|
| +#define DEFAULT_TTY_COLS 80
|
| +#define DEFAULT_TTY_ROWS 30
|
| +
|
| namespace nacl_io {
|
|
|
| MountNodeTty::MountNodeTty(Mount* mount) : MountNodeCharDevice(mount),
|
| - is_readable_(false) {
|
| + is_readable_(false),
|
| + did_resize_(false),
|
| + rows_(DEFAULT_TTY_ROWS),
|
| + cols_(DEFAULT_TTY_COLS) {
|
| + output_handler_.handler = NULL;
|
| pthread_cond_init(&is_readable_cond_, NULL);
|
| InitTermios();
|
| }
|
| @@ -68,49 +78,37 @@ Error MountNodeTty::Write(size_t offs,
|
| const void* buf,
|
| size_t count,
|
| int* out_bytes) {
|
| - return Write(offs, buf, count, out_bytes, false);
|
| -}
|
| -
|
| -Error MountNodeTty::Write(size_t offs,
|
| - const void* buf,
|
| - size_t count,
|
| - int* out_bytes,
|
| - bool locked) {
|
| + AUTO_LOCK(output_lock_);
|
| *out_bytes = 0;
|
|
|
| - if (!mount_->ppapi())
|
| - return ENOSYS;
|
| -
|
| - MessagingInterface* msg_intr = mount_->ppapi()->GetMessagingInterface();
|
| - VarInterface* var_intr = mount_->ppapi()->GetVarInterface();
|
| + // No handler registered.
|
| + if (output_handler_.handler == NULL)
|
| + return EIO;
|
|
|
| - if (!(var_intr && msg_intr))
|
| - return ENOSYS;
|
| + int rtn = output_handler_.handler(static_cast<const char*>(buf),
|
| + count,
|
| + output_handler_.user_data);
|
|
|
| - // We append the prefix_ to the data in buf, then package it up
|
| - // and post it as a message.
|
| - const char* data = static_cast<const char*>(buf);
|
| - std::string message;
|
| - if (locked) {
|
| - message = prefix_;
|
| - } else {
|
| - AUTO_LOCK(node_lock_);
|
| - message = prefix_;
|
| - }
|
| + // Negative return value means an error occured and the return
|
| + // value is a negated errno value.
|
| + if (rtn < 0)
|
| + return -rtn;
|
|
|
| - message.append(data, count);
|
| - uint32_t len = static_cast<uint32_t>(message.size());
|
| - struct PP_Var val = var_intr->VarFromUtf8(message.data(), len);
|
| - msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val);
|
| - var_intr->Release(val);
|
| - *out_bytes = count;
|
| + *out_bytes = rtn;
|
| return 0;
|
| }
|
|
|
| Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
|
| AUTO_LOCK(node_lock_);
|
| + did_resize_ = false;
|
| while (!is_readable_) {
|
| pthread_cond_wait(&is_readable_cond_, node_lock_.mutex());
|
| + if (!is_readable_ && did_resize_) {
|
| + // If an async resize event occured then return the failure and
|
| + // set EINTR.
|
| + *out_bytes = 0;
|
| + return EINTR;
|
| + }
|
| }
|
|
|
| size_t bytes_to_copy = std::min(count, input_buffer_.size());
|
| @@ -151,7 +149,7 @@ Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
|
|
|
| Error MountNodeTty::Echo(const char* string, int count) {
|
| int wrote;
|
| - Error error = Write(0, string, count, &wrote, true);
|
| + Error error = Write(0, string, count, &wrote);
|
| if (error != 0 || wrote != count) {
|
| // TOOD(sbc): Do something more useful in response to a
|
| // failure to echo.
|
| @@ -163,15 +161,11 @@ Error MountNodeTty::Echo(const char* string, int count) {
|
|
|
| Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) {
|
| AUTO_LOCK(node_lock_);
|
| - if (message->length < prefix_.size() ||
|
| - strncmp(message->buffer, prefix_.data(), prefix_.size()) != 0) {
|
| - return ENOTTY;
|
| - }
|
|
|
| - const char* buffer = message->buffer + prefix_.size();
|
| - int num_bytes = message->length - prefix_.size();
|
| + const char* buffer = message->buffer;
|
| + size_t num_bytes = message->length;
|
|
|
| - for (int i = 0; i < num_bytes; i++) {
|
| + for (size_t i = 0; i < num_bytes; i++) {
|
| char c = buffer[i];
|
| // Transform characters according to input flags.
|
| if (c == '\r') {
|
| @@ -233,28 +227,56 @@ Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) {
|
| RaiseEvent(POLLIN);
|
| pthread_cond_broadcast(&is_readable_cond_);
|
| }
|
| +
|
| return 0;
|
| }
|
|
|
| Error MountNodeTty::Ioctl(int request, char* arg) {
|
| - if (request == TIOCNACLPREFIX) {
|
| - // This ioctl is used to change the prefix for this tty node.
|
| - // The prefix is used to distinguish messages intended for this
|
| - // tty node from all the other messages cluttering up the
|
| - // javascript postMessage() channel.
|
| - AUTO_LOCK(node_lock_);
|
| - prefix_ = arg;
|
| - return 0;
|
| - } else if (request == TIOCNACLINPUT) {
|
| - // This ioctl is used to deliver data from the user to this tty node's
|
| - // input buffer. We check if the prefix in the input data matches the
|
| - // prefix for this node, and only deliver the data if so.
|
| - struct tioc_nacl_input_string* message =
|
| - reinterpret_cast<struct tioc_nacl_input_string*>(arg);
|
| - return ProcessInput(message);
|
| - } else {
|
| - return EINVAL;
|
| + switch (request) {
|
| + case TIOCNACLOUTPUT: {
|
| + AUTO_LOCK(output_lock_);
|
| + if (arg == NULL) {
|
| + output_handler_.handler = NULL;
|
| + return 0;
|
| + }
|
| + if (output_handler_.handler != NULL)
|
| + return EALREADY;
|
| + output_handler_ = *reinterpret_cast<tioc_nacl_output*>(arg);
|
| + return 0;
|
| + }
|
| + case TIOCNACLINPUT: {
|
| + // This ioctl is used to deliver data from the user to this tty node's
|
| + // input buffer.
|
| + struct tioc_nacl_input_string* message =
|
| + reinterpret_cast<struct tioc_nacl_input_string*>(arg);
|
| + return ProcessInput(message);
|
| + }
|
| + case TIOCSWINSZ: {
|
| + struct winsize* size = reinterpret_cast<struct winsize*>(arg);
|
| + {
|
| + AUTO_LOCK(node_lock_);
|
| + rows_ = size->ws_row;
|
| + cols_ = size->ws_col;
|
| + }
|
| + kill(getpid(), SIGWINCH);
|
| +
|
| + // Wake up any thread waiting on Read
|
| + {
|
| + AUTO_LOCK(node_lock_);
|
| + did_resize_ = true;
|
| + pthread_cond_broadcast(&is_readable_cond_);
|
| + }
|
| + return 0;
|
| + }
|
| + case TIOCGWINSZ: {
|
| + struct winsize* size = reinterpret_cast<struct winsize*>(arg);
|
| + size->ws_row = rows_;
|
| + size->ws_col = cols_;
|
| + return 0;
|
| + }
|
| }
|
| +
|
| + return EINVAL;
|
| }
|
|
|
| Error MountNodeTty::Tcgetattr(struct termios* termios_p) {
|
|
|