Chromium Code Reviews| 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..8b25616f2fe2adbbc9205676e214abafa57d45c7 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), |
| + output_handler_(NULL), |
| + rows_(DEFAULT_TTY_ROWS), |
| + cols_(DEFAULT_TTY_COLS) { |
| pthread_cond_init(&is_readable_cond_, NULL); |
| InitTermios(); |
| } |
| @@ -68,49 +78,40 @@ Error MountNodeTty::Write(size_t offs, |
| const void* buf, |
| size_t count, |
| int* out_bytes) { |
| - return Write(offs, buf, count, out_bytes, false); |
| + AUTO_LOCK(node_lock_); |
| + return WriteWithLock(offs, buf, count, out_bytes); |
| } |
| -Error MountNodeTty::Write(size_t offs, |
| + |
| +Error MountNodeTty::WriteWithLock(size_t offs, |
| const void* buf, |
| size_t count, |
| - int* out_bytes, |
| - bool locked) { |
| + int* out_bytes) { |
| *out_bytes = 0; |
| - if (!mount_->ppapi()) |
| - return ENOSYS; |
| + // No handler registered. |
| + if (output_handler_ == NULL) |
| + return EIO; |
| - MessagingInterface* msg_intr = mount_->ppapi()->GetMessagingInterface(); |
| - VarInterface* var_intr = mount_->ppapi()->GetVarInterface(); |
| + int rtn = output_handler_(reinterpret_cast<const char*>(buf), count); |
|
binji
2013/08/22 18:09:36
static_cast
binji
2013/08/22 18:09:36
Not sure I like holding the node lock while callin
Sam Clegg
2013/08/22 19:52:25
Done.
Sam Clegg
2013/08/22 19:52:25
Done.
|
| + if (rtn == -1) |
| + return EIO; |
|
binji
2013/08/22 18:09:36
hm, we could delegate the errno return to the outp
Sam Clegg
2013/08/22 19:52:25
Done.
|
| - if (!(var_intr && msg_intr)) |
| - return ENOSYS; |
| - |
| - // 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_; |
| - } |
| - |
| - 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 +152,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 = WriteWithLock(0, string, count, &wrote); |
| if (error != 0 || wrote != count) { |
| // TOOD(sbc): Do something more useful in response to a |
| // failure to echo. |
| @@ -163,15 +164,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 +230,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(node_lock_); |
| + if (arg == NULL) { |
| + output_handler_ = NULL; |
| + return 0; |
| + } |
| + if (output_handler_ != NULL) |
| + return EALREADY; |
| + output_handler_ = reinterpret_cast<nacl_io_tty_output_handler_t>(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) { |