summaryrefslogtreecommitdiff
path: root/native_client_sdk
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2013-08-07 11:04:47 +0100
committerBen Murdoch <benm@google.com>2013-08-07 11:04:47 +0100
commit3240926e260ce088908e02ac07a6cf7b0c0cbf44 (patch)
tree5ff5fa16b2fb9278c6d731b3d19123731f3f8626 /native_client_sdk
parent3b21a50ee4fe6f71bb117cbee9998a4f465eea9d (diff)
downloadchromium_org-3240926e260ce088908e02ac07a6cf7b0c0cbf44.tar.gz
Merge from Chromium at DEPS revision r216133
This commit was generated by merge_to_master.py. Change-Id: I541d5d1d8520b6b3829fbc1fa18552bf9ad4a5c7
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/build_tools/sdk_files.list16
-rwxr-xr-xnative_client_sdk/src/build_tools/test_projects.py3
-rw-r--r--native_client_sdk/src/examples/demo/earth/earth.cc336
-rw-r--r--native_client_sdk/src/examples/demo/earth/example.dsc2
-rw-r--r--native_client_sdk/src/examples/demo/voronoi/example.dsc2
-rw-r--r--native_client_sdk/src/examples/demo/voronoi/voronoi.cc292
-rw-r--r--native_client_sdk/src/libraries/nacl_io/event_emitter.h6
-rw-r--r--native_client_sdk/src/libraries/nacl_io/event_listener.cc7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/event_listener.h10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/include/sys/utsname.h20
-rw-r--r--native_client_sdk/src/libraries/nacl_io/inet_ntoa.cc65
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc9
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.h4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc181
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.h7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc14
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc82
-rw-r--r--native_client_sdk/src/libraries/nacl_io/library.dsc19
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.cc6
-rw-r--r--native_client_sdk/src/libraries/nacl_io/ossocket.h4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/poll.h38
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/poll.c10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/select.c11
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/uname.c14
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/event_test.cc120
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h3
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc11
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/socket_test.cc107
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/library.dsc2
-rw-r--r--native_client_sdk/src/libraries/third_party/newlib-extras/sys/select.h20
-rw-r--r--native_client_sdk/src/tools/common.mk13
-rwxr-xr-xnative_client_sdk/src/tools/sel_ldr.py8
32 files changed, 1014 insertions, 428 deletions
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index cbf0b8d7be..c3fd8302b7 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -355,12 +355,18 @@ include/newlib/arpa/inet.h
include/newlib/netdb.h
include/newlib/netinet/in.h
include/newlib/netinet6/in6.h
+include/newlib/poll.h
+include/newlib/sys/select.h
include/newlib/sys/socket.h
+include/newlib/sys/utsname.h
include/pnacl/arpa/inet.h
include/pnacl/netdb.h
include/pnacl/netinet/in.h
include/pnacl/netinet6/in6.h
+include/pnacl/poll.h
+include/pnacl/sys/select.h
include/pnacl/sys/socket.h
+include/pnacl/sys/utsname.h
include/ppapi/c/dev/deprecated_bool.h
include/ppapi/c/dev/pp_cursor_type_dev.h
include/ppapi/c/dev/pp_print_settings_dev.h
@@ -597,9 +603,11 @@ include/sdk_util/thread_safe_queue.h
[win]include/win/context.h
[win]include/win/implement.h
[win]include/win/need_errno.h
+include/win/poll.h
[win]include/win/pthread.h
[win]include/win/sched.h
[win]include/win/semaphore.h
+
[linux]lib/${PLATFORM}_host/Debug/libgmock.a
[linux]lib/${PLATFORM}_host/Debug/libgtest.a
[linux]lib/${PLATFORM}_host/Debug/libjsoncpp.a
@@ -617,23 +625,19 @@ include/sdk_util/thread_safe_queue.h
[win]lib/${PLATFORM}_x86_32_host/Debug/gmock.lib
[win]lib/${PLATFORM}_x86_32_host/Debug/gtest.lib
[win]lib/${PLATFORM}_x86_32_host/Debug/jsoncpp.lib
-[win]lib/${PLATFORM}_x86_32_host/Debug/nacl_io.lib
[win]lib/${PLATFORM}_x86_32_host/Debug/ppapi.lib
[win]lib/${PLATFORM}_x86_32_host/Debug/ppapi_cpp.lib
[win]lib/${PLATFORM}_x86_32_host/Debug/ppapi_cpp_private.lib
[win]lib/${PLATFORM}_x86_32_host/Debug/ppapi_gles2.lib
-[win]lib/${PLATFORM}_x86_32_host/Debug/ppapi_simple.lib
[win]lib/${PLATFORM}_x86_32_host/Debug/pthread.lib
[win]lib/${PLATFORM}_x86_32_host/Debug/sdk_util.lib
[win]lib/${PLATFORM}_x86_32_host/Release/gmock.lib
[win]lib/${PLATFORM}_x86_32_host/Release/gtest.lib
[win]lib/${PLATFORM}_x86_32_host/Release/jsoncpp.lib
-[win]lib/${PLATFORM}_x86_32_host/Release/nacl_io.lib
[win]lib/${PLATFORM}_x86_32_host/Release/ppapi.lib
[win]lib/${PLATFORM}_x86_32_host/Release/ppapi_cpp.lib
[win]lib/${PLATFORM}_x86_32_host/Release/ppapi_cpp_private.lib
[win]lib/${PLATFORM}_x86_32_host/Release/ppapi_gles2.lib
-[win]lib/${PLATFORM}_x86_32_host/Release/ppapi_simple.lib
[win]lib/${PLATFORM}_x86_32_host/Release/pthread.lib
[win]lib/${PLATFORM}_x86_32_host/Release/sdk_util.lib
lib/glibc_x86_32/Debug/libgmock.a
@@ -828,6 +832,7 @@ src/jsoncpp/README.chromium
src/Makefile
src/nacl_io/event_emitter.cc
src/nacl_io/event_listener.cc
+src/nacl_io/inet_ntoa.cc
src/nacl_io/kernel_handle.cc
src/nacl_io/kernel_intercept.cc
src/nacl_io/kernel_object.cc
@@ -868,9 +873,12 @@ src/nacl_io/syscalls/lchown.c
src/nacl_io/syscalls/link.c
src/nacl_io/syscalls/mkdir.c
src/nacl_io/syscalls/mount.c
+src/nacl_io/syscalls/poll.c
src/nacl_io/syscalls/remove.c
src/nacl_io/syscalls/rmdir.c
+src/nacl_io/syscalls/select.c
src/nacl_io/syscalls/umount.c
+src/nacl_io/syscalls/uname.c
src/nacl_io/syscalls/unlink.c
src/nacl_io/syscalls/utime.c
[win]src/ppapi/make.bat
diff --git a/native_client_sdk/src/build_tools/test_projects.py b/native_client_sdk/src/build_tools/test_projects.py
index 8aac430c7a..a74292304e 100755
--- a/native_client_sdk/src/build_tools/test_projects.py
+++ b/native_client_sdk/src/build_tools/test_projects.py
@@ -105,6 +105,9 @@ def GetBrowserTesterCommand(desc, toolchain, config):
ppapi_plugin += '.so'
args.extend(['--ppapi_plugin', ppapi_plugin])
+ if toolchain == 'pnacl':
+ args.extend(['--browser_flag', '--enable-pnacl'])
+
url = 'index.html'
url += '?tc=%s&config=%s&test=true' % (toolchain, config)
args.extend(['--url', url])
diff --git a/native_client_sdk/src/examples/demo/earth/earth.cc b/native_client_sdk/src/examples/demo/earth/earth.cc
index f363b39eaf..d0c6de740c 100644
--- a/native_client_sdk/src/examples/demo/earth/earth.cc
+++ b/native_client_sdk/src/examples/demo/earth/earth.cc
@@ -4,16 +4,8 @@
#include <assert.h>
#include <math.h>
-#include <ppapi/c/pp_point.h>
#include <ppapi/c/ppb_input_event.h>
-#include <ppapi/cpp/completion_callback.h>
-#include <ppapi/cpp/graphics_2d.h>
-#include <ppapi/cpp/image_data.h>
#include <ppapi/cpp/input_event.h>
-#include <ppapi/cpp/instance.h>
-#include <ppapi/cpp/module.h>
-#include <ppapi/cpp/rect.h>
-#include <ppapi/cpp/size.h>
#include <ppapi/cpp/var.h>
#include <ppapi/cpp/var_array.h>
#include <ppapi/cpp/var_array_buffer.h>
@@ -28,6 +20,11 @@
#include <algorithm>
#include <string>
+#include "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_context_2d.h"
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_interface.h"
+#include "ppapi_simple/ps_main.h"
#include "sdk_util/macros.h"
#include "sdk_util/thread_pool.h"
@@ -179,20 +176,14 @@ inline uint32_t Clamp255(float x) {
// The main object that runs the Earth demo.
-class Planet : public pp::Instance {
+class Planet {
public:
- explicit Planet(PP_Instance instance);
+ Planet();
virtual ~Planet();
-
- virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
-
- virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip);
-
- // Catch events.
- virtual bool HandleInputEvent(const pp::InputEvent& event);
-
- // Catch messages posted from Javascript.
- virtual void HandleMessage(const pp::Var& message);
+ // Runs a tick of the simulations, update 2D output.
+ void Update();
+ // Handle event from user, or message from JS.
+ void HandleEvent(PSEvent* ps_event);
private:
// Methods prefixed with 'w' are run on worker threads.
@@ -219,26 +210,14 @@ class Planet : public pp::Instance {
uint32_t* pixels);
void Reset();
- void PostInit(int32_t result);
+ void RequestTextures();
void UpdateSim();
void Render();
void Draw();
void StartBenchmark();
void EndBenchmark();
-
- // Runs a tick of the simulations, updating all buffers. Flushes the
- // contents of |image_data_| to the 2D graphics context.
- void Update();
-
// Post a small key-value message to update JS.
void PostUpdateMessage(const char* message_name, double value);
- // Create and initialize the 2D context used for drawing.
- void CreateContext(const pp::Size& size);
- // Destroy the 2D drawing context.
- void DestroyContext();
- // Push the pixels to the browser, then attempt to flush the 2D context.
- void FlushPixelBuffer();
- static void FlushCallback(void* data, int32_t result);
// User Interface settings. These settings are controlled via html
// controls or via user input.
@@ -280,33 +259,22 @@ class Planet : public pp::Instance {
Texture* night_tex_;
int width_for_tex_;
int height_for_tex_;
- std::string name_for_tex_;
// Quick ArcCos helper.
ArcCosine acos_;
// Misc.
- pp::Graphics2D* graphics_2d_context_;
- pp::ImageData* image_data_;
+ PSContext2D_t* ps_context_;
int num_threads_;
- int num_regions_;
ThreadPool* workers_;
- int width_;
- int height_;
- uint32_t stride_in_pixels_;
- uint32_t* pixel_buffer_;
- int benchmark_frame_counter_;
bool benchmarking_;
+ int benchmark_frame_counter_;
double benchmark_start_time_;
double benchmark_end_time_;
};
-bool Planet::Init(uint32_t argc, const char* argn[], const char* argv[]) {
- // Request PPAPI input events for mouse & keyboard.
- RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
- RequestInputEvents(PP_INPUTEVENT_CLASS_WHEEL);
- RequestInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
+void Planet::RequestTextures() {
// Request a set of images from JS. After images are loaded by JS, a
// message from JS -> NaCl will arrive containing the pixel data. See
// HandleMessage() method in this file.
@@ -316,8 +284,7 @@ bool Planet::Init(uint32_t argc, const char* argn[], const char* argv[]) {
names.Set(0, "earth.jpg");
names.Set(1, "earthnight.jpg");
message.Set("names", names);
- PostMessage(message);
- return true;
+ PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
}
void Planet::Reset() {
@@ -378,47 +345,35 @@ void Planet::Reset() {
}
-Planet::Planet(PP_Instance instance) : pp::Instance(instance),
- graphics_2d_context_(NULL),
- image_data_(NULL),
- num_regions_(256) {
- width_ = 0;
- height_ = 0;
- stride_in_pixels_ = 0;
- pixel_buffer_ = NULL;
- benchmark_frame_counter_ = 0;
- benchmarking_ = false;
- base_tex_ = NULL;
- night_tex_ = NULL;
- name_for_tex_ = "";
+Planet::Planet() : base_tex_(NULL), night_tex_(NULL), num_threads_(0),
+ benchmarking_(false), benchmark_frame_counter_(0) {
Reset();
-
+ RequestTextures();
// By default, render from the dispatch thread.
- num_threads_ = 0;
workers_ = new ThreadPool(num_threads_);
+ PSEventSetFilter(PSE_ALL);
+ ps_context_ = PSContext2DAllocate();
}
Planet::~Planet() {
delete workers_;
- DestroyContext();
+ PSContext2DFree(ps_context_);
}
// Given a region r, derive a rectangle.
// This rectangle shouldn't overlap with work being done by other workers.
// If multithreading, this function is only called by the worker threads.
void Planet::wMakeRect(int r, int *x, int *y, int *w, int *h) {
- int dy = height_ / num_regions_;
*x = 0;
- *w = width_;
- *y = r * dy;
- *h = dy;
+ *w = ps_context_->width;
+ *y = r;
+ *h = 1;
}
inline uint32_t* Planet::wGetAddr(int x, int y) {
- assert(pixel_buffer_);
- return (pixel_buffer_ + y * stride_in_pixels_) + x;
+ return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t);
}
// This is the meat of the ray tracer. Given a pixel span (x0, x1) on
@@ -430,7 +385,7 @@ void Planet::wRenderPixelSpan(int x0, int x1, int y) {
const int kColorBlack = MakeRGBA(0, 0, 0, 0xFF);
float y0 = eye_y_;
float z0 = eye_z_;
- float y1 = (static_cast<float>(y) / height_) * 2.0f - 1.0f;
+ float y1 = (static_cast<float>(y) / ps_context_->height) * 2.0f - 1.0f;
float z1 = 0.0f;
float dy = (y1 - y0);
float dz = (z1 - z0);
@@ -439,7 +394,7 @@ void Planet::wRenderPixelSpan(int x0, int x1, int y) {
2.0f * dz * (z0 - planet_z_);
float planet_xyz_eye_xyz = planet_xyz_ + eye_xyz_;
float y_y0_z_z0 = planet_y_ * y0 + planet_z_ * z0;
- float oowidth = 1.0f / width_;
+ float oowidth = 1.0f / ps_context_->width;
uint32_t* pixels = this->wGetAddr(x0, y);
for (int x = x0; x <= x1; ++x) {
// scan normalized screen -1..1
@@ -565,12 +520,8 @@ void Planet::wRenderRegionEntry(int region, void* thiz) {
}
// Renders the planet, dispatching the work to multiple threads.
-// Note: This Dispatch() is from the main PPAPI thread, so care must be taken
-// not to attempt PPAPI calls from the worker threads, since Dispatch() will
-// block here until all work is complete. The worker threads are compute only
-// and do not make any PPAPI calls.
void Planet::Render() {
- workers_->Dispatch(num_regions_, wRenderRegionEntry, this);
+ workers_->Dispatch(ps_context_->height, wRenderRegionEntry, this);
}
// Pre-calculations to make inner loops faster.
@@ -669,16 +620,6 @@ void Planet::UpdateSim() {
SetPlanetSpin(x, y);
}
-void Planet::DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
- if (position.size().width() == width_ &&
- position.size().height() == height_)
- return; // Size didn't change, no need to update anything.
- // Create a new device context with the new size.
- DestroyContext();
- CreateContext(position.size());
- Update();
-}
-
void Planet::StartBenchmark() {
// For more consistent benchmark numbers, reset to default state.
Reset();
@@ -723,43 +664,81 @@ void Planet::SetTexture(const std::string& name, int width, int height,
}
}
-// Handle input events from the user.
-bool Planet::HandleInputEvent(const pp::InputEvent& event) {
- switch (event.GetType()) {
- case PP_INPUTEVENT_TYPE_KEYDOWN: {
- pp::KeyboardInputEvent key(event);
- uint32_t key_code = key.GetKeyCode();
- if (key_code == 84) // 't' key
- if (!benchmarking_)
- StartBenchmark();
- break;
- }
- case PP_INPUTEVENT_TYPE_MOUSEMOVE:
- case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
- pp::MouseInputEvent mouse = pp::MouseInputEvent(event);
- if (mouse.GetModifiers() & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
- PP_Point delta = mouse.GetMovement();
- float delta_x = static_cast<float>(delta.x);
- float delta_y = static_cast<float>(delta.y);
- float spin_x = std::min(4.0f, std::max(-4.0f, delta_x * 0.5f));
- float spin_y = std::min(4.0f, std::max(-4.0f, delta_y * 0.5f));
- ui_spin_x_ = spin_x / 100.0f;
- ui_spin_y_ = spin_y / 100.0f;
+// Handle input events from the user and messages from JS.
+void Planet::HandleEvent(PSEvent* ps_event) {
+ // Give the 2D context a chance to process the event.
+ if (0 != PSContext2DHandleEvent(ps_context_, ps_event))
+ return;
+ if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) {
+ // Convert Pepper Simple event to a PPAPI C++ event
+ pp::InputEvent event(ps_event->as_resource);
+ switch (event.GetType()) {
+ case PP_INPUTEVENT_TYPE_KEYDOWN: {
+ pp::KeyboardInputEvent key(event);
+ uint32_t key_code = key.GetKeyCode();
+ if (key_code == 84) // 't' key
+ if (!benchmarking_)
+ StartBenchmark();
+ break;
}
- break;
+ case PP_INPUTEVENT_TYPE_MOUSEMOVE:
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
+ pp::MouseInputEvent mouse = pp::MouseInputEvent(event);
+ if (mouse.GetModifiers() & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
+ PP_Point delta = mouse.GetMovement();
+ float delta_x = static_cast<float>(delta.x);
+ float delta_y = static_cast<float>(delta.y);
+ float spin_x = std::min(4.0f, std::max(-4.0f, delta_x * 0.5f));
+ float spin_y = std::min(4.0f, std::max(-4.0f, delta_y * 0.5f));
+ ui_spin_x_ = spin_x / 100.0f;
+ ui_spin_y_ = spin_y / 100.0f;
+ }
+ break;
+ }
+ case PP_INPUTEVENT_TYPE_WHEEL: {
+ pp::WheelInputEvent wheel = pp::WheelInputEvent(event);
+ PP_FloatPoint ticks = wheel.GetTicks();
+ SetZoom(ui_zoom_ + (ticks.x + ticks.y) * kWheelSpeed);
+ // Update html slider by sending update message to JS.
+ PostUpdateMessage("set_zoom", ui_zoom_);
+ break;
+ }
+ default:
+ break;
}
- case PP_INPUTEVENT_TYPE_WHEEL: {
- pp::WheelInputEvent wheel = pp::WheelInputEvent(event);
- PP_FloatPoint ticks = wheel.GetTicks();
- SetZoom(ui_zoom_ + (ticks.x + ticks.y) * kWheelSpeed);
- // Update html slider by sending update message to JS.
- PostUpdateMessage("set_zoom", ui_zoom_);
- break;
+ } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) {
+ // Convert Pepper Simple message to PPAPI C++ vars
+ pp::Var var(ps_event->as_var);
+ if (var.is_dictionary()) {
+ pp::VarDictionary dictionary(var);
+ std::string message = dictionary.Get("message").AsString();
+ if (message == "run benchmark" && !benchmarking_) {
+ StartBenchmark();
+ } else if (message == "set_light") {
+ SetLight(static_cast<float>(dictionary.Get("value").AsDouble()));
+ } else if (message == "set_zoom") {
+ SetZoom(static_cast<float>(dictionary.Get("value").AsDouble()));
+ } else if (message == "set_threads") {
+ int threads = dictionary.Get("value").AsInt();
+ delete workers_;
+ workers_ = new ThreadPool(threads);
+ } else if (message == "texture") {
+ std::string name = dictionary.Get("name").AsString();
+ int width = dictionary.Get("width").AsInt();
+ int height = dictionary.Get("height").AsInt();
+ pp::VarArrayBuffer array_buffer(dictionary.Get("data"));
+ if (!name.empty() && !array_buffer.is_null()) {
+ if (width > 0 && height > 0) {
+ uint32_t* pixels = static_cast<uint32_t*>(array_buffer.Map());
+ SetTexture(name, width, height, pixels);
+ array_buffer.Unmap();
+ }
+ }
+ }
+ } else {
+ printf("Handle message unknown type: %s\n", var.DebugString().c_str());
}
- default:
- return false;
}
- return true;
}
// PostUpdateMessage() helper function for sending small messages to JS.
@@ -767,53 +746,17 @@ void Planet::PostUpdateMessage(const char* message_name, double value) {
pp::VarDictionary message;
message.Set("message", message_name);
message.Set("value", value);
- PostMessage(message);
-}
-
-// Handle message sent from Javascript.
-void Planet::HandleMessage(const pp::Var& var) {
- if (var.is_dictionary()) {
- pp::VarDictionary dictionary(var);
- std::string message = dictionary.Get("message").AsString();
- if (message == "run benchmark" && !benchmarking_) {
- StartBenchmark();
- } else if (message == "set_light") {
- SetLight(static_cast<float>(dictionary.Get("value").AsDouble()));
- } else if (message == "set_zoom") {
- SetZoom(static_cast<float>(dictionary.Get("value").AsDouble()));
- } else if (message == "set_threads") {
- int threads = dictionary.Get("value").AsInt();
- delete workers_;
- workers_ = new ThreadPool(threads);
- } else if (message == "texture") {
- std::string name = dictionary.Get("name").AsString();
- int width = dictionary.Get("width").AsInt();
- int height = dictionary.Get("height").AsInt();
- pp::VarArrayBuffer array_buffer(dictionary.Get("data"));
- if (!name.empty() && width > 0 && height > 0 && !array_buffer.is_null()) {
- uint32_t* pixels = static_cast<uint32_t*>(array_buffer.Map());
- SetTexture(name, width, height, pixels);
- array_buffer.Unmap();
- }
- }
- } else {
- printf("Handle message unknown type: %s\n", var.DebugString().c_str());
- }
-}
-
-void Planet::FlushCallback(void* thiz, int32_t result) {
- static_cast<Planet*>(thiz)->Update();
-}
-
-// Update the 2d region and flush to make it visible on the page.
-void Planet::FlushPixelBuffer() {
- graphics_2d_context_->PaintImageData(*image_data_, pp::Point(0, 0));
- graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
+ PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
}
void Planet::Update() {
- // Don't call FlushPixelBuffer() when benchmarking - vsync is enabled by
- // default, and will throttle the benchmark results.
+ // When benchmarking is running, don't update display via
+ // PSContext2DSwapBuffer() - vsync is enabled by default, and will throttle
+ // the benchmark results.
+ PSContext2DGetBuffer(ps_context_);
+ if (NULL == ps_context_->data)
+ return;
+
do {
UpdateSim();
Render();
@@ -823,51 +766,28 @@ void Planet::Update() {
if (benchmarking_)
EndBenchmark();
- FlushPixelBuffer();
-}
-
-void Planet::CreateContext(const pp::Size& size) {
- graphics_2d_context_ = new pp::Graphics2D(this, size, false);
- if (graphics_2d_context_->is_null())
- printf("Failed to create a 2D resource!\n");
- if (!BindGraphics(*graphics_2d_context_))
- printf("Couldn't bind the device context\n");
- image_data_ = new pp::ImageData(this,
- PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- size,
- false);
- width_ = image_data_->size().width();
- height_ = image_data_->size().height();
- stride_in_pixels_ = static_cast<uint32_t>(image_data_->stride() / 4);
- pixel_buffer_ = static_cast<uint32_t*>(image_data_->data());
- num_regions_ = height_;
-}
-
-void Planet::DestroyContext() {
- delete graphics_2d_context_;
- delete image_data_;
- graphics_2d_context_ = NULL;
- image_data_ = NULL;
- width_ = 0;
- height_ = 0;
- stride_in_pixels_ = 0;
- pixel_buffer_ = NULL;
-}
-
-class PlanetModule : public pp::Module {
- public:
- PlanetModule() : pp::Module() {}
- virtual ~PlanetModule() {}
+ PSContext2DSwapBuffer(ps_context_);
+}
+
- // Create and return a Planet instance.
- virtual pp::Instance* CreateInstance(PP_Instance instance) {
- return new Planet(instance);
+// Starting point for the module. We do not use main since it would
+// collide with main in libppapi_cpp.
+int example_main(int argc, char* argv[]) {
+ Planet earth;
+ while (true) {
+ PSEvent* ps_event;
+ // Consume all available events
+ while ((ps_event = PSEventTryAcquire()) != NULL) {
+ earth.HandleEvent(ps_event);
+ PSEventRelease(ps_event);
+ }
+ // Do simulation, render and present.
+ earth.Update();
}
-};
-namespace pp {
-Module* CreateModule() {
- return new PlanetModule();
+ return 0;
}
-} // namespace pp
+// Register the function to call once the Instance Object is initialized.
+// see: pappi_simple/ps_main.h
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
diff --git a/native_client_sdk/src/examples/demo/earth/example.dsc b/native_client_sdk/src/examples/demo/earth/example.dsc
index 21eb60c354..4d4829c93d 100644
--- a/native_client_sdk/src/examples/demo/earth/example.dsc
+++ b/native_client_sdk/src/examples/demo/earth/example.dsc
@@ -7,7 +7,7 @@
'SOURCES' : [
'earth.cc'
],
- 'LIBS': ['sdk_util', 'ppapi_cpp', 'ppapi', 'pthread']
+ 'LIBS': ['ppapi_simple', 'nacl_io', 'sdk_util', 'ppapi_cpp', 'ppapi', 'pthread']
}
],
'DATA': [
diff --git a/native_client_sdk/src/examples/demo/voronoi/example.dsc b/native_client_sdk/src/examples/demo/voronoi/example.dsc
index d9fabcebc9..1d766d6b4d 100644
--- a/native_client_sdk/src/examples/demo/voronoi/example.dsc
+++ b/native_client_sdk/src/examples/demo/voronoi/example.dsc
@@ -8,7 +8,7 @@
'voronoi.cc'
],
- 'LIBS': ['sdk_util', 'ppapi_cpp', 'ppapi', 'pthread']
+ 'LIBS': ['ppapi_simple', 'nacl_io', 'sdk_util', 'ppapi_cpp', 'ppapi', 'pthread']
}
],
'DATA': [
diff --git a/native_client_sdk/src/examples/demo/voronoi/voronoi.cc b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
index d85d185e04..7cadb1a1b5 100644
--- a/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
+++ b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
@@ -4,15 +4,11 @@
#include <assert.h>
#include <math.h>
-#include <ppapi/cpp/completion_callback.h>
-#include <ppapi/cpp/graphics_2d.h>
-#include <ppapi/cpp/image_data.h>
+#include <ppapi/c/ppb_input_event.h>
#include <ppapi/cpp/input_event.h>
-#include <ppapi/cpp/instance.h>
-#include <ppapi/cpp/module.h>
-#include <ppapi/cpp/rect.h>
-#include <ppapi/cpp/size.h>
#include <ppapi/cpp/var.h>
+#include <ppapi/cpp/var_array.h>
+#include <ppapi/cpp/var_array_buffer.h>
#include <ppapi/cpp/var_dictionary.h>
#include <pthread.h>
#include <stdio.h>
@@ -24,6 +20,11 @@
#include <algorithm>
#include <string>
+#include "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_context_2d.h"
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_interface.h"
+#include "ppapi_simple/ps_main.h"
#include "sdk_util/thread_pool.h"
using namespace sdk_util; // For sdk_util::ThreadPool
@@ -39,6 +40,7 @@ const int kFramesToBenchmark = 100;
const unsigned int kRandomStartSeed = 0xC0DE533D;
const int kMaxPointCount = 1024;
const int kStartPointCount = 256;
+const int kDefaultNumRegions = 256;
unsigned int g_rand_state = kRandomStartSeed;
@@ -91,25 +93,18 @@ struct Vec2 {
};
// The main object that runs Voronoi simulation.
-class Voronoi : public pp::Instance {
+class Voronoi {
public:
- explicit Voronoi(PP_Instance instance);
+ Voronoi();
virtual ~Voronoi();
-
- virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
- return true;
- }
-
- virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip);
-
- // Catch events.
- virtual bool HandleInputEvent(const pp::InputEvent& event);
-
- // Catch messages posted from Javascript.
- virtual void HandleMessage(const pp::Var& message);
+ // Runs a tick of the simulations, update 2D output.
+ void Update();
+ // Handle event from user, or message from JS.
+ void HandleEvent(PSEvent* ps_event);
private:
// Methods prefixed with 'w' are run on worker threads.
+ uint32_t* wGetAddr(int x, int y);
int wCell(float x, float y);
inline void wFillSpan(uint32_t *pixels, uint32_t color, int width);
void wRenderTile(int x, int y, int w, int h);
@@ -131,39 +126,21 @@ class Voronoi : public pp::Instance {
void Draw();
void StartBenchmark();
void EndBenchmark();
-
- // Runs a tick of the simulations, updating all buffers. Flushes the
- // contents of |image_data_| to the 2D graphics context.
- void Update();
-
// Helper to post small update messages to JS.
void PostUpdateMessage(const char* message_name, double value);
- // Create and initialize the 2D context used for drawing.
- void CreateContext(const pp::Size& size);
- // Destroy the 2D drawing context.
- void DestroyContext();
- // Push the pixels to the browser, then attempt to flush the 2D context.
- void FlushPixelBuffer();
- static void FlushCallback(void* data, int32_t result);
-
- pp::Graphics2D* graphics_2d_context_;
- pp::ImageData* image_data_;
+ PSContext2D_t* ps_context_;
Vec2 positions_[kMaxPointCount];
Vec2 screen_positions_[kMaxPointCount];
Vec2 velocities_[kMaxPointCount];
uint32_t colors_[kMaxPointCount];
float ang_;
- int point_count_;
- int num_threads_;
const int num_regions_;
+ int num_threads_;
+ int point_count_;
bool draw_points_;
bool draw_interiors_;
ThreadPool* workers_;
- int width_;
- int height_;
- uint32_t stride_in_pixels_;
- uint32_t* pixel_buffer_;
int benchmark_frame_counter_;
bool benchmarking_;
double benchmark_start_time_;
@@ -171,7 +148,6 @@ class Voronoi : public pp::Instance {
};
-
void Voronoi::Reset() {
rand_reset(kRandomStartSeed);
ang_ = 0.0f;
@@ -190,34 +166,23 @@ void Voronoi::Reset() {
}
}
-Voronoi::Voronoi(PP_Instance instance) : pp::Instance(instance),
- graphics_2d_context_(NULL),
- image_data_(NULL),
- num_regions_(256) {
- draw_points_ = true;
- draw_interiors_ = true;
- width_ = 0;
- height_ = 0;
- stride_in_pixels_ = 0;
- pixel_buffer_ = NULL;
- benchmark_frame_counter_ = 0;
- benchmarking_ = false;
-
- point_count_ = kStartPointCount;
+Voronoi::Voronoi() : num_regions_(kDefaultNumRegions), num_threads_(0),
+ point_count_(kStartPointCount), draw_points_(true), draw_interiors_(true),
+ benchmark_frame_counter_(0), benchmarking_(false) {
Reset();
-
// By default, render from the dispatch thread.
- num_threads_ = 0;
workers_ = new ThreadPool(num_threads_);
-
- // Request PPAPI input events for mouse & keyboard.
- RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
- RequestInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
+ PSEventSetFilter(PSE_ALL);
+ ps_context_ = PSContext2DAllocate();
}
Voronoi::~Voronoi() {
delete workers_;
- DestroyContext();
+ PSContext2DFree(ps_context_);
+}
+
+inline uint32_t* Voronoi::wGetAddr(int x, int y) {
+ return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t);
}
// This is the core of the Voronoi calculation. At a given point on the
@@ -249,8 +214,8 @@ int Voronoi::wCell(float x, float y) {
void Voronoi::wMakeRect(int r, int* x, int* y, int* w, int* h) {
const int parts = 16;
assert(parts * parts == num_regions_);
- *w = width_ / parts;
- *h = height_ / parts;
+ *w = ps_context_->width / parts;
+ *h = ps_context_->height / parts;
*x = *w * (r % parts);
*y = *h * ((r / parts) % parts);
}
@@ -293,11 +258,11 @@ inline void Voronoi::wFillSpan(uint32_t* pixels, uint32_t color, int width) {
// the width w parameter is evenly divisible by 4.
// If multithreading, this function is only called by the worker threads.
void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) {
- const uint32_t pitch = width_;
- uint32_t* pixels = pixel_buffer_ + y * pitch + x;
+ const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
+ uint32_t* pixels = wGetAddr(x, y);
for (int j = 0; j < h; j++) {
wFillSpan(pixels, color, w);
- pixels += pitch;
+ pixels += stride_in_pixels;
}
}
@@ -309,7 +274,8 @@ void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) {
// voronoi membership per pixel.
void Voronoi::wRenderTile(int x, int y, int w, int h) {
// rip through a tile
- uint32_t* pixels = pixel_buffer_ + y * stride_in_pixels_ + x;
+ const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
+ uint32_t* pixels = wGetAddr(x, y);
for (int j = 0; j < h; j++) {
// get start and end cell values
int ms = wCell(x + 0, y + j);
@@ -327,7 +293,7 @@ void Voronoi::wRenderTile(int x, int y, int w, int h) {
}
*p++ = colors_[me];
}
- pixels += stride_in_pixels_;
+ pixels += stride_in_pixels;
}
}
@@ -402,8 +368,8 @@ void Voronoi::UpdateSim() {
for (int j = 0; j < kMaxPointCount; j++) {
positions_[j].x += (velocities_[j].x) * z;
positions_[j].y += (velocities_[j].y) * z;
- screen_positions_[j].x = positions_[j].x * width_;
- screen_positions_[j].y = positions_[j].y * height_;
+ screen_positions_[j].x = positions_[j].x * ps_context_->width;
+ screen_positions_[j].y = positions_[j].y * ps_context_->height;
}
}
@@ -411,18 +377,19 @@ void Voronoi::UpdateSim() {
void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) {
const int ix = static_cast<int>(x);
const int iy = static_cast<int>(y);
+ const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t);
// clip it against window
if (ix < 1) return;
- if (ix >= (width_ - 1)) return;
+ if (ix >= (ps_context_->width - 1)) return;
if (iy < 1) return;
- if (iy >= (height_ - 1)) return;
- uint32_t* pixel = pixel_buffer_ + iy * stride_in_pixels_ + ix;
+ if (iy >= (ps_context_->height - 1)) return;
+ uint32_t* pixel = wGetAddr(ix, iy);
// render dot as a small diamond
*pixel = color1;
*(pixel - 1) = color2;
*(pixel + 1) = color2;
- *(pixel - stride_in_pixels_) = color2;
- *(pixel + stride_in_pixels_) = color2;
+ *(pixel - stride_in_pixels) = color2;
+ *(pixel + stride_in_pixels) = color2;
}
// Superimposes dots on the positions.
@@ -436,27 +403,12 @@ void Voronoi::SuperimposePositions() {
}
// Renders the Voronoi diagram, dispatching the work to multiple threads.
-// Note: This Dispatch() is from the main PPAPI thread, so care must be taken
-// not to attempt PPAPI calls from the worker threads, since Dispatch() will
-// block here until all work is complete. The worker threads are compute only
-// and do not make any PPAPI calls.
void Voronoi::Render() {
workers_->Dispatch(num_regions_, wRenderRegionEntry, this);
if (draw_points_)
SuperimposePositions();
}
-void Voronoi::DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
- if (position.size().width() == width_ &&
- position.size().height() == height_)
- return; // Size didn't change, no need to update anything.
-
- // Create a new device context with the new size.
- DestroyContext();
- CreateContext(position.size());
- Update();
-}
-
void Voronoi::StartBenchmark() {
Reset();
printf("Benchmark started...\n");
@@ -475,41 +427,46 @@ void Voronoi::EndBenchmark() {
PostUpdateMessage("benchmark_result", result);
}
-// Handle input events from the user.
-bool Voronoi::HandleInputEvent(const pp::InputEvent& event) {
- switch (event.GetType()) {
- case PP_INPUTEVENT_TYPE_KEYDOWN: {
- pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event);
- uint32_t key_code = key.GetKeyCode();
- if (key_code == 84) // 't' key
- if (!benchmarking_)
- StartBenchmark();
- break;
+// Handle input events from the user and messages from JS.
+void Voronoi::HandleEvent(PSEvent* ps_event) {
+ // Give the 2D context a chance to process the event.
+ if (0 != PSContext2DHandleEvent(ps_context_, ps_event))
+ return;
+ if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) {
+ // Convert Pepper Simple event to a PPAPI C++ event
+ pp::InputEvent event(ps_event->as_resource);
+ switch (event.GetType()) {
+ case PP_INPUTEVENT_TYPE_KEYDOWN: {
+ pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event);
+ uint32_t key_code = key.GetKeyCode();
+ if (key_code == 84) // 't' key
+ if (!benchmarking_)
+ StartBenchmark();
+ break;
+ }
+ default:
+ break;
}
- default:
- return false;
- }
- return true;
-}
-
-// Handle messages sent from Javascript.
-void Voronoi::HandleMessage(const pp::Var& var) {
- if (var.is_dictionary()) {
- pp::VarDictionary dictionary(var);
- std::string message = dictionary.Get("message").AsString();
- if (message == "run_benchmark" && !benchmarking_)
- StartBenchmark();
- else if (message == "draw_points")
- draw_points_ = dictionary.Get("value").AsBool();
- else if (message == "draw_interiors")
- draw_interiors_ = dictionary.Get("value").AsBool();
- else if (message == "set_points") {
- int num_points = dictionary.Get("value").AsInt();
- point_count_ = std::min(kMaxPointCount, std::max(0, num_points));
- } else if (message == "set_threads") {
- int thread_count = dictionary.Get("value").AsInt();
- delete workers_;
- workers_ = new ThreadPool(thread_count);
+ } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) {
+ // Convert Pepper Simple message to PPAPI C++ var
+ pp::Var var(ps_event->as_var);
+ if (var.is_dictionary()) {
+ pp::VarDictionary dictionary(var);
+ std::string message = dictionary.Get("message").AsString();
+ if (message == "run_benchmark" && !benchmarking_)
+ StartBenchmark();
+ else if (message == "draw_points")
+ draw_points_ = dictionary.Get("value").AsBool();
+ else if (message == "draw_interiors")
+ draw_interiors_ = dictionary.Get("value").AsBool();
+ else if (message == "set_points") {
+ int num_points = dictionary.Get("value").AsInt();
+ point_count_ = std::min(kMaxPointCount, std::max(0, num_points));
+ } else if (message == "set_threads") {
+ int thread_count = dictionary.Get("value").AsInt();
+ delete workers_;
+ workers_ = new ThreadPool(thread_count);
+ }
}
}
}
@@ -519,22 +476,19 @@ void Voronoi::PostUpdateMessage(const char* message_name, double value) {
pp::VarDictionary message;
message.Set("message", message_name);
message.Set("value", value);
- PostMessage(message);
-}
-
-void Voronoi::FlushCallback(void* thiz, int32_t result) {
- static_cast<Voronoi*>(thiz)->Update();
-}
-
-// Update the 2d region and flush to make it visible on the page.
-void Voronoi::FlushPixelBuffer() {
- graphics_2d_context_->PaintImageData(*image_data_, pp::Point(0, 0));
- graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
+ PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
}
void Voronoi::Update() {
- // Don't call FlushPixelBuffer() when benchmarking - vsync is enabled by
- // default, and will throttle the benchmark results.
+ PSContext2DGetBuffer(ps_context_);
+ if (NULL == ps_context_->data)
+ return;
+ assert(is_pow2(ps_context_->width));
+ assert(is_pow2(ps_context_->height));
+
+ // When benchmarking is running, don't update display via
+ // PSContext2DSwapBuffer() - vsync is enabled by default, and will throttle
+ // the benchmark results.
do {
UpdateSim();
Render();
@@ -543,50 +497,28 @@ void Voronoi::Update() {
} while (benchmark_frame_counter_ > 0);
if (benchmarking_)
EndBenchmark();
- FlushPixelBuffer();
-}
-
-void Voronoi::CreateContext(const pp::Size& size) {
- graphics_2d_context_ = new pp::Graphics2D(this, size, false);
- if (!BindGraphics(*graphics_2d_context_))
- printf("Couldn't bind the device context\n");
- image_data_ = new pp::ImageData(this,
- PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- size,
- false);
- width_ = image_data_->size().width();
- height_ = image_data_->size().height();
- // This demo requires power of two width & height buffers.
- assert(is_pow2(width_) && is_pow2(height_));
- stride_in_pixels_ = static_cast<uint32_t>(image_data_->stride() / 4);
- pixel_buffer_ = static_cast<uint32_t*>(image_data_->data());
-}
-void Voronoi::DestroyContext() {
- delete graphics_2d_context_;
- delete image_data_;
- graphics_2d_context_ = NULL;
- image_data_ = NULL;
- width_ = 0;
- height_ = 0;
- stride_in_pixels_ = 0;
- pixel_buffer_ = NULL;
+ PSContext2DSwapBuffer(ps_context_);
}
-class VoronoiModule : public pp::Module {
- public:
- VoronoiModule() : pp::Module() {}
- virtual ~VoronoiModule() {}
-
- // Create and return a Voronoi instance.
- virtual pp::Instance* CreateInstance(PP_Instance instance) {
- return new Voronoi(instance);
+// Starting point for the module. We do not use main since it would
+// collide with main in libppapi_cpp.
+int example_main(int argc, char* argv[]) {
+ Voronoi voronoi;
+ while (true) {
+ PSEvent* ps_event;
+ // Consume all available events.
+ while ((ps_event = PSEventTryAcquire()) != NULL) {
+ voronoi.HandleEvent(ps_event);
+ PSEventRelease(ps_event);
+ }
+ // Do simulation, render and present.
+ voronoi.Update();
}
-};
-namespace pp {
-Module* CreateModule() {
- return new VoronoiModule();
+ return 0;
}
-} // namespace pp
+// Register the function to call once the Instance Object is initialized.
+// see: pappi_simple/ps_main.h
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
diff --git a/native_client_sdk/src/libraries/nacl_io/event_emitter.h b/native_client_sdk/src/libraries/nacl_io/event_emitter.h
index 4cca72fe26..96670b6c36 100644
--- a/native_client_sdk/src/libraries/nacl_io/event_emitter.h
+++ b/native_client_sdk/src/libraries/nacl_io/event_emitter.h
@@ -29,10 +29,10 @@ struct EventInfo : public sdk_util::RefObject {
// User provied data to be returned on EventListener::Wait
uint64_t user_data;
- // Bitfield of enum KernelEventType currently signaled.
+ // Bitfield of POLL events currently signaled.
uint32_t events;
- // Bitfield of enum KernelEventType that can signal.
+ // Bitfield of POLL events of interest.
uint32_t filter;
// We do not use a ScopedRef to prevent circular references.
@@ -71,7 +71,7 @@ class EventEmitter : public sdk_util::RefObject {
void UnregisterEventInfo(const ScopedEventInfo& info);
public:
- // Returns the current state of the emitter as KernelEventType bitfield.
+ // Returns the current state of the emitter as POLL events bitfield.
virtual uint32_t GetEventStatus() = 0;
// Returns the type of the emitter (compatible with st_mode in stat)
diff --git a/native_client_sdk/src/libraries/nacl_io/event_listener.cc b/native_client_sdk/src/libraries/nacl_io/event_listener.cc
index 5eaa0603fc..d8b293da47 100644
--- a/native_client_sdk/src/libraries/nacl_io/event_listener.cc
+++ b/native_client_sdk/src/libraries/nacl_io/event_listener.cc
@@ -4,6 +4,7 @@
*/
#include <errno.h>
+#include <poll.h>
#include <pthread.h>
#include <stdio.h>
@@ -44,7 +45,7 @@ void EventListener::Destroy() {
uint32_t EventListener::GetEventStatus() {
// Always writable, but we can only assume it to be readable if there
// is an event waiting.
- return signaled_.empty() ? KE_WRITE_READY : KE_WRITE_READY | KE_READ_READY;
+ return signaled_.empty() ? POLLOUT : POLLIN | POLLOUT;
}
int EventListener::GetType() {
@@ -235,8 +236,8 @@ void EventListener::AbandonedEventInfo(const ScopedEventInfo& event) {
}
// EventInfos abandoned by the destroyed emitter must still be kept in
- // signaled_ set for KE_SHUTDOWN.
- event->events = KE_SHUTDOWN;
+ // signaled_ set for POLLHUP.
+ event->events = POLLHUP;
Signal(event);
}
diff --git a/native_client_sdk/src/libraries/nacl_io/event_listener.h b/native_client_sdk/src/libraries/nacl_io/event_listener.h
index bf2e30761c..cb93f116b2 100644
--- a/native_client_sdk/src/libraries/nacl_io/event_listener.h
+++ b/native_client_sdk/src/libraries/nacl_io/event_listener.h
@@ -64,14 +64,8 @@
namespace nacl_io {
-enum KernelEventType {
- KE_READ_READY = 1,
- KE_WRITE_READY = 2,
- KE_SHUTDOWN = 4
-};
-
struct EventData {
- // Bit Mask of signaled KernelEvents
+ // Bit Mask of signaled POLL events.
uint32_t events;
uint64_t user_data;
};
@@ -105,7 +99,7 @@ class EventListener : public EventEmitter {
// The number of events recored is returned in |count|.
Error Wait(EventData* events, int max, int ms_timeout, int* out_count);
- // Tracks a new set of KernelEventTypes for a given unique |id|. The
+ // Tracks a new set of POLL events for a given unique |id|. The
// |user_data| will be returned in the Wait when an event of type |filter|
// is received with that |id|.
Error Track(int id,
diff --git a/native_client_sdk/src/libraries/nacl_io/include/sys/utsname.h b/native_client_sdk/src/libraries/nacl_io/include/sys/utsname.h
new file mode 100644
index 0000000000..2e3cd3daa2
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/include/sys/utsname.h
@@ -0,0 +1,20 @@
+/* Copyright 2013 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 LIBRARIES_NACL_SYS_UTSNAME_H_
+#define LIBRARIES_NACL_SYS_UTSNAME_H_
+
+#define _UTSNAME_LENGTH 65
+
+struct utsname {
+ char sysname[_UTSNAME_LENGTH];
+ char nodename[_UTSNAME_LENGTH];
+ char release[_UTSNAME_LENGTH];
+ char version[_UTSNAME_LENGTH];
+ char machine[_UTSNAME_LENGTH];
+};
+
+int uname(struct utsname *buf);
+
+#endif
diff --git a/native_client_sdk/src/libraries/nacl_io/inet_ntoa.cc b/native_client_sdk/src/libraries/nacl_io/inet_ntoa.cc
new file mode 100644
index 0000000000..fdeae089b7
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/inet_ntoa.cc
@@ -0,0 +1,65 @@
+// Copyright 2013 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 "nacl_io/ossocket.h"
+
+#ifdef PROVIDES_SOCKET_API
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+static inline uint8_t get_byte(const void* addr, int byte) {
+ const char* buf = static_cast<const char*>(addr);
+ return static_cast<uint8_t>(buf[byte]);
+}
+
+char* inet_ntoa(struct in_addr in) {
+ static char addr[INET_ADDRSTRLEN];
+ snprintf(addr, INET_ADDRSTRLEN, "%u.%u.%u.%u",
+ get_byte(&in, 0), get_byte(&in, 1),
+ get_byte(&in, 2), get_byte(&in, 3));
+ return addr;
+}
+
+const char* inet_ntop(int af, const void* src, char* dst, socklen_t size) {
+ if (AF_INET == af) {
+ if (size < INET_ADDRSTRLEN) {
+ errno = ENOSPC;
+ return NULL;
+ }
+ struct in_addr in;
+ memcpy(&in, src, sizeof(in));
+ char* result = inet_ntoa(in);
+ memcpy(dst, result, strlen(result) + 1);
+ return dst;
+ }
+
+ if (AF_INET6 == af) {
+ if (size < INET6_ADDRSTRLEN) {
+ errno = ENOSPC;
+ return NULL;
+ }
+ const uint8_t* tuples = static_cast<const uint8_t*>(src);
+ std::stringstream output;
+ for (int i = 0; i < 8; i++) {
+ uint16_t tuple = (tuples[2*i] << 8) + tuples[2*i+1];
+ output << std::hex << tuple;
+ if (i < 7) {
+ output << ":";
+ }
+ }
+ memcpy(dst, output.str().c_str(), output.str().size() + 1);
+ return dst;
+ }
+
+ errno = EAFNOSUPPORT;
+ return NULL;
+}
+
+#endif // PROVIDES_SOCKET_API
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
index 4aaa019db8..a479f9ca94 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
@@ -233,6 +233,15 @@ int ki_utime(const char* filename, const struct utimbuf* times) {
return s_kp->utime(filename, times);
}
+int ki_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
+ return s_kp->poll(fds, nfds, timeout);
+}
+
+int ki_select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, struct timeval* timeout) {
+ return s_kp->select(nfds, readfds, writefds, exceptfds, timeout);
+}
+
#ifdef PROVIDES_SOCKET_API
// Socket Functions
int ki_accept(int fd, struct sockaddr* addr, socklen_t* len) {
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
index 2f998b6355..90fecf962f 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
@@ -66,6 +66,10 @@ int ki_fchown(int fd, uid_t owner, gid_t group);
int ki_lchown(const char* path, uid_t owner, gid_t group);
int ki_utime(const char* filename, const struct utimbuf* times);
+int ki_poll(struct pollfd *fds, nfds_t nfds, int timeout);
+int ki_select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, struct timeval* timeout);
+
#ifdef PROVIDES_SOCKET_API
// Socket Functions
int ki_accept(int fd, struct sockaddr* addr, socklen_t* len);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
index d5f44b595c..1e6ae64734 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -4,12 +4,17 @@
#include "nacl_io/kernel_proxy.h"
+
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
+#include <sys/time.h>
+
#include <iterator>
#include <string>
@@ -644,6 +649,182 @@ int KernelProxy::munmap(void* addr, size_t length) {
#ifdef PROVIDES_SOCKET_API
+int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, struct timeval* timeout) {
+ ScopedEventListener listener(new EventListener);
+ std::vector<struct pollfd> fds;
+
+ fd_set readout, writeout, exceptout;
+
+ FD_ZERO(&readout);
+ FD_ZERO(&writeout);
+ FD_ZERO(&exceptout);
+
+ int fd;
+ size_t event_cnt = 0;
+ int event_track = 0;
+ for (fd = 0; fd < nfds; fd++) {
+ int events = 0;
+
+ if (readfds != NULL && FD_ISSET(fd, readfds))
+ events |= POLLIN;
+
+ if (writefds != NULL && FD_ISSET(fd, writefds))
+ events |= POLLOUT;
+
+ if (exceptfds != NULL && FD_ISSET(fd, exceptfds))
+ events |= POLLERR | POLLHUP;
+
+ // If we are not interested in this FD, skip it
+ if (0 == events) continue;
+
+ ScopedKernelHandle handle;
+ Error err = AcquireHandle(fd, &handle);
+
+ // Select will return immediately if there are bad FDs.
+ if (err != 0) {
+ errno = EBADF;
+ return -1;
+ }
+
+ int status = handle->node()->GetEventStatus() & events;
+ if (status & POLLIN) {
+ FD_SET(fd, &readout);
+ event_cnt++;
+ }
+
+ if (status & POLLOUT) {
+ FD_SET(fd, &writeout);
+ event_cnt++;
+ }
+
+ if (status & (POLLERR | POLLHUP)) {
+ FD_SET(fd, &exceptout);
+ event_cnt++;
+ }
+
+ // Otherwise track it.
+ if (0 == status) {
+ err = listener->Track(fd, handle->node(), events, fd);
+ if (err != 0) {
+ errno = EBADF;
+ return -1;
+ }
+ event_track++;
+ }
+ }
+
+ // If nothing is signaled, then we must wait.
+ if (event_cnt == 0) {
+ std::vector<EventData> events;
+ int ready_cnt;
+ int ms_timeout;
+
+ // NULL timeout signals wait forever.
+ if (timeout == NULL) {
+ ms_timeout = -1;
+ } else {
+ int64_t ms = timeout->tv_sec * 1000 + ((timeout->tv_usec + 500) / 1000);
+
+ // If the timeout is invalid or too long (larger than signed 32 bit).
+ if ((timeout->tv_sec < 0) || (timeout->tv_sec >= (INT_MAX / 1000)) ||
+ (timeout->tv_usec < 0) || (timeout->tv_usec >= 1000) ||
+ (ms < 0) || (ms >= INT_MAX)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ms_timeout = static_cast<int>(ms);
+ }
+
+ events.resize(event_track);
+ listener->Wait(events.data(), event_track, ms_timeout, &ready_cnt);
+ for (fd = 0; static_cast<int>(fd) < ready_cnt; fd++) {
+ if (events[fd].events & POLLIN) {
+ FD_SET(events[fd].user_data, &readout);
+ event_cnt++;
+ }
+
+ if (events[fd].events & POLLOUT) {
+ FD_SET(events[fd].user_data, &writeout);
+ event_cnt++;
+ }
+
+ if (events[fd].events & (POLLERR | POLLHUP)) {
+ FD_SET(events[fd].user_data, &exceptout);
+ event_cnt++;
+ }
+ }
+ }
+
+ // Copy out the results
+ if (readfds != NULL)
+ *readfds = readout;
+
+ if (writefds != NULL)
+ *writefds = writeout;
+
+ if (exceptfds != NULL)
+ *exceptfds = exceptout;
+
+ return event_cnt;
+}
+
+int KernelProxy::poll(struct pollfd *fds, nfds_t nfds, int timeout) {
+ ScopedEventListener listener(new EventListener);
+
+ int index;
+ size_t event_cnt = 0;
+ size_t event_track = 0;
+ for (index = 0; static_cast<nfds_t>(index) < nfds; index++) {
+ ScopedKernelHandle handle;
+ struct pollfd* info = &fds[index];
+ Error err = AcquireHandle(info->fd, &handle);
+
+ // If the node isn't open, or somehow invalid, mark it so.
+ if (err != 0) {
+ info->revents = POLLNVAL;
+ event_cnt++;
+ continue;
+ }
+
+ // If it's already signaled, then just capture the event
+ if (handle->node()->GetEventStatus() & info->events) {
+ info->revents = info->events & handle->node()->GetEventStatus();
+ event_cnt++;
+ continue;
+ }
+
+ // Otherwise try to track it.
+ err = listener->Track(info->fd, handle->node(), info->events, index);
+ if (err != 0) {
+ info->revents = POLLNVAL;
+ event_cnt++;
+ continue;
+ }
+ event_track++;
+ }
+
+ // If nothing is signaled, then we must wait.
+ if (0 == event_cnt) {
+ std::vector<EventData> events;
+ int ready_cnt;
+
+ events.resize(event_track);
+ listener->Wait(events.data(), event_track, timeout, &ready_cnt);
+ for (index = 0; index < ready_cnt; index++) {
+ struct pollfd* info = &fds[events[index].user_data];
+
+ info->revents = events[index].events;
+ event_cnt++;
+ }
+ }
+
+ return event_cnt;
+}
+
+
+
// Socket Functions
int KernelProxy::accept(int fd, struct sockaddr* addr, socklen_t* len) {
if (NULL == addr || NULL == len) {
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
index cd118ade72..e0dff69244 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
@@ -14,6 +14,8 @@
#include "nacl_io/ostypes.h"
#include "nacl_io/osutime.h"
+struct timeval;
+
namespace nacl_io {
class PepperInterface;
@@ -118,6 +120,11 @@ class KernelProxy : protected KernelObject {
virtual int munmap(void* addr, size_t length);
#ifdef PROVIDES_SOCKET_API
+ virtual int select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, struct timeval* timeout);
+
+ virtual int poll(struct pollfd *fds, nfds_t nfds, int timeout);
+
// Socket support functions
virtual int accept(int fd, struct sockaddr* addr, socklen_t* len);
virtual int bind(int fd, const struct sockaddr* addr, socklen_t len);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
index 9bbcd1db95..b4e80e9093 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
@@ -126,10 +126,12 @@ EXTERN_C_BEGIN
OP(getdents); \
OP(mkdir); \
OP(open); \
+ OP(poll);\
OP(read); \
OP(rmdir); \
OP(seek); \
OP(stat); \
+ OP(select); \
OP(write); \
OP(mmap); \
OP(munmap); \
@@ -228,6 +230,12 @@ int WRAP(open_resource)(const char* file, int* fd) {
return (*fd < 0) ? errno : 0;
}
+int WRAP(poll)(struct pollfd *fds, nfds_t nfds, int timeout, int* count) {
+ *count = ki_poll(fds, nfds, timeout);
+ return (*count < 0) ? errno : 0;
+
+}
+
int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) {
if (!ki_is_initialized())
return REAL(read)(fd, buf, count, nread);
@@ -246,6 +254,12 @@ int WRAP(seek)(int fd, off_t offset, int whence, off_t* new_offset) {
return (*new_offset < 0) ? errno : 0;
}
+int WRAP(select)(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, struct timeval* timeout, int* count) {
+ *count = ki_select(nfds, readfds, writefds, exceptfds, timeout);
+ return (*count < 0) ? errno : 0;
+}
+
int WRAP(stat)(const char *pathname, struct nacl_abi_stat *nacl_buf) {
struct stat buf;
memset(&buf, 0, sizeof(struct stat));
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
index 1b6f42cef0..c2f91a1a5d 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
@@ -118,11 +118,11 @@ int WRAP(seek)(int fd, off_t offset, int whence, off_t* new_offset) {
return (*new_offset < 0) ? errno : 0;
}
-int WRAP(stat)(const char *pathname, struct stat *buf) {
+int WRAP(stat)(const char* pathname, struct stat* buf) {
return (ki_stat(pathname, buf) < 0) ? errno : 0;
}
-int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) {
+int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) {
if (!ki_is_initialized())
return REAL(write)(fd, buf, count, nwrote);
@@ -131,6 +131,76 @@ int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) {
return (signed_nwrote < 0) ? errno : 0;
}
+// Socket functions
+int accept(int fd, struct sockaddr* addr, socklen_t* len) {
+ return ki_accept(fd, addr, len);
+}
+
+int bind(int fd, const struct sockaddr* addr, socklen_t len) {
+ return ki_bind(fd, addr, len);
+}
+
+int connect(int fd, const struct sockaddr* addr, socklen_t len) {
+ return ki_connect(fd, addr, len);
+}
+
+int getpeername(int fd, struct sockaddr* addr, socklen_t* len) {
+ return ki_getpeername(fd, addr, len);
+}
+
+int getsockname(int fd, struct sockaddr* addr, socklen_t* len) {
+ return ki_getsockname(fd, addr, len);
+}
+int getsockopt(int fd, int lvl, int optname, void* optval, socklen_t* len) {
+ return ki_getsockopt(fd, lvl, optname, optval, len);
+}
+
+int listen(int fd, int backlog) {
+ return ki_listen(fd, backlog);
+}
+
+ssize_t recv(int fd, void* buf, size_t len, int flags) {
+ return ki_recv(fd, buf, len, flags);
+}
+
+ssize_t recvfrom(int fd, void* buf, size_t len, int flags,
+ struct sockaddr* addr, socklen_t* addrlen) {
+ return ki_recvfrom(fd, buf, len, flags, addr, addrlen);
+}
+
+ssize_t recvmsg(int fd, struct msghdr* msg, int flags) {
+ return ki_recvmsg(fd, msg, flags);
+}
+
+ssize_t send(int fd, const void* buf, size_t len, int flags) {
+ return ki_send(fd, buf, len, flags);
+}
+
+ssize_t sendto(int fd, const void* buf, size_t len, int flags,
+ const struct sockaddr* addr, socklen_t addrlen) {
+ return ki_sendto(fd, buf, len, flags, addr, addrlen);
+}
+
+ssize_t sendmsg(int fd, const struct msghdr* msg, int flags) {
+ return ki_sendmsg(fd, msg, flags);
+}
+
+int setsockopt(int fd, int lvl, int optname, const void* optval,
+ socklen_t len) {
+ return ki_setsockopt(fd, lvl, optname, optval, len);
+}
+
+int shutdown(int fd, int how) {
+ return ki_shutdown(fd, how);
+}
+
+int socket(int domain, int type, int protocol) {
+ return ki_socket(domain, type, protocol);
+}
+
+int socketpair(int domain, int type, int protocol, int* sv) {
+ return ki_socketpair(domain, type, protocol, sv);
+}
// "real" functions, i.e. the unwrapped original functions.
@@ -138,11 +208,11 @@ int _real_close(int fd) {
return REAL(close)(fd);
}
-int _real_fstat(int fd, struct stat *buf) {
+int _real_fstat(int fd, struct stat* buf) {
return REAL(fstat)(fd, buf);
}
-int _real_getdents(int fd, dirent* nacl_buf, size_t nacl_count, size_t *nread) {
+int _real_getdents(int fd, dirent* nacl_buf, size_t nacl_count, size_t* nread) {
return REAL(getdents)(fd, nacl_buf, nacl_count, nread);
}
@@ -171,7 +241,7 @@ int _real_open_resource(const char* file, int* fd) {
return ENOSYS;
}
-int _real_read(int fd, void *buf, size_t count, size_t *nread) {
+int _real_read(int fd, void* buf, size_t count, size_t* nread) {
return REAL(read)(fd, buf, count, nread);
}
@@ -179,7 +249,7 @@ int _real_rmdir(const char* pathname) {
return ENOSYS;
}
-int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
+int _real_write(int fd, const void* buf, size_t count, size_t* nwrote) {
return REAL(write)(fd, buf, count, nwrote);
}
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index dd27fcb58e..8b4ed00cdd 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -1,9 +1,10 @@
{
- 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'],
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
'SEARCH': [
'.',
'pepper',
'../third_party/newlib-extras',
+ 'include',
],
'TARGETS': [
{
@@ -12,6 +13,7 @@
'SOURCES' : [
"event_emitter.cc",
"event_listener.cc",
+ "inet_ntoa.cc",
"kernel_handle.cc",
"kernel_intercept.cc",
"kernel_object.cc",
@@ -50,10 +52,13 @@
"syscalls/lchown.c",
"syscalls/mkdir.c",
"syscalls/mount.c",
+ "syscalls/poll.c",
"syscalls/remove.c",
"syscalls/rmdir.c",
+ "syscalls/select.c",
"syscalls/unlink.c",
"syscalls/umount.c",
+ "syscalls/uname.c",
"syscalls/utime.c",
],
}
@@ -107,7 +112,10 @@
"netdb.h",
"netinet/in.h",
"netinet6/in6.h",
+ "poll.h",
+ "sys/select.h",
"sys/socket.h",
+ "sys/utsname.h",
],
'DEST': 'include/newlib',
},
@@ -117,12 +125,21 @@
"netdb.h",
"netinet/in.h",
"netinet6/in6.h",
+ "poll.h",
+ "sys/select.h",
"sys/socket.h",
+ "sys/utsname.h",
],
'DEST': 'include/pnacl',
},
{
'FILES': [
+ "poll.h",
+ ],
+ 'DEST': 'include/win',
+ },
+ {
+ 'FILES': [
"all_interfaces.h",
"define_empty_macros.h",
"undef_macros.h",
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.cc b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
index e8178cc1c0..3e423da3f9 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <poll.h>
#include <string.h>
#include <sys/stat.h>
@@ -49,9 +50,10 @@ void MountNode::Destroy() {
}
// Declared in EventEmitter, default to regular files which always return
-// a ready of TRUE.
+// a ready of TRUE for read, write, or error.
uint32_t MountNode::GetEventStatus() {
- return KE_READ_READY | KE_WRITE_READY | KE_SHUTDOWN;
+ uint32_t val = POLLIN | POLLOUT | POLLERR;
+ return val;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/ossocket.h b/native_client_sdk/src/libraries/nacl_io/ossocket.h
index e95b32747e..784086af8c 100644
--- a/native_client_sdk/src/libraries/nacl_io/ossocket.h
+++ b/native_client_sdk/src/libraries/nacl_io/ossocket.h
@@ -5,11 +5,13 @@
#ifndef LIBRARIES_NACL_IO_OSSOCKET_H_
#define LIBRARIES_NACL_IO_OSSOCKET_H_
-#if defined(__native_client__) && defined(__GLIBC__)
+#if defined(__native_client__)
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
+#include <poll.h>
#include <sys/socket.h>
+#include <sys/select.h>
#define PROVIDES_SOCKET_API
#endif
diff --git a/native_client_sdk/src/libraries/nacl_io/poll.h b/native_client_sdk/src/libraries/nacl_io/poll.h
new file mode 100644
index 0000000000..6c1d378e8f
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/poll.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2013 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 LIBRARIES_NACL_IO_POLL_H_
+#define LIBRARIES_NACL_IO_POLL_H_
+
+#include <stdint.h>
+
+#include "sdk_util/macros.h"
+
+EXTERN_C_BEGIN
+
+/* This header adds definitions of flags and structures for use with poll on
+ * toolchains with 'C' libraries which do not normally supply poll. */
+
+/* Node state flags */
+#define POLLIN 0x0001 /* Will not block READ select/poll. */
+#define POLLOUT 0x0002 /* Will not block WRITE select/poll. */
+#define POLLERR 0x0008 /* Will not block EXECPT select/poll. */
+#define POLLHUP 0x0010 /* Connection closed on far side. */
+#define POLLNVAL 0x0020 /* Invalid FD. */
+
+/* Number of file descriptors. */
+typedef int nfds_t;
+
+struct pollfd {
+ int fd;
+ uint16_t events;
+ uint16_t revents;
+};
+
+int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
+
+EXTERN_C_END
+
+#endif /* LIBRARIES_NACL_IO_POLL_H_ */
+
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/poll.c b/native_client_sdk/src/libraries/nacl_io/syscalls/poll.c
new file mode 100644
index 0000000000..b5ddff7892
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/poll.c
@@ -0,0 +1,10 @@
+/* Copyright (c) 2013 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 "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int poll(struct pollfd *fds, nfds_t nfds, int timeout) {
+ return ki_poll(fds, nfds, timeout);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/select.c b/native_client_sdk/src/libraries/nacl_io/syscalls/select.c
new file mode 100644
index 0000000000..a486ecd3b4
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/select.c
@@ -0,0 +1,11 @@
+/* Copyright (c) 2013 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 "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, struct timeval* timeout) {
+ return ki_select(nfds, readfds, writefds, exceptfds, timeout);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/uname.c b/native_client_sdk/src/libraries/nacl_io/syscalls/uname.c
new file mode 100644
index 0000000000..293b989ee4
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/uname.c
@@ -0,0 +1,14 @@
+/* Copyright (c) 2013 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 <stdio.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+int uname(struct utsname* buf) {
+ memset(buf, 0, sizeof(struct utsname));
+ snprintf(buf->sysname, _UTSNAME_LENGTH, "NaCl");
+ /* TODO(sbc): Fill out the other fields with useful information. */
+ return 0;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/event_test.cc b/native_client_sdk/src/libraries/nacl_io_test/event_test.cc
index aca9d9efbf..c342799afa 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/event_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/event_test.cc
@@ -5,6 +5,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -12,20 +13,27 @@
#include "nacl_io/event_emitter.h"
#include "nacl_io/event_listener.h"
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/kernel_wrap.h"
using namespace nacl_io;
using namespace sdk_util;
-class EventEmitterTester : public EventEmitter {
+class EventEmitterTester : public MountNode {
public:
- EventEmitterTester() : event_status_(0), event_cnt_(0) {}
+ EventEmitterTester() : MountNode(NULL), event_status_(0), event_cnt_(0) {}
void SetEventStatus(uint32_t bits) { event_status_ = bits; }
uint32_t GetEventStatus() { return event_status_; }
- int GetType() { return S_IFSOCK; }
+ Error Ioctl(int request, char* arg) {
+ event_status_ = static_cast<uint32_t>(request);
+ return 0;
+ }
+ int GetType() { return S_IFSOCK; }
int NumEvents() { return event_cnt_; }
public:
@@ -364,3 +372,109 @@ TEST(EventTest, EmitterSignalling) {
EXPECT_EQ(USER_DATA_A, ev[0].user_data);
EXPECT_EQ(KE_EXPECTED, ev[0].events);
}
+
+
+namespace {
+
+class KernelProxyPolling : public KernelProxy {
+ public:
+ virtual int socket(int domain, int type, int protocol) {
+ ScopedMount mnt;
+ ScopedMountNode node(new EventEmitterTester());
+ ScopedKernelHandle handle(new KernelHandle(mnt, node));
+
+ Error error = handle->Init(0);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ return AllocateFD(handle);
+ }
+};
+
+class KernelProxyPollingTest : public ::testing::Test {
+ public:
+ KernelProxyPollingTest() : kp_(new KernelProxyPolling) {
+ ki_init(kp_);
+ }
+
+ ~KernelProxyPollingTest() {
+ ki_uninit();
+ delete kp_;
+ }
+
+ KernelProxyPolling* kp_;
+};
+
+} // namespace
+
+
+#define SOCKET_CNT 4
+void SetFDs(fd_set* set, int* fds) {
+ FD_ZERO(set);
+
+ FD_SET(0, set);
+ FD_SET(1, set);
+ FD_SET(2, set);
+
+ for (int index = 0; index < SOCKET_CNT; index++)
+ FD_SET(fds[index], set);
+}
+
+TEST_F(KernelProxyPollingTest, Select) {
+ int fds[SOCKET_CNT];
+
+ fd_set rd_set;
+ fd_set wr_set;
+
+ FD_ZERO(&rd_set);
+ FD_ZERO(&wr_set);
+
+ FD_SET(0, &rd_set);
+ FD_SET(1, &rd_set);
+ FD_SET(2, &rd_set);
+
+ FD_SET(0, &wr_set);
+ FD_SET(1, &wr_set);
+ FD_SET(2, &wr_set);
+
+ // Expect normal files to select as read, write, and error
+ int cnt = select(4, &rd_set, &rd_set, &rd_set, NULL);
+ EXPECT_EQ(3 * 3, cnt);
+ EXPECT_NE(0, FD_ISSET(0, &rd_set));
+ EXPECT_NE(0, FD_ISSET(1, &rd_set));
+ EXPECT_NE(0, FD_ISSET(2, &rd_set));
+
+ for (int index = 0 ; index < SOCKET_CNT; index++) {
+ fds[index] = socket(0, 0, 0);
+ EXPECT_NE(-1, fds[index]);
+ }
+
+ // Highest numbered fd
+ const int fdnum = fds[SOCKET_CNT - 1] + 1;
+
+ // Expect only the normal files to select
+ SetFDs(&rd_set, fds);
+ cnt = select(fds[SOCKET_CNT-1] + 1, &rd_set, NULL, NULL, NULL);
+ EXPECT_EQ(3, cnt);
+ EXPECT_NE(0, FD_ISSET(0, &rd_set));
+ EXPECT_NE(0, FD_ISSET(1, &rd_set));
+ EXPECT_NE(0, FD_ISSET(2, &rd_set));
+ for (int index = 0 ; index < SOCKET_CNT; index++) {
+ EXPECT_EQ(0, FD_ISSET(fds[index], &rd_set));
+ }
+
+ // Poke one of the pollable nodes to be READ ready
+ ioctl(fds[0], POLLIN, NULL);
+
+ // Expect normal files to be read/write and one pollable node to be read.
+ SetFDs(&rd_set, fds);
+ SetFDs(&wr_set, fds);
+ cnt = select(fdnum, &rd_set, &wr_set, NULL, NULL);
+ EXPECT_EQ(7, cnt);
+ EXPECT_NE(0, FD_ISSET(fds[0], &rd_set));
+ EXPECT_EQ(0, FD_ISSET(fds[0], &wr_set));
+}
+
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
index d2fa5310e4..eeaf104f9e 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
@@ -53,6 +53,9 @@ class KernelProxyMock : public nacl_io::KernelProxy {
MOCK_METHOD1(open_resource, int(const char*));
#ifdef PROVIDES_SOCKET_API
+ MOCK_METHOD3(poll, int(struct pollfd*, nfds_t, int));
+ MOCK_METHOD5(select, int(int, fd_set*, fd_set*, fd_set*, struct timeval*));
+
// Socket support functions
MOCK_METHOD3(accept, int(int, struct sockaddr*, socklen_t*));
MOCK_METHOD3(bind, int(int, const struct sockaddr*, socklen_t));
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
index 5989ce4e5e..92577e094b 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
@@ -287,8 +287,17 @@ TEST_F(KernelWrapTest, write) {
}
#ifdef PROVIDES_SOCKET_API
-// Socket Functions
+TEST_F(KernelWrapTest, poll) {
+ EXPECT_CALL(mock, poll(NULL, 5, -1));
+ poll(NULL, 5, -1);
+}
+TEST_F(KernelWrapTest, select) {
+ EXPECT_CALL(mock, select(123, NULL, NULL, NULL, NULL));
+ select(123, NULL, NULL, NULL, NULL);
+}
+
+// Socket Functions
TEST_F(KernelWrapTest, accept) {
EXPECT_CALL(mock, accept(123, NULL, NULL)).Times(1);
accept(123, NULL, NULL);
diff --git a/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc b/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc
index 57d3adea4e..9768c1339f 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc
@@ -259,4 +259,111 @@ TEST_F(SocketTest, Socketpair) {
EXPECT_EQ(errno, EPROTONOSUPPORT);
}
+// These functions don't go through KernelProxy, so they don't require a test
+// fixture
+
+static struct in_addr generate_ipv4_addr(int tuple1, int tuple2,
+ int tuple3, int tuple4) {
+ unsigned char addr[4];
+ addr[0] = static_cast<unsigned char>(tuple1);
+ addr[1] = static_cast<unsigned char>(tuple2);
+ addr[2] = static_cast<unsigned char>(tuple3);
+ addr[3] = static_cast<unsigned char>(tuple4);
+ struct in_addr* real_addr = reinterpret_cast<struct in_addr*>(addr);
+ return *real_addr;
+}
+
+static struct in6_addr generate_ipv6_addr(int* tuples) {
+ unsigned char addr[16];
+ for (int i = 0; i < 8; i++) {
+ addr[2*i] = (tuples[i] >> 8) & 0xFF;
+ addr[2*i+1] = tuples[i] & 0xFF;
+ }
+ struct in6_addr* real_addr = reinterpret_cast<struct in6_addr*>(addr);
+ return *real_addr;
+}
+
+TEST(SocketUtilityFunctions, Inet_ntoa) {
+ char* stringified_addr = inet_ntoa(generate_ipv4_addr(0,0,0,0));
+ ASSERT_TRUE(NULL != stringified_addr);
+ EXPECT_STREQ("0.0.0.0", stringified_addr);
+
+ stringified_addr = inet_ntoa(generate_ipv4_addr(127,0,0,1));
+ ASSERT_TRUE(NULL != stringified_addr);
+ EXPECT_STREQ("127.0.0.1", stringified_addr);
+
+ stringified_addr = inet_ntoa(generate_ipv4_addr(255,255,255,255));
+ ASSERT_TRUE(NULL != stringified_addr);
+ EXPECT_STREQ("255.255.255.255", stringified_addr);
+}
+
+TEST(SocketUtilityFunctions, Inet_ntop_ipv4) {
+ char stringified_addr[INET_ADDRSTRLEN];
+
+ struct in_addr real_addr = generate_ipv4_addr(0,0,0,0);
+ EXPECT_TRUE(NULL != inet_ntop(AF_INET, &real_addr,
+ stringified_addr, INET_ADDRSTRLEN));
+ EXPECT_STREQ("0.0.0.0", stringified_addr);
+
+ real_addr = generate_ipv4_addr(127,0,0,1);
+ EXPECT_TRUE(NULL != inet_ntop(AF_INET, &real_addr,
+ stringified_addr, INET_ADDRSTRLEN));
+ EXPECT_STREQ("127.0.0.1", stringified_addr);
+
+ real_addr = generate_ipv4_addr(255,255,255,255);
+ EXPECT_TRUE(NULL != inet_ntop(AF_INET, &real_addr,
+ stringified_addr, INET_ADDRSTRLEN));
+ EXPECT_STREQ("255.255.255.255", stringified_addr);
+}
+
+TEST(SocketUtilityFunctions, Inet_ntop_ipv6) {
+ char stringified_addr[INET6_ADDRSTRLEN];
+
+ {
+ int addr_tuples[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ struct in6_addr real_addr = generate_ipv6_addr(addr_tuples);
+ EXPECT_TRUE(NULL != inet_ntop(AF_INET6, &real_addr,
+ stringified_addr, INET6_ADDRSTRLEN));
+ EXPECT_STREQ("0:0:0:0:0:0:0:0", stringified_addr);
+ }
+
+ {
+ int addr_tuples[8] = { 0x1234, 0xa, 0x12, 0x0000,
+ 0x5678, 0x9abc, 0xdef, 0xffff };
+ struct in6_addr real_addr = generate_ipv6_addr(addr_tuples);
+ EXPECT_TRUE(NULL != inet_ntop(AF_INET6, &real_addr,
+ stringified_addr, INET6_ADDRSTRLEN));
+ EXPECT_STREQ("1234:a:12:0:5678:9abc:def:ffff", stringified_addr);
+ }
+
+ {
+ int addr_tuples[8] = { 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff };
+ struct in6_addr real_addr = generate_ipv6_addr(addr_tuples);
+ EXPECT_TRUE(NULL != inet_ntop(AF_INET6, &real_addr,
+ stringified_addr, INET6_ADDRSTRLEN));
+ EXPECT_STREQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", stringified_addr);
+ }
+}
+
+TEST(SocketUtilityFunctions, Inet_ntop_failure) {
+ char addr_name[INET6_ADDRSTRLEN];
+ int addr_tuples[8] = { 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff };
+ struct in6_addr ipv6_addr = generate_ipv6_addr(addr_tuples);
+ struct in_addr ipv4_addr = generate_ipv4_addr(255,255,255,255);
+
+ EXPECT_TRUE(NULL == inet_ntop(AF_UNIX, &ipv6_addr,
+ addr_name, INET6_ADDRSTRLEN));
+ EXPECT_EQ(errno, EAFNOSUPPORT);
+
+ EXPECT_TRUE(NULL == inet_ntop(AF_INET, &ipv4_addr,
+ addr_name, INET_ADDRSTRLEN - 1));
+ EXPECT_EQ(errno, ENOSPC);
+
+ EXPECT_TRUE(NULL == inet_ntop(AF_INET6, &ipv6_addr,
+ addr_name, INET6_ADDRSTRLEN - 1));
+ EXPECT_EQ(errno, ENOSPC);
+}
+
#endif // PROVIDES_SOCKETPAIR_API
diff --git a/native_client_sdk/src/libraries/ppapi_simple/library.dsc b/native_client_sdk/src/libraries/ppapi_simple/library.dsc
index 841aeedf8f..8cb2c056bf 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/library.dsc
+++ b/native_client_sdk/src/libraries/ppapi_simple/library.dsc
@@ -1,5 +1,5 @@
{
- 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'],
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
'TARGETS': [
{
'NAME' : 'ppapi_simple',
diff --git a/native_client_sdk/src/libraries/third_party/newlib-extras/sys/select.h b/native_client_sdk/src/libraries/third_party/newlib-extras/sys/select.h
new file mode 100644
index 0000000000..2ec7612533
--- /dev/null
+++ b/native_client_sdk/src/libraries/third_party/newlib-extras/sys/select.h
@@ -0,0 +1,20 @@
+#ifndef _SYS_SELECT_H
+#define _SYS_SELECT_H 1
+
+#include <sys/types.h>
+#include <time.h>
+
+#include "sdk_util/macros.h"
+
+EXTERN_C_BEGIN
+
+struct timeval;
+
+int select (int __nfds, fd_set *__restrict __readfds,
+ fd_set *__restrict __writefds,
+ fd_set *__restrict __exceptfds,
+ struct timeval *__restrict __timeout) __THROW;
+
+EXTERN_C_END
+
+#endif /* sys/select.h */
diff --git a/native_client_sdk/src/tools/common.mk b/native_client_sdk/src/tools/common.mk
index 91d123da57..11feea8276 100644
--- a/native_client_sdk/src/tools/common.mk
+++ b/native_client_sdk/src/tools/common.mk
@@ -431,7 +431,7 @@ RUN_PY := python $(NACL_SDK_ROOT)/tools/run.py
CHROME_ENV ?=
# Additional arguments to pass to Chrome.
-CHROME_ARGS += --enable-nacl --no-first-run
+CHROME_ARGS += --enable-nacl --enable-pnacl --no-first-run
CHROME_ARGS += --user-data-dir=$(CURDIR)/user-data-dir
@@ -443,18 +443,25 @@ PPAPI_RELEASE = $(abspath $(OSNAME)/Release/$(TARGET)$(HOST_EXT));application/x-
SYSARCH := $(shell $(GETOS) --nacl-arch)
SEL_LDR_PATH := python $(NACL_SDK_ROOT)/tools/sel_ldr.py
+#
+# Common Compile Options
+#
+ifeq ($(CONFIG),Debug)
+SEL_LDR_ARGS += --debug-libs
+endif
+
ifdef SEL_LDR
run: all
ifndef NACL_ARCH
$(error Cannot run in sel_ldr unless $$NACL_ARCH is set)
endif
- $(SEL_LDR_PATH) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe
+ $(SEL_LDR_PATH) $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe
debug: all
ifndef NACL_ARCH
$(error Cannot run in sel_ldr unless $$NACL_ARCH is set)
endif
- $(SEL_LDR_PATH) -d $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe
+ $(SEL_LDR_PATH) -d $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe
else
PAGE ?= index.html
PAGE_TC_CONFIG ?= "$(PAGE)?tc=$(TOOLCHAIN)&config=$(CONFIG)"
diff --git a/native_client_sdk/src/tools/sel_ldr.py b/native_client_sdk/src/tools/sel_ldr.py
index 01de0be789..e500192d17 100755
--- a/native_client_sdk/src/tools/sel_ldr.py
+++ b/native_client_sdk/src/tools/sel_ldr.py
@@ -85,8 +85,12 @@ def main(argv):
cmd.insert(0, helper)
if dynamic:
- libpath = os.path.join(NACL_SDK_ROOT, 'lib',
- 'glibc_%s' % arch_suffix, 'Release')
+ if options.debug_libs:
+ libpath = os.path.join(NACL_SDK_ROOT, 'lib',
+ 'glibc_%s' % arch_suffix, 'Debug')
+ else:
+ libpath = os.path.join(NACL_SDK_ROOT, 'lib',
+ 'glibc_%s' % arch_suffix, 'Release')
toolchain = '%s_x86_glibc' % osname
sdk_lib_dir = os.path.join(NACL_SDK_ROOT, 'toolchain',
toolchain, 'x86_64-nacl')