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

Side by Side Diff: native_client_sdk/src/libraries/nacl_io/devfs/jspipe_event_emitter.cc

Issue 242533005: [NaCl SDK] nacl_io: Add flow control the JavaScript pipes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 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
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "nacl_io/devfs/jspipe_event_emitter.h"
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <string.h>
10
11 #include <algorithm>
12
13 #define TRACE(format, ...) \
14 LOG_TRACE("jspipe[%s]: " format, name_.c_str(), ##__VA_ARGS__)
15 #define ERROR(format, ...) \
16 LOG_ERROR("jspipe[%s]: " format, name_.c_str(), ##__VA_ARGS__)
17
18 #include "nacl_io/log.h"
19 #include "nacl_io/osinttypes.h"
20 #include "nacl_io/pepper_interface.h"
21
22 namespace {
23 const size_t kMaxPostMessageSize = 64*1024;
24 const char* kDictKeyPipe = "pipe";
25 const char* kDictKeyOperation = "operation";
26 const char* kDictKeyPayload = "payload";
27 const char* kOperationNameAck = "ack";
28 const char* kOperationNameWrite = "write";
29 }
30
31 namespace nacl_io {
32
33 JSPipeEventEmitter::JSPipeEventEmitter(PepperInterface* ppapi, size_t size)
34 : input_fifo_(size),
35 post_message_buffer_size_(size),
36 bytes_sent_(0),
37 bytes_acked_(0),
38 bytes_read_(0),
39 ppapi_(ppapi),
40 messaging_iface_(NULL),
41 var_iface_(NULL),
42 array_iface_(NULL),
43 buffer_iface_(NULL),
44 dict_iface_(NULL),
45 pipe_name_var_(PP_MakeUndefined()),
46 pipe_key_(PP_MakeUndefined()),
47 operation_key_(PP_MakeUndefined()),
48 payload_key_(PP_MakeUndefined()),
49 write_var_(PP_MakeUndefined()),
50 ack_var_(PP_MakeUndefined()) {
51 UpdateStatus_Locked();
52 if (ppapi == NULL) {
53 TRACE("missing PPAPI provider");
54 return;
55 }
56 messaging_iface_ = ppapi->GetMessagingInterface();
57 var_iface_ = ppapi->GetVarInterface();
58 array_iface_ = ppapi->GetVarArrayInterface();
59 buffer_iface_ = ppapi->GetVarArrayBufferInterface();
60 dict_iface_ = ppapi->GetVarDictionaryInterface();
61
62 if (var_iface_ == NULL)
63 return;
64
65 pipe_key_ = VarFromCStr(kDictKeyPipe);
66 operation_key_ = VarFromCStr(kDictKeyOperation);
67 payload_key_ = VarFromCStr(kDictKeyPayload);
68 write_var_ = VarFromCStr(kOperationNameWrite);
69 ack_var_ = VarFromCStr(kOperationNameAck);
70 }
71
72 void JSPipeEventEmitter::Destroy() {
73 if (var_iface_ == NULL)
74 return;
75 var_iface_->Release(pipe_name_var_);
76 var_iface_->Release(pipe_key_);
77 var_iface_->Release(operation_key_);
78 var_iface_->Release(payload_key_);
79 var_iface_->Release(write_var_);
80 var_iface_->Release(ack_var_);
81 }
82
83 PP_Var JSPipeEventEmitter::VarFromCStr(const char* string) {
84 assert(var_iface_);
85 return var_iface_->VarFromUtf8(string, strlen(string));
86 }
87
88 void JSPipeEventEmitter::UpdateStatus_Locked() {
89 uint32_t status = 0;
90 if (!input_fifo_.IsEmpty())
91 status |= POLLIN;
92
93 if (GetOSpace() > 0)
94 status |= POLLOUT;
95
96 ClearEvents_Locked(~status);
97 RaiseEvents_Locked(status);
98 }
99
100 Error JSPipeEventEmitter::Read_Locked(char* data, size_t len, int* out_bytes) {
101 *out_bytes = input_fifo_.Read(data, len);
102 if (*out_bytes > 0) {
103 bytes_read_ += *out_bytes;
104 Error err = SendAckMessage(bytes_read_);
105 if (err != 0)
106 ERROR("Sending ACK failed: %d\n", err.error);
107 }
108
109 UpdateStatus_Locked();
110 return 0;
111 }
112
113 Error JSPipeEventEmitter::SendWriteMessage(const void* buf, size_t count) {
114 TRACE("SendWriteMessage [%"PRIuS"] total=%"PRIuS, count, bytes_sent_);
115 if (!var_iface_ || !buffer_iface_)
116 return EIO;
117
118 // Copy payload data in a new ArrayBuffer
119 PP_Var buffer = buffer_iface_->Create(count);
120 memcpy(buffer_iface_->Map(buffer), buf, count);
121 buffer_iface_->Unmap(buffer);
122
123 Error rtn = SendMessageToJS(write_var_, buffer);
124 var_iface_->Release(buffer);
125 return rtn;
126 }
127
128 Error JSPipeEventEmitter::SetName(const char* name) {
129 if (var_iface_ == NULL)
130 return EIO;
131
132 // name can only be set once
133 if (!name_.empty())
134 return EIO;
135
136 // new name must not be empty
137 if (!name || strlen(name) == 0)
138 return EIO;
139
140 TRACE("set name: %s", name);
141 name_ = name;
142 pipe_name_var_ = VarFromCStr(name);
143 return 0;
144 }
145
146 Error JSPipeEventEmitter::SendMessageToJS(PP_Var operation,
147 PP_Var payload) {
148 if (!ppapi_ || !messaging_iface_ || !var_iface_ || !dict_iface_)
149 return EIO;
150
151 // Create dict object which will be sent to JavaScript.
152 PP_Var dict = dict_iface_->Create();
153
154 // Set try keys in the dictionaty: 'pipe', 'operation', and 'payload'
155 dict_iface_->Set(dict, pipe_key_, pipe_name_var_);
binji 2014/05/08 18:18:33 nice
156 dict_iface_->Set(dict, operation_key_, operation);
157 dict_iface_->Set(dict, payload_key_, payload);
158
159 // Send the dict via PostMessage
160 messaging_iface_->PostMessage(ppapi_->GetInstance(), dict);
161
162 // Release the dict
163 var_iface_->Release(dict);
164 return 0;
165 }
166
167 Error JSPipeEventEmitter::SendAckMessage(size_t byte_count) {
168 TRACE("SendAckMessage %"PRIuS, byte_count);
169 PP_Var payload;
170 payload.type = PP_VARTYPE_INT32;
171 payload.value.as_int = (int32_t)byte_count;
172
173 return SendMessageToJS(ack_var_, payload);
174 }
175
176 size_t JSPipeEventEmitter::HandleJSWrite(const char* data, size_t len) {
177 size_t out_len = input_fifo_.Write(data, len);
178 UpdateStatus_Locked();
179 return out_len;
180 }
181
182 void JSPipeEventEmitter::HandleJSAck(size_t byte_count) {
183 if (byte_count > bytes_sent_) {
184 ERROR("HandleAck unexpected byte count: %"PRIuS, byte_count);
185 return;
186 }
187
188 bytes_acked_ = byte_count;
189 TRACE("HandleAck: %" SCNuS "/%" PRIuS, bytes_acked_, bytes_sent_);
binji 2014/05/08 18:18:33 PRIuS, SCNuS is for scanf
190 UpdateStatus_Locked();
191 }
192
193 Error JSPipeEventEmitter::HandleJSWrite(struct PP_Var message) {
194 TRACE("HandleJSWrite");
195 if (message.type != PP_VARTYPE_ARRAY_BUFFER) {
196 TRACE("HandleJSWrite expected ArrayBuffer but got %d.", message.type);
197 return EINVAL;
198 }
199 uint32_t length;
200 if (buffer_iface_->ByteLength(message, &length) != PP_TRUE)
201 return EINVAL;
202
203 char* buffer = (char*)buffer_iface_->Map(message);
204
205 // Write data to the input fifo
206 size_t wrote = HandleJSWrite(buffer, length);
207 buffer_iface_->Unmap(message);
208 if (wrote != length) {
209 LOG_ERROR("Only wrote %d of %d bytes to pipe", (int)wrote, (int)length);
binji 2014/05/08 18:18:33 why cast?
210 return EIO;
211 }
212 TRACE("done HandleWrite: %d", length);
213 return 0;
214 }
215
216 Error JSPipeEventEmitter::HandleJSAck(PP_Var message) {
217 if (message.type != PP_VARTYPE_INT32) {
218 TRACE("HandleAck integer object expected but got %d.", message.type);
219 return EINVAL;
220 }
221 HandleJSAck(message.value.as_int);
222 return 0;
223 }
224
225 int JSPipeEventEmitter::VarStrcmp(PP_Var a, PP_Var b) {
226 uint32_t length_a = 0;
227 uint32_t length_b = 0;
228 const char* cstring_a = var_iface_->VarToUtf8(a, &length_a);
229 const char* cstring_b = var_iface_->VarToUtf8(a, &length_b);
230 std::string string_a(cstring_a, length_a);
binji 2014/05/08 18:18:33 seems a bit cheesy to create a std::string just to
231 std::string string_b(cstring_b, length_a);
232 return strcmp(string_a.c_str(), string_b.c_str());
233 }
234
235 Error JSPipeEventEmitter::HandleJSMessage(struct PP_Var message) {
236 Error err = 0;
237 if (!messaging_iface_ || !var_iface_ || !dict_iface_ || !buffer_iface_) {
238 TRACE("HandleJSMessage: missing PPAPI interfaces");
239 return ENOSYS;
240 }
241
242 // Verify that we have an array with size two.
243 if (message.type != PP_VARTYPE_DICTIONARY) {
244 TRACE("HandleJSMessage passed non-dictionary var");
245 return EINVAL;
246 }
247
248 #ifndef NDEBUG
249 PP_Var pipe_name_var = dict_iface_->Get(message, pipe_key_);
250 if (VarStrcmp(pipe_name_var, pipe_name_var_)) {
251 TRACE("HandleJSMessage wrong pipe name");
252 return EINVAL;
253 }
254 var_iface_->Release(pipe_name_var);
255 #endif
256
257 PP_Var operation_var = dict_iface_->Get(message, operation_key_);
258 if (operation_var.type != PP_VARTYPE_STRING) {
259 TRACE("HandleJSMessage invalid operation");
260 err = EINVAL;
261 } else {
262 uint32_t length;
263 const char* operation_string;
264 operation_string = var_iface_->VarToUtf8(operation_var, &length);
265 std::string message_type(operation_string, length);
266
267 TRACE("HandleJSMessage %s", message_type.c_str());
268 PP_Var payload = dict_iface_->Get(message, payload_key_);
269 if (message_type == kOperationNameWrite) {
270 err = HandleJSWrite(payload);
271 } else if (message_type == kOperationNameAck) {
272 err = HandleJSAck(payload);
273 } else {
274 TRACE("Unknown message type: %s", message_type.c_str());
275 err = EINVAL;
276 }
277 var_iface_->Release(payload);
278 }
279
280 var_iface_->Release(operation_var);
281 return err;
282 }
283
284 Error JSPipeEventEmitter::Write_Locked(const char* data, size_t len,
285 int* out_bytes) {
286 if (GetOSpace() == 0) {
287 *out_bytes = 0;
288 return 0;
289 }
290
291 if (len > GetOSpace())
292 len = GetOSpace();
293
294 // Limit the size of the data we send with PostMessage to kMaxPostMessageSize
295 if (len > kMaxPostMessageSize)
296 len = kMaxPostMessageSize;
297
298 Error err = SendWriteMessage(data, len);
299 if (err != 0)
300 return err;
301 *out_bytes = len;
302 bytes_sent_ += len;
303
304 UpdateStatus_Locked();
305 return 0;
306 }
307
308 } // namespace nacl_io
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698