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

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

Issue 23498015: [NaCl SDK] Support non blocking TCP/UDP (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge Created 7 years, 3 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 <signal.h>
10 #include <stdio.h> 10 #include <stdio.h>
(...skipping 14 matching lines...) Expand all
25 #define IS_ECHOE CHECK_LFLAG(termios_, ECHOE) 25 #define IS_ECHOE CHECK_LFLAG(termios_, ECHOE)
26 #define IS_ECHONL CHECK_LFLAG(termios_, ECHONL) 26 #define IS_ECHONL CHECK_LFLAG(termios_, ECHONL)
27 #define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL) 27 #define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL)
28 #define IS_ICANON CHECK_LFLAG(termios_, ICANON) 28 #define IS_ICANON CHECK_LFLAG(termios_, ICANON)
29 29
30 #define DEFAULT_TTY_COLS 80 30 #define DEFAULT_TTY_COLS 80
31 #define DEFAULT_TTY_ROWS 30 31 #define DEFAULT_TTY_ROWS 30
32 32
33 namespace nacl_io { 33 namespace nacl_io {
34 34
35 MountNodeTty::MountNodeTty(Mount* mount) : MountNodeCharDevice(mount), 35 MountNodeTty::MountNodeTty(Mount* mount)
36 is_readable_(false), 36 : MountNodeCharDevice(mount),
37 rows_(DEFAULT_TTY_ROWS), 37 emitter_(new EventEmitter),
38 cols_(DEFAULT_TTY_COLS) { 38 rows_(DEFAULT_TTY_ROWS),
39 cols_(DEFAULT_TTY_COLS) {
39 output_handler_.handler = NULL; 40 output_handler_.handler = NULL;
40 pthread_cond_init(&is_readable_cond_, NULL);
41 InitTermios(); 41 InitTermios();
42
43 // Output will never block
44 emitter_->RaiseEvents_Locked(POLLOUT);
42 } 45 }
43 46
44 void MountNodeTty::InitTermios() { 47 void MountNodeTty::InitTermios() {
45 // Some sane values that produce good result. 48 // Some sane values that produce good result.
46 termios_.c_iflag = ICRNL | IXON | IXOFF | IUTF8; 49 termios_.c_iflag = ICRNL | IXON | IXOFF | IUTF8;
47 termios_.c_oflag = OPOST | ONLCR; 50 termios_.c_oflag = OPOST | ONLCR;
48 termios_.c_cflag = CREAD | 077; 51 termios_.c_cflag = CREAD | 077;
49 termios_.c_lflag = 52 termios_.c_lflag =
50 ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; 53 ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
51 termios_.c_ispeed = B38400; 54 termios_.c_ispeed = B38400;
(...skipping 10 matching lines...) Expand all
62 termios_.c_cc[VSTOP] = 19; 65 termios_.c_cc[VSTOP] = 19;
63 termios_.c_cc[VSUSP] = 26; 66 termios_.c_cc[VSUSP] = 26;
64 termios_.c_cc[VEOL] = 0; 67 termios_.c_cc[VEOL] = 0;
65 termios_.c_cc[VREPRINT] = 18; 68 termios_.c_cc[VREPRINT] = 18;
66 termios_.c_cc[VDISCARD] = 15; 69 termios_.c_cc[VDISCARD] = 15;
67 termios_.c_cc[VWERASE] = 23; 70 termios_.c_cc[VWERASE] = 23;
68 termios_.c_cc[VLNEXT] = 22; 71 termios_.c_cc[VLNEXT] = 22;
69 termios_.c_cc[VEOL2] = 0; 72 termios_.c_cc[VEOL2] = 0;
70 } 73 }
71 74
72 MountNodeTty::~MountNodeTty() { 75 EventEmitter* MountNodeTty::GetEventEmitter() {
73 pthread_cond_destroy(&is_readable_cond_); 76 return emitter_.get();
74 } 77 }
75 78
76 Error MountNodeTty::Write(size_t offs, 79 Error MountNodeTty::Write(size_t offs,
77 const void* buf, 80 const void* buf,
78 size_t count, 81 size_t count,
79 int* out_bytes) { 82 int* out_bytes) {
83
80 AUTO_LOCK(output_lock_); 84 AUTO_LOCK(output_lock_);
81 *out_bytes = 0; 85 *out_bytes = 0;
82 86
83 // No handler registered. 87 // No handler registered.
84 if (output_handler_.handler == NULL) 88 if (output_handler_.handler == NULL)
85 return EIO; 89 return EIO;
86 90
87 int rtn = output_handler_.handler(static_cast<const char*>(buf), 91 int rtn = output_handler_.handler(static_cast<const char*>(buf),
88 count, 92 count,
89 output_handler_.user_data); 93 output_handler_.user_data);
90 94
91 // Negative return value means an error occured and the return 95 // Negative return value means an error occured and the return
92 // value is a negated errno value. 96 // value is a negated errno value.
93 if (rtn < 0) 97 if (rtn < 0)
94 return -rtn; 98 return -rtn;
95 99
96 *out_bytes = rtn; 100 *out_bytes = rtn;
97 return 0; 101 return 0;
98 } 102 }
99 103
104
100 Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) { 105 Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
101 AUTO_LOCK(node_lock_); 106 EventListenerLock wait(GetEventEmitter());
102 while (!is_readable_) { 107 *out_bytes = 0;
103 pthread_cond_wait(&is_readable_cond_, node_lock_.mutex()); 108
104 } 109 // If interrupted, return
110 Error err = wait.WaitOnEvent(POLLIN, -1);
111 if (err != 0)
112 return err;
105 113
106 size_t bytes_to_copy = std::min(count, input_buffer_.size()); 114 size_t bytes_to_copy = std::min(count, input_buffer_.size());
107
108 if (IS_ICANON) { 115 if (IS_ICANON) {
109 // Only read up to (and including) the first newline 116 // Only read up to (and including) the first newline
110 std::deque<char>::iterator nl = std::find(input_buffer_.begin(), 117 std::deque<char>::iterator nl = std::find(input_buffer_.begin(),
111 input_buffer_.end(), 118 input_buffer_.end(),
112 '\n'); 119 '\n');
113 120
114 if (nl != input_buffer_.end()) { 121 if (nl != input_buffer_.end()) {
115 // We found a newline in the buffer, adjust bytes_to_copy accordingly 122 // We found a newline in the buffer, adjust bytes_to_copy accordingly
116 size_t line_len = static_cast<size_t>(nl - input_buffer_.begin()) + 1; 123 size_t line_len = static_cast<size_t>(nl - input_buffer_.begin()) + 1;
117 bytes_to_copy = std::min(bytes_to_copy, line_len); 124 bytes_to_copy = std::min(bytes_to_copy, line_len);
118 } 125 }
119 } 126 }
120 127
121 128
122 // Copies data from the input buffer into buf. 129 // Copies data from the input buffer into buf.
123 std::copy(input_buffer_.begin(), input_buffer_.begin() + bytes_to_copy, 130 std::copy(input_buffer_.begin(), input_buffer_.begin() + bytes_to_copy,
124 static_cast<char*>(buf)); 131 static_cast<char*>(buf));
125 *out_bytes = bytes_to_copy; 132 *out_bytes = bytes_to_copy;
126 input_buffer_.erase(input_buffer_.begin(), 133 input_buffer_.erase(input_buffer_.begin(),
127 input_buffer_.begin() + bytes_to_copy); 134 input_buffer_.begin() + bytes_to_copy);
128 135
129 // mark input as no longer readable if we consumed 136 // mark input as no longer readable if we consumed
130 // the entire buffer or, in the case of buffered input, 137 // the entire buffer or, in the case of buffered input,
131 // we consumed the final \n char. 138 // we consumed the final \n char.
139 bool avail;
132 if (IS_ICANON) 140 if (IS_ICANON)
133 is_readable_ = 141 avail = std::find(input_buffer_.begin(),
134 std::find(input_buffer_.begin(), 142 input_buffer_.end(), '\n') != input_buffer_.end();
135 input_buffer_.end(), '\n') != input_buffer_.end();
136 else 143 else
137 is_readable_ = input_buffer_.size() > 0; 144 avail = input_buffer_.size() > 0;
145
146 if (!avail)
147 emitter_->ClearEvents_Locked(POLLIN);
138 148
139 return 0; 149 return 0;
140 } 150 }
141 151
142 Error MountNodeTty::Echo(const char* string, int count) { 152 Error MountNodeTty::Echo(const char* string, int count) {
143 int wrote; 153 int wrote;
144 Error error = Write(0, string, count, &wrote); 154 Error error = Write(0, string, count, &wrote);
145 if (error != 0 || wrote != count) { 155 if (error != 0 || wrote != count) {
146 // TOOD(sbc): Do something more useful in response to a 156 // TOOD(sbc): Do something more useful in response to a
147 // failure to echo. 157 // failure to echo.
148 return error; 158 return error;
149 } 159 }
150 160
151 return 0; 161 return 0;
152 } 162 }
153 163
154 Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) { 164 Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) {
155 AUTO_LOCK(node_lock_); 165 AUTO_LOCK(emitter_->GetLock())
156 166
157 const char* buffer = message->buffer; 167 const char* buffer = message->buffer;
158 size_t num_bytes = message->length; 168 size_t num_bytes = message->length;
159 169
160 for (size_t i = 0; i < num_bytes; i++) { 170 for (size_t i = 0; i < num_bytes; i++) {
161 char c = buffer[i]; 171 char c = buffer[i];
162 // Transform characters according to input flags. 172 // Transform characters according to input flags.
163 if (c == '\r') { 173 if (c == '\r') {
164 if (termios_.c_iflag & IGNCR) 174 if (termios_.c_iflag & IGNCR)
165 continue; 175 continue;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 } else { 215 } else {
206 Echo(&c, 1); 216 Echo(&c, 1);
207 } 217 }
208 } 218 }
209 } 219 }
210 220
211 if (!skip) 221 if (!skip)
212 input_buffer_.push_back(c); 222 input_buffer_.push_back(c);
213 223
214 if (c == '\n' || c == termios_.c_cc[VEOF] || !IS_ICANON) 224 if (c == '\n' || c == termios_.c_cc[VEOF] || !IS_ICANON)
215 is_readable_ = true; 225 emitter_->RaiseEvents_Locked(POLLIN);
216 }
217
218 if (is_readable_) {
219 RaiseEvent(POLLIN);
220 pthread_cond_broadcast(&is_readable_cond_);
221 } 226 }
222 227
223 return 0; 228 return 0;
224 } 229 }
225 230
226 Error MountNodeTty::Ioctl(int request, char* arg) { 231 Error MountNodeTty::Ioctl(int request, char* arg) {
227 switch (request) { 232 switch (request) {
228 case TIOCNACLOUTPUT: { 233 case TIOCNACLOUTPUT: {
229 AUTO_LOCK(output_lock_); 234 AUTO_LOCK(output_lock_);
230 if (arg == NULL) { 235 if (arg == NULL) {
(...skipping 13 matching lines...) Expand all
244 return ProcessInput(message); 249 return ProcessInput(message);
245 } 250 }
246 case TIOCSWINSZ: { 251 case TIOCSWINSZ: {
247 struct winsize* size = reinterpret_cast<struct winsize*>(arg); 252 struct winsize* size = reinterpret_cast<struct winsize*>(arg);
248 { 253 {
249 AUTO_LOCK(node_lock_); 254 AUTO_LOCK(node_lock_);
250 rows_ = size->ws_row; 255 rows_ = size->ws_row;
251 cols_ = size->ws_col; 256 cols_ = size->ws_col;
252 } 257 }
253 kill(getpid(), SIGWINCH); 258 kill(getpid(), SIGWINCH);
259 {
260 // Wake up any thread waiting on Read with POLLERR then immediate
261 // clear it to signal EINTR.
262 AUTO_LOCK(emitter_->GetLock())
263 emitter_->RaiseEvents_Locked(POLLERR);
264 emitter_->ClearEvents_Locked(POLLERR);
265 }
254 return 0; 266 return 0;
255 } 267 }
256 case TIOCGWINSZ: { 268 case TIOCGWINSZ: {
257 struct winsize* size = reinterpret_cast<struct winsize*>(arg); 269 struct winsize* size = reinterpret_cast<struct winsize*>(arg);
258 size->ws_row = rows_; 270 size->ws_row = rows_;
259 size->ws_col = cols_; 271 size->ws_col = cols_;
260 return 0; 272 return 0;
261 } 273 }
262 } 274 }
263 275
264 return EINVAL; 276 return EINVAL;
265 } 277 }
266 278
267 Error MountNodeTty::Tcgetattr(struct termios* termios_p) { 279 Error MountNodeTty::Tcgetattr(struct termios* termios_p) {
268 AUTO_LOCK(node_lock_); 280 AUTO_LOCK(node_lock_);
269 *termios_p = termios_; 281 *termios_p = termios_;
270 return 0; 282 return 0;
271 } 283 }
272 284
273 Error MountNodeTty::Tcsetattr(int optional_actions, 285 Error MountNodeTty::Tcsetattr(int optional_actions,
274 const struct termios *termios_p) { 286 const struct termios *termios_p) {
275 AUTO_LOCK(node_lock_); 287 AUTO_LOCK(node_lock_);
276 termios_ = *termios_p; 288 termios_ = *termios_p;
277 return 0; 289 return 0;
278 } 290 }
279 291
280 } 292 }
OLDNEW
« no previous file with comments | « native_client_sdk/src/libraries/nacl_io/mount_node_tty.h ('k') | native_client_sdk/src/libraries/nacl_io/mount_node_udp.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698