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

Side by Side Diff: native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc

Issue 23005005: [NaCl SDK] nacl_io: Add initial implementations of kill and signal (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 months 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "nacl_io/mount_node_tty.h" 5 #include "nacl_io/mount_node_tty.h"
6 6
7 #include <assert.h> 7 #include <assert.h>
8 #include <errno.h> 8 #include <errno.h>
9 #include <signal.h>
9 #include <stdio.h> 10 #include <stdio.h>
10 #include <string.h> 11 #include <string.h>
12 #include <sys/ioctl.h>
13 #include <unistd.h>
11 14
12 #include <algorithm> 15 #include <algorithm>
13 16
14 #include "nacl_io/ioctl.h" 17 #include "nacl_io/ioctl.h"
15 #include "nacl_io/mount.h" 18 #include "nacl_io/mount.h"
16 #include "nacl_io/pepper_interface.h" 19 #include "nacl_io/pepper_interface.h"
17 #include "sdk_util/auto_lock.h" 20 #include "sdk_util/auto_lock.h"
18 21
19 #define CHECK_LFLAG(TERMIOS, FLAG) (TERMIOS .c_lflag & FLAG) 22 #define CHECK_LFLAG(TERMIOS, FLAG) (TERMIOS .c_lflag & FLAG)
20 23
21 #define IS_ECHO CHECK_LFLAG(termios_, ECHO) 24 #define IS_ECHO CHECK_LFLAG(termios_, ECHO)
22 #define IS_ECHOE CHECK_LFLAG(termios_, ECHOE) 25 #define IS_ECHOE CHECK_LFLAG(termios_, ECHOE)
23 #define IS_ECHONL CHECK_LFLAG(termios_, ECHONL) 26 #define IS_ECHONL CHECK_LFLAG(termios_, ECHONL)
24 #define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL) 27 #define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL)
25 #define IS_ICANON CHECK_LFLAG(termios_, ICANON) 28 #define IS_ICANON CHECK_LFLAG(termios_, ICANON)
26 29
30 #define DEFAULT_TTY_COLS 80
31 #define DEFAULT_TTY_ROWS 30
32
27 namespace nacl_io { 33 namespace nacl_io {
28 34
29 MountNodeTty::MountNodeTty(Mount* mount) : MountNodeCharDevice(mount), 35 MountNodeTty::MountNodeTty(Mount* mount) : MountNodeCharDevice(mount),
30 is_readable_(false) { 36 is_readable_(false),
37 did_resize_(false),
38 output_handler_(NULL),
39 rows_(DEFAULT_TTY_ROWS),
40 cols_(DEFAULT_TTY_COLS) {
31 pthread_cond_init(&is_readable_cond_, NULL); 41 pthread_cond_init(&is_readable_cond_, NULL);
32 InitTermios(); 42 InitTermios();
33 } 43 }
34 44
35 void MountNodeTty::InitTermios() { 45 void MountNodeTty::InitTermios() {
36 // Some sane values that produce good result. 46 // Some sane values that produce good result.
37 termios_.c_iflag = ICRNL | IXON | IXOFF | IUTF8; 47 termios_.c_iflag = ICRNL | IXON | IXOFF | IUTF8;
38 termios_.c_oflag = OPOST | ONLCR; 48 termios_.c_oflag = OPOST | ONLCR;
39 termios_.c_cflag = CREAD | 077; 49 termios_.c_cflag = CREAD | 077;
40 termios_.c_lflag = 50 termios_.c_lflag =
(...skipping 20 matching lines...) Expand all
61 } 71 }
62 72
63 MountNodeTty::~MountNodeTty() { 73 MountNodeTty::~MountNodeTty() {
64 pthread_cond_destroy(&is_readable_cond_); 74 pthread_cond_destroy(&is_readable_cond_);
65 } 75 }
66 76
67 Error MountNodeTty::Write(size_t offs, 77 Error MountNodeTty::Write(size_t offs,
68 const void* buf, 78 const void* buf,
69 size_t count, 79 size_t count,
70 int* out_bytes) { 80 int* out_bytes) {
71 return Write(offs, buf, count, out_bytes, false); 81 AUTO_LOCK(node_lock_);
82 return WriteWithLock(offs, buf, count, out_bytes);
72 } 83 }
73 84
74 Error MountNodeTty::Write(size_t offs, 85
86 Error MountNodeTty::WriteWithLock(size_t offs,
75 const void* buf, 87 const void* buf,
76 size_t count, 88 size_t count,
77 int* out_bytes, 89 int* out_bytes) {
78 bool locked) {
79 *out_bytes = 0; 90 *out_bytes = 0;
80 91
81 if (!mount_->ppapi()) 92 // No handler registered.
82 return ENOSYS; 93 if (output_handler_ == NULL)
94 return EIO;
83 95
84 MessagingInterface* msg_intr = mount_->ppapi()->GetMessagingInterface(); 96 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.
85 VarInterface* var_intr = mount_->ppapi()->GetVarInterface(); 97 if (rtn == -1)
98 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.
86 99
87 if (!(var_intr && msg_intr)) 100 *out_bytes = rtn;
88 return ENOSYS;
89
90 // We append the prefix_ to the data in buf, then package it up
91 // and post it as a message.
92 const char* data = static_cast<const char*>(buf);
93 std::string message;
94 if (locked) {
95 message = prefix_;
96 } else {
97 AUTO_LOCK(node_lock_);
98 message = prefix_;
99 }
100
101 message.append(data, count);
102 uint32_t len = static_cast<uint32_t>(message.size());
103 struct PP_Var val = var_intr->VarFromUtf8(message.data(), len);
104 msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val);
105 var_intr->Release(val);
106 *out_bytes = count;
107 return 0; 101 return 0;
108 } 102 }
109 103
110 Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) { 104 Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
111 AUTO_LOCK(node_lock_); 105 AUTO_LOCK(node_lock_);
106 did_resize_ = false;
112 while (!is_readable_) { 107 while (!is_readable_) {
113 pthread_cond_wait(&is_readable_cond_, node_lock_.mutex()); 108 pthread_cond_wait(&is_readable_cond_, node_lock_.mutex());
109 if (!is_readable_ && did_resize_) {
110 // If an async resize event occured then return the failure and
111 // set EINTR.
112 *out_bytes = 0;
113 return EINTR;
114 }
114 } 115 }
115 116
116 size_t bytes_to_copy = std::min(count, input_buffer_.size()); 117 size_t bytes_to_copy = std::min(count, input_buffer_.size());
117 118
118 if (IS_ICANON) { 119 if (IS_ICANON) {
119 // Only read up to (and including) the first newline 120 // Only read up to (and including) the first newline
120 std::deque<char>::iterator nl = std::find(input_buffer_.begin(), 121 std::deque<char>::iterator nl = std::find(input_buffer_.begin(),
121 input_buffer_.end(), 122 input_buffer_.end(),
122 '\n'); 123 '\n');
123 124
(...skipping 20 matching lines...) Expand all
144 std::find(input_buffer_.begin(), 145 std::find(input_buffer_.begin(),
145 input_buffer_.end(), '\n') != input_buffer_.end(); 146 input_buffer_.end(), '\n') != input_buffer_.end();
146 else 147 else
147 is_readable_ = input_buffer_.size() > 0; 148 is_readable_ = input_buffer_.size() > 0;
148 149
149 return 0; 150 return 0;
150 } 151 }
151 152
152 Error MountNodeTty::Echo(const char* string, int count) { 153 Error MountNodeTty::Echo(const char* string, int count) {
153 int wrote; 154 int wrote;
154 Error error = Write(0, string, count, &wrote, true); 155 Error error = WriteWithLock(0, string, count, &wrote);
155 if (error != 0 || wrote != count) { 156 if (error != 0 || wrote != count) {
156 // TOOD(sbc): Do something more useful in response to a 157 // TOOD(sbc): Do something more useful in response to a
157 // failure to echo. 158 // failure to echo.
158 return error; 159 return error;
159 } 160 }
160 161
161 return 0; 162 return 0;
162 } 163 }
163 164
164 Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) { 165 Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) {
165 AUTO_LOCK(node_lock_); 166 AUTO_LOCK(node_lock_);
166 if (message->length < prefix_.size() ||
167 strncmp(message->buffer, prefix_.data(), prefix_.size()) != 0) {
168 return ENOTTY;
169 }
170 167
171 const char* buffer = message->buffer + prefix_.size(); 168 const char* buffer = message->buffer;
172 int num_bytes = message->length - prefix_.size(); 169 size_t num_bytes = message->length;
173 170
174 for (int i = 0; i < num_bytes; i++) { 171 for (size_t i = 0; i < num_bytes; i++) {
175 char c = buffer[i]; 172 char c = buffer[i];
176 // Transform characters according to input flags. 173 // Transform characters according to input flags.
177 if (c == '\r') { 174 if (c == '\r') {
178 if (termios_.c_iflag & IGNCR) 175 if (termios_.c_iflag & IGNCR)
179 continue; 176 continue;
180 if (termios_.c_iflag & ICRNL) 177 if (termios_.c_iflag & ICRNL)
181 c = '\n'; 178 c = '\n';
182 } else if (c == '\n') { 179 } else if (c == '\n') {
183 if (termios_.c_iflag & INLCR) 180 if (termios_.c_iflag & INLCR)
184 c = '\r'; 181 c = '\r';
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 input_buffer_.push_back(c); 223 input_buffer_.push_back(c);
227 224
228 if (c == '\n' || c == termios_.c_cc[VEOF] || !IS_ICANON) 225 if (c == '\n' || c == termios_.c_cc[VEOF] || !IS_ICANON)
229 is_readable_ = true; 226 is_readable_ = true;
230 } 227 }
231 228
232 if (is_readable_) { 229 if (is_readable_) {
233 RaiseEvent(POLLIN); 230 RaiseEvent(POLLIN);
234 pthread_cond_broadcast(&is_readable_cond_); 231 pthread_cond_broadcast(&is_readable_cond_);
235 } 232 }
233
236 return 0; 234 return 0;
237 } 235 }
238 236
239 Error MountNodeTty::Ioctl(int request, char* arg) { 237 Error MountNodeTty::Ioctl(int request, char* arg) {
240 if (request == TIOCNACLPREFIX) { 238 switch (request) {
241 // This ioctl is used to change the prefix for this tty node. 239 case TIOCNACLOUTPUT: {
242 // The prefix is used to distinguish messages intended for this 240 AUTO_LOCK(node_lock_);
243 // tty node from all the other messages cluttering up the 241 if (arg == NULL) {
244 // javascript postMessage() channel. 242 output_handler_ = NULL;
245 AUTO_LOCK(node_lock_); 243 return 0;
246 prefix_ = arg; 244 }
247 return 0; 245 if (output_handler_ != NULL)
248 } else if (request == TIOCNACLINPUT) { 246 return EALREADY;
249 // This ioctl is used to deliver data from the user to this tty node's 247 output_handler_ = reinterpret_cast<nacl_io_tty_output_handler_t>(arg);
250 // input buffer. We check if the prefix in the input data matches the 248 return 0;
251 // prefix for this node, and only deliver the data if so. 249 }
252 struct tioc_nacl_input_string* message = 250 case TIOCNACLINPUT: {
253 reinterpret_cast<struct tioc_nacl_input_string*>(arg); 251 // This ioctl is used to deliver data from the user to this tty node's
254 return ProcessInput(message); 252 // input buffer.
255 } else { 253 struct tioc_nacl_input_string* message =
256 return EINVAL; 254 reinterpret_cast<struct tioc_nacl_input_string*>(arg);
255 return ProcessInput(message);
256 }
257 case TIOCSWINSZ: {
258 struct winsize* size = reinterpret_cast<struct winsize*>(arg);
259 {
260 AUTO_LOCK(node_lock_);
261 rows_ = size->ws_row;
262 cols_ = size->ws_col;
263 }
264 kill(getpid(), SIGWINCH);
265
266 // Wake up any thread waiting on Read
267 {
268 AUTO_LOCK(node_lock_);
269 did_resize_ = true;
270 pthread_cond_broadcast(&is_readable_cond_);
271 }
272 return 0;
273 }
274 case TIOCGWINSZ: {
275 struct winsize* size = reinterpret_cast<struct winsize*>(arg);
276 size->ws_row = rows_;
277 size->ws_col = cols_;
278 return 0;
279 }
257 } 280 }
281
282 return EINVAL;
258 } 283 }
259 284
260 Error MountNodeTty::Tcgetattr(struct termios* termios_p) { 285 Error MountNodeTty::Tcgetattr(struct termios* termios_p) {
261 AUTO_LOCK(node_lock_); 286 AUTO_LOCK(node_lock_);
262 *termios_p = termios_; 287 *termios_p = termios_;
263 return 0; 288 return 0;
264 } 289 }
265 290
266 Error MountNodeTty::Tcsetattr(int optional_actions, 291 Error MountNodeTty::Tcsetattr(int optional_actions,
267 const struct termios *termios_p) { 292 const struct termios *termios_p) {
268 AUTO_LOCK(node_lock_); 293 AUTO_LOCK(node_lock_);
269 termios_ = *termios_p; 294 termios_ = *termios_p;
270 return 0; 295 return 0;
271 } 296 }
272 297
273 } 298 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698