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..69b7f8c774c917ffde01fc57c75dfea7da34ae6e 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,11 +6,15 @@ |
| #include <assert.h> |
| #include <errno.h> |
| +#include <signal.h> |
| #include <stdio.h> |
| #include <string.h> |
| +#include <sys/ioctl.h> |
| +#include <unistd.h> |
| #include <algorithm> |
| +#include "nacl_io/dbgprint.h" |
| #include "nacl_io/ioctl.h" |
| #include "nacl_io/mount.h" |
| #include "nacl_io/pepper_interface.h" |
| @@ -27,7 +31,10 @@ |
| namespace nacl_io { |
| MountNodeTty::MountNodeTty(Mount* mount) : MountNodeCharDevice(mount), |
| - is_readable_(false) { |
| + is_readable_(false), |
| + did_resize_(false), |
| + rows_(10), |
|
binji
2013/08/21 17:42:01
use consts. BTW, why 10?
Sam Clegg
2013/08/22 03:32:45
Done.
Changed default rows to 30. Is there a mor
binji
2013/08/22 18:09:36
25 or 50, is what I remember, but I guess it proba
|
| + cols_(80) { |
| pthread_cond_init(&is_readable_cond_, NULL); |
| InitTermios(); |
| } |
| @@ -109,8 +116,15 @@ Error MountNodeTty::Write(size_t offs, |
| 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()); |
| @@ -162,7 +176,7 @@ Error MountNodeTty::Echo(const char* string, int count) { |
| } |
| Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) { |
| - AUTO_LOCK(node_lock_); |
| + sdk_util::AutoLock lock(node_lock_); |
| if (message->length < prefix_.size() || |
| strncmp(message->buffer, prefix_.data(), prefix_.size()) != 0) { |
| return ENOTTY; |
| @@ -171,6 +185,28 @@ Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) { |
| const char* buffer = message->buffer + prefix_.size(); |
| int num_bytes = message->length - prefix_.size(); |
| + if (!strncmp(buffer, "resize:", 7)) { |
| + num_bytes -= 7; |
| + buffer += 7; |
| + |
| + struct winsize size; |
| + int rtn = sscanf(buffer, "%hdx%hd", &size.ws_col, &size.ws_row); |
| + if (rtn != 2) { |
| + dbgprintf("error parsing resize: '%s' %d\n", buffer, rtn); |
| + return ENOTTY; |
| + } |
| + lock.Unlock(); |
| + //dbgprintf("got resize from JS\n"); |
| + this->Ioctl(TIOCSWINSZ, reinterpret_cast<char*>(&size)); |
| + return 0; |
| + } else if (!strncmp(buffer, "input:", 6)) { |
| + num_bytes -= 6; |
| + buffer += 6; |
| + } else { |
| + dbgprintf("error parsing input: '%s'\n", message->buffer); |
| + return ENOTTY; |
| + } |
| + |
| for (int i = 0; i < num_bytes; i++) { |
| char c = buffer[i]; |
| // Transform characters according to input flags. |
| @@ -237,27 +273,55 @@ Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) { |
| } |
| 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 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; |
| + } |
| + case 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); |
| + } |
| + case TIOCSWINSZ: { |
| + struct winsize* size = reinterpret_cast<struct winsize*>(arg); |
| + { |
| + AUTO_LOCK(node_lock_); |
| + rows_ = size->ws_row; |
| + cols_ = size->ws_col; |
| + } |
| + //dbgprintf("tty TIOCSWINSZ: %d %d\n", cols_, rows_); |
| + 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_; |
| + //dbgprintf("tty TIOCGWINSZ: %d %d\n", cols_, rows_); |
| + return 0; |
| + } |
| } |
| + return EINVAL; |
| } |
| Error MountNodeTty::Tcgetattr(struct termios* termios_p) { |
| + //dbgprintf("tcgetattr\n"); |
| AUTO_LOCK(node_lock_); |
| *termios_p = termios_; |
| return 0; |
| @@ -265,6 +329,7 @@ Error MountNodeTty::Tcgetattr(struct termios* termios_p) { |
| Error MountNodeTty::Tcsetattr(int optional_actions, |
| const struct termios *termios_p) { |
| + //dbgprintf("tcsetattr\n"); |
| AUTO_LOCK(node_lock_); |
| termios_ = *termios_p; |
| return 0; |