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

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: nits 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 rows_(DEFAULT_TTY_ROWS),
39 cols_(DEFAULT_TTY_COLS) {
40 output_handler_.handler = NULL;
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(output_lock_);
72 }
73
74 Error MountNodeTty::Write(size_t offs,
75 const void* buf,
76 size_t count,
77 int* out_bytes,
78 bool locked) {
79 *out_bytes = 0; 82 *out_bytes = 0;
80 83
81 if (!mount_->ppapi()) 84 // No handler registered.
82 return ENOSYS; 85 if (output_handler_.handler == NULL)
86 return EIO;
83 87
84 MessagingInterface* msg_intr = mount_->ppapi()->GetMessagingInterface(); 88 int rtn = output_handler_.handler(static_cast<const char*>(buf),
85 VarInterface* var_intr = mount_->ppapi()->GetVarInterface(); 89 count,
90 output_handler_.user_data);
86 91
87 if (!(var_intr && msg_intr)) 92 // Negative return value means an error occured and the return
88 return ENOSYS; 93 // value is a negated errno value.
94 if (rtn < 0)
95 return -rtn;
89 96
90 // We append the prefix_ to the data in buf, then package it up 97 *out_bytes = rtn;
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; 98 return 0;
108 } 99 }
109 100
110 Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) { 101 Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
111 AUTO_LOCK(node_lock_); 102 AUTO_LOCK(node_lock_);
103 did_resize_ = false;
112 while (!is_readable_) { 104 while (!is_readable_) {
113 pthread_cond_wait(&is_readable_cond_, node_lock_.mutex()); 105 pthread_cond_wait(&is_readable_cond_, node_lock_.mutex());
106 if (!is_readable_ && did_resize_) {
107 // If an async resize event occured then return the failure and
108 // set EINTR.
109 *out_bytes = 0;
110 return EINTR;
111 }
114 } 112 }
115 113
116 size_t bytes_to_copy = std::min(count, input_buffer_.size()); 114 size_t bytes_to_copy = std::min(count, input_buffer_.size());
117 115
118 if (IS_ICANON) { 116 if (IS_ICANON) {
119 // Only read up to (and including) the first newline 117 // Only read up to (and including) the first newline
120 std::deque<char>::iterator nl = std::find(input_buffer_.begin(), 118 std::deque<char>::iterator nl = std::find(input_buffer_.begin(),
121 input_buffer_.end(), 119 input_buffer_.end(),
122 '\n'); 120 '\n');
123 121
(...skipping 20 matching lines...) Expand all
144 std::find(input_buffer_.begin(), 142 std::find(input_buffer_.begin(),
145 input_buffer_.end(), '\n') != input_buffer_.end(); 143 input_buffer_.end(), '\n') != input_buffer_.end();
146 else 144 else
147 is_readable_ = input_buffer_.size() > 0; 145 is_readable_ = input_buffer_.size() > 0;
148 146
149 return 0; 147 return 0;
150 } 148 }
151 149
152 Error MountNodeTty::Echo(const char* string, int count) { 150 Error MountNodeTty::Echo(const char* string, int count) {
153 int wrote; 151 int wrote;
154 Error error = Write(0, string, count, &wrote, true); 152 Error error = Write(0, string, count, &wrote);
155 if (error != 0 || wrote != count) { 153 if (error != 0 || wrote != count) {
156 // TOOD(sbc): Do something more useful in response to a 154 // TOOD(sbc): Do something more useful in response to a
157 // failure to echo. 155 // failure to echo.
158 return error; 156 return error;
159 } 157 }
160 158
161 return 0; 159 return 0;
162 } 160 }
163 161
164 Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) { 162 Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) {
165 AUTO_LOCK(node_lock_); 163 AUTO_LOCK(node_lock_);
166 if (message->length < prefix_.size() ||
167 strncmp(message->buffer, prefix_.data(), prefix_.size()) != 0) {
168 return ENOTTY;
169 }
170 164
171 const char* buffer = message->buffer + prefix_.size(); 165 const char* buffer = message->buffer;
172 int num_bytes = message->length - prefix_.size(); 166 size_t num_bytes = message->length;
173 167
174 for (int i = 0; i < num_bytes; i++) { 168 for (size_t i = 0; i < num_bytes; i++) {
175 char c = buffer[i]; 169 char c = buffer[i];
176 // Transform characters according to input flags. 170 // Transform characters according to input flags.
177 if (c == '\r') { 171 if (c == '\r') {
178 if (termios_.c_iflag & IGNCR) 172 if (termios_.c_iflag & IGNCR)
179 continue; 173 continue;
180 if (termios_.c_iflag & ICRNL) 174 if (termios_.c_iflag & ICRNL)
181 c = '\n'; 175 c = '\n';
182 } else if (c == '\n') { 176 } else if (c == '\n') {
183 if (termios_.c_iflag & INLCR) 177 if (termios_.c_iflag & INLCR)
184 c = '\r'; 178 c = '\r';
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 input_buffer_.push_back(c); 220 input_buffer_.push_back(c);
227 221
228 if (c == '\n' || c == termios_.c_cc[VEOF] || !IS_ICANON) 222 if (c == '\n' || c == termios_.c_cc[VEOF] || !IS_ICANON)
229 is_readable_ = true; 223 is_readable_ = true;
230 } 224 }
231 225
232 if (is_readable_) { 226 if (is_readable_) {
233 RaiseEvent(POLLIN); 227 RaiseEvent(POLLIN);
234 pthread_cond_broadcast(&is_readable_cond_); 228 pthread_cond_broadcast(&is_readable_cond_);
235 } 229 }
230
236 return 0; 231 return 0;
237 } 232 }
238 233
239 Error MountNodeTty::Ioctl(int request, char* arg) { 234 Error MountNodeTty::Ioctl(int request, char* arg) {
240 if (request == TIOCNACLPREFIX) { 235 switch (request) {
241 // This ioctl is used to change the prefix for this tty node. 236 case TIOCNACLOUTPUT: {
242 // The prefix is used to distinguish messages intended for this 237 AUTO_LOCK(output_lock_);
243 // tty node from all the other messages cluttering up the 238 if (arg == NULL) {
244 // javascript postMessage() channel. 239 output_handler_.handler = NULL;
245 AUTO_LOCK(node_lock_); 240 return 0;
246 prefix_ = arg; 241 }
247 return 0; 242 if (output_handler_.handler != NULL)
248 } else if (request == TIOCNACLINPUT) { 243 return EALREADY;
249 // This ioctl is used to deliver data from the user to this tty node's 244 output_handler_ = *reinterpret_cast<tioc_nacl_output*>(arg);
250 // input buffer. We check if the prefix in the input data matches the 245 return 0;
251 // prefix for this node, and only deliver the data if so. 246 }
252 struct tioc_nacl_input_string* message = 247 case TIOCNACLINPUT: {
253 reinterpret_cast<struct tioc_nacl_input_string*>(arg); 248 // This ioctl is used to deliver data from the user to this tty node's
254 return ProcessInput(message); 249 // input buffer.
255 } else { 250 struct tioc_nacl_input_string* message =
256 return EINVAL; 251 reinterpret_cast<struct tioc_nacl_input_string*>(arg);
252 return ProcessInput(message);
253 }
254 case TIOCSWINSZ: {
255 struct winsize* size = reinterpret_cast<struct winsize*>(arg);
256 {
257 AUTO_LOCK(node_lock_);
258 rows_ = size->ws_row;
259 cols_ = size->ws_col;
260 }
261 kill(getpid(), SIGWINCH);
262
263 // Wake up any thread waiting on Read
264 {
265 AUTO_LOCK(node_lock_);
266 did_resize_ = true;
267 pthread_cond_broadcast(&is_readable_cond_);
268 }
269 return 0;
270 }
271 case TIOCGWINSZ: {
272 struct winsize* size = reinterpret_cast<struct winsize*>(arg);
273 size->ws_row = rows_;
274 size->ws_col = cols_;
275 return 0;
276 }
257 } 277 }
278
279 return EINVAL;
258 } 280 }
259 281
260 Error MountNodeTty::Tcgetattr(struct termios* termios_p) { 282 Error MountNodeTty::Tcgetattr(struct termios* termios_p) {
261 AUTO_LOCK(node_lock_); 283 AUTO_LOCK(node_lock_);
262 *termios_p = termios_; 284 *termios_p = termios_;
263 return 0; 285 return 0;
264 } 286 }
265 287
266 Error MountNodeTty::Tcsetattr(int optional_actions, 288 Error MountNodeTty::Tcsetattr(int optional_actions,
267 const struct termios *termios_p) { 289 const struct termios *termios_p) {
268 AUTO_LOCK(node_lock_); 290 AUTO_LOCK(node_lock_);
269 termios_ = *termios_p; 291 termios_ = *termios_p;
270 return 0; 292 return 0;
271 } 293 }
272 294
273 } 295 }
OLDNEW
« no previous file with comments | « native_client_sdk/src/libraries/nacl_io/mount_node_tty.h ('k') | native_client_sdk/src/libraries/ppapi_simple/ps_instance.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698