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

Side by Side Diff: native_client_sdk/src/examples/demo/nacl_io/nacl_io_demo.c

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
1 /* Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 /* Copyright (c) 2012 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 5
6 #include "nacl_io_demo.h" 6 #include "nacl_io_demo.h"
7 7
8 #include <assert.h> 8 #include <assert.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <limits.h>
9 #include <stdio.h> 12 #include <stdio.h>
10 #include <stdlib.h> 13 #include <stdlib.h>
11 #include <string.h> 14 #include <string.h>
15 #include <sys/ioctl.h>
12 #include <sys/mount.h> 16 #include <sys/mount.h>
17 #include <sys/param.h>
18 #include <sys/select.h>
19 #include <sys/stat.h>
13 #include <pthread.h> 20 #include <pthread.h>
21 #include <unistd.h>
14 22
15 #include "ppapi/c/pp_errors.h" 23 #include "ppapi/c/pp_errors.h"
16 #include "ppapi/c/pp_module.h" 24 #include "ppapi/c/pp_module.h"
17 #include "ppapi/c/ppb.h" 25 #include "ppapi/c/ppb.h"
18 #include "ppapi/c/ppb_instance.h" 26 #include "ppapi/c/ppb_instance.h"
19 #include "ppapi/c/ppb_messaging.h" 27 #include "ppapi/c/ppb_messaging.h"
20 #include "ppapi/c/ppb_var.h" 28 #include "ppapi/c/ppb_var.h"
21 #include "ppapi/c/ppb_var_array.h" 29 #include "ppapi/c/ppb_var_array.h"
22 #include "ppapi/c/ppb_var_dictionary.h" 30 #include "ppapi/c/ppb_var_dictionary.h"
23 #include "ppapi/c/ppp.h" 31 #include "ppapi/c/ppp.h"
24 #include "ppapi/c/ppp_instance.h" 32 #include "ppapi/c/ppp_instance.h"
25 #include "ppapi/c/ppp_messaging.h" 33 #include "ppapi/c/ppp_messaging.h"
34 #include "nacl_io/ioctl.h"
26 #include "nacl_io/nacl_io.h" 35 #include "nacl_io/nacl_io.h"
27 36
28 #include "handlers.h" 37 #include "handlers.h"
29 #include "queue.h" 38 #include "queue.h"
30 39
31 #if defined(WIN32) 40 #if defined(WIN32)
32 #define va_copy(d, s) ((d) = (s)) 41 #define va_copy(d, s) ((d) = (s))
33 #endif 42 #endif
34 43
35 typedef struct { 44 typedef struct {
36 const char* name; 45 const char* name;
37 HandleFunc function; 46 HandleFunc function;
38 } FuncNameMapping; 47 } FuncNameMapping;
39 48
40 PP_Instance g_instance = 0; 49 static PP_Instance g_instance = 0;
41 PPB_GetInterface g_get_browser_interface = NULL; 50 static PPB_GetInterface g_get_browser_interface = NULL;
42 PPB_Messaging* g_ppb_messaging = NULL; 51 static PPB_Messaging* g_ppb_messaging = NULL;
43 PPB_Var* g_ppb_var = NULL; 52 PPB_Var* g_ppb_var = NULL;
44 PPB_VarArray* g_ppb_var_array = NULL; 53 PPB_VarArray* g_ppb_var_array = NULL;
45 PPB_VarDictionary* g_ppb_var_dictionary = NULL; 54 PPB_VarDictionary* g_ppb_var_dictionary = NULL;
46 55
47 static FuncNameMapping g_function_map[] = { 56 static FuncNameMapping g_function_map[] = {
48 {"fopen", HandleFopen}, 57 {"fopen", HandleFopen},
49 {"fwrite", HandleFwrite}, 58 {"fwrite", HandleFwrite},
50 {"fread", HandleFread}, 59 {"fread", HandleFread},
51 {"fseek", HandleFseek}, 60 {"fseek", HandleFseek},
52 {"fclose", HandleFclose}, 61 {"fclose", HandleFclose},
(...skipping 10 matching lines...) Expand all
63 {"gethostbyname", HandleGethostbyname}, 72 {"gethostbyname", HandleGethostbyname},
64 {"connect", HandleConnect}, 73 {"connect", HandleConnect},
65 {"send", HandleSend}, 74 {"send", HandleSend},
66 {"recv", HandleRecv}, 75 {"recv", HandleRecv},
67 {"close", HandleClose}, 76 {"close", HandleClose},
68 {NULL, NULL}, 77 {NULL, NULL},
69 }; 78 };
70 79
71 /** A handle to the thread the handles messages. */ 80 /** A handle to the thread the handles messages. */
72 static pthread_t g_handle_message_thread; 81 static pthread_t g_handle_message_thread;
82 static pthread_t g_echo_thread;
73 83
74 /** 84 /**
75 * Create a new PP_Var from a C string. 85 * Create a new PP_Var from a C string.
76 * @param[in] str The string to convert. 86 * @param[in] str The string to convert.
77 * @return A new PP_Var with the contents of |str|. 87 * @return A new PP_Var with the contents of |str|.
78 */ 88 */
79 struct PP_Var CStrToVar(const char* str) { 89 struct PP_Var CStrToVar(const char* str) {
80 return g_ppb_var->VarFromUtf8(str, strlen(str)); 90 return g_ppb_var->VarFromUtf8(str, strlen(str));
81 } 91 }
82 92
(...skipping 28 matching lines...) Expand all
111 char* PrintfToNewString(const char* format, ...) { 121 char* PrintfToNewString(const char* format, ...) {
112 va_list args; 122 va_list args;
113 char* result; 123 char* result;
114 va_start(args, format); 124 va_start(args, format);
115 result = VprintfToNewString(format, args); 125 result = VprintfToNewString(format, args);
116 va_end(args); 126 va_end(args);
117 return result; 127 return result;
118 } 128 }
119 129
120 /** 130 /**
121 * Printf to a new PP_Var. 131 * Vprintf to a new PP_Var.
122 * @param[in] format A print format string. 132 * @param[in] format A print format string.
123 * @param[in] ... The printf arguments. 133 * @param[in] va_list The printf arguments.
124 * @return A new PP_Var. 134 * @return A new PP_Var.
125 */ 135 */
126 struct PP_Var PrintfToVar(const char* format, ...) { 136 static struct PP_Var VprintfToVar(const char* format, va_list args) {
127 char* string;
128 va_list args;
129 struct PP_Var var; 137 struct PP_Var var;
130 138 char* string = VprintfToNewString(format, args);
131 va_start(args, format);
132 string = VprintfToNewString(format, args);
133 va_end(args);
134
135 var = g_ppb_var->VarFromUtf8(string, strlen(string)); 139 var = g_ppb_var->VarFromUtf8(string, strlen(string));
136 free(string); 140 free(string);
137
138 return var; 141 return var;
139 } 142 }
140 143
141 /** 144 /**
142 * Convert a PP_Var to a C string, given a buffer. 145 * Convert a PP_Var to a C string.
143 * @param[in] var The PP_Var to convert. 146 * @param[in] var The PP_Var to convert.
144 * @param[out] buffer The buffer to write to. 147 * @return A newly allocated, NULL-terminated string.
145 * @param[in] length The length of |buffer|.
146 * @return The number of characters written.
147 */ 148 */
148 const char* VarToCStr(struct PP_Var var) { 149 static const char* VarToCStr(struct PP_Var var) {
149 uint32_t length; 150 uint32_t length;
150 const char* str = g_ppb_var->VarToUtf8(var, &length); 151 const char* str = g_ppb_var->VarToUtf8(var, &length);
151 if (str == NULL) { 152 if (str == NULL) {
152 return NULL; 153 return NULL;
153 } 154 }
154 155
155 /* str is NOT NULL-terminated. Copy using memcpy. */ 156 /* str is NOT NULL-terminated. Copy using memcpy. */
156 char* new_str = (char*)malloc(length + 1); 157 char* new_str = (char*)malloc(length + 1);
157 memcpy(new_str, str, length); 158 memcpy(new_str, str, length);
158 new_str[length] = 0; 159 new_str[length] = 0;
159 return new_str; 160 return new_str;
160 } 161 }
161 162
162 /** 163 /**
163 * Get a value from a Dictionary, given a string key. 164 * Get a value from a Dictionary, given a string key.
164 * @param[in] dict The dictionary to look in. 165 * @param[in] dict The dictionary to look in.
165 * @param[in] key The key to look up. 166 * @param[in] key The key to look up.
166 * @return PP_Var The value at |key| in the |dict|. If the key doesn't exist, 167 * @return PP_Var The value at |key| in the |dict|. If the key doesn't exist,
167 * return a PP_Var with the undefined value. 168 * return a PP_Var with the undefined value.
168 */ 169 */
169 struct PP_Var GetDictVar(struct PP_Var dict, const char* key) { 170 struct PP_Var GetDictVar(struct PP_Var dict, const char* key) {
170 struct PP_Var key_var = CStrToVar(key); 171 struct PP_Var key_var = CStrToVar(key);
171 struct PP_Var value = g_ppb_var_dictionary->Get(dict, key_var); 172 struct PP_Var value = g_ppb_var_dictionary->Get(dict, key_var);
172 g_ppb_var->Release(key_var); 173 g_ppb_var->Release(key_var);
173 return value; 174 return value;
174 } 175 }
175 176
176 /** 177 /**
177 * Send a newly-created PP_Var to JavaScript, then release it. 178 * Post a message to JavaScript.
178 * @param[in] var The PP_Var to send. 179 * @param[in] format A printf format string.
180 * @param[in] ... The printf arguments.
179 */ 181 */
180 static void PostMessageVar(struct PP_Var var) { 182 static void PostMessage(const char* format, ...) {
183 struct PP_Var var;
184 va_list args;
185
186 va_start(args, format);
187 var = VprintfToVar(format, args);
188 va_end(args);
189
181 g_ppb_messaging->PostMessage(g_instance, var); 190 g_ppb_messaging->PostMessage(g_instance, var);
182 g_ppb_var->Release(var); 191 g_ppb_var->Release(var);
183 } 192 }
184 193
185 /** 194 /**
186 * Given a message from JavaScript, parse it for functions and parameters. 195 * Given a message from JavaScript, parse it for functions and parameters.
187 * 196 *
188 * The format of the message is: 197 * The format of the message is:
189 * { 198 * {
190 * "cmd": <function name>, 199 * "cmd": <function name>,
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 245
237 /** 246 /**
238 * Handle as message from JavaScript on the worker thread. 247 * Handle as message from JavaScript on the worker thread.
239 * 248 *
240 * @param[in] message The message to parse and handle. 249 * @param[in] message The message to parse and handle.
241 */ 250 */
242 static void HandleMessage(struct PP_Var message) { 251 static void HandleMessage(struct PP_Var message) {
243 const char* function_name; 252 const char* function_name;
244 struct PP_Var params; 253 struct PP_Var params;
245 if (ParseMessage(message, &function_name, &params)) { 254 if (ParseMessage(message, &function_name, &params)) {
246 PostMessageVar(CStrToVar("Error: Unable to parse message")); 255 PostMessage("Error: Unable to parse message");
247 return; 256 return;
248 } 257 }
249 258
250 HandleFunc function = GetFunctionByName(function_name); 259 HandleFunc function = GetFunctionByName(function_name);
251 if (!function) { 260 if (!function) {
252 /* Function name wasn't found. Error. */ 261 /* Function name wasn't found. Error. */
253 PostMessageVar( 262 PostMessage("Error: Unknown function \"%s\"", function_name);
254 PrintfToVar("Error: Unknown function \"%s\"", function_name));
255 return; 263 return;
256 } 264 }
257 265
258 /* Function name was found, call it. */ 266 /* Function name was found, call it. */
259 struct PP_Var result_var; 267 struct PP_Var result_var;
260 const char* error; 268 const char* error;
261 int result = (*function)(params, &result_var, &error); 269 int result = (*function)(params, &result_var, &error);
262 if (result != 0) { 270 if (result != 0) {
263 /* Error. */ 271 /* Error. */
264 struct PP_Var var;
265 if (error != NULL) { 272 if (error != NULL) {
266 var = PrintfToVar("Error: \"%s\" failed: %s.", function_name, error); 273 PostMessage("Error: \"%s\" failed: %s.", function_name, error);
267 free((void*)error); 274 free((void*)error);
268 } else { 275 } else {
269 var = PrintfToVar("Error: \"%s\" failed.", function_name); 276 PostMessage("Error: \"%s\" failed.", function_name);
270 } 277 }
271
272 /* Post the error to JavaScript, so the user can see it. */
273 PostMessageVar(var);
274 return; 278 return;
275 } 279 }
276 280
277 /* Function returned an output dictionary. Send it to JavaScript. */ 281 /* Function returned an output dictionary. Send it to JavaScript. */
278 PostMessageVar(result_var); 282 g_ppb_messaging->PostMessage(g_instance, result_var);
279 g_ppb_var->Release(result_var); 283 g_ppb_var->Release(result_var);
280 } 284 }
281 285
286
287 /**
288 * Helper function used by EchoThread which reads from a file descriptor
289 * and writes all the data that it reads back to the same descriptor.
290 */
291 static void EchoInput(int fd) {
292 char buffer[512];
293 while (1) {
294 int rtn = read(fd, buffer, 512);
295 if (rtn > 0) {
296 int wrote = write(fd, buffer, rtn);
297 if (wrote < rtn)
298 PostMessage("only wrote %d/%d bytes\n", wrote, rtn);
299 } else {
300 if (rtn < 0 && errno != EAGAIN)
301 PostMessage("read failed: %d (%s)\n", errno, strerror(errno));
302 break;
303 }
304 }
305 }
306
307 /**
308 * Worker thread that listens for input on JS pipe nodes and echos all input
309 * back to the same pipe.
310 */
311 static void* EchoThread(void* user_data) {
312 int fd1 = open("/dev/jspipe1", O_RDWR | O_NONBLOCK);
313 int fd2 = open("/dev/jspipe2", O_RDWR | O_NONBLOCK);
314 int fd3 = open("/dev/jspipe3", O_RDWR | O_NONBLOCK);
315 int nfds = MAX(fd1, fd2);
316 nfds = MAX(nfds, fd3);
317 while (1) {
318 fd_set readfds;
319 FD_ZERO(&readfds);
320 FD_SET(fd1, &readfds);
321 FD_SET(fd2, &readfds);
322 FD_SET(fd3, &readfds);
323 int rtn = select(nfds + 1, &readfds, NULL, NULL, NULL);
324 if (rtn < 0 && errno != EAGAIN) {
325 PostMessage("select failed: %s\n", strerror(errno));
326 break;
327 }
328 if (rtn > 0) {
329 if (FD_ISSET(fd1, &readfds))
330 EchoInput(fd1);
331 if (FD_ISSET(fd2, &readfds))
332 EchoInput(fd2);
333 if (FD_ISSET(fd3, &readfds))
334 EchoInput(fd3);
335 }
336
337 }
338 close(fd1);
339 close(fd2);
340 close(fd3);
341 return 0;
342 }
343
282 /** 344 /**
283 * A worker thread that handles messages from JavaScript. 345 * A worker thread that handles messages from JavaScript.
284 * @param[in] user_data Unused. 346 * @param[in] user_data Unused.
285 * @return unused. 347 * @return unused.
286 */ 348 */
287 void* HandleMessageThread(void* user_data) { 349 void* HandleMessageThread(void* user_data) {
288 while (1) { 350 while (1) {
289 struct PP_Var message = DequeueMessage(); 351 struct PP_Var message = DequeueMessage();
290 HandleMessage(message); 352 HandleMessage(message);
291 g_ppb_var->Release(message); 353 g_ppb_var->Release(message);
(...skipping 19 matching lines...) Expand all
311 0, /* mountflags */ 373 0, /* mountflags */
312 "type=PERSISTENT,expected_size=1048576"); /* data */ 374 "type=PERSISTENT,expected_size=1048576"); /* data */
313 375
314 mount("", /* source. Use relative URL */ 376 mount("", /* source. Use relative URL */
315 "/http", /* target */ 377 "/http", /* target */
316 "httpfs", /* filesystemtype */ 378 "httpfs", /* filesystemtype */
317 0, /* mountflags */ 379 0, /* mountflags */
318 ""); /* data */ 380 ""); /* data */
319 381
320 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL); 382 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL);
383 pthread_create(&g_echo_thread, NULL, &EchoThread, NULL);
321 InitializeMessageQueue(); 384 InitializeMessageQueue();
322 385
323 return PP_TRUE; 386 return PP_TRUE;
324 } 387 }
325 388
326 static void Instance_DidDestroy(PP_Instance instance) { 389 static void Instance_DidDestroy(PP_Instance instance) {
327 } 390 }
328 391
329 static void Instance_DidChangeView(PP_Instance instance, 392 static void Instance_DidChangeView(PP_Instance instance,
330 PP_Resource view_resource) { 393 PP_Resource view_resource) {
331 } 394 }
332 395
333 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { 396 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {
334 } 397 }
335 398
336 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, 399 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
337 PP_Resource url_loader) { 400 PP_Resource url_loader) {
338 /* NaCl modules do not need to handle the document load function. */ 401 /* NaCl modules do not need to handle the document load function. */
339 return PP_FALSE; 402 return PP_FALSE;
340 } 403 }
341 404
342 static void Messaging_HandleMessage(PP_Instance instance, 405 static void Messaging_HandleMessage(PP_Instance instance,
343 struct PP_Var message) { 406 struct PP_Var message) {
407 /* Special case for jspipe input handling */
408 if (message.type != PP_VARTYPE_DICTIONARY) {
409 PostMessage("Got unexpected message type: %d\n", message.type);
410 return;
411 }
412
413 struct PP_Var pipe_var = CStrToVar("pipe");
414 struct PP_Var pipe_name = g_ppb_var_dictionary->Get(message, pipe_var);
415 g_ppb_var->Release(pipe_var);
416
417 /* Special case for jspipe input handling */
418 if (pipe_name.type == PP_VARTYPE_STRING) {
419 char file_name[PATH_MAX];
420 snprintf(file_name, PATH_MAX, "/dev/%s", VarToCStr(pipe_name));
421 int fd = open(file_name, O_RDONLY);
422 g_ppb_var->Release(pipe_name);
423 if (fd < 0) {
424 PostMessage("Warning: opening %s failed.", file_name);
425 goto done;
426 }
427 if (ioctl(fd, NACL_IOC_HANDLEMESSAGE, &message) != 0) {
428 PostMessage("Error: ioctl on %s failed: %s", file_name, strerror(errno));
429 }
430 close(fd);
431 goto done;
432 }
433
344 g_ppb_var->AddRef(message); 434 g_ppb_var->AddRef(message);
345 if (!EnqueueMessage(message)) { 435 if (!EnqueueMessage(message)) {
346 g_ppb_var->Release(message); 436 g_ppb_var->Release(message);
347 PostMessageVar( 437 PostMessage("Warning: dropped message because the queue was full.");
348 PrintfToVar("Warning: dropped message because the queue was full."));
349 } 438 }
439
440 done:
441 g_ppb_var->Release(pipe_name);
350 } 442 }
351 443
352 #define GET_INTERFACE(var, type, name) \ 444 #define GET_INTERFACE(var, type, name) \
353 var = (type*)(get_browser(name)); \ 445 var = (type*)(get_browser(name)); \
354 if (!var) { \ 446 if (!var) { \
355 printf("Unable to get interface " name "\n"); \ 447 printf("Unable to get interface " name "\n"); \
356 return PP_ERROR_FAILED; \ 448 return PP_ERROR_FAILED; \
357 } 449 }
358 450
359 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, 451 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
(...skipping 21 matching lines...) Expand all
381 static PPP_Messaging messaging_interface = { 473 static PPP_Messaging messaging_interface = {
382 &Messaging_HandleMessage, 474 &Messaging_HandleMessage,
383 }; 475 };
384 return &messaging_interface; 476 return &messaging_interface;
385 } 477 }
386 return NULL; 478 return NULL;
387 } 479 }
388 480
389 PP_EXPORT void PPP_ShutdownModule() { 481 PP_EXPORT void PPP_ShutdownModule() {
390 } 482 }
OLDNEW
« no previous file with comments | « native_client_sdk/src/examples/demo/nacl_io/nacl_io_demo.h ('k') | native_client_sdk/src/libraries/nacl_io/devfs/dev_fs.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698