summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-18 00:06:24 +0000
committerbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-18 00:06:24 +0000
commit0f5e11c4d7e510ff5283b8cb359c0ef0cab66ed1 (patch)
treebe3815790e23582e6690d779c3bfb72c5a18f9fe /native_client_sdk
parent05e38fd0546e5301f476cfb388f998c75fd0ec37 (diff)
downloadchromium_src-0f5e11c4d7e510ff5283b8cb359c0ef0cab66ed1.zip
chromium_src-0f5e11c4d7e510ff5283b8cb359c0ef0cab66ed1.tar.gz
chromium_src-0f5e11c4d7e510ff5283b8cb359c0ef0cab66ed1.tar.bz2
[NaCl SDK] Add html5fs mount to pepper example.
Requires calling all nacl_mounts calls off main thread. BUG=none TBR=noelallen@chromium.org NOTRY=true Review URL: https://codereview.chromium.org/11610003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173585 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/example.dsc2
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/example.js13
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c124
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/index.html23
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/queue.c115
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/queue.h30
6 files changed, 263 insertions, 44 deletions
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc b/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc
index 7c40eac..abffe26 100644
--- a/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc
@@ -9,6 +9,8 @@
'handlers.h',
'hello_nacl_mounts.c',
'hello_nacl_mounts.h',
+ 'queue.c',
+ 'queue.h',
],
'LIBS': ['ppapi', 'pthread', 'nacl_mounts']
}
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/example.js b/native_client_sdk/src/examples/hello_nacl_mounts/example.js
index 5dcb456..bc6786b 100644
--- a/native_client_sdk/src/examples/hello_nacl_mounts/example.js
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/example.js
@@ -2,12 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Start up the paint timer when the NaCl module has loaded.
function moduleDidLoad() {
common.hideModule();
}
// Called by the common.js module.
+function domContentLoaded(name, tc, config, width, height) {
+ window.webkitStorageInfo.requestQuota(window.PERSISTENT, 1024*1024,
+ function(bytes) {
+ common.updateStatus(
+ 'Allocated '+bytes+' bytes of persistant storage.');
+ common.createNaClModule(name, tc, config, width, height);
+ common.attachDefaultListeners();
+ },
+ function(e) { alert('Failed to allocate space') });
+}
+
+// Called by the common.js module.
function attachListeners() {
var radioEls = document.querySelectorAll('input[type="radio"]');
for (var i = 0; i < radioEls.length; ++i) {
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c b/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c
index 850f921..9782e9e 100644
--- a/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <pthread.h>
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_module.h"
@@ -22,7 +23,7 @@
#include "nacl_mounts/kernel_intercept.h"
#include "handlers.h"
-
+#include "queue.h"
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
@@ -30,6 +31,9 @@
#define va_copy(d, s) ((d) = (s))
#endif
+int mount(const char *source, const char *target, const char *filesystemtype,
+ unsigned long mountflags, const void *data);
+
typedef struct {
const char* name;
@@ -37,10 +41,12 @@ typedef struct {
} FuncNameMapping;
+static PP_Instance g_instance = 0;
+static PPB_GetInterface get_browser_interface = NULL;
static PPB_Messaging* ppb_messaging_interface = NULL;
static PPB_Var* ppb_var_interface = NULL;
-static FuncNameMapping g_FunctionMap[] = {
+static FuncNameMapping g_function_map[] = {
{ "fopen", HandleFopen },
{ "fwrite", HandleFwrite },
{ "fread", HandleFread },
@@ -49,6 +55,8 @@ static FuncNameMapping g_FunctionMap[] = {
{ NULL, NULL },
};
+/** A handle to the thread the handles messages. */
+static pthread_t g_handle_message_thread;
/**
* Create a new PP_Var from a C string.
@@ -197,7 +205,7 @@ static size_t ParseMessage(char* message,
* @param[in] function_name The function name to look up.
* @return The handler function mapped to |function_name|. */
static HandleFunc GetFunctionByName(const char* function_name) {
- FuncNameMapping* map_iter = g_FunctionMap;
+ FuncNameMapping* map_iter = g_function_map;
for (; map_iter->name; ++map_iter) {
if (strcmp(map_iter->name, function_name) == 0) {
return map_iter->function;
@@ -207,37 +215,10 @@ static HandleFunc GetFunctionByName(const char* function_name) {
return NULL;
}
-
-static PP_Bool Instance_DidCreate(PP_Instance instance,
- uint32_t argc,
- const char* argn[],
- const char* argv[]) {
- /* Initialize nacl mounts. */
- ki_init(NULL);
- return PP_TRUE;
-}
-
-
-static void Instance_DidDestroy(PP_Instance instance) {
-}
-
-static void Instance_DidChangeView(PP_Instance instance,
- PP_Resource view_resource) {
-}
-
-static void Instance_DidChangeFocus(PP_Instance instance,
- PP_Bool has_focus) {
-}
-
-static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
- PP_Resource url_loader) {
- /* NaCl modules do not need to handle the document load function. */
- return PP_FALSE;
-}
-
-static void Messaging_HandleMessage(PP_Instance instance,
- struct PP_Var message) {
- char buffer[1024];
+/** Handle as message from JavaScript on the worker thread.
+ *
+ * @param[in] message The message to parse and handle. */
+static void HandleMessage(char* message) {
char* function_name;
char* params[MAX_PARAMS];
size_t num_params;
@@ -245,17 +226,13 @@ static void Messaging_HandleMessage(PP_Instance instance,
int result;
HandleFunc function;
- /* Read the message from JavaScript. */
- VarToCStr(message, &buffer[0], 1024);
-
- /* Parse it */
- num_params = ParseMessage(buffer, &function_name, &params[0], MAX_PARAMS);
+ num_params = ParseMessage(message, &function_name, &params[0], MAX_PARAMS);
function = GetFunctionByName(function_name);
if (!function) {
/* Function name wasn't found. Error. */
ppb_messaging_interface->PostMessage(
- instance, PrintfToVar("Error: Unknown function \"%s\"", function));
+ g_instance, PrintfToVar("Error: Unknown function \"%s\"", function));
}
/* Function name was found, call it. */
@@ -274,19 +251,82 @@ static void Messaging_HandleMessage(PP_Instance instance,
}
/* Post the error to JavaScript, so the user can see it. */
- ppb_messaging_interface->PostMessage(instance, var);
+ ppb_messaging_interface->PostMessage(g_instance, var);
return;
}
if (output != NULL) {
/* Function returned an output string. Send it to JavaScript. */
- ppb_messaging_interface->PostMessage(instance, CStrToVar(output));
+ ppb_messaging_interface->PostMessage(g_instance, CStrToVar(output));
free(output);
}
}
+/** A worker thread that handles messages from JavaScript.
+ * @param[in] user_data Unused.
+ * @return unused. */
+void* HandleMessageThread(void* user_data) {
+ while (1) {
+ char* message = DequeueMessage();
+ HandleMessage(message);
+ free(message);
+ }
+}
+
+
+static PP_Bool Instance_DidCreate(PP_Instance instance,
+ uint32_t argc,
+ const char* argn[],
+ const char* argv[]) {
+ g_instance = instance;
+ ki_init_ppapi(NULL, instance, get_browser_interface);
+ mount(
+ "", /* source */
+ "/persistent", /* target */
+ "html5fs", /* filesystemtype */
+ 0, /* mountflags */
+ "type=PERSISTENT,expected_size=1048576"); /* data */
+
+ pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL);
+ InitializeMessageQueue();
+
+ return PP_TRUE;
+}
+
+
+static void Instance_DidDestroy(PP_Instance instance) {
+}
+
+static void Instance_DidChangeView(PP_Instance instance,
+ PP_Resource view_resource) {
+}
+
+static void Instance_DidChangeFocus(PP_Instance instance,
+ PP_Bool has_focus) {
+}
+
+static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
+ PP_Resource url_loader) {
+ /* NaCl modules do not need to handle the document load function. */
+ return PP_FALSE;
+}
+
+static void Messaging_HandleMessage(PP_Instance instance,
+ struct PP_Var message) {
+ char buffer[1024];
+ VarToCStr(message, &buffer[0], 1024);
+ if (!EnqueueMessage(strdup(buffer))) {
+ struct PP_Var var;
+ var = PrintfToVar(
+ "Warning: dropped message \"%s\" because the queue was full.",
+ message);
+ ppb_messaging_interface->PostMessage(g_instance, var);
+ }
+}
+
PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
PPB_GetInterface get_browser) {
+ get_browser_interface = get_browser;
ppb_messaging_interface =
(PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE));
ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE));
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/index.html b/native_client_sdk/src/examples/hello_nacl_mounts/index.html
index a30b2b2..e216a51 100644
--- a/native_client_sdk/src/examples/hello_nacl_mounts/index.html
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/index.html
@@ -12,9 +12,30 @@ found in the LICENSE file.
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript" src="example.js"></script>
</head>
-<body data-name="<NAME>" data-tc="<tc>" data-path="<path>">
+<body data-name="<NAME>" data-tc="<tc>" data-path="<path>"
+ data-custom-load="true">
<h1><TITLE></h1>
<h2>Status: <code id="statusField">NO-STATUS</code></h2>
+ <p>
+ This example shows how you can use standard C library file operation
+ functions in Native Client using a library called nacl_mounts.
+ </p>
+ <p>
+ nacl_mounts provides a virtual filesystem. The filesystem can be "mounted"
+ in a given directory tree. When you perform operations on files in those
+ directories, the mount determines how those operations should be performed.
+ </p>
+ <p>
+ This example has three mounts by default.
+ <ol>
+ <li><i>/</i> the root of the filesystem. This is a memory mount, and
+ is non-persistent.</li>
+ <li><i>/persistent</i> a persistent storage area. Any data written
+ here can be read back after Chrome is restarted.</li>
+ <li><i>/dev</i> a mount containing some utility files. /dev/null,
+ /dev/zero, etc.</li>
+ </ol>
+ </p>
<div>
<span>
<input type="radio" id="radiofopen" name="group" checked="checked">fopen
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/queue.c b/native_client_sdk/src/examples/hello_nacl_mounts/queue.c
new file mode 100644
index 0000000..bd0c438
--- /dev/null
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/queue.c
@@ -0,0 +1,115 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "queue.h"
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#define MAX_QUEUE_SIZE 16
+
+/** A mutex that guards |g_queue|. */
+static pthread_mutex_t g_queue_mutex;
+
+/** A condition variable that is signalled when |g_queue| is not empty. */
+static pthread_cond_t g_queue_not_empty_cond;
+
+/** A circular queue of messages from JavaScript to be handled.
+ *
+ * If g_queue_start < g_queue_end:
+ * all elements in the range [g_queue_start, g_queue_end) are valid.
+ * If g_queue_start > g_queue_end:
+ * all elements in the ranges [0, g_queue_end) and
+ * [g_queue_start, MAX_QUEUE_SIZE) are valid.
+ * If g_queue_start == g_queue_end, and g_queue_size > 0:
+ * all elements in the g_queue are valid.
+ * If g_queue_start == g_queue_end, and g_queue_size == 0:
+ * No elements are valid. */
+static char* g_queue[MAX_QUEUE_SIZE];
+
+/** The index of the head of the queue. */
+static int g_queue_start = 0;
+
+/** The index of the tail of the queue, non-inclusive. */
+static int g_queue_end = 0;
+
+/** The size of the queue. */
+static int g_queue_size = 0;
+
+/** Return whether the queue is empty.
+ *
+ * NOTE: this function assumes g_queue_mutex lock is held.
+ * @return non-zero if the queue is empty. */
+static int IsQueueEmpty() {
+ return g_queue_size == 0;
+}
+
+/** Return whether the queue is full.
+ *
+ * NOTE: this function assumes g_queue_mutex lock is held.
+ * @return non-zero if the queue is full. */
+static int IsQueueFull() {
+ return g_queue_size == MAX_QUEUE_SIZE;
+}
+
+/** Initialize the message queue. */
+void InitializeMessageQueue() {
+ pthread_mutex_init(&g_queue_mutex, NULL);
+ pthread_cond_init(&g_queue_not_empty_cond, NULL);
+}
+
+/** Enqueue a message (i.e. add to the end)
+ *
+ * If the queue is full, the message will be dropped.
+ *
+ * NOTE: this function assumes g_queue_mutex is _NOT_ held.
+ * @param[in] message The message to enqueue.
+ * @return non-zero if the message was added to the queue. */
+int EnqueueMessage(char* message) {
+ pthread_mutex_lock(&g_queue_mutex);
+
+ /* We shouldn't block the main thread waiting for the queue to not be full,
+ * so just drop the message. */
+ if (IsQueueFull()) {
+ pthread_mutex_unlock(&g_queue_mutex);
+ free(message);
+ return 0;
+ }
+
+ g_queue[g_queue_end] = message;
+ g_queue_end = (g_queue_end + 1) % MAX_QUEUE_SIZE;
+ g_queue_size++;
+
+ pthread_cond_signal(&g_queue_not_empty_cond);
+
+ pthread_mutex_unlock(&g_queue_mutex);
+
+ return 1;
+}
+
+/** Dequeue a message and return it.
+ *
+ * This function blocks until a message is available. It should not be called
+ * on the main thread.
+ *
+ * NOTE: this function assumes g_queue_mutex is _NOT_ held.
+ * @return The message at the head of the queue. */
+char* DequeueMessage() {
+ char* message = NULL;
+
+ pthread_mutex_lock(&g_queue_mutex);
+
+ while (IsQueueEmpty()) {
+ pthread_cond_wait(&g_queue_not_empty_cond, &g_queue_mutex);
+ }
+
+ message = g_queue[g_queue_start];
+ g_queue_start = (g_queue_start + 1) % MAX_QUEUE_SIZE;
+ g_queue_size--;
+
+ pthread_mutex_unlock(&g_queue_mutex);
+
+ return message;
+}
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/queue.h b/native_client_sdk/src/examples/hello_nacl_mounts/queue.h
new file mode 100644
index 0000000..ed267f8
--- /dev/null
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/queue.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef QUEUE_H_
+#define QUEUE_H_
+
+/* This file implements a single-producer/single-consumer queue, using a mutex
+ * and a condition variable.
+ *
+ * There are techniques to implement a queue like this without using memory
+ * barriers or locks on x86, but ARM's memory system is different from x86, so
+ * we cannot make the same assuptions about visibility order of writes. Using a
+ * mutex is slower, but also simpler.
+ *
+ * We make the assumption that messages are only enqueued on the main thread
+ * and consumed on the worker thread. Because we don't want to block the main
+ * thread, EnqueueMessage will return zero if the message could not be enqueued.
+ *
+ * DequeueMessage will block until a message is available using a condition
+ * variable. Again, this may not be as fast as spin-waiting, but will consume
+ * much less CPU (and battery), which is important to consider for ChromeOS
+ * devices. */
+
+void InitializeMessageQueue();
+int EnqueueMessage(char* message);
+char* DequeueMessage();
+
+#endif /* QUEUE_H_ */