summaryrefslogtreecommitdiff
path: root/native_client_sdk
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2013-07-10 11:40:50 +0100
committerBen Murdoch <benm@google.com>2013-07-10 11:40:50 +0100
commiteb525c5499e34cc9c4b825d6d9e75bb07cc06ace (patch)
treed908ce4bfe1717d2cd53f41327d8b9ba8304355f /native_client_sdk
parent3c54152607de4272b3da0c146b71dcba8a0e5610 (diff)
downloadchromium_org-eb525c5499e34cc9c4b825d6d9e75bb07cc06ace.tar.gz
Merge from Chromium at DEPS revision r210036
This commit was generated by merge_to_master.py. Change-Id: Ib0e33a83ad5dfa541481e83d7acfc6970e68f471
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/OWNERS1
-rw-r--r--native_client_sdk/src/README8
-rw-r--r--native_client_sdk/src/README.Makefiles95
-rwxr-xr-xnative_client_sdk/src/build_tools/build_projects.py82
-rwxr-xr-xnative_client_sdk/src/build_tools/build_sdk.py245
-rw-r--r--native_client_sdk/src/build_tools/build_version.py9
-rw-r--r--native_client_sdk/src/build_tools/json/naclsdk_manifest2.json30
-rw-r--r--native_client_sdk/src/build_tools/library.mk75
-rwxr-xr-xnative_client_sdk/src/build_tools/parse_dsc.py5
-rw-r--r--native_client_sdk/src/build_tools/sdk_files.list117
-rw-r--r--native_client_sdk/src/build_tools/template.mk119
-rwxr-xr-xnative_client_sdk/src/build_tools/test_sdk.py37
-rwxr-xr-xnative_client_sdk/src/build_tools/tests/verify_filelist_test.py2
-rwxr-xr-xnative_client_sdk/src/build_tools/verify_filelist.py17
-rw-r--r--native_client_sdk/src/documentation/Doxyfile1663
-rw-r--r--native_client_sdk/src/documentation/build.scons28
-rwxr-xr-xnative_client_sdk/src/documentation/check.sh26
-rw-r--r--native_client_sdk/src/documentation/footer.dox22
-rw-r--r--native_client_sdk/src/documentation/header.dox14
-rw-r--r--native_client_sdk/src/documentation/images-dox/README.txt9
-rw-r--r--native_client_sdk/src/documentation/index.dox46
-rw-r--r--native_client_sdk/src/documentation/modules.dox22
-rw-r--r--native_client_sdk/src/documentation/stylesheet-dox.css478
-rw-r--r--native_client_sdk/src/documentation/stylesheet.css101
-rw-r--r--native_client_sdk/src/examples/api/file_io/example.js167
-rw-r--r--native_client_sdk/src/examples/api/file_io/file_io.cc77
-rw-r--r--native_client_sdk/src/examples/api/file_io/index.html72
-rw-r--r--native_client_sdk/src/examples/api/input_event/index.html2
-rw-r--r--native_client_sdk/src/examples/api/url_loader/example.js2
-rw-r--r--native_client_sdk/src/examples/api/websocket/example.js3
-rw-r--r--native_client_sdk/src/examples/api/websocket/index.html3
-rw-r--r--native_client_sdk/src/examples/api/websocket/websocket.cc66
-rw-r--r--native_client_sdk/src/examples/demo/earth/earth.cc871
-rw-r--r--native_client_sdk/src/examples/demo/earth/earth.jpgbin0 -> 194522 bytes
-rw-r--r--native_client_sdk/src/examples/demo/earth/earthnight.jpgbin0 -> 351716 bytes
-rw-r--r--native_client_sdk/src/examples/demo/earth/example.dsc22
-rw-r--r--native_client_sdk/src/examples/demo/earth/example.js88
-rw-r--r--native_client_sdk/src/examples/demo/earth/index.html68
-rw-r--r--native_client_sdk/src/examples/demo/flock/example.dsc26
-rw-r--r--native_client_sdk/src/examples/demo/flock/flock.cc150
-rw-r--r--native_client_sdk/src/examples/demo/flock/frame_counter.cc43
-rw-r--r--native_client_sdk/src/examples/demo/flock/frame_counter.h46
-rw-r--r--native_client_sdk/src/examples/demo/flock/goose.cc204
-rw-r--r--native_client_sdk/src/examples/demo/flock/goose.h129
-rw-r--r--native_client_sdk/src/examples/demo/flock/index.html27
-rw-r--r--native_client_sdk/src/examples/demo/flock/sprite.cc91
-rw-r--r--native_client_sdk/src/examples/demo/flock/sprite.h57
-rw-r--r--native_client_sdk/src/examples/demo/flock/vector2.h81
-rw-r--r--native_client_sdk/src/examples/demo/life/index.html2
-rw-r--r--native_client_sdk/src/examples/demo/nacl_io/example.js7
-rw-r--r--native_client_sdk/src/examples/demo/pi_generator/example.dsc4
-rw-r--r--native_client_sdk/src/examples/demo/pi_generator/example.js9
-rw-r--r--native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc378
-rw-r--r--native_client_sdk/src/examples/demo/voronoi/example.js34
-rw-r--r--native_client_sdk/src/examples/demo/voronoi/voronoi.cc44
-rw-r--r--native_client_sdk/src/examples/getting_started/hello_world/index.html4
-rw-r--r--native_client_sdk/src/examples/getting_started/simple_hello_world/index.html2
-rw-r--r--native_client_sdk/src/examples/tutorial/dlopen/index.html2
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_event_listener.cc98
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_event_listener.h47
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_instance.cc45
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_instance.h29
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_module.cc9
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_module.h18
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_nacl_environment.cc14
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_nacl_environment.h34
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_runner.cc71
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/gtest_runner.h57
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/library.dsc33
-rw-r--r--native_client_sdk/src/libraries/gtest_ppapi/thread_condition.h65
-rw-r--r--native_client_sdk/src/libraries/nacl_io/ioctl.h25
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_handle.cc12
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_handle.h22
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc20
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.h7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.cc95
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.h21
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc252
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.h30
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap.h7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc27
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc27
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc21
-rw-r--r--native_client_sdk/src/libraries/nacl_io/library.dsc5
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount.cc15
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount.h48
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.cc134
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.h11
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_factory.h29
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc30
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_html5fs.h7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_http.cc121
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_http.h16
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_mem.cc92
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_mem.h15
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.cc36
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.h21
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc12
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_dir.h9
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc9
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_http.cc26
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc23
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.h10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/nacl_io.cc1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/ostypes.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/osunistd.h22
-rw-r--r--native_client_sdk/src/libraries/nacl_io/osutime.h15
-rw-r--r--native_client_sdk/src/libraries/nacl_io/path.cc1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/typed_mount_factory.h29
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/example.dsc12
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/example.js79
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/index.html7
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc240
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc4
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h5
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc181
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc39
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/main.cc55
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/module.cc12
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc105
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc103
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_mock.cc11
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_mock.h30
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.cc11
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.h44
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc41
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_test.cc200
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/path_test.cc1
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc1
-rw-r--r--native_client_sdk/src/libraries/ppapi/library.dsc132
-rw-r--r--native_client_sdk/src/libraries/ppapi_cpp/library.dsc261
-rw-r--r--native_client_sdk/src/libraries/ppapi_cpp_private/library.dsc35
-rw-r--r--native_client_sdk/src/libraries/ppapi_gles2/library.dsc38
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/library.dsc6
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps.h25
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc134
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h67
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_event.h10
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc222
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_instance.h33
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_interface.cc64
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_interface.h72
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_main.h9
-rw-r--r--native_client_sdk/src/libraries/sdk_util/atomicops.h44
-rw-r--r--native_client_sdk/src/libraries/sdk_util/library.dsc2
-rw-r--r--native_client_sdk/src/libraries/sdk_util/ref_object.h39
-rw-r--r--native_client_sdk/src/libraries/sdk_util/scoped_ref.h91
-rw-r--r--native_client_sdk/src/libraries/xray/demangle.c26
-rw-r--r--native_client_sdk/src/libraries/xray/hashtable.c201
-rw-r--r--native_client_sdk/src/libraries/xray/library.dsc34
-rw-r--r--native_client_sdk/src/libraries/xray/stringpool.c92
-rw-r--r--native_client_sdk/src/libraries/xray/symtable.c264
-rw-r--r--native_client_sdk/src/libraries/xray/xray.c825
-rw-r--r--native_client_sdk/src/libraries/xray/xray.h84
-rw-r--r--native_client_sdk/src/libraries/xray/xray.html85
-rw-r--r--native_client_sdk/src/libraries/xray/xray.odtbin0 -> 52527 bytes
-rw-r--r--native_client_sdk/src/libraries/xray/xray_priv.h117
-rw-r--r--native_client_sdk/src/project_templates/README45
-rw-r--r--native_client_sdk/src/project_templates/c/build.scons15
-rw-r--r--native_client_sdk/src/project_templates/c/project_file.c227
-rw-r--r--native_client_sdk/src/project_templates/cc/build.scons16
-rw-r--r--native_client_sdk/src/project_templates/cc/project_file.cc87
-rw-r--r--native_client_sdk/src/project_templates/html/project_file.html95
-rwxr-xr-xnative_client_sdk/src/project_templates/init_project.py505
-rwxr-xr-xnative_client_sdk/src/project_templates/init_project_test.py263
-rwxr-xr-xnative_client_sdk/src/project_templates/scons47
-rwxr-xr-xnative_client_sdk/src/project_templates/scons.bat50
-rw-r--r--native_client_sdk/src/project_templates/test.scons26
-rw-r--r--native_client_sdk/src/project_templates/vs/project_file.sln20
-rw-r--r--native_client_sdk/src/project_templates/vs/project_file.vcproj184
-rw-r--r--native_client_sdk/src/tools/common.mk22
-rwxr-xr-xnative_client_sdk/src/tools/create_html.py4
-rwxr-xr-xnative_client_sdk/src/tools/fix_deps.py95
-rwxr-xr-xnative_client_sdk/src/tools/getos.py2
-rw-r--r--native_client_sdk/src/tools/host_gcc.mk10
-rw-r--r--native_client_sdk/src/tools/nacl_gcc.mk73
-rw-r--r--native_client_sdk/src/tools/nacl_llvm.mk33
-rwxr-xr-xnative_client_sdk/src/tools/tests/fix_deps_test.py89
-rwxr-xr-xnative_client_sdk/src/tools/tests/getos_test.py2
181 files changed, 7620 insertions, 6345 deletions
diff --git a/native_client_sdk/OWNERS b/native_client_sdk/OWNERS
index 9cd1776b7d..2f918b8434 100644
--- a/native_client_sdk/OWNERS
+++ b/native_client_sdk/OWNERS
@@ -3,3 +3,4 @@ noelallen@chromium.org
erikkay@chromium.org
binji@chromium.org
sbc@chromium.org
+nfullagar@chromium.org
diff --git a/native_client_sdk/src/README b/native_client_sdk/src/README
index c85406fa01..82503b9a83 100644
--- a/native_client_sdk/src/README
+++ b/native_client_sdk/src/README
@@ -1,8 +1,10 @@
-Welcome to the Native Client SDK.
+Welcome to the Native Client SDK
+================================
Native Client Tools Bundle
Version: ${VERSION}
-Revision: ${REVISION}
+Chrome Revision: ${CHROME_REVISION}
+Native Client Revision: ${NACL_REVISION}
Build Date: ${DATE}
Please refer to the online documentation here:
@@ -10,6 +12,7 @@ Please refer to the online documentation here:
http://code.google.com/chrome/nativeclient
OTHER DEVELOPMENT
+-----------------
If you want to contribute to the Native Client SDK itself, please read the
online documentation on contributing code to Chromium here:
@@ -17,6 +20,7 @@ online documentation on contributing code to Chromium here:
http://www.chromium.org/developers/contributing-code
KNOWN ISSUES
+------------
Please refer to the online documentation here:
diff --git a/native_client_sdk/src/README.Makefiles b/native_client_sdk/src/README.Makefiles
new file mode 100644
index 0000000000..117939561e
--- /dev/null
+++ b/native_client_sdk/src/README.Makefiles
@@ -0,0 +1,95 @@
+Build System for Native Client SDK examples
+===========================================
+
+The examples and libraries that ship with the Native Client SDK use a
+build system based on GNU Make.
+
+Each example or library is contained in its own directory along with a
+Makefile. The Makefiles are capable of building Native Client
+applications and libraries using any of the available toolchains as well
+as building host applications with the host's toolchain. In order to
+keep the top-level Makefiles simple, most of actual build rules are
+specified in as set of shared rules files in the $NACL_SDK_ROOT/tools
+directory.
+
+This document describes some of the variables and macros used by in the
+build system. For more details please see the .mk files in the tools
+folder.
+
+Using the build system for new projects
+--------------------------------------
+
+It is perfectly possible to use the included build system for projects
+outside of the Native Client SDK. A good starting point for doing this
+would be to copy the Makefile from the hello_world example. In most
+simple cases the only changes needed are to update the SOURCES and
+TARGET variables.
+
+User Variables
+--------------
+
+TARGET
+ This variable holds the name of your project. Normally this is the
+ basename of the library or executable which is the final target.
+
+SOURCES
+ The list of sources to be built. In most cases this list is passed to
+ the compile and link macros.
+
+VALID_TOOLCHAINS
+ This variable can be used to control which toolchains are supported by
+ the project. Valid entries for this list are: newlib, glibc, pnacl,
+ linux, mac, win. The default value is: "newlib glibc pnacl".
+
+NACL_SDK_ROOT
+ Optionally force the build system to use a certain location for the
+ Native Client SDK. If not set within the Makefile the $NACL_SDK_ROOT
+ environment variable will by used. It is an error if this variable is
+ neither set within the Makefile nor in the environment.
+
+Macros / Rules
+--------------
+
+The following macros can be used in the Makefiles to generate the rules
+for building the various kinds types of target. These are designed to
+be used via the 'call' macro. e.g. $(call COMPILE_RULE,$(SOURCES))
+
+COMPILE_RULE
+ This rule is used to build object files from a list of sources.
+
+SO_RULE
+ Used to build shared objects from a list of sources.
+
+LIB_RULE
+ Used to build static libraries from a list of sources.
+
+NMF_RULE
+ Used to build nmf metadata file from a native client executable (or
+ set of executables). This is needed in order to run the executable in
+ chrome.
+
+HTML_RULE
+ Used to build both html and nmf files from a native client executable
+ (or set of executables) which will allow the executable to be run
+ in chrome.
+
+For more information on how to use these rules in your Makefile see
+the shared Makefiles in the tools folders:
+
+common.mk
+ Top level shared rules file that include the toolchain specific
+ rules.
+
+nacl_gcc.mk
+ Rules for building using the gcc-based NaCl toolchains.
+
+nacl_llvm.mk
+ Rules for building using the llvm-based PNaCl toolchains.
+
+host_gcc.mk
+ Rules for building using the linux/mac host gcc toolchain.
+
+host_vc.mk
+ Rules for building using the windows Visual Studio toolchain.
+
+.. vim: ft=rst tw=72
diff --git a/native_client_sdk/src/build_tools/build_projects.py b/native_client_sdk/src/build_tools/build_projects.py
index db07e323b9..3b6780be6f 100755
--- a/native_client_sdk/src/build_tools/build_projects.py
+++ b/native_client_sdk/src/build_tools/build_projects.py
@@ -3,6 +3,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import multiprocessing
import optparse
import os
import sys
@@ -30,6 +31,12 @@ LIB_DICT = {
}
VALID_TOOLCHAINS = ['newlib', 'glibc', 'pnacl', 'win', 'linux', 'mac']
+# Global verbosity setting.
+# If set to try (normally via a command line arg) then build_projects will
+# add V=1 to all calls to 'make'
+verbose = False
+
+
def CopyFilesFromTo(filelist, srcdir, dstdir):
for filename in filelist:
@@ -38,9 +45,10 @@ def CopyFilesFromTo(filelist, srcdir, dstdir):
buildbot_common.CopyFile(srcpath, dstpath)
-def UpdateHelpers(pepperdir, platform, clobber=False):
- if not os.path.exists(os.path.join(pepperdir, 'tools')):
- buildbot_common.ErrorExit('Examples depend on missing tools.')
+def UpdateHelpers(pepperdir, clobber=False):
+ tools_dir = os.path.join(pepperdir, 'tools')
+ if not os.path.exists(tools_dir):
+ buildbot_common.ErrorExit('SDK tools dir is missing: %s' % tools_dir)
exampledir = os.path.join(pepperdir, 'examples')
if clobber:
@@ -58,15 +66,15 @@ def UpdateHelpers(pepperdir, platform, clobber=False):
# Copy tools scripts and make includes
buildbot_common.CopyDir(os.path.join(SDK_SRC_DIR, 'tools', '*.py'),
- os.path.join(pepperdir, 'tools'))
+ tools_dir)
buildbot_common.CopyDir(os.path.join(SDK_SRC_DIR, 'tools', '*.mk'),
- os.path.join(pepperdir, 'tools'))
+ tools_dir)
# On Windows add a prebuilt make
- if platform == 'win':
+ if getos.GetPlatform() == 'win':
buildbot_common.BuildStep('Add MAKE')
http_download.HttpDownload(GSTORE + MAKE,
- os.path.join(pepperdir, 'tools', 'make.exe'))
+ os.path.join(tools_dir, 'make.exe'))
def ValidateToolchains(toolchains):
@@ -76,7 +84,7 @@ def ValidateToolchains(toolchains):
', '.join(invalid_toolchains)))
-def UpdateProjects(pepperdir, platform, project_tree, toolchains,
+def UpdateProjects(pepperdir, project_tree, toolchains,
clobber=False, configs=None, first_toolchain=False):
if configs is None:
configs = ['Debug', 'Release']
@@ -89,6 +97,7 @@ def UpdateProjects(pepperdir, platform, project_tree, toolchains,
# Create the library output directories
libdir = os.path.join(pepperdir, 'lib')
+ platform = getos.GetPlatform()
for config in configs:
for arch in LIB_DICT[platform]:
dirpath = os.path.join(libdir, '%s_%s_host' % (platform, arch), config)
@@ -141,44 +150,56 @@ def UpdateProjects(pepperdir, platform, project_tree, toolchains,
targets)
-def BuildProjectsBranch(pepperdir, platform, branch, deps, clean, config):
+def BuildProjectsBranch(pepperdir, branch, deps, clean, config):
make_dir = os.path.join(pepperdir, branch)
print "\n\nMake: " + make_dir
- if platform == 'win':
+
+ if getos.GetPlatform() == 'win':
# We need to modify the environment to build host on Windows.
make = os.path.join(make_dir, 'make.bat')
else:
make = 'make'
- extra_args = ['CONFIG='+config]
+ env = None
+ if os.environ.get('USE_GOMA') == '1':
+ env = dict(os.environ)
+ env['NACL_COMPILER_PREFIX'] = 'gomacc'
+ # Add -m32 to the CFLAGS when building using i686-nacl-gcc
+ # otherwise goma won't recognise it as different to the x86_64
+ # build.
+ env['X86_32_CFLAGS'] = '-m32'
+ env['X86_32_CXXFLAGS'] = '-m32'
+ jobs = '50'
+ else:
+ jobs = str(multiprocessing.cpu_count())
+
+ make_cmd = [make, '-j', jobs, 'TOOLCHAIN=all']
+
+ make_cmd.append('CONFIG='+config)
if not deps:
- extra_args += ['IGNORE_DEPS=1']
+ make_cmd.append('IGNORE_DEPS=1')
- try:
- buildbot_common.Run([make, '-j8', 'TOOLCHAIN=all'] + extra_args,
- cwd=make_dir)
- except:
- print 'Failed to build ' + branch
- raise
+ if verbose:
+ make_cmd.append('V=1')
+ buildbot_common.Run(make_cmd, cwd=make_dir, env=env)
if clean:
# Clean to remove temporary files but keep the built
- buildbot_common.Run([make, '-j8', 'clean', 'TOOLCHAIN=all'] + extra_args,
- cwd=make_dir)
+ buildbot_common.Run(make_cmd + ['clean'], cwd=make_dir, env=env)
-def BuildProjects(pepperdir, platform, project_tree, deps=True,
+def BuildProjects(pepperdir, project_tree, deps=True,
clean=False, config='Debug'):
# First build libraries
build_order = ['src', 'testlibs']
for branch in build_order:
if branch in project_tree:
- BuildProjectsBranch(pepperdir, platform, branch, deps, clean, config)
+ BuildProjectsBranch(pepperdir, branch, deps, clean, config)
# Build everything else.
for branch in project_tree:
if branch not in build_order:
- BuildProjectsBranch(pepperdir, platform, branch, deps, clean, config)
+ BuildProjectsBranch(pepperdir, branch, deps, clean, config)
def main(args):
@@ -215,15 +236,14 @@ def main(args):
pepper_ver = str(int(build_version.ChromeMajorVersion()))
pepperdir = os.path.join(OUT_DIR, 'pepper_' + pepper_ver)
- platform = getos.GetPlatform()
if not options.toolchain:
options.toolchain = ['newlib', 'glibc', 'pnacl', 'host']
if 'host' in options.toolchain:
options.toolchain.remove('host')
- options.toolchain.append(platform)
- print 'Adding platform: ' + platform
+ options.toolchain.append(getos.GetPlatform())
+ print 'Adding platform: ' + getos.GetPlatform()
ValidateToolchains(options.toolchain)
@@ -243,17 +263,21 @@ def main(args):
project_tree = parse_dsc.LoadProjectTree(SDK_SRC_DIR, filters=filters)
parse_dsc.PrintProjectTree(project_tree)
- UpdateHelpers(pepperdir, platform, clobber=options.clobber)
- UpdateProjects(pepperdir, platform, project_tree, options.toolchain,
+ UpdateHelpers(pepperdir, clobber=options.clobber)
+ UpdateProjects(pepperdir, project_tree, options.toolchain,
clobber=options.clobber)
+ if options.verbose:
+ global verbose
+ verbose = True
+
if options.build:
if options.config:
configs = [options.config]
else:
configs = ['Debug', 'Release']
for config in configs:
- BuildProjects(pepperdir, platform, project_tree, config=config)
+ BuildProjects(pepperdir, project_tree, config=config)
return 0
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py
index 7b189912ce..0212d0741f 100755
--- a/native_client_sdk/src/build_tools/build_sdk.py
+++ b/native_client_sdk/src/build_tools/build_sdk.py
@@ -42,7 +42,7 @@ import parse_dsc
import verify_filelist
from build_paths import SCRIPT_DIR, SDK_SRC_DIR, SRC_DIR, NACL_DIR, OUT_DIR
-from build_paths import PPAPI_DIR, NACLPORTS_DIR, GSTORE
+from build_paths import NACLPORTS_DIR, GSTORE
# Add SDK make tools scripts to the python path.
sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
@@ -61,21 +61,21 @@ GYPBUILD_DIR = 'gypbuild'
options = None
-def GetGlibcToolchain(platform, arch):
+def GetGlibcToolchain(arch):
tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
- tcname = 'toolchain_%s_%s.tar.bz2' % (platform, arch)
+ tcname = 'toolchain_%s_%s.tar.bz2' % (getos.GetPlatform(), arch)
return os.path.join(tcdir, tcname)
-def GetNewlibToolchain(platform, arch):
+def GetNewlibToolchain(arch):
tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
- tcname = 'naclsdk_%s_%s.tgz' % (platform, arch)
+ tcname = 'naclsdk_%s_%s.tgz' % (getos.GetPlatform(), arch)
return os.path.join(tcdir, tcname)
-def GetPNaClToolchain(os_platform, arch):
+def GetPNaClToolchain(arch):
tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
- tcname = 'naclsdk_pnacl_%s_%s.tgz' % (os_platform, arch)
+ tcname = 'naclsdk_pnacl_%s_%s.tgz' % (getos.GetPlatform(), arch)
return os.path.join(tcdir, tcname)
@@ -120,7 +120,7 @@ def GetSconsArgs(tcpath, outdir, arch, xarch=None):
Only used for pnacl builds.
"""
- if sys.platform in ['cygwin', 'win32']:
+ if getos.GetPlatform() == 'win':
scons = 'scons.bat'
else:
scons = './scons'
@@ -154,17 +154,23 @@ def BuildStepMakePepperDirs(pepperdir, subdirs):
for subdir in subdirs:
buildbot_common.MakeDir(os.path.join(pepperdir, subdir))
+TEXT_FILES = [
+ 'AUTHORS',
+ 'COPYING',
+ 'LICENSE',
+ 'README.Makefiles',
+]
-def BuildStepCopyTextFiles(pepperdir, pepper_ver, revision):
+def BuildStepCopyTextFiles(pepperdir, pepper_ver, chrome_revision,
+ nacl_revision):
buildbot_common.BuildStep('Add Text Files')
- files = ['AUTHORS', 'COPYING', 'LICENSE']
- files = [os.path.join(SDK_SRC_DIR, filename) for filename in files]
- oshelpers.Copy(['-v'] + files + [pepperdir])
+ InstallFiles(SDK_SRC_DIR, pepperdir, TEXT_FILES)
# Replace a few placeholders in README
readme_text = open(os.path.join(SDK_SRC_DIR, 'README')).read()
readme_text = readme_text.replace('${VERSION}', pepper_ver)
- readme_text = readme_text.replace('${REVISION}', revision)
+ readme_text = readme_text.replace('${CHROME_REVISION}', chrome_revision)
+ readme_text = readme_text.replace('${NACL_REVISION}', nacl_revision)
# Year/Month/Day Hour:Minute:Second
time_format = '%Y/%m/%d %H:%M:%S'
@@ -174,8 +180,9 @@ def BuildStepCopyTextFiles(pepperdir, pepper_ver, revision):
open(os.path.join(pepperdir, 'README'), 'w').write(readme_text)
-def BuildStepUntarToolchains(pepperdir, platform, arch, toolchains):
+def BuildStepUntarToolchains(pepperdir, arch, toolchains):
buildbot_common.BuildStep('Untar Toolchains')
+ platform = getos.GetPlatform()
tcname = platform + '_' + arch
tmpdir = os.path.join(OUT_DIR, 'tc_temp')
buildbot_common.RemoveDir(tmpdir)
@@ -183,7 +190,7 @@ def BuildStepUntarToolchains(pepperdir, platform, arch, toolchains):
if 'newlib' in toolchains:
# Untar the newlib toolchains
- tarfile = GetNewlibToolchain(platform, arch)
+ tarfile = GetNewlibToolchain(arch)
buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
cwd=NACL_DIR)
@@ -202,7 +209,7 @@ def BuildStepUntarToolchains(pepperdir, platform, arch, toolchains):
if 'glibc' in toolchains:
# Untar the glibc toolchains
- tarfile = GetGlibcToolchain(platform, arch)
+ tarfile = GetGlibcToolchain(arch)
buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
cwd=NACL_DIR)
@@ -216,7 +223,7 @@ def BuildStepUntarToolchains(pepperdir, platform, arch, toolchains):
tmpdir = os.path.join(tmpdir, 'pnacl')
buildbot_common.RemoveDir(tmpdir)
buildbot_common.MakeDir(tmpdir)
- tarfile = GetPNaClToolchain(platform, arch)
+ tarfile = GetPNaClToolchain(arch)
buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
cwd=NACL_DIR)
@@ -226,7 +233,7 @@ def BuildStepUntarToolchains(pepperdir, platform, arch, toolchains):
buildbot_common.RemoveDir(tmpdir)
- if options.gyp and sys.platform not in ['cygwin', 'win32']:
+ if options.gyp and platform != 'win':
# If the gyp options is specified we install a toolchain
# wrapper so that gyp can switch toolchains via a commandline
# option.
@@ -274,79 +281,6 @@ NACL_HEADER_MAP = {
'host': []
}
-# Source relative to 'ppapi' foler. Destiniation relative
-# to SDK include folder.
-PPAPI_HEADER_MAP = [
- # Copy the KHR headers
- ('lib/gl/include/KHR/khrplatform.h', 'KHR/'),
-
- # Copy the GLES2 headers
- ('lib/gl/include/GLES2/gl2.h', 'GLES2/'),
- ('lib/gl/include/GLES2/gl2ext.h', 'GLES2/'),
- ('lib/gl/include/GLES2/gl2platform.h', 'GLES2/'),
-
- # Copy the EGL headers
- ('lib/gl/include/EGL/egl.h', 'EGL/'),
- ('lib/gl/include/EGL/eglext.h', 'EGL/'),
- ('lib/gl/include/EGL/eglplatform.h', 'EGL/'),
-
- # Copy in the gles2 headers
- ('lib/gl/gles2/gl2ext_ppapi.h', 'ppapi/gles2/'),
- # Create a duplicate copy of this header
- # TODO(sbc), remove this copy once we find a way to build gl2ext_ppapi.c.
- ('lib/gl/gles2/gl2ext_ppapi.h', 'ppapi/lib/gl/gles2/'),
-
- # Copy in the C++ headers
- ('utility/graphics/paint_aggregator.h', 'ppapi/utility/graphics/'),
- ('utility/graphics/paint_manager.h', 'ppapi/utility/graphics/'),
- ('utility/threading/lock.h', 'ppapi/utility/threading/'),
- ('utility/threading/simple_thread.h', 'ppapi/utility/threading/'),
- ('utility/websocket/websocket_api.h', 'ppapi/utility/websocket/'),
- ('utility/completion_callback_factory.h','ppapi/utility/'),
- ('utility/completion_callback_factory_thread_traits.h', 'ppapi/utility/'),
-
- # Copy in c, c/dev and c/extensions/dev headers
- # TODO(sbc): remove the use of wildcards here so that we can more
- # tightly control what ends up in the SDK.
- ('c/*.h', 'ppapi/c/'),
- ('c/dev/*.h', 'ppapi/c/dev/'),
- ('c/extensions/dev/*.h', 'ppapi/c/extensions/dev/'),
-
- # Copy in cpp, cpp/dev, cpp/extensions/, cpp/extensions/dev
- ('cpp/*.h', 'ppapi/cpp/'),
- ('cpp/extensions/*.h', 'ppapi/cpp/extensions/'),
- ('cpp/dev/*.h', 'ppapi/cpp/dev/'),
- ('cpp/extensions/dev/*.h', 'ppapi/cpp/extensions/dev/'),
-
- # Copy certain private headers (specifically these are the ones
- # that are used by nacl-mounts)
- ('cpp/private/ext_crx_file_system_private.h', 'ppapi/cpp/private/'),
- ('cpp/private/file_io_private.h', 'ppapi/cpp/private/'),
- ('cpp/private/net_address_private.h', 'ppapi/cpp/private/'),
- ('cpp/private/tcp_server_socket_private.h', 'ppapi/cpp/private/'),
- ('cpp/private/host_resolver_private.h', 'ppapi/cpp/private/'),
- ('cpp/private/pass_file_handle.h', 'ppapi/cpp/private/'),
- ('cpp/private/tcp_socket_private.h', 'ppapi/cpp/private/'),
- ('cpp/private/udp_socket_private.h', 'ppapi/cpp/private/'),
- ('cpp/private/x509_certificate_private.h', 'ppapi/cpp/private/'),
-
- ('c/private/pp_file_handle.h', 'ppapi/c/private/'),
- ('c/private/ppb_ext_crx_file_system_private.h', 'ppapi/c/private/'),
- ('c/private/ppb_file_io_private.h', 'ppapi/c/private/'),
- ('c/private/ppb_file_ref_private.h', 'ppapi/c/private/'),
- ('c/private/ppb_host_resolver_private.h', 'ppapi/c/private/'),
- ('c/private/ppb_tcp_server_socket_private.h', 'ppapi/c/private/'),
- ('c/private/ppb_net_address_private.h', 'ppapi/c/private/'),
- ('c/private/ppb_tcp_socket_private.h', 'ppapi/c/private/'),
- ('c/private/ppb_udp_socket_private.h', 'ppapi/c/private/'),
- ('c/private/ppb_x509_certificate_private.h', 'ppapi/c/private/'),
-]
-
-
-def InstallCommonHeaders(inc_path):
- InstallFiles(PPAPI_DIR, inc_path, PPAPI_HEADER_MAP)
-
-
def InstallFiles(src_root, dest_root, file_list):
"""Copy a set of files from src_root to dest_root according
to the given mapping. This allows files to be copied from
@@ -435,7 +369,7 @@ TOOLCHAIN_LIBS = {
}
-def GypNinjaInstall(pepperdir, platform, toolchains):
+def GypNinjaInstall(pepperdir, toolchains):
build_dir = GYPBUILD_DIR
ninja_out_dir = os.path.join(OUT_DIR, build_dir, 'Release')
tools_files = [
@@ -444,18 +378,17 @@ def GypNinjaInstall(pepperdir, platform, toolchains):
['irt_core_newlib_x32.nexe', 'irt_core_x86_32.nexe'],
['irt_core_newlib_x64.nexe', 'irt_core_x86_64.nexe'],
]
- if sys.platform not in ['cygwin', 'win32']:
- minidump_files = [
- ['dump_syms', 'dump_syms'],
- ['minidump_dump', 'minidump_dump'],
- ['minidump_stackwalk', 'minidump_stackwalk']
- ]
- tools_files.extend(minidump_files)
+
+ platform = getos.GetPlatform()
# TODO(binji): dump_syms doesn't currently build on Windows. See
# http://crbug.com/245456
if platform != 'win':
- tools_files.append(['dump_syms', 'dump_syms'])
+ tools_files += [
+ ['dump_syms', 'dump_syms'],
+ ['minidump_dump', 'minidump_dump'],
+ ['minidump_stackwalk', 'minidump_stackwalk']
+ ]
if platform != 'mac':
# Mac doesn't build 64-bit binaries.
@@ -504,7 +437,7 @@ def GypNinjaInstall(pepperdir, platform, toolchains):
-def GypNinjaBuild_NaCl(platform, rel_out_dir):
+def GypNinjaBuild_NaCl(rel_out_dir):
gyp_py = os.path.join(NACL_DIR, 'build', 'gyp_nacl')
nacl_core_sdk_gyp = os.path.join(NACL_DIR, 'build', 'nacl_core_sdk.gyp')
all_gyp = os.path.join(NACL_DIR, 'build', 'all.gyp')
@@ -515,6 +448,7 @@ def GypNinjaBuild_NaCl(platform, rel_out_dir):
GypNinjaBuild('arm', gyp_py, nacl_core_sdk_gyp, 'nacl_core_sdk', out_dir_arm)
GypNinjaBuild('ia32', gyp_py, all_gyp, 'ncval_new', out_dir)
+ platform = getos.GetPlatform()
if platform == 'win':
NinjaBuild('sel_ldr64', out_dir)
elif platform == 'linux':
@@ -534,10 +468,10 @@ def GypNinjaBuild_NaCl(platform, rel_out_dir):
os.path.join(SRC_DIR, out_dir, 'Release', dst))
-def GypNinjaBuild_Breakpad(platform, rel_out_dir):
+def GypNinjaBuild_Breakpad(rel_out_dir):
# TODO(binji): dump_syms doesn't currently build on Windows. See
# http://crbug.com/245456
- if platform == 'win':
+ if getos.GetPlatform() == 'win':
return
gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium')
@@ -613,12 +547,13 @@ def NinjaBuild(targets, out_dir):
buildbot_common.Run(['ninja', '-C', out_config_dir] + targets, cwd=SRC_DIR)
-def BuildStepBuildToolchains(pepperdir, platform, toolchains):
+def BuildStepBuildToolchains(pepperdir, toolchains):
buildbot_common.BuildStep('SDK Items')
- GypNinjaBuild_NaCl(platform, GYPBUILD_DIR)
- GypNinjaBuild_Breakpad(platform, GYPBUILD_DIR)
+ GypNinjaBuild_NaCl(GYPBUILD_DIR)
+ GypNinjaBuild_Breakpad(GYPBUILD_DIR)
+ platform = getos.GetPlatform()
tcname = platform + '_x86'
newlibdir = os.path.join(pepperdir, 'toolchain', tcname + '_newlib')
glibcdir = os.path.join(pepperdir, 'toolchain', tcname + '_glibc')
@@ -630,7 +565,7 @@ def BuildStepBuildToolchains(pepperdir, platform, toolchains):
if 'arm' in toolchains:
GypNinjaBuild_PPAPI('arm', GYPBUILD_DIR + '-arm')
- GypNinjaInstall(pepperdir, platform, toolchains)
+ GypNinjaInstall(pepperdir, toolchains)
if 'newlib' in toolchains:
InstallNaClHeaders(GetToolchainNaClInclude('newlib', newlibdir, 'x86'),
@@ -693,12 +628,12 @@ def MakeDirectoryOrClobber(pepperdir, dirname, clobber):
return dirpath
-def BuildStepUpdateHelpers(pepperdir, platform, clobber):
+def BuildStepUpdateHelpers(pepperdir, clobber):
buildbot_common.BuildStep('Update project helpers')
- build_projects.UpdateHelpers(pepperdir, platform, clobber=clobber)
+ build_projects.UpdateHelpers(pepperdir, clobber=clobber)
-def BuildStepUpdateUserProjects(pepperdir, platform, toolchains,
+def BuildStepUpdateUserProjects(pepperdir, toolchains,
build_experimental, clobber):
buildbot_common.BuildStep('Update examples and libraries')
@@ -714,7 +649,7 @@ def BuildStepUpdateUserProjects(pepperdir, platform, toolchains,
if 'host' in toolchains:
toolchains.remove('host')
- toolchains.append(platform)
+ toolchains.append(getos.GetPlatform())
filters['TOOLS'] = toolchains
@@ -728,37 +663,20 @@ def BuildStepUpdateUserProjects(pepperdir, platform, toolchains,
]
tree = parse_dsc.LoadProjectTree(SDK_SRC_DIR, filters=filters)
- build_projects.UpdateProjects(pepperdir, platform, tree, clobber=clobber,
+ build_projects.UpdateProjects(pepperdir, tree, clobber=clobber,
toolchains=toolchains)
-def BuildStepMakeAll(pepperdir, platform, directory, step_name,
- clean=False, deps=True, config='Debug'):
+def BuildStepMakeAll(pepperdir, directory, step_name,
+ deps=True, clean=False, config='Debug'):
buildbot_common.BuildStep(step_name)
- make_dir = os.path.join(pepperdir, directory)
+ build_projects.BuildProjectsBranch(pepperdir, directory, clean, deps, config)
- print "\n\nMake: " + make_dir
- if platform == 'win':
- make = os.path.join(make_dir, 'make.bat')
- else:
- make = 'make'
-
- extra_args = ['CONFIG='+config]
- if not deps:
- extra_args += ['IGNORE_DEPS=1']
-
- buildbot_common.Run([make, '-j8', 'TOOLCHAIN=all'] + extra_args,
- cwd=make_dir)
- if clean:
- # Clean to remove temporary files but keep the built libraries.
- buildbot_common.Run([make, '-j8', 'clean', 'TOOLCHAIN=all'] + extra_args,
- cwd=make_dir)
-
-def BuildStepBuildLibraries(pepperdir, platform, directory):
- BuildStepMakeAll(pepperdir, platform, directory, 'Build Libraries Debug',
+def BuildStepBuildLibraries(pepperdir, directory):
+ BuildStepMakeAll(pepperdir, directory, 'Build Libraries Debug',
clean=True, config='Debug')
- BuildStepMakeAll(pepperdir, platform, directory, 'Build Libraries Release',
+ BuildStepMakeAll(pepperdir, directory, 'Build Libraries Release',
clean=True, config='Release')
@@ -782,11 +700,11 @@ def GenerateNotice(fileroot, output_filename='NOTICE', extra_files=None):
generate_notice.Generate(output_filename, fileroot, license_files)
-def BuildStepVerifyFilelist(pepperdir, platform):
+def BuildStepVerifyFilelist(pepperdir):
buildbot_common.BuildStep('Verify SDK Files')
file_list_path = os.path.join(SCRIPT_DIR, 'sdk_files.list')
try:
- verify_filelist.Verify(platform, file_list_path, pepperdir)
+ verify_filelist.Verify(file_list_path, pepperdir)
print 'OK'
except verify_filelist.ParseException, e:
buildbot_common.ErrorExit('Parsing sdk_files.list failed:\n\n%s' % e)
@@ -818,7 +736,8 @@ def BuildStepTarBundle(pepper_ver, tarfile):
-def GetManifestBundle(pepper_ver, revision, tarfile, archive_url):
+def GetManifestBundle(pepper_ver, chrome_revision, nacl_revision, tarfile,
+ archive_url):
with open(tarfile, 'rb') as tarfile_stream:
archive_sha1, archive_size = manifest_util.DownloadAndComputeHash(
tarfile_stream)
@@ -829,17 +748,20 @@ def GetManifestBundle(pepper_ver, revision, tarfile, archive_url):
archive.checksum = archive_sha1
bundle = manifest_util.Bundle('pepper_' + pepper_ver)
- bundle.revision = int(revision)
+ bundle.revision = int(chrome_revision)
bundle.repath = 'pepper_' + pepper_ver
bundle.version = int(pepper_ver)
- bundle.description = 'Chrome %s bundle, revision %s' % (pepper_ver, revision)
+ bundle.description = (
+ 'Chrome %s bundle. Chrome revision: %s. NaCl revision: %s' % (
+ pepper_ver, chrome_revision, nacl_revision))
bundle.stability = 'dev'
bundle.recommended = 'no'
bundle.archives = [archive]
return bundle
-def BuildStepArchiveBundle(name, pepper_ver, revision, tarfile):
+def BuildStepArchiveBundle(name, pepper_ver, chrome_revision, nacl_revision,
+ tarfile):
buildbot_common.BuildStep('Archive %s' % name)
bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/%s' % (
build_version.ChromeVersion(),)
@@ -850,7 +772,8 @@ def BuildStepArchiveBundle(name, pepper_ver, revision, tarfile):
# generate "manifest snippet" for this archive.
archive_url = GSTORE + 'nacl_sdk/%s/%s' % (
build_version.ChromeVersion(), tarname)
- bundle = GetManifestBundle(pepper_ver, revision, tarfile, archive_url)
+ bundle = GetManifestBundle(pepper_ver, chrome_revision, nacl_revision,
+ tarfile, archive_url)
manifest_snippet_file = os.path.join(OUT_DIR, tarname + '.json')
with open(manifest_snippet_file, 'wb') as manifest_snippet_stream:
@@ -956,7 +879,6 @@ def main(args):
global options
options, args = parser.parse_args(args[1:])
- platform = getos.GetPlatform()
arch = 'x86'
generate_make.use_gyp = options.gyp
@@ -971,49 +893,48 @@ def main(args):
parser.error('Incompatible arguments with archive.')
chrome_version = int(build_version.ChromeMajorVersion())
- clnumber = build_version.ChromeRevision()
+ chrome_revision = build_version.ChromeRevision()
+ nacl_revision = build_version.NaClRevision()
pepper_ver = str(chrome_version)
pepper_old = str(chrome_version - 1)
pepperdir = os.path.join(OUT_DIR, 'pepper_' + pepper_ver)
pepperdir_old = os.path.join(OUT_DIR, 'pepper_' + pepper_old)
- tarname = 'naclsdk_' + platform + '.tar.bz2'
+ tarname = 'naclsdk_' + getos.GetPlatform() + '.tar.bz2'
tarfile = os.path.join(OUT_DIR, tarname)
if options.release:
pepper_ver = options.release
- print 'Building PEPPER %s at %s' % (pepper_ver, clnumber)
+ print 'Building PEPPER %s at %s' % (pepper_ver, chrome_revision)
if 'NACL_SDK_ROOT' in os.environ:
# We don't want the currently configured NACL_SDK_ROOT to have any effect
# of the build.
del os.environ['NACL_SDK_ROOT']
- BuildStepCleanPepperDirs(pepperdir, pepperdir_old)
- BuildStepMakePepperDirs(pepperdir, ['include', 'toolchain', 'tools'])
-
if not options.skip_toolchain:
+ BuildStepCleanPepperDirs(pepperdir, pepperdir_old)
+ BuildStepMakePepperDirs(pepperdir, ['include', 'toolchain', 'tools'])
BuildStepDownloadToolchains()
- BuildStepUntarToolchains(pepperdir, platform, arch, toolchains)
+ BuildStepUntarToolchains(pepperdir, arch, toolchains)
- BuildStepCopyTextFiles(pepperdir, pepper_ver, clnumber)
- BuildStepBuildToolchains(pepperdir, platform, toolchains)
- InstallCommonHeaders(os.path.join(pepperdir, 'include'))
+ BuildStepCopyTextFiles(pepperdir, pepper_ver, chrome_revision, nacl_revision)
+ BuildStepBuildToolchains(pepperdir, toolchains)
- BuildStepUpdateHelpers(pepperdir, platform, True)
- BuildStepUpdateUserProjects(pepperdir, platform, toolchains,
+ BuildStepUpdateHelpers(pepperdir, True)
+ BuildStepUpdateUserProjects(pepperdir, toolchains,
options.build_experimental, True)
# Ship with libraries prebuilt, so run that first.
- BuildStepBuildLibraries(pepperdir, platform, 'src')
+ BuildStepBuildLibraries(pepperdir, 'src')
GenerateNotice(pepperdir)
# Verify the SDK contains what we expect.
- BuildStepVerifyFilelist(pepperdir, platform)
+ BuildStepVerifyFilelist(pepperdir)
if not options.skip_tar:
BuildStepTarBundle(pepper_ver, tarfile)
- if options.build_ports and platform == 'linux':
+ if options.build_ports and getos.GetPlatform() == 'linux':
ports_tarfile = os.path.join(OUT_DIR, 'naclports.tar.bz2')
BuildStepSyncNaClPorts()
BuildStepBuildNaClPorts(pepper_ver, pepperdir)
@@ -1022,9 +943,11 @@ def main(args):
# Archive on non-trybots.
if options.archive:
- BuildStepArchiveBundle('build', pepper_ver, clnumber, tarfile)
- if options.build_ports and platform == 'linux':
- BuildStepArchiveBundle('naclports', pepper_ver, clnumber, ports_tarfile)
+ BuildStepArchiveBundle('build', pepper_ver, chrome_revision, nacl_revision,
+ tarfile)
+ if options.build_ports and getos.GetPlatform() == 'linux':
+ BuildStepArchiveBundle('naclports', pepper_ver, chrome_revision,
+ nacl_revision, ports_tarfile)
BuildStepArchiveSDKTools()
return 0
diff --git a/native_client_sdk/src/build_tools/build_version.py b/native_client_sdk/src/build_tools/build_version.py
index ffe8cf0d38..6e0aaa7421 100644
--- a/native_client_sdk/src/build_tools/build_version.py
+++ b/native_client_sdk/src/build_tools/build_version.py
@@ -62,3 +62,12 @@ def ChromeRevision():
The Chrome revision as a string. e.g. "12345"
'''
return lastchange.FetchVersionInfo(None).revision
+
+def NaClRevision():
+ '''Extract NaCl revision from svn.
+
+ Returns:
+ The NaCl revision as a string. e.g. "12345"
+ '''
+ nacl_dir = os.path.join(SRC_DIR, 'native_client')
+ return lastchange.FetchVersionInfo(None, nacl_dir).revision
diff --git a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
index 3c237f5b6d..9d415c9a02 100644
--- a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
+++ b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
@@ -35,16 +35,6 @@
},
{
"archives": [],
- "description": "Chrome 23 bundle, revision xxxxx",
- "name": "pepper_23",
- "recommended": "no",
- "repath": "pepper_23",
- "revision": 0,
- "stability": "post_stable",
- "version": 23
- },
- {
- "archives": [],
"description": "Chrome 24 bundle, revision xxxxx",
"name": "pepper_24",
"recommended": "no",
@@ -67,20 +57,20 @@
"archives": [],
"description": "Chrome 26 bundle, revision xxxxx",
"name": "pepper_26",
- "recommended": "yes",
+ "recommended": "no",
"repath": "pepper_26",
"revision": 0,
- "stability": "stable",
+ "stability": "post_stable",
"version": 26
},
{
"archives": [],
"description": "Chrome 27 bundle, revision xxxxx",
"name": "pepper_27",
- "recommended": "no",
+ "recommended": "yes",
"repath": "pepper_27",
"revision": 0,
- "stability": "beta",
+ "stability": "stable",
"version": 27
},
{
@@ -90,11 +80,21 @@
"recommended": "no",
"repath": "pepper_28",
"revision": 0,
- "stability": "dev",
+ "stability": "beta",
"version": 28
},
{
"archives": [],
+ "description": "Chrome 29 bundle, revision xxxxx",
+ "name": "pepper_29",
+ "recommended": "no",
+ "repath": "pepper_29",
+ "revision": 0,
+ "stability": "dev",
+ "version": 29
+ },
+ {
+ "archives": [],
"description": "Chrome Canary",
"name": "pepper_canary",
"recommended": "no",
diff --git a/native_client_sdk/src/build_tools/library.mk b/native_client_sdk/src/build_tools/library.mk
index 2ee3490006..1d44b3316b 100644
--- a/native_client_sdk/src/build_tools/library.mk
+++ b/native_client_sdk/src/build_tools/library.mk
@@ -1,78 +1,37 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
-
-#
-# GNU Make based build file. For details on GNU Make see:
-# http://www.gnu.org/software/make/manual/make.html
-#
-#
-
-# Default configuration
-#
-# By default we will build a Debug configuration using the GCC newlib toolchain
-# to override this, specify TOOLCHAIN=newlib|glibc or CONFIG=Debug|Release on
-# the make command-line or in this file prior to including common.mk. The
-# toolchain we use by default will be the first valid one listed
-VALID_TOOLCHAINS:={{' '.join(tools)}}
-
-
-[[# Only one target is allowed in a library project]]
[[target = targets[0] ]]
-[[name = target['NAME'] ]]
[[flags = ' '.join(target.get('CCFLAGS', []))]]
[[flags += ' '.join(target.get('CXXFLAGS', []))]]
-#
-# Get pepper directory for toolchain and includes.
-#
-# If NACL_SDK_ROOT is not set, then assume it can be found relative to
-# to this Makefile.
-#
-NACL_SDK_ROOT?=$(abspath $(CURDIR)/../..)
-EXTRA_INC_PATHS={{' '.join(target.get('INCLUDES', []))}}
+# GNU Makefile based on shared rules provided by the Native Client SDK.
+# See README.Makefiles for more details.
-include $(NACL_SDK_ROOT)/tools/common.mk
+VALID_TOOLCHAINS := {{' '.join(tools)}}
+NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../..)
+[[if 'INCLUDES' in target:]]
+EXTRA_INC_PATHS={{' '.join(target['INCLUDES'])}}
+[[]]
-#
-# Target Name
-#
-# The base name of the final library, also the name of the NMF file containing
-# the mapping between architecture and actual NEXE.
-#
-TARGET={{name}}
+include $(NACL_SDK_ROOT)/tools/common.mk
-#
-# List of sources to compile
-#
-SOURCES= \
+TARGET = {{target['NAME']}}
+CFLAGS = {{flags}}
+SOURCES = \
[[for source in sorted(target['SOURCES']):]]
{{source}} \
[[]]
+all: install
-
-#
-# Use the compile macro for each source.
+# Build rules generated by macros from common.mk:
#
-$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),{{flags}})))
-
-#
-# Use the lib macro for this target on the list of sources.
-#
-$(eval $(call LIB_RULE,{{name}},$(SOURCES)))
+$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
+$(eval $(call LIB_RULE,$(TARGET),$(SOURCES)))
[[if target['TYPE'] != 'static-lib':]]
ifeq ($(TOOLCHAIN),glibc)
-#
-# When building with GLIBC, also build a shared object version of the
-# library.
-#
-$(eval $(call SO_RULE,{{name}},$(SOURCES)))
+$(eval $(call SO_RULE,$(TARGET),$(SOURCES)))
endif
[[]]
-
-#
-# Install the resulting libraries in the SDK library directory.
-#
-all: install
diff --git a/native_client_sdk/src/build_tools/parse_dsc.py b/native_client_sdk/src/build_tools/parse_dsc.py
index fb04af8951..f26b908ef4 100755
--- a/native_client_sdk/src/build_tools/parse_dsc.py
+++ b/native_client_sdk/src/build_tools/parse_dsc.py
@@ -9,12 +9,13 @@ import optparse
import os
import sys
+VALID_TOOLCHAINS = ['newlib', 'glibc', 'pnacl', 'win', 'linux', 'mac']
+
# 'KEY' : ( <TYPE>, [Accepted Values], <Required?>)
DSC_FORMAT = {
'DISABLE': (bool, [True, False], False),
'DISABLE_PACKAGE': (bool, [True, False], False),
- 'TOOLS' : (list, ['newlib:arm', 'newlib:x64', 'newlib:x86', 'newlib',
- 'glibc', 'pnacl', 'win', 'linux'], True),
+ 'TOOLS' : (list, VALID_TOOLCHAINS, True),
'CONFIGS' : (list, ['Debug', 'Release'], False),
'PREREQ' : (list, '', False),
'TARGETS' : (list, {
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index 97d7cb8716..ffc959ac98 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -114,6 +114,31 @@ examples/demo/drive/Makefile
examples/demo/drive/manifest.json
[win]examples/demo/make.bat
examples/demo/Makefile
+examples/demo/earth/background.js
+examples/demo/earth/common.js
+examples/demo/earth/example.js
+examples/demo/earth/icon128.png
+examples/demo/earth/index.html
+examples/demo/earth/Makefile
+[win]examples/demo/earth/make.bat
+examples/demo/earth/manifest.json
+examples/demo/earth/earth.cc
+examples/demo/earth/earth.jpg
+examples/demo/earth/earthnight.jpg
+[win]examples/demo/flock/make.bat
+examples/demo/flock/Makefile
+examples/demo/flock/background.js
+examples/demo/flock/common.js
+examples/demo/flock/flock.cc
+examples/demo/flock/goose.cc
+examples/demo/flock/goose.h
+examples/demo/flock/icon128.png
+examples/demo/flock/images/flock_green.raw
+examples/demo/flock/index.html
+examples/demo/flock/manifest.json
+examples/demo/flock/sprite.cc
+examples/demo/flock/sprite.h
+examples/demo/flock/vector2.h
[win]examples/demo/life/make.bat
examples/demo/life/Makefile
examples/demo/life/background.js
@@ -214,9 +239,6 @@ examples/tutorial/load_progress/Makefile
examples/tutorial/load_progress/manifest.json
[win]examples/tutorial/make.bat
examples/tutorial/Makefile
-include/EGL/eglext.h
-include/EGL/egl.h
-include/EGL/eglplatform.h
include/error_handling/error_handling.h
include/error_handling/string_stream.h
include/GLES2/gl2ext.h
@@ -234,6 +256,7 @@ include/json/writer.h
include/KHR/khrplatform.h
include/nacl_io/error.h
include/nacl_io/inode_pool.h
+include/nacl_io/ioctl.h
include/nacl_io/kernel_handle.h
include/nacl_io/kernel_intercept.h
include/nacl_io/kernel_object.h
@@ -242,6 +265,7 @@ include/nacl_io/kernel_wrap.h
include/nacl_io/kernel_wrap_real.h
include/nacl_io/mount_dev.h
include/nacl_io/mount.h
+include/nacl_io/mount_factory.h
include/nacl_io/mount_html5fs.h
include/nacl_io/mount_http.h
include/nacl_io/mount_mem.h
@@ -257,12 +281,15 @@ include/nacl_io/osinttypes.h
include/nacl_io/osmman.h
include/nacl_io/osstat.h
include/nacl_io/ostypes.h
+include/nacl_io/osunistd.h
+include/nacl_io/osutime.h
include/nacl_io/path.h
include/nacl_io/pepper/all_interfaces.h
include/nacl_io/pepper/define_empty_macros.h
include/nacl_io/pepper_interface.h
include/nacl_io/pepper/undef_macros.h
include/nacl_io/real_pepper_interface.h
+include/nacl_io/typed_mount_factory.h
include/ppapi/c/dev/deprecated_bool.h
include/ppapi/c/dev/ppb_audio_input_dev.h
include/ppapi/c/dev/ppb_buffer_dev.h
@@ -275,25 +302,19 @@ include/ppapi/c/dev/ppb_find_dev.h
include/ppapi/c/dev/ppb_font_dev.h
include/ppapi/c/dev/ppb_gles_chromium_texture_mapping_dev.h
include/ppapi/c/dev/ppb_graphics_2d_dev.h
-include/ppapi/c/dev/ppb_host_resolver_dev.h
include/ppapi/c/dev/ppb_ime_input_event_dev.h
include/ppapi/c/dev/ppb_keyboard_input_event_dev.h
include/ppapi/c/dev/ppb_memory_dev.h
-include/ppapi/c/dev/ppb_net_address_dev.h
include/ppapi/c/dev/ppb_opengles2ext_dev.h
include/ppapi/c/dev/ppb_printing_dev.h
include/ppapi/c/dev/ppb_resource_array_dev.h
include/ppapi/c/dev/ppb_scrollbar_dev.h
-include/ppapi/c/dev/ppb_tcp_socket_dev.h
include/ppapi/c/dev/ppb_testing_dev.h
include/ppapi/c/dev/ppb_text_input_dev.h
include/ppapi/c/dev/ppb_trace_event_dev.h
include/ppapi/c/dev/ppb_truetype_font_dev.h
-include/ppapi/c/dev/ppb_udp_socket_dev.h
include/ppapi/c/dev/ppb_url_util_dev.h
-include/ppapi/c/dev/ppb_var_array_dev.h
include/ppapi/c/dev/ppb_var_deprecated.h
-include/ppapi/c/dev/ppb_var_dictionary_dev.h
include/ppapi/c/dev/ppb_video_capture_dev.h
include/ppapi/c/dev/ppb_video_decoder_dev.h
include/ppapi/c/dev/ppb_view_dev.h
@@ -333,6 +354,7 @@ include/ppapi/c/ppb_gamepad.h
include/ppapi/c/ppb_graphics_2d.h
include/ppapi/c/ppb_graphics_3d.h
include/ppapi/c/ppb.h
+include/ppapi/c/ppb_host_resolver.h
include/ppapi/c/ppb_image_data.h
include/ppapi/c/ppb_input_event.h
include/ppapi/c/ppb_instance.h
@@ -340,12 +362,18 @@ include/ppapi/c/ppb_message_loop.h
include/ppapi/c/ppb_messaging.h
include/ppapi/c/ppb_mouse_cursor.h
include/ppapi/c/ppb_mouse_lock.h
+include/ppapi/c/ppb_net_address.h
+include/ppapi/c/ppb_network_proxy.h
include/ppapi/c/pp_bool.h
include/ppapi/c/ppb_opengles2.h
+include/ppapi/c/ppb_tcp_socket.h
+include/ppapi/c/ppb_udp_socket.h
include/ppapi/c/ppb_url_loader.h
include/ppapi/c/ppb_url_request_info.h
include/ppapi/c/ppb_url_response_info.h
include/ppapi/c/ppb_var_array_buffer.h
+include/ppapi/c/ppb_var_array.h
+include/ppapi/c/ppb_var_dictionary.h
include/ppapi/c/ppb_var.h
include/ppapi/c/ppb_view.h
include/ppapi/c/ppb_websocket.h
@@ -380,22 +408,16 @@ include/ppapi/cpp/dev/file_chooser_dev.h
include/ppapi/cpp/dev/find_dev.h
include/ppapi/cpp/dev/font_dev.h
include/ppapi/cpp/dev/graphics_2d_dev.h
-include/ppapi/cpp/dev/host_resolver_dev.h
include/ppapi/cpp/dev/ime_input_event_dev.h
include/ppapi/cpp/dev/memory_dev.h
-include/ppapi/cpp/dev/net_address_dev.h
include/ppapi/cpp/dev/printing_dev.h
include/ppapi/cpp/dev/resource_array_dev.h
include/ppapi/cpp/dev/scriptable_object_deprecated.h
include/ppapi/cpp/dev/scrollbar_dev.h
include/ppapi/cpp/dev/selection_dev.h
-include/ppapi/cpp/dev/tcp_socket_dev.h
include/ppapi/cpp/dev/text_input_dev.h
include/ppapi/cpp/dev/truetype_font_dev.h
-include/ppapi/cpp/dev/udp_socket_dev.h
include/ppapi/cpp/dev/url_util_dev.h
-include/ppapi/cpp/dev/var_array_dev.h
-include/ppapi/cpp/dev/var_dictionary_dev.h
include/ppapi/cpp/dev/video_capture_client_dev.h
include/ppapi/cpp/dev/video_capture_dev.h
include/ppapi/cpp/dev/video_decoder_client_dev.h
@@ -425,6 +447,7 @@ include/ppapi/cpp/graphics_2d.h
include/ppapi/cpp/graphics_3d_client.h
include/ppapi/c/pp_graphics_3d.h
include/ppapi/cpp/graphics_3d.h
+include/ppapi/cpp/host_resolver.h
include/ppapi/cpp/image_data.h
include/ppapi/c/pp_input_event.h
include/ppapi/cpp/input_event.h
@@ -440,6 +463,8 @@ include/ppapi/cpp/module.h
include/ppapi/cpp/module_impl.h
include/ppapi/cpp/mouse_cursor.h
include/ppapi/cpp/mouse_lock.h
+include/ppapi/cpp/net_address.h
+include/ppapi/cpp/network_proxy.h
include/ppapi/cpp/output_traits.h
include/ppapi/cpp/pass_ref.h
include/ppapi/c/ppp_graphics_3d.h
@@ -457,13 +482,17 @@ include/ppapi/cpp/resource.h
include/ppapi/c/pp_size.h
include/ppapi/cpp/size.h
include/ppapi/c/pp_stdint.h
+include/ppapi/cpp/tcp_socket.h
include/ppapi/c/pp_time.h
include/ppapi/c/pp_touch_point.h
include/ppapi/cpp/touch_point.h
+include/ppapi/cpp/udp_socket.h
include/ppapi/cpp/url_loader.h
include/ppapi/cpp/url_request_info.h
include/ppapi/cpp/url_response_info.h
include/ppapi/cpp/var_array_buffer.h
+include/ppapi/cpp/var_array.h
+include/ppapi/cpp/var_dictionary.h
include/ppapi/c/pp_var.h
include/ppapi/cpp/var.h
include/ppapi/cpp/view.h
@@ -471,8 +500,10 @@ include/ppapi/cpp/websocket.h
include/ppapi/gles2/gl2ext_ppapi.h
include/ppapi/lib/gl/gles2/gl2ext_ppapi.h
include/ppapi_simple/ps.h
+include/ppapi_simple/ps_context_2d.h
include/ppapi_simple/ps_event.h
include/ppapi_simple/ps_instance.h
+include/ppapi_simple/ps_interface.h
include/ppapi_simple/ps_main.h
include/ppapi/utility/completion_callback_factory.h
include/ppapi/utility/completion_callback_factory_thread_traits.h
@@ -488,9 +519,11 @@ include/ppapi/utility/websocket/websocket_api.h
[win]include/win/pthread.h
[win]include/win/sched.h
[win]include/win/semaphore.h
+include/sdk_util/atomicops.h
include/sdk_util/auto_lock.h
include/sdk_util/macros.h
include/sdk_util/ref_object.h
+include/sdk_util/scoped_ref.h
include/sdk_util/thread_safe_queue.h
include/sdk_util/thread_pool.h
lib/glibc_x86_32/Debug/libjsoncpp.a
@@ -550,12 +583,12 @@ lib/glibc_x86_64/Release/libppapi_simple.so
lib/glibc_x86_64/Release/libsdk_util.a
lib/glibc_x86_64/Release/libsdk_util.so
[linux]lib/${PLATFORM}_host/Debug/libjsoncpp.a
-[linux]lib/${PLATFORM}_host/Debug/libppapi.a
+[linux,mac]lib/${PLATFORM}_host/Debug/libppapi.a
[linux]lib/${PLATFORM}_host/Debug/libppapi_cpp.a
[linux]lib/${PLATFORM}_host/Debug/libppapi_cpp_private.a
[linux]lib/${PLATFORM}_host/Debug/libppapi_gles2.a
[linux]lib/${PLATFORM}_host/Release/libjsoncpp.a
-[linux]lib/${PLATFORM}_host/Release/libppapi.a
+[linux,mac]lib/${PLATFORM}_host/Release/libppapi.a
[linux]lib/${PLATFORM}_host/Release/libppapi_cpp.a
[linux]lib/${PLATFORM}_host/Release/libppapi_cpp_private.a
[linux]lib/${PLATFORM}_host/Release/libppapi_gles2.a
@@ -565,6 +598,7 @@ lib/glibc_x86_64/Release/libsdk_util.so
[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.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/Release/jsoncpp.lib
[win]lib/${PLATFORM}_x86_32_host/Release/nacl_io.lib
@@ -572,6 +606,7 @@ lib/glibc_x86_64/Release/libsdk_util.so
[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.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/Debug/sdk_util.lib
[win]lib/${PLATFORM}_x86_32_host/Release/sdk_util.lib
@@ -640,6 +675,7 @@ lib/pnacl/Release/libsdk_util.a
LICENSE
NOTICE
README
+README.Makefiles
src/error_handling/error_handling.c
[win]src/error_handling/make.bat
src/error_handling/Makefile
@@ -682,43 +718,81 @@ src/nacl_io/nacl_io.cc
src/nacl_io/path.cc
src/nacl_io/pepper_interface.cc
src/nacl_io/real_pepper_interface.cc
+src/ppapi_cpp/alarms_dev.cc
src/ppapi_cpp/array_output.cc
src/ppapi_cpp/audio.cc
src/ppapi_cpp/audio_config.cc
+src/ppapi_cpp/audio_input_dev.cc
+src/ppapi_cpp/buffer_dev.cc
src/ppapi_cpp/core.cc
+src/ppapi_cpp/crypto_dev.cc
+src/ppapi_cpp/cursor_control_dev.cc
+src/ppapi_cpp/device_ref_dev.cc
src/ppapi_cpp/directory_entry.cc
+src/ppapi_cpp/event_base.cc
+src/ppapi_cpp/events_dev.cc
+src/ppapi_cpp/file_chooser_dev.cc
src/ppapi_cpp/file_io.cc
src/ppapi_cpp/file_ref.cc
src/ppapi_cpp/file_system.cc
+src/ppapi_cpp/find_dev.cc
+src/ppapi_cpp/font_dev.cc
src/ppapi_cpp/fullscreen.cc
src/ppapi_cpp/graphics_2d.cc
+src/ppapi_cpp/graphics_2d_dev.cc
src/ppapi_cpp/graphics_3d.cc
src/ppapi_cpp/graphics_3d_client.cc
+src/ppapi_cpp/host_resolver.cc
src/ppapi_cpp/image_data.cc
+src/ppapi_cpp/ime_input_event_dev.cc
src/ppapi_cpp/input_event.cc
src/ppapi_cpp/instance.cc
src/ppapi_cpp/instance_handle.cc
src/ppapi_cpp/lock.cc
-[win]src/ppapi_cpp/make.bat
src/ppapi_cpp/Makefile
+src/ppapi_cpp/memory_dev.cc
src/ppapi_cpp/message_loop.cc
src/ppapi_cpp/module.cc
src/ppapi_cpp/mouse_cursor.cc
src/ppapi_cpp/mouse_lock.cc
+src/ppapi_cpp/net_address.cc
+src/ppapi_cpp/network_proxy.cc
src/ppapi_cpp/paint_aggregator.cc
src/ppapi_cpp/paint_manager.cc
src/ppapi_cpp/ppp_entrypoints.cc
+src/ppapi_cpp/printing_dev.cc
src/ppapi_cpp/rect.cc
+src/ppapi_cpp/resource_array_dev.cc
src/ppapi_cpp/resource.cc
+src/ppapi_cpp/scriptable_object_deprecated.cc
+src/ppapi_cpp/scrollbar_dev.cc
+src/ppapi_cpp/selection_dev.cc
src/ppapi_cpp/simple_thread.cc
+src/ppapi_cpp/socket_dev.cc
+src/ppapi_cpp/tcp_socket.cc
+src/ppapi_cpp/text_input_dev.cc
+src/ppapi_cpp/truetype_font_dev.cc
+src/ppapi_cpp/udp_socket.cc
src/ppapi_cpp/url_loader.cc
src/ppapi_cpp/url_request_info.cc
src/ppapi_cpp/url_response_info.cc
+src/ppapi_cpp/url_util_dev.cc
src/ppapi_cpp/var_array_buffer.cc
+src/ppapi_cpp/var_array.cc
src/ppapi_cpp/var.cc
+src/ppapi_cpp/var_dictionary.cc
+src/ppapi_cpp/video_capture_client_dev.cc
+src/ppapi_cpp/video_capture_dev.cc
+src/ppapi_cpp/video_decoder_client_dev.cc
+src/ppapi_cpp/video_decoder_dev.cc
src/ppapi_cpp/view.cc
+src/ppapi_cpp/view_dev.cc
src/ppapi_cpp/websocket_api.cc
src/ppapi_cpp/websocket.cc
+src/ppapi_cpp/widget_client_dev.cc
+src/ppapi_cpp/widget_dev.cc
+src/ppapi_cpp/zoom_dev.cc
+[win]src/ppapi_cpp/make.bat
src/ppapi_gles2/gl2ext_ppapi.c
src/ppapi_gles2/gles2.c
[win]src/ppapi_gles2/make.bat
@@ -726,8 +800,10 @@ src/ppapi_gles2/Makefile
[win]src/ppapi_simple/make.bat
src/ppapi_simple/Makefile
src/ppapi_simple/ps.cc
+src/ppapi_simple/ps_context_2d.cc
src/ppapi_simple/ps_event.cc
src/ppapi_simple/ps_instance.cc
+src/ppapi_simple/ps_interface.cc
src/ppapi_simple/ps_main.cc
src/ppapi_cpp_private/Makefile
[win]src/ppapi_cpp_private/make.bat
@@ -885,8 +961,8 @@ src/ppapi_cpp_private/x509_certificate_private.cc
[win]src/pthread/signal.c
[win]src/pthread/w32_CancelableWait.c
[win]src/ppapi/make.bat
-[win,linux]src/ppapi/Makefile
-[win,linux]src/ppapi/ppapi_externs.c
+src/ppapi/Makefile
+src/ppapi/ppapi_externs.c
src/sdk_util/Makefile
[win]src/sdk_util/make.bat
src/sdk_util/thread_pool.cc
@@ -999,6 +1075,7 @@ tools/create_html.py
tools/create_nmf.py
tools/decode_dump.py
[linux,mac]tools/dump_syms
+tools/fix_deps.py
[linux,mac]tools/minidump_stackwalk
[linux,mac]tools/minidump_dump
tools/genhttpfs.py
diff --git a/native_client_sdk/src/build_tools/template.mk b/native_client_sdk/src/build_tools/template.mk
index 19583eadd2..4d76ec5bdc 100644
--- a/native_client_sdk/src/build_tools/template.mk
+++ b/native_client_sdk/src/build_tools/template.mk
@@ -1,105 +1,68 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
-#
-# GNU Make based build file. For details on GNU Make see:
-# http://www.gnu.org/software/make/manual/make.html
-#
-
-
-#
-# Default configuration
-#
-# By default we will build a Debug configuration using the GCC newlib toolchain
-# to override this, specify TOOLCHAIN=newlib|glibc or CONFIG=Debug|Release on
-# the make command-line or in this file prior to including common.mk. The
-# toolchain we use by default will be the first valid one listed
-VALID_TOOLCHAINS:={{' '.join(tools)}}
+# GNU Makefile based on shared rules provided by the Native Client SDK.
+# See README.Makefiles for more details.
+VALID_TOOLCHAINS := {{' '.join(tools)}}
{{pre}}
-#
-# Get pepper directory for toolchain and includes.
-#
-# If NACL_SDK_ROOT is not set, then assume it can be found relative to
-# to this Makefile.
-#
-NACL_SDK_ROOT?=$(abspath $(CURDIR)/{{rel_sdk}})
+NACL_SDK_ROOT ?= $(abspath $(CURDIR)/{{rel_sdk}})
include $(NACL_SDK_ROOT)/tools/common.mk
-
-#
-# Target Name
-#
-# The base name of the final NEXE, also the name of the NMF file containing
-# the mapping between architecture and actual NEXE.
-#
-TARGET={{targets[0]['NAME']}}
-
-#
-# List of sources to compile
-#
+TARGET = {{targets[0]['NAME']}}
+[[if targets[0].get('DEPS'):]]
+DEPS = {{' '.join(targets[0].get('DEPS', []))}}
+LIBS = $(DEPS) {{' '.join(targets[0].get('LIBS'))}}
+[[else:]]
+LIBS = {{' '.join(targets[0].get('LIBS'))}}
+[[]]
[[for target in targets:]]
-{{target['NAME']}}_SOURCES= \
-[[ for source in sorted(target['SOURCES']):]]
-[[ if not source.endswith('.h'):]]
- {{source}} \
+[[ source_list = (s for s in sorted(target['SOURCES']) if not s.endswith('.h'))]]
+[[ source_list = ' \\\n '.join(source_list)]]
+[[ sources = target['NAME'] + '_SOURCES']]
+[[ cflags = target['NAME'] + '_CFLAGS']]
+[[ flags = ' '.join(target.get('CCFLAGS', []))]]
+[[ flags += ' '.join(target.get('CXXFLAGS', []))]]
+[[ if len(targets) == 1:]]
+[[ sources = 'SOURCES']]
+[[ cflags = 'CFLAGS']]
[[ ]]
-
+[[ if flags:]]
+{{cflags}} = {{flags}}
+[[ ]]
+{{sources}} = {{source_list}}
[[]]
+# Build rules generated by macros from common.mk:
-#
-# List of libraries to link against. Unlike some tools, the GCC and LLVM
-# based tools require libraries to be specified in the correct order. The
-# order should be symbol reference followed by symbol definition, with direct
-# sources to the link (object files) are left most. In this case:
-# hello_world -> ppapi_main -> ppapi_cpp -> ppapi -> pthread -> libc
-# Notice that libc is implied and come last through standard compiler/link
-# switches.
-#
-# We break this list down into two parts, the set we need to rebuild (DEPS)
-# and the set we do not. This example does not have a any additional library
-# dependencies.
-#
-DEPS={{' '.join(targets[0].get('DEPS', []))}}
-LIBS=$(DEPS) {{' '.join(targets[0].get('LIBS'))}}
-
-
-#
-# Use the library dependency macro for each dependency
-#
+[[if targets[0].get('DEPS'):]]
$(foreach dep,$(DEPS),$(eval $(call DEPEND_RULE,$(dep))))
-
-#
-# Use the compile macro for each source.
-#
-[[for target in targets:]]
-[[ name = target['NAME'] ]]
-[[ flags = ' '.join(target.get('CCFLAGS', []))]]
-[[ flags += ' '.join(target.get('CXXFLAGS', []))]]
-$(foreach src,$({{name}}_SOURCES),$(eval $(call COMPILE_RULE,$(src),{{flags}})))
+[[if len(targets) > 1:]]
+[[ for target in targets:]]
+[[ name = target['NAME'] ]]
+$(foreach src,$({{name}}_SOURCES),$(eval $(call COMPILE_RULE,$(src),$({{name}}_CFLAGS))))
+[[else:]]
+$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
[[]]
-#
-# Use the link macro for this target on the list of sources.
-#
[[for target in targets:]]
+[[ sources = target['NAME'] + '_SOURCES']]
[[ name = target['NAME'] ]]
+[[ if len(targets) == 1:]]
+[[ sources = 'SOURCES']]
+[[ name = '$(TARGET)']]
[[ if target['TYPE'] == 'so':]]
-$(eval $(call SO_RULE,{{name}},$({{name}}_SOURCES)))
+$(eval $(call SO_RULE,{{name}},$({{sources}})))
[[ elif target['TYPE'] == 'so-standalone':]]
-$(eval $(call SO_RULE,{{name}},$({{name}}_SOURCES),,,1))
+$(eval $(call SO_RULE,{{name}},$({{sources}}),,,1))
[[ else:]]
ifeq ($(CONFIG),Release)
-$(eval $(call LINK_RULE,{{name}}_unstripped,$({{name}}_SOURCES),$(LIBS),$(DEPS)))
+$(eval $(call LINK_RULE,{{name}}_unstripped,$({{sources}}),$(LIBS),$(DEPS)))
$(eval $(call STRIP_RULE,{{name}},{{name}}_unstripped))
else
-$(eval $(call LINK_RULE,{{name}},$({{name}}_SOURCES),$(LIBS),$(DEPS)))
+$(eval $(call LINK_RULE,{{name}},$({{sources}}),$(LIBS),$(DEPS)))
endif
[[]]
-#
-# Specify the NMF to be created with no additional arguments.
-#
$(eval $(call NMF_RULE,$(TARGET),)){{post}}
diff --git a/native_client_sdk/src/build_tools/test_sdk.py b/native_client_sdk/src/build_tools/test_sdk.py
index 0d8fc4a984..c2b7b7d4bb 100755
--- a/native_client_sdk/src/build_tools/test_sdk.py
+++ b/native_client_sdk/src/build_tools/test_sdk.py
@@ -25,20 +25,9 @@ sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
import getos
-TEST_EXAMPLE_LIST = [
- 'nacl_io_test',
-]
-
-TEST_LIBRARY_LIST = [
- 'gmock',
- 'gtest',
- 'gtest_ppapi',
-]
-
-
-def BuildStepBuildExamples(pepperdir, platform):
+def BuildStepBuildExamples(pepperdir):
for config in ('Debug', 'Release'):
- build_sdk.BuildStepMakeAll(pepperdir, platform, 'examples',
+ build_sdk.BuildStepMakeAll(pepperdir, 'examples',
'Build Examples (%s)' % config,
deps=False, config=config)
@@ -54,18 +43,17 @@ def BuildStepCopyTests(pepperdir, toolchains, build_experimental):
filters['EXPERIMENTAL'] = False
tree = parse_dsc.LoadProjectTree(SDK_SRC_DIR, filters=filters)
- platform = getos.GetPlatform()
- build_projects.UpdateHelpers(pepperdir, platform, clobber=False)
- build_projects.UpdateProjects(pepperdir, platform, tree, clobber=False,
+ build_projects.UpdateHelpers(pepperdir, clobber=False)
+ build_projects.UpdateProjects(pepperdir, tree, clobber=False,
toolchains=toolchains)
-def BuildStepBuildTests(pepperdir, platform):
+def BuildStepBuildTests(pepperdir):
for config in ('Debug', 'Release'):
- build_sdk.BuildStepMakeAll(pepperdir, platform, 'testlibs',
+ build_sdk.BuildStepMakeAll(pepperdir, 'testlibs',
'Build Test Libraries (%s)' % config,
config=config)
- build_sdk.BuildStepMakeAll(pepperdir, platform, 'tests',
+ build_sdk.BuildStepMakeAll(pepperdir, 'tests',
'Build Tests (%s)' % config,
deps=False, config=config)
@@ -74,6 +62,7 @@ def main(args):
parser = optparse.OptionParser()
parser.add_option('--experimental', help='build experimental tests',
action='store_true')
+ parser.add_option('--verbose', help='Verbose output', action='store_true')
if 'NACL_SDK_ROOT' in os.environ:
# We don't want the currently configured NACL_SDK_ROOT to have any effect
@@ -82,15 +71,17 @@ def main(args):
options, args = parser.parse_args(args[1:])
- platform = getos.GetPlatform()
pepper_ver = str(int(build_version.ChromeMajorVersion()))
pepperdir = os.path.join(OUT_DIR, 'pepper_' + pepper_ver)
toolchains = ['newlib', 'glibc', 'pnacl']
- toolchains.append(platform)
+ toolchains.append(getos.GetPlatform())
+
+ if options.verbose:
+ build_projects.verbose = True
- BuildStepBuildExamples(pepperdir, platform)
+ BuildStepBuildExamples(pepperdir)
BuildStepCopyTests(pepperdir, toolchains, options.experimental)
- BuildStepBuildTests(pepperdir, platform)
+ BuildStepBuildTests(pepperdir)
return 0
diff --git a/native_client_sdk/src/build_tools/tests/verify_filelist_test.py b/native_client_sdk/src/build_tools/tests/verify_filelist_test.py
index a8ca2f51ee..a1da59150e 100755
--- a/native_client_sdk/src/build_tools/tests/verify_filelist_test.py
+++ b/native_client_sdk/src/build_tools/tests/verify_filelist_test.py
@@ -15,7 +15,7 @@ import verify_filelist
def Verify(platform, rules_contents, directory_list):
- rules = verify_filelist.Rules(platform, 'test', rules_contents)
+ rules = verify_filelist.Rules('test', platform, rules_contents)
rules.VerifyDirectoryList(directory_list)
diff --git a/native_client_sdk/src/build_tools/verify_filelist.py b/native_client_sdk/src/build_tools/verify_filelist.py
index b97e4205ec..f43e99f9bb 100755
--- a/native_client_sdk/src/build_tools/verify_filelist.py
+++ b/native_client_sdk/src/build_tools/verify_filelist.py
@@ -32,15 +32,16 @@ class VerifyException(Exception):
pass
class Rules(object):
- def __init__(self, platform, filename, contents=None):
+ def __init__(self, filename, platform=None, contents=None):
self.glob_prefixes = []
self.exact_filenames = set()
self.filename = filename
- self.platform = platform
- self.exe_ext = '.exe' if platform == 'win' else ''
+ self.platform = platform or getos.GetPlatform()
+ self.exe_ext = '.exe' if self.platform == 'win' else ''
- if platform not in VALID_PLATFORMS:
- raise ParseException(self.filename, 1, 'Unknown platform %s' % platform)
+ if self.platform not in VALID_PLATFORMS:
+ raise ParseException(self.filename, 1,
+ 'Unknown platform %s' % self.platform)
if not contents:
with open(filename) as f:
@@ -141,8 +142,8 @@ def GetDirectoryList(directory_path):
return result
-def Verify(platform, rule_path, directory_path):
- rules = Rules(platform, rule_path)
+def Verify(rule_path, directory_path, platform=None):
+ rules = Rules(rule_path, platform=platform)
directory_list = GetDirectoryList(directory_path)
rules.VerifyDirectoryList(directory_list)
@@ -164,7 +165,7 @@ def main(args):
platform = getos.GetPlatform()
try:
- return Verify(platform, rule_path, directory_path)
+ return Verify(rule_path, directory_path, platform)
except ParseException, e:
print >> sys.stderr, 'Error parsing rules:\n', e
return 1
diff --git a/native_client_sdk/src/documentation/Doxyfile b/native_client_sdk/src/documentation/Doxyfile
deleted file mode 100644
index 54b8213b28..0000000000
--- a/native_client_sdk/src/documentation/Doxyfile
+++ /dev/null
@@ -1,1663 +0,0 @@
-# Doxyfile 1.7.2
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
-
-DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-
-PROJECT_NAME = "c_salt"
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY = scons-out/documentation
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
-
-OUTPUT_LANGUAGE = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
-
-STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
-
-JAVADOC_AUTOBRIEF = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-
-INHERIT_DOCS = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
-
-SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE = 8
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
-
-OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
-
-OPTIMIZE_OUTPUT_VHDL = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
-
-EXTENSION_MAPPING =
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-
-BUILTIN_STL_SUPPORT = YES
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-
-CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
-
-SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
-SUBGROUPING = YES
-
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-
-TYPEDEF_HIDES_STRUCT = NO
-
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
-
-SYMBOL_CACHE_SIZE = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
-EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespaces are hidden.
-
-EXTRACT_ANON_NSPACES = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES = YES
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
-SHOW_INCLUDE_FILES = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
-
-SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES = YES
-
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES = NO
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
-
-SHOW_FILES = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page.
-# This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
-
-SHOW_NAMESPACES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
-
-FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. The create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
-
-LAYOUT_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
-WARNINGS = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR = YES
-
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
-
-WARN_NO_PARAMDOC = YES
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT = ./c_salt \
- ./examples \
- ./documentation
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
-
-INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.vhd *.vhdl
-
-FILE_PATTERNS = *.h \
- *.dox
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix filesystem feature) are excluded
-# from the input.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS = _*.h
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-
-EXCLUDE_SYMBOLS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS = *
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
-IMAGE_PATH = ./documentation/images-dox
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be
-# ignored.
-
-INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.
-# Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.
-# The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
-# is applied to all files.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
-REFERENCES_RELATION = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
-
-USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX = YES
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
-
-HTML_HEADER = documentation/header.dox
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER = documentation/footer.dox
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET = documentation/stylesheet-dox.css
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the stylesheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
-
-HTML_COLORSTYLE_HUE = 30
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
-
-HTML_COLORSTYLE_SAT = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
-
-HTML_TIMESTAMP = YES
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS = NO
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded. For this to work a browser that supports
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
-
-HTML_DYNAMIC_SECTIONS = NO
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-
-GENERATE_DOCSET = NO
-
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-
-CHM_FILE =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
-
-CHM_INDEX_ENCODING =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
-
-QHP_NAMESPACE = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
-
-QHP_SECT_FILTER_ATTRS =
-
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-# will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-
-DISABLE_INDEX = NO
-
-# This tag can be used to set the number of enum values (range [0,1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-# Note that a value of 0 will completely suppress the enum values from appearing in the overview section.
-
-ENUM_VALUES_PER_LINE = 4
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-
-GENERATE_TREEVIEW = NO
-
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES = NO
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
-TREEVIEW_WIDTH = 251
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
-
-FORMULA_TRANSPARENT = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you also need to install MathJax separately and
-# configure the path to it using the MATHJAX_RELPATH option.
-
-USE_MATHJAX = NO
-
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the mathjax.org site, so you can quickly see the result without installing
-# MathJax, but it is strongly recommended to install a local copy of MathJax
-# before deployment.
-
-MATHJAX_RELPATH = http://www.mathjax.org/mathjax
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
-
-SEARCHENGINE = NO
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
-
-SERVER_BASED_SEARCH = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS = YES
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
-USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
-LATEX_HIDE_INDICES = NO
-
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
-
-LATEX_SOURCE_CODE = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.
-# This is useful
-# if you want to understand what is going on.
-# On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION = YES
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF = YES
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
-
-PREDEFINED = __native_client__ \
- DOXYGEN_SHOULD_SKIP_THIS \
- __attribute__(x)= \
- EXTERN_C_BEGIN= \
- EXTERN_C_END=
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse
-# the parser if not removed.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-#
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-#
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
-EXTERNAL_GROUPS = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
-
-CLASS_DIAGRAMS = NO
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT = YES
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
-
-DOT_NUM_THREADS = 0
-
-# By default doxygen will write a font called FreeSans.ttf to the output
-# directory and reference it in all dot files that doxygen generates. This
-# font does not include all possible unicode characters however, so when you need
-# these (or just want a differently looking font) you can specify the font name
-# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
-# which can be done by putting it in a standard location or by setting the
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
-# containing the font.
-
-DOT_FONTNAME = FreeSans.ttf
-
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the output directory to look for the
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a
-# different font using DOT_FONTNAME you can set the path where dot
-# can find it using this tag.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
-
-GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-
-UML_LOOK = YES
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
-INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
-
-CALL_GRAPH = YES
-
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
-
-CALLER_GRAPH = YES
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
-DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif.
-# If left blank png will be used.
-
-DOT_IMAGE_FORMAT = png
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
-DOTFILE_DIRS =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
-# \mscfile command).
-
-MSCFILE_DIRS =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-
-DOT_GRAPH_MAX_NODES = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
-MAX_DOT_GRAPH_DEPTH = 10
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
-
-DOT_TRANSPARENT = YES
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
-
-DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
-DOT_CLEANUP = YES
diff --git a/native_client_sdk/src/documentation/build.scons b/native_client_sdk/src/documentation/build.scons
deleted file mode 100644
index b4751f83a1..0000000000
--- a/native_client_sdk/src/documentation/build.scons
+++ /dev/null
@@ -1,28 +0,0 @@
-#! -*- python -*-
-#
-# Copyright (c) 2010 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.
-
-"""scons script for building the Doxygen-based documentation for c_salt"""
-
-Import('env')
-
-env.SetDefault(DOXYGEN=ARGUMENTS.get('DOXYGEN', 'doxygen'))
-
-# Gate on host platform rather than target, since all are supported.
-if env['PLATFORM'] in ['win32', 'cygwin']:
- env['ENV']['NACL_SDK_PLATFORM'] = 'windows'
-elif env['PLATFORM'] in ['darwin']:
- env['ENV']['NACL_SDK_PLATFORM'] = 'mac'
-else:
- env['ENV']['NACL_SDK_PLATFORM'] = 'linux'
-
-# The output is generated into scons-out/doc (c.f. Doxyfile).
-# Point your browser at scons-out/doc/html/index.html
-node = env.Command(
- target='doxygen.log',
- source='Doxyfile',
- action='${DOXYGEN} documentation/Doxyfile 2>&1 > ${TARGET}')
-AlwaysBuild(node)
-env.AddNodeAliases(node, [], 'docs')
diff --git a/native_client_sdk/src/documentation/check.sh b/native_client_sdk/src/documentation/check.sh
deleted file mode 100755
index ce3b49f4c2..0000000000
--- a/native_client_sdk/src/documentation/check.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-
-# simple script to check html via tidy. Either specify html files on
-# command line or rely on default which checks all html files in
-# current directory
-set -o nounset
-set -o errexit
-
-
-CheckFile () {
- echo "========================================"
- echo "checking $1"
- echo "========================================"
- tidy -e -q $1
-}
-
-
-if [ $# -eq 0 ] ; then
- for file in *.html ; do
- CheckFile ${file}
- done
-else
- for file in $* ; do
- CheckFile ${file}
- done
-fi
diff --git a/native_client_sdk/src/documentation/footer.dox b/native_client_sdk/src/documentation/footer.dox
deleted file mode 100644
index 8a944c13e4..0000000000
--- a/native_client_sdk/src/documentation/footer.dox
+++ /dev/null
@@ -1,22 +0,0 @@
- <p id="license">
- Except as otherwise
- <a href="http://code.google.com/policies.html#restrictions">noted</a>,
- the content of this page is licensed under a
- <a href="http://www.google.com/url?sa=D&amp;q=http%3A%2F%2Fcreativecommons.org/licenses/by/2.5/">Creative Commons
- Attribution 2.5 license</a>.
- </p>
-
- <p align="center"><b>Warning: This API is
- currently in development and is subject to change.</b></p>
-
- <address>
- &copy;2010 Google
- </address>
-
- <address>
- Generated $date by
- <a href="http://www.doxygen.org/index.html">doxygen</a> $doxygenversion
- </address>
-
- </body>
-</html>
diff --git a/native_client_sdk/src/documentation/header.dox b/native_client_sdk/src/documentation/header.dox
deleted file mode 100644
index a261dd3170..0000000000
--- a/native_client_sdk/src/documentation/header.dox
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
- <title>$title</title>
- <link href="./tabs.css" rel="stylesheet" type="text/css">
- <link href="./stylesheet-dox.css" rel="stylesheet" type="text/css">
- <link href="./stylesheet-dox-all.css" rel="stylesheet" type="text/css">
- </head>
- <body>
- <div id="toplinks">
- <a href="http://code.google.com/p/nativeclient-sdk/">
- Native Client SDK homepage</a>
- </div>
diff --git a/native_client_sdk/src/documentation/images-dox/README.txt b/native_client_sdk/src/documentation/images-dox/README.txt
deleted file mode 100644
index 9a9e18c725..0000000000
--- a/native_client_sdk/src/documentation/images-dox/README.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This directory holds all images that go into the doxygen-generated
-API reference doc. To include an image, use code like the following:
-
-@image html figure.jpg
-
-If you want a caption, specify it like this:
-
-@image html figure.jpg "Test image"
-
diff --git a/native_client_sdk/src/documentation/index.dox b/native_client_sdk/src/documentation/index.dox
deleted file mode 100644
index 2af602e99f..0000000000
--- a/native_client_sdk/src/documentation/index.dox
+++ /dev/null
@@ -1,46 +0,0 @@
-/** @mainpage c_salt Reference Documentation
-
- This reference documentation describes the c_salt API, which is
- an open-source API for browser plugins that layers on
- top of the Pepper API and the NPAPI.
- You can use the c_salt API
- in <a href="http://code.google.com/p/nativeclient-sdk">Native Client</a>
- modules to communicate with the Google Chrome browser.
- This page has the following contents:
-
- - @ref reading
- - @ref modules
- - @ref about
-
-
- @section reading Before you start
-
- This documentation assumes that you have read and understood
- the following pages in the Native Client SDK project:
-
- - <a href="http://code.google.com/p/nativeclient-sdk/">Getting started</a>
-
-
- @section modules API categories
-
-The c_salt API consists of a C++ API in the c_salt namespace.
-
-(Details TBD)...
-
-
- @section about About this doc
-
- <p>
- The tabs at the top of each page take you to the following sections.
- </p>
-
- - <b>Main Page</b>: This page
- - <a href="modules.html"><b>Modules</b></a>: Lets you find API by functional area
- - <a href="annotated.html"><b>Data Structures</b></a>:
- List of classes and data structures in c_salt.
- - <a href="files.html"><b>Files</b></a>:
- The header files used to generate this documentation,
- with file descriptions and links to generated doc.
- Don't miss the <a href="globals.html">File member index</a>.
-
- */ \ No newline at end of file
diff --git a/native_client_sdk/src/documentation/modules.dox b/native_client_sdk/src/documentation/modules.dox
deleted file mode 100644
index 3923ccb5e9..0000000000
--- a/native_client_sdk/src/documentation/modules.dox
+++ /dev/null
@@ -1,22 +0,0 @@
-// This is a doxygen file that describes the documentation groups
-
-/**
-
-@defgroup c_salt C Salt C++ API
-Description of c_salt C++ API goes here.
-
-@defgroup examples c_salt examples
-Here are the examples that use c_salt
-
-@defgroup npapi NPAPI bindings for c_salt
-@ingroup c_salt
-Defines the NPAPI bindings for c_salt
-
-@defgroup ppapi PPAPI bindings for c_salt
-@ingroup c_salt
-Defines the PPAPI (i.e. Pepper2) bindings for c_salt
-
-@defgroup tests c_salt integration and unit tests
-Integration and unit tests for c_salt.
-
-*/
diff --git a/native_client_sdk/src/documentation/stylesheet-dox.css b/native_client_sdk/src/documentation/stylesheet-dox.css
deleted file mode 100644
index 81d1a4251c..0000000000
--- a/native_client_sdk/src/documentation/stylesheet-dox.css
+++ /dev/null
@@ -1,478 +0,0 @@
-body, table, div, p, dl {
- font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
- font-size: 12px;
-}
-
-/* @group Heading Levels */
-
-h1 {
- text-align: center;
- font-size: 150%;
-}
-
-h1 a, h2 a, h3 a, h4 a {
- font-weight:bold;
-}
-
-h2 {
- font-size: 120%;
- margin-top: 2.0em;
- margin-bottom: 0.5em;
-}
-
-h3 {
- font-size: 100%;
-}
-
-div.contents {
- margin-top: 2.0em;
-}
-
-/* @end */
-
-caption {
- font-weight: bold;
- font-size: 9px;
-}
-
-div.qindex, div.navpath, div.navtab{
- background-color: #e8eef2;
- border: 1px solid #84b0c7;
- text-align: center;
- margin: 2px;
- padding: 2px;
-}
-
-div.qindex, div.navpath {
- width: 100%;
- line-height: 140%;
-}
-
-div.navtab {
- margin-right: 15px;
-}
-
-/* @group Link Styling */
-
-a {
- color: #153788;
- font-weight: normal;
- text-decoration: none;
-}
-
-.contents a:visited {
- color: #1b77c5;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-a.qindex {
- font-weight: bold;
-}
-
-a.qindexHL {
- font-weight: bold;
- background-color: #6666cc;
- color: #ffffff;
- border: 1px double #9295C2;
-}
-
-a.el {
- font-weight: bold;
-}
-
-a.elRef {
-}
-
-a.code {
-}
-
-a.codeRef {
-}
-
-/* @end */
-
-dl.el {
- margin-left: -1cm;
-}
-
-.fragment {
- font-family: monospace, fixed;
- font-size: 105%;
-}
-
-pre.fragment {
- border: 1px solid #CCCCCC;
- background-color: #f5f5f5;
- padding: 4px 6px;
- margin: 4px 8px 4px 2px;
-}
-
-div.ah {
- background-color: black;
- font-weight: bold;
- color: #ffffff;
- margin-bottom: 3px;
- margin-top: 3px
-}
-
-div.groupHeader {
- margin-left: 16px;
- margin-top: 12px;
- margin-bottom: 6px;
- font-weight: bold;
-}
-
-div.groupText {
- margin-left: 16px;
- font-style: italic;
-}
-
-body {
- background: white;
- color: black;
- margin-right: 20px;
- margin-left: 20px;
-}
-
-td.indexkey {
- background-color: #e8eef2;
- font-weight: bold;
- border: 1px solid #CCCCCC;
- margin: 2px 0px 2px 0;
- padding: 2px 10px;
-}
-
-td.indexvalue {
- background-color: #e8eef2;
- border: 1px solid #CCCCCC;
- padding: 2px 10px;
- margin: 2px 0px;
-}
-
-tr.memlist {
- background-color: #f0f0f0;
-}
-
-p.formulaDsp {
- text-align: center;
-}
-
-img.formulaDsp {
-}
-
-img.formulaInl {
- vertical-align: middle;
-}
-
-/* @group Code Colorization */
-
-span.keyword {
- color: #008000
-}
-
-span.keywordtype {
- color: #604020
-}
-
-span.keywordflow {
- color: #e08000
-}
-
-span.comment {
- color: #800000
-}
-
-span.preprocessor {
- color: #806020
-}
-
-span.stringliteral {
- color: #002080
-}
-
-span.charliteral {
- color: #008080
-}
-
-span.vhdldigit {
- color: #ff00ff
-}
-
-span.vhdlchar {
- color: #000000
-}
-
-span.vhdlkeyword {
- color: #700070
-}
-
-span.vhdllogic {
- color: #ff0000
-}
-
-/* @end */
-
-.search {
- color: #003399;
- font-weight: bold;
-}
-
-form.search {
- margin-bottom: 0px;
- margin-top: 0px;
-}
-
-input.search {
- font-size: 75%;
- color: #000080;
- font-weight: normal;
- background-color: #e8eef2;
-}
-
-td.tiny {
- font-size: 75%;
-}
-
-.dirtab {
- padding: 4px;
- border-collapse: collapse;
- border: 1px solid #84b0c7;
-}
-
-th.dirtab {
- background: #e8eef2;
- font-weight: bold;
-}
-
-hr {
- height: 0;
- border: none;
- border-top: 1px solid #666;
-}
-
-/* @group Member Descriptions */
-
-.mdescLeft, .mdescRight,
-.memItemLeft, .memItemRight,
-.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
- background-color: #FAFAFA;
- border: none;
- margin: 4px;
- padding: 1px 0 0 8px;
-}
-
-.mdescLeft, .mdescRight {
- padding: 0px 8px 4px 8px;
- color: #555;
-}
-
-.memItemLeft, .memItemRight, .memTemplParams {
- border-top: 1px solid #ccc;
-}
-
-.memTemplParams {
- color: #606060;
-}
-
-/* @end */
-
-/* @group Member Details */
-
-/* Styles for detailed member documentation */
-
-.memtemplate {
- font-size: 80%;
- color: #606060;
- font-weight: normal;
- margin-left: 3px;
-}
-
-.memnav {
- background-color: #e8eef2;
- border: 1px solid #84b0c7;
- text-align: center;
- margin: 2px;
- margin-right: 15px;
- padding: 2px;
-}
-
-.memitem {
- padding: 0;
-}
-
-.memname {
- white-space: nowrap;
- font-weight: bold;
-}
-
-.memproto, .memdoc {
- border: 1px solid #84b0c7;
-}
-
-.memproto {
- padding: 0;
- background-color: #d5e1e8;
- font-weight: bold;
- -webkit-border-top-left-radius: 8px;
- -webkit-border-top-right-radius: 8px;
- -moz-border-radius-topleft: 8px;
- -moz-border-radius-topright: 8px;
-}
-
-.memdoc {
- padding: 2px 5px;
- background-color: #eef3f5;
- border-top-width: 0;
- -webkit-border-bottom-left-radius: 8px;
- -webkit-border-bottom-right-radius: 8px;
- -moz-border-radius-bottomleft: 8px;
- -moz-border-radius-bottomright: 8px;
-}
-
-.memdoc p, .memdoc dl, .memdoc ul {
- margin: 6px 0;
-}
-
-.paramkey {
- text-align: right;
-}
-
-.paramtype {
- white-space: nowrap;
-}
-
-.paramname {
- color: #602020;
- white-space: nowrap;
-}
-.paramname em {
- font-style: normal;
-}
-
-/* @end */
-
-/* @group Directory (tree) */
-
-/* for the tree view */
-
-.ftvtree {
- font-family: sans-serif;
- margin: 0.5em;
-}
-
-/* these are for tree view when used as main index */
-
-.directory {
- font-size: 9pt;
- font-weight: bold;
-}
-
-.directory h3 {
- margin: 0px;
- margin-top: 1em;
- font-size: 11pt;
-}
-
-/*
-The following two styles can be used to replace the root node title
-with an image of your choice. Simply uncomment the next two styles,
-specify the name of your image and be sure to set 'height' to the
-proper pixel height of your image.
-*/
-
-/*
-.directory h3.swap {
- height: 61px;
- background-repeat: no-repeat;
- background-image: url("yourimage.gif");
-}
-.directory h3.swap span {
- display: none;
-}
-*/
-
-.directory > h3 {
- margin-top: 0;
-}
-
-.directory p {
- margin: 0px;
- white-space: nowrap;
-}
-
-.directory div {
- display: none;
- margin: 0px;
-}
-
-.directory img {
- vertical-align: -30%;
-}
-
-/* these are for tree view when not used as main index */
-
-.directory-alt {
- font-size: 100%;
- font-weight: bold;
-}
-
-.directory-alt h3 {
- margin: 0px;
- margin-top: 1em;
- font-size: 11pt;
-}
-
-.directory-alt > h3 {
- margin-top: 0;
-}
-
-.directory-alt p {
- margin: 0px;
- white-space: nowrap;
-}
-
-.directory-alt div {
- display: none;
- margin: 0px;
-}
-
-.directory-alt img {
- vertical-align: -30%;
-}
-
-/* @end */
-
-address {
- font-style: normal;
- text-align: center;
- font-size: 90%;
- color: gray;
-}
-
-DIV.tabs A, #toplinks
-{
- font-size : 9px;
-}
-
-#toplinks {
- text-align: right;
- margin-bottom: -1.9em;
-}
-
-.pending {
- /* display:none; */
- color:red; font-weight:bold;
-}
-
-#license {
- color:gray;
- font-size:90%;
- border-top:1px solid;
- border-color:gray;
- padding-top:1em;
- margin-top:3em;
- text-align:center;
-}
diff --git a/native_client_sdk/src/documentation/stylesheet.css b/native_client_sdk/src/documentation/stylesheet.css
deleted file mode 100644
index 3d17af00ca..0000000000
--- a/native_client_sdk/src/documentation/stylesheet.css
+++ /dev/null
@@ -1,101 +0,0 @@
-@charset "utf-8";
-a:link { color: #0000cc; }
-body {
- background: #fff; margin: 3px 8px;
- font-family: arial, sans-serif;
-}
-
-body { font-size: 83%;}
-pre, code, p kbd { font-size: 120%;}
-
-h1 { font-size: x-large; }
-h2 { font-size: large; }
-h3 { font-size: medium; }
-h4 { font-size: small; }
-
-img { border: 1px solid #ccc; }
-
-pre {
- margin-left: 2em;
- padding: 0.5em;
- border-left: 3px solid #ccc;
-}
-
-pre.no-bar {
- padding: 0;
- border-left: 0;
-}
-
-table {
- border: 1px solid #999999;
- border-collapse: collapse;
-}
-
-th {
- border: 1px solid #999999;
- padding: 0.25em 0.5em;
- background: #ccc;
-}
-
-td {
- border-bottom: 1px dotted #999999;
- border-left: 1px dotted #999999;
- text-align: left;
- padding: 0.25em 0.5em;
-}
-
-td pre.listing {
- margin: 0.25em 0.25em 0.25em 0;
-}
-
-pre.listing {
- padding: 0;
- background-color: #fff;
- border: none;
-}
-
-div#toplink {
- font-size: small;
- text-align: right;
- margin-bottom: -2em;
-}
-
-.caption {
- font-weight:bold
-}
-
-#license {
- color:gray;
- font-size:small;
- border-top:1px solid;
- border-color:gray;
- padding:1em;
- margin-top:3em;
- text-align:center;
-}
-
-.technote {
- border:1px solid #999;
- background:#ccc;
- margin:0em 5em;
- padding: 0.25em 0.5em;
-}
-
-.notapplicable {
- color:lightgray;
- font-style:italic;
-}
-
-pre kbd {
- background:rgb(221, 248, 204);
-}
-
-table caption {
- font-style:italic;
- text-align:left;
-}
-
-.comment {
- display:none; /* comment this line out if you want to see comments */
- color:red; font-weight:bold;
-}
diff --git a/native_client_sdk/src/examples/api/file_io/example.js b/native_client_sdk/src/examples/api/file_io/example.js
index 1183c9cd43..37be1cb47f 100644
--- a/native_client_sdk/src/examples/api/file_io/example.js
+++ b/native_client_sdk/src/examples/api/file_io/example.js
@@ -2,88 +2,151 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+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') });
+ navigator.webkitPersistentStorage.requestQuota(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() {
- document.getElementById('saveButton').addEventListener('click', saveFile);
- document.getElementById('loadButton').addEventListener('click', loadFile);
- document.getElementById('deleteButton').addEventListener('click', deleteFile);
- document.getElementById('listButton').addEventListener('click', listDir);
+ var radioEls = document.querySelectorAll('input[type="radio"]');
+ for (var i = 0; i < radioEls.length; ++i) {
+ radioEls[i].addEventListener('click', onRadioClicked);
+ }
+
+ function addEventListenerToButton(parentId, func) {
+ document.querySelector('#' + parentId + ' button')
+ .addEventListener('click', func);
+ }
+
+ addEventListenerToButton('saveFile', saveFile);
+ addEventListenerToButton('loadFile', loadFile);
+ addEventListenerToButton('delete', deleteFileOrDirectory);
+ addEventListenerToButton('listDir', listDir);
+ addEventListenerToButton('makeDir', makeDir);
}
-function loadFile() {
- if (common.naclModule) {
- var fileName = document.getElementById('fileName').value;
+function onRadioClicked(e) {
+ var divId = this.id.slice(6); // skip "radio_"
+ var functionEls = document.querySelectorAll('.function');
+ for (var i = 0; i < functionEls.length; ++i) {
+ var visible = functionEls[i].id === divId;
+ if (functionEls[i].id === divId)
+ functionEls[i].removeAttribute('hidden');
+ else
+ functionEls[i].setAttribute('hidden');
+ }
+}
- // Package a message using a simple protocol containing:
- // instruction file_name_length file_name
- var msg = "ld " + fileName.length + " " + fileName;
- common.naclModule.postMessage(msg);
+function makeMessage(command, path) {
+ // Package a message using a simple protocol containing:
+ // command <path length> <path> <space-separated extra args>
+ var msg = command;
+ msg += ' ';
+ msg += path.length;
+ msg += ' ';
+ msg += path;
+ // Maybe add extra args
+ for (var i = 2; i < arguments.length; ++i) {
+ msg += ' ' + arguments[i];
}
+ return msg;
}
function saveFile() {
if (common.naclModule) {
- var fileName = document.getElementById('fileName').value;
- var fileText = document.getElementById('fileEditor').value;
-
- // Package a message using a simple protocol containing:
- // instruction file_name_length file_name file_contents
- var msg = "sv " + fileName.length + " " + fileName + " " + fileText;
- common.naclModule.postMessage(msg);
+ var fileName = document.querySelector('#saveFile input').value;
+ var fileText = document.querySelector('#saveFile textarea').value;
+ common.naclModule.postMessage(makeMessage('sv', fileName, fileText));
+ // clear the editor.
+ fileText.value = '';
}
}
-function deleteFile() {
+function loadFile() {
if (common.naclModule) {
- var fileName = document.getElementById('fileName').value;
+ var fileName = document.querySelector('#loadFile input').value;
+ // clear the editor first (in case there is an error and there is no
+ // output).
+ document.querySelector('#loadFile textarea').value = '';
+ common.naclModule.postMessage(makeMessage('ld', fileName));
+ }
+}
- // Package a message using a simple protocol containing:
- // instruction file_name_length file_name
- var msg = "de " + fileName.length + " " + fileName;
- common.naclModule.postMessage(msg);
+function deleteFileOrDirectory() {
+ if (common.naclModule) {
+ var fileName = document.querySelector('#delete input').value;
+ common.naclModule.postMessage(makeMessage('de', fileName));
}
}
function listDir() {
if (common.naclModule) {
- var dirName = document.getElementById('dirName').value;
+ var dirName = document.querySelector('#listDir input').value;
+ common.naclModule.postMessage(makeMessage('ls', dirName));
+ }
+}
- // Package a message using a simple protocol containing:
- // instruction file_name_length file_name
- var msg = "ls " + dirName.length + " " + dirName;
- common.naclModule.postMessage(msg);
+function makeDir() {
+ if (common.naclModule) {
+ var dirName = document.querySelector('#makeDir input').value;
+ common.naclModule.postMessage(makeMessage('md', dirName));
}
}
// Called by the common.js module.
function handleMessage(message_event) {
- var messageParts = message_event.data.split("|", 3);
+ var msg = message_event.data;
+ var parts = msg.split('|');
+ var command = parts[0];
+ var args = parts.slice(1);
- if (messageParts[0] == "ERR") {
- common.updateStatus(messageParts[1]);
- document.getElementById('statusField').style.color = "red";
- }
- else if(messageParts[0] == "STAT") {
- common.updateStatus(messageParts[1]);
- }
- else if (messageParts[0] == "DISP") {
- // Display the message in the file edit box
- document.getElementById('fileEditor').value = messageParts[1];
- }
- else if (messageParts[0] == "READY") {
- var statusField = document.getElementById('statusField');
- common.updateStatus(statusField.innerHTML + ' Ready!');
+ if (command == 'ERR') {
+ common.logMessage('Error: ' + args[0] + '\n');
+ } else if (command == 'STAT') {
+ common.logMessage(args[0] + '\n');
+ } else if (command == 'READY') {
+ common.logMessage('Filesystem ready!\n');
+ } else if (command == 'DISP') {
+ // Find the file editor that is currently visible.
+ var fileEditorEl =
+ document.querySelector('.function:not([hidden]) > textarea');
+ // Rejoin args with pipe (|) -- there is only one argument, and it can
+ // contain the pipe character.
+ fileEditorEl.value = args.join('|');
+ } else if (command == 'LIST') {
+ var listDirOutputEl = document.getElementById('listDirOutput');
+
+ // NOTE: files with | in their names will be incorrectly split. Fixing this
+ // is left as an exercise for the reader.
+
+ // Remove all children of this element...
+ while (listDirOutputEl.firstChild) {
+ listDirOutputEl.removeChild(listDirOutputEl.firstChild);
+ }
+
+ if (args.length) {
+ // Add new <li> elements for each file.
+ for (var i = 0; i < args.length; ++i) {
+ var itemEl = document.createElement('li');
+ itemEl.textContent = args[i];
+ listDirOutputEl.appendChild(itemEl);
+ }
+ } else {
+ var itemEl = document.createElement('li');
+ itemEl.textContent = '<empty directory>';
+ listDirOutputEl.appendChild(itemEl);
+ }
}
}
diff --git a/native_client_sdk/src/examples/api/file_io/file_io.cc b/native_client_sdk/src/examples/api/file_io/file_io.cc
index d8e27afd0f..cf8be2689b 100644
--- a/native_client_sdk/src/examples/api/file_io/file_io.cc
+++ b/native_client_sdk/src/examples/api/file_io/file_io.cc
@@ -41,6 +41,7 @@ const char* const kLoadPrefix = "ld";
const char* const kSavePrefix = "sv";
const char* const kDeletePrefix = "de";
const char* const kListPrefix = "ls";
+const char* const kMakeDirPrefix = "md";
}
/// The Instance class. One of these exists for each instance of your NaCl
@@ -115,41 +116,35 @@ class FileIoInstance : public pp::Instance {
}
// Dispatch the instruction
- if (instruction.compare(kLoadPrefix) == 0) {
+ if (instruction == kLoadPrefix) {
file_thread_.message_loop().PostWork(
callback_factory_.NewCallback(&FileIoInstance::Load, file_name));
- return;
- }
-
- if (instruction.compare(kSavePrefix) == 0) {
+ } else if (instruction == kSavePrefix) {
// Read the rest of the message as the file text
reader.ignore(1); // Eat the delimiter
std::string file_text = message.substr(reader.tellg());
file_thread_.message_loop().PostWork(callback_factory_.NewCallback(
&FileIoInstance::Save, file_name, file_text));
- return;
- }
-
- if (instruction.compare(kDeletePrefix) == 0) {
+ } else if (instruction == kDeletePrefix) {
file_thread_.message_loop().PostWork(
callback_factory_.NewCallback(&FileIoInstance::Delete, file_name));
- return;
- }
-
- if (instruction.compare(kListPrefix) == 0) {
+ } else if (instruction == kListPrefix) {
const std::string& dir_name = file_name;
file_thread_.message_loop().PostWork(
callback_factory_.NewCallback(&FileIoInstance::List, dir_name));
- return;
+ } else if (instruction == kMakeDirPrefix) {
+ const std::string& dir_name = file_name;
+ file_thread_.message_loop().PostWork(
+ callback_factory_.NewCallback(&FileIoInstance::MakeDir, dir_name));
}
}
void OpenFileSystem(int32_t /* result */) {
- int32_t rv = file_system_.Open(1024 * 1024, pp::CompletionCallback());
+ int32_t rv = file_system_.Open(1024 * 1024, pp::BlockUntilComplete());
if (rv == PP_OK) {
file_system_ready_ = true;
// Notify the user interface that we're ready
- PostMessage(pp::Var("READY|"));
+ PostMessage("READY|");
} else {
ShowErrorMessage("Failed to open file system", rv);
}
@@ -169,7 +164,7 @@ class FileIoInstance : public pp::Instance {
file.Open(ref,
PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE |
PP_FILEOPENFLAG_TRUNCATE,
- pp::CompletionCallback());
+ pp::BlockUntilComplete());
if (open_result != PP_OK) {
ShowErrorMessage("File open for write failed", open_result);
return;
@@ -188,7 +183,7 @@ class FileIoInstance : public pp::Instance {
bytes_written = file.Write(offset,
file_contents.data() + offset,
file_contents.length(),
- pp::CompletionCallback());
+ pp::BlockUntilComplete());
if (bytes_written > 0) {
offset += bytes_written;
} else {
@@ -198,7 +193,7 @@ class FileIoInstance : public pp::Instance {
} while (bytes_written < static_cast<int64_t>(file_contents.length()));
}
// All bytes have been written, flush the write buffer to complete
- int32_t flush_result = file.Flush(pp::CompletionCallback());
+ int32_t flush_result = file.Flush(pp::BlockUntilComplete());
if (flush_result != PP_OK) {
ShowErrorMessage("File fail to flush", flush_result);
return;
@@ -215,7 +210,7 @@ class FileIoInstance : public pp::Instance {
pp::FileIO file(this);
int32_t open_result =
- file.Open(ref, PP_FILEOPENFLAG_READ, pp::CompletionCallback());
+ file.Open(ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
if (open_result == PP_ERROR_FILENOTFOUND) {
ShowStatusMessage("File not found");
return;
@@ -224,7 +219,7 @@ class FileIoInstance : public pp::Instance {
return;
}
PP_FileInfo info;
- int32_t query_result = file.Query(&info, pp::CompletionCallback());
+ int32_t query_result = file.Query(&info, pp::BlockUntilComplete());
if (query_result != PP_OK) {
ShowErrorMessage("File query failed", query_result);
return;
@@ -242,7 +237,7 @@ class FileIoInstance : public pp::Instance {
bytes_read = file.Read(offset,
&data[offset],
data.size() - offset,
- pp::CompletionCallback());
+ pp::BlockUntilComplete());
if (bytes_read > 0)
offset += bytes_read;
} while (bytes_read > 0);
@@ -254,7 +249,7 @@ class FileIoInstance : public pp::Instance {
PP_DCHECK(bytes_read == 0);
// Done reading, send content to the user interface
std::string string_data(data.begin(), data.end());
- PostMessage(pp::Var("DISP|" + string_data));
+ PostMessage("DISP|" + string_data);
ShowStatusMessage("Load complete");
}
@@ -265,15 +260,15 @@ class FileIoInstance : public pp::Instance {
}
pp::FileRef ref(file_system_, file_name.c_str());
- int32_t result = ref.Delete(pp::CompletionCallback());
+ int32_t result = ref.Delete(pp::BlockUntilComplete());
if (result == PP_ERROR_FILENOTFOUND) {
- ShowStatusMessage("File not found");
+ ShowStatusMessage("File/Directory not found");
return;
} else if (result != PP_OK) {
ShowErrorMessage("Deletion failed", result);
return;
}
- ShowStatusMessage("File deleted");
+ ShowStatusMessage("File/Directory deleted");
}
void List(int32_t /* result */, const std::string& dir_name) {
@@ -281,6 +276,7 @@ class FileIoInstance : public pp::Instance {
ShowErrorMessage("File system is not open", PP_ERROR_FAILED);
return;
}
+
pp::FileRef ref(file_system_, dir_name.c_str());
// Pass ref along to keep it alive.
@@ -296,27 +292,44 @@ class FileIoInstance : public pp::Instance {
return;
}
- std::string buffer = "File list:";
+ std::stringstream ss;
+ ss << "LIST";
for (size_t i = 0; i < entries.size(); ++i) {
pp::Var name = entries[i].file_ref().GetName();
- if (name.is_string())
- buffer += " " + name.AsString();
+ if (name.is_string()) {
+ ss << "|" << name.AsString();
+ }
+ }
+ PostMessage(ss.str());
+ }
+
+ void MakeDir(int32_t /* result */, const std::string& dir_name) {
+ if (!file_system_ready_) {
+ ShowErrorMessage("File system is not open", PP_ERROR_FAILED);
+ return;
+ }
+ pp::FileRef ref(file_system_, dir_name.c_str());
+
+ int32_t result = ref.MakeDirectory(pp::BlockUntilComplete());
+ if (result != PP_OK) {
+ ShowErrorMessage("Make directory failed", result);
+ return;
}
- ShowStatusMessage(buffer);
+ ShowStatusMessage("Made directory");
}
/// Encapsulates our simple javascript communication protocol
void ShowErrorMessage(const std::string& message, int32_t result) {
std::stringstream ss;
ss << "ERR|" << message << " -- Error #: " << result;
- PostMessage(pp::Var(ss.str()));
+ PostMessage(ss.str());
}
/// Encapsulates our simple javascript communication protocol
void ShowStatusMessage(const std::string& message) {
std::stringstream ss;
ss << "STAT|" << message;
- PostMessage(pp::Var(ss.str()));
+ PostMessage(ss.str());
}
};
diff --git a/native_client_sdk/src/examples/api/file_io/index.html b/native_client_sdk/src/examples/api/file_io/index.html
index 7c62ebdd9c..f08a4d09c4 100644
--- a/native_client_sdk/src/examples/api/file_io/index.html
+++ b/native_client_sdk/src/examples/api/file_io/index.html
@@ -18,21 +18,65 @@
<p>The File IO example demonstrates saving, loading, and deleting files
from the persistent file store.</p>
- <textarea id="fileEditor"
- cols="40"
- rows="10"
- wrap="hard"
- placeholder="Enter some text to save in a file..."></textarea>
- <br>File Name
- <input type="text" id="fileName" action="" value="/filename.txt">
- <button id="saveButton" action="">Save</button>
- <button id="loadButton" action="">Load</button>
- <button id="deleteButton" action="">Delete</button>
-
- <br>Directory Name
- <input type="text" id="dirName" action="" value="/">
- <button id="listButton" action="">List</button>
+ <div>
+ <span>
+ <input type="radio" id="radio_saveFile" name="group" checked="checked">
+ Save File
+ <input type="radio" id="radio_loadFile" name="group">Load File
+ <input type="radio" id="radio_delete" name="group">Delete File/Directory
+ <input type="radio" id="radio_listDir" name="group">List Directory
+ <input type="radio" id="radio_makeDir" name="group">Make Directory
+ </span>
+ </div>
+ <div class="function" id="saveFile">
+ <div>
+ <span>
+ Filename:
+ <input type="text" value="/filename.txt">
+ <button>Save</button>
+ </span>
+ </div>
+ <textarea id="saveFileEditor" cols="40" rows="10" wrap="hard"
+ placeholder="Enter some text to save in a file..."></textarea>
+ </div>
+ <div class="function" id="loadFile" hidden>
+ <div>
+ <span>
+ Filename:
+ <input type="text" value="/filename.txt">
+ <button>Load</button>
+ </span>
+ </div>
+ <textarea cols="40" rows="10" wrap="hard"></textarea>
+ </div>
+ <div class="function" id="delete" hidden>
+ <span>
+ Filename/Directory:
+ <input type="text" value="/filename.txt">
+ <button>Delete</button>
+ </span>
+ </div>
+ <div class="function" id="listDir" hidden>
+ <div>
+ <span>
+ Directory:
+ <input type="text" value="/">
+ <button>List Directory</button>
+ </span>
+ </div>
+ Result:
+ <ul id="listDirOutput">
+ </ul>
+ </div>
+ <div class="function" id="makeDir" hidden>
+ <span>
+ Directory:
+ <input type="text" value="/directory">
+ <button>Make Directory</button>
+ </span>
+ </div>
+ <pre id="log" style="font-weight: bold"></pre>
<!-- The NaCl plugin will be embedded inside the element with id "listener".
See common.js.-->
<div id="listener"></div>
diff --git a/native_client_sdk/src/examples/api/input_event/index.html b/native_client_sdk/src/examples/api/input_event/index.html
index 2e97b9884b..0739c7ac6c 100644
--- a/native_client_sdk/src/examples/api/input_event/index.html
+++ b/native_client_sdk/src/examples/api/input_event/index.html
@@ -19,7 +19,7 @@ found in the LICENSE file.
multi-threaded application. The main thread converts input events to
non-pepper events and puts them on a queue. The worker thread pulls them
off of the queue, converts them to a string, and then uses
- CallOnMainThread so that PostMessage can be send the result of the worker
+ CallOnMainThread so that PostMessage can send the result of the worker
thread to the browser.</p>
<p>If you press the 'Kill worker thread and queue' button, then the main
thread (which puts events on the queue) will call CancelQueue, indicating
diff --git a/native_client_sdk/src/examples/api/url_loader/example.js b/native_client_sdk/src/examples/api/url_loader/example.js
index 2ebdfeb29e..9c62dce42f 100644
--- a/native_client_sdk/src/examples/api/url_loader/example.js
+++ b/native_client_sdk/src/examples/api/url_loader/example.js
@@ -15,7 +15,7 @@ function attachListeners() {
}
function loadUrl() {
- common.naclModule.postMessage('getUrl:geturl_success.html');
+ common.naclModule.postMessage('getUrl:url_loader_success.html');
}
// Called by the common.js module.
diff --git a/native_client_sdk/src/examples/api/websocket/example.js b/native_client_sdk/src/examples/api/websocket/example.js
index 561d044e32..ed0b9274e9 100644
--- a/native_client_sdk/src/examples/api/websocket/example.js
+++ b/native_client_sdk/src/examples/api/websocket/example.js
@@ -26,7 +26,8 @@ function doConnect(event) {
function doSend() {
// Send a request message. See also websocket.cc for the request format.
var message = document.getElementById('message').value;
- common.naclModule.postMessage('s;' + message);
+ var type = document.getElementById('is_binary').checked ? 'b;' : 't;';
+ common.naclModule.postMessage(type + message);
event.preventDefault();
}
diff --git a/native_client_sdk/src/examples/api/websocket/index.html b/native_client_sdk/src/examples/api/websocket/index.html
index f077fcdc7e..e7caa26b17 100644
--- a/native_client_sdk/src/examples/api/websocket/index.html
+++ b/native_client_sdk/src/examples/api/websocket/index.html
@@ -23,13 +23,14 @@ found in the LICENSE file.
</p>
<form id="connectForm">
<input type="text" id="url" style="width: 400px"
- value="ws://html5rocks.websocket.org/echo?encoding=text">
+ value="ws://html5rocks.websocket.org/echo">
<input type="submit" value="Connect">
</form>
<form id="sendForm">
<input type="text" id="message" value="hello" style="width: 400px">
<input type="submit" value="Send">
+ <input type="checkbox" id="type">as a binary message
</form>
<button id="closeButton">Close</button>
diff --git a/native_client_sdk/src/examples/api/websocket/websocket.cc b/native_client_sdk/src/examples/api/websocket/websocket.cc
index bc5949b794..be994c5817 100644
--- a/native_client_sdk/src/examples/api/websocket/websocket.cc
+++ b/native_client_sdk/src/examples/api/websocket/websocket.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stdio.h>
+#include <sstream>
+
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
@@ -21,7 +24,8 @@ class WebSocketInstance : public pp::Instance {
void Open(const std::string& url);
void Close();
- void Send(const std::string& message);
+ void SendAsBinary(const std::string& message);
+ void SendAsText(const std::string& message);
void Receive();
void OnConnectCompletion(int32_t result);
@@ -36,6 +40,23 @@ class WebSocketInstance : public pp::Instance {
pp::Var receive_var_;
};
+#define MAX_TO_CONVERT 8
+#define BYTES_PER_CHAR 4
+#define TAIL_AND_NUL_SIZE 4
+
+static std::string ArrayToString(pp::VarArrayBuffer& array) {
+ char tmp[MAX_TO_CONVERT * BYTES_PER_CHAR + TAIL_AND_NUL_SIZE];
+ uint32_t offs = 0;
+ uint8_t* data = static_cast<uint8_t*>(array.Map());
+
+ for (offs = 0; offs < array.ByteLength() && offs < MAX_TO_CONVERT; offs++)
+ sprintf(&tmp[offs * BYTES_PER_CHAR], "%02Xh ", data[offs]);
+
+ sprintf(&tmp[offs * BYTES_PER_CHAR], "...");
+ array.Unmap();
+ return std::string(tmp);
+}
+
void WebSocketInstance::HandleMessage(const pp::Var& var_message) {
if (!var_message.is_string())
return;
@@ -54,10 +75,15 @@ void WebSocketInstance::HandleMessage(const pp::Var& var_message) {
// The command 'c' requests to close without any argument like "c;"
Close();
break;
- case 's':
- // The command 's' requests to send a message as a text frame. The message
- // is passed as an argument like "s;message".
- Send(message.substr(2));
+ case 'b':
+ // The command 'b' requests to send a message as a binary frame. The
+ // message is passed as an argument like "b;message".
+ SendAsBinary(message.substr(2));
+ break;
+ case 't':
+ // The command 't' requests to send a message as a text frame. The message
+ // is passed as an argument like "t;message".
+ SendAsText(message.substr(2));
break;
}
}
@@ -87,11 +113,25 @@ void WebSocketInstance::Close() {
PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var("bye"), callback);
}
-void WebSocketInstance::Send(const std::string& message) {
+void WebSocketInstance::SendAsBinary(const std::string& message) {
+ if (!IsConnected())
+ return;
+ uint32_t size = message.size();
+ pp::VarArrayBuffer array_buffer(size);
+ char* data = static_cast<char*>(array_buffer.Map());
+ for (uint32_t i = 0; i < size; ++i)
+ data[i] = message[i];
+ array_buffer.Unmap();
+ websocket_->SendMessage(array_buffer);
+ std::string message_text = ArrayToString(array_buffer);
+ PostMessage(pp::Var("send (binary): " + message_text));
+}
+
+void WebSocketInstance::SendAsText(const std::string& message) {
if (!IsConnected())
return;
websocket_->SendMessage(pp::Var(message));
- PostMessage(pp::Var(std::string("send: ") + message));
+ PostMessage(pp::Var("send (text): " + message));
}
void WebSocketInstance::Receive() {
@@ -116,10 +156,14 @@ void WebSocketInstance::OnCloseCompletion(int32_t result) {
void WebSocketInstance::OnReceiveCompletion(int32_t result) {
if (result == PP_OK) {
- if (receive_var_.is_array_buffer())
- PostMessage(pp::Var("receive: binary data"));
- else
- PostMessage(pp::Var(std::string("receive: ") + receive_var_.AsString()));
+ if (receive_var_.is_array_buffer()) {
+ pp::VarArrayBuffer array_buffer(receive_var_);
+ std::string message_text = ArrayToString(array_buffer);
+ PostMessage("receive (binary): " + message_text);
+ }
+ else {
+ PostMessage("receive (text): " + receive_var_.AsString());
+ }
}
Receive();
}
diff --git a/native_client_sdk/src/examples/demo/earth/earth.cc b/native_client_sdk/src/examples/demo/earth/earth.cc
new file mode 100644
index 0000000000..d8e35462a5
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/earth/earth.cc
@@ -0,0 +1,871 @@
+// 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 <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>
+#include <ppapi/cpp/var_dictionary.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <string>
+
+#include "sdk_util/macros.h"
+#include "sdk_util/thread_pool.h"
+
+// Global properties used to setup Earth demo.
+namespace {
+const float kHugeZ = 1.0e38f;
+const float kPI = M_PI;
+const float kTwoPI = kPI * 2.0f;
+const float kOneOverPI = 1.0f / kPI;
+const float kOneOver2PI = 1.0f / kTwoPI;
+const float kOneOver255 = 1.0f / 255.0f;
+const int kArcCosineTableSize = 4096;
+const int kFramesToBenchmark = 100;
+const float kZoomMin = 1.0f;
+const float kZoomMax = 50.0f;
+const float kWheelSpeed = 2.0f;
+const float kLightMin = 0.0f;
+const float kLightMax = 2.0f;
+const int kFrameTimeBufferSize = 512;
+
+// Timer helper for benchmarking. Returns seconds elapsed since program start,
+// as a double.
+timeval start_tv;
+int start_tv_retv = gettimeofday(&start_tv, NULL);
+
+inline double getseconds() {
+ const double usec_to_sec = 0.000001;
+ timeval tv;
+ if ((0 == start_tv_retv) && (0 == gettimeofday(&tv, NULL)))
+ return (tv.tv_sec - start_tv.tv_sec) + tv.tv_usec * usec_to_sec;
+ return 0.0;
+}
+
+// RGBA helper functions.
+inline float ExtractR(uint32_t c) {
+ return static_cast<float>(c & 0xFF) * kOneOver255;
+}
+
+inline float ExtractG(uint32_t c) {
+ return static_cast<float>((c & 0xFF00) >> 8) * kOneOver255;
+}
+
+inline float ExtractB(uint32_t c) {
+ return static_cast<float>((c & 0xFF0000) >> 16) * kOneOver255;
+}
+
+inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+ return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
+}
+
+// simple container for earth texture
+struct Texture {
+ int width, height;
+ uint32_t* pixels;
+ Texture(int w, int h) : width(w), height(h) {
+ pixels = new uint32_t[w * h];
+ memset(pixels, 0, sizeof(uint32_t) * w * h);
+ }
+ explicit Texture(int w, int h, uint32_t* p) : width(w), height(h) {
+ pixels = new uint32_t[w * h];
+ memcpy(pixels, p, sizeof(uint32_t) * w * h);
+ }
+ ~Texture() { delete[] pixels; }
+
+ DISALLOW_COPY_AND_ASSIGN(Texture);
+};
+
+
+
+struct ArcCosine {
+ // slightly larger table so we can interpolate beyond table size
+ float table[kArcCosineTableSize + 2];
+ float TableLerp(float x);
+ ArcCosine();
+};
+
+ArcCosine::ArcCosine() {
+ // build a slightly larger table to allow for numeric imprecision
+ for (int i = 0; i < (kArcCosineTableSize + 2); ++i) {
+ float f = static_cast<float>(i) / kArcCosineTableSize;
+ f = f * 2.0f - 1.0f;
+ table[i] = acos(f);
+ }
+}
+
+// looks up acos(f) using a table and lerping between entries
+// (it is expected that input f is between -1 and 1)
+float ArcCosine::TableLerp(float f) {
+ float x = (f + 1.0f) * 0.5f;
+ x = x * kArcCosineTableSize;
+ int ix = static_cast<int>(x);
+ float fx = static_cast<float>(ix);
+ float dx = x - fx;
+ float af = table[ix];
+ float af2 = table[ix + 1];
+ return af + (af2 - af) * dx;
+}
+
+// Helper functions for quick but approximate sqrt.
+union Convert {
+ float f;
+ int i;
+ Convert(int x) { i = x; }
+ Convert(float x) { f = x; }
+ int AsInt() { return i; }
+ float AsFloat() { return f; }
+};
+
+inline const int AsInteger(const float f) {
+ Convert u(f);
+ return u.AsInt();
+}
+
+inline const float AsFloat(const int i) {
+ Convert u(i);
+ return u.AsFloat();
+}
+
+const long int kOneAsInteger = AsInteger(1.0f);
+const float kScaleUp = float(0x00800000);
+const float kScaleDown = 1.0f / kScaleUp;
+
+inline float inline_quick_sqrt(float x) {
+ int i;
+ i = (AsInteger(x) >> 1) + (kOneAsInteger >> 1);
+ return AsFloat(i);
+}
+
+inline float inline_sqrt(float x) {
+ float y;
+ y = inline_quick_sqrt(x);
+ y = (y * y + x) / (2.0f * y);
+ y = (y * y + x) / (2.0f * y);
+ return y;
+}
+
+// takes a -0..1+ color, clamps it to 0..1 and maps it to 0..255 integer
+inline uint32_t Clamp255(float x) {
+ if (x < 0.0f) {
+ x = 0.0f;
+ } else if (x > 1.0f) {
+ x = 1.0f;
+ }
+ return static_cast<uint32_t>(x * 255.0f);
+}
+} // namespace
+
+
+// The main object that runs the Earth demo.
+class Planet : public pp::Instance {
+ public:
+ explicit Planet(PP_Instance instance);
+ 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);
+
+ private:
+ // Methods prefixed with 'w' are run on worker threads.
+ uint32_t* wGetAddr(int x, int y);
+ void wRenderPixelSpan(int x0, int x1, int y);
+ void wMakeRect(int r, int *x, int *y, int *w, int *h);
+ void wRenderRect(int x0, int y0, int x1, int y1);
+ void wRenderRegion(int region);
+ static void wRenderRegionEntry(int region, void *thiz);
+
+ // These methods are only called by the main thread.
+ void CacheCalcs();
+ void SetPlanetXYZR(float x, float y, float z, float r);
+ void SetPlanetPole(float x, float y, float z);
+ void SetPlanetEquator(float x, float y, float z);
+ void SetPlanetSpin(float x, float y);
+ void SetEyeXYZ(float x, float y, float z);
+ void SetLightXYZ(float x, float y, float z);
+ void SetAmbientRGB(float r, float g, float b);
+ void SetDiffuseRGB(float r, float g, float b);
+ void SetZoom(float zoom);
+ void SetLight(float zoom);
+ void SetTexture(const std::string& name, int width, int height,
+ uint32_t* pixels);
+
+ void Reset();
+ void PostInit(int32_t result);
+ 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.
+ float ui_light_;
+ float ui_zoom_;
+ float ui_spin_x_;
+ float ui_spin_y_;
+
+ // Various settings for position & orientation of planet. Do not change
+ // these variables, instead use SetPlanet*() functions.
+ float planet_radius_;
+ float planet_spin_x_;
+ float planet_spin_y_;
+ float planet_x_, planet_y_, planet_z_;
+ float planet_pole_x_, planet_pole_y_, planet_pole_z_;
+ float planet_equator_x_, planet_equator_y_, planet_equator_z_;
+
+ // Observer's eye. Do not change these variables, instead use SetEyeXYZ().
+ float eye_x_, eye_y_, eye_z_;
+
+ // Light position, ambient and diffuse settings. Do not change these
+ // variables, instead use SetLightXYZ(), SetAmbientRGB() and SetDiffuseRGB().
+ float light_x_, light_y_, light_z_;
+ float diffuse_r_, diffuse_g_, diffuse_b_;
+ float ambient_r_, ambient_g_, ambient_b_;
+
+ // Cached calculations. Do not change these variables - they are updated by
+ // CacheCalcs() function.
+ float planet_xyz_;
+ float planet_pole_x_equator_x_;
+ float planet_pole_x_equator_y_;
+ float planet_pole_x_equator_z_;
+ float planet_radius2_;
+ float planet_one_over_radius_;
+ float eye_xyz_;
+
+ // Source texture (earth map).
+ Texture* base_tex_;
+ 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_;
+ 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_;
+ 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);
+ // 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.
+ pp::VarDictionary message;
+ message.Set("message", "request_textures");
+ pp::VarArray names;
+ names.Set(0, "earth.jpg");
+ names.Set(1, "earthnight.jpg");
+ message.Set("names", names);
+ PostMessage(message);
+ return true;
+}
+
+void Planet::Reset() {
+ // Reset has to first fill in all variables with valid floats, so
+ // CacheCalcs() doesn't potentially propagate NaNs when calling Set*()
+ // functions further below.
+ planet_radius_ = 1.0f;
+ planet_spin_x_ = 0.0f;
+ planet_spin_y_ = 0.0f;
+ planet_x_ = 0.0f;
+ planet_y_ = 0.0f;
+ planet_z_ = 0.0f;
+ planet_pole_x_ = 0.0f;
+ planet_pole_y_ = 0.0f;
+ planet_pole_z_ = 0.0f;
+ planet_equator_x_ = 0.0f;
+ planet_equator_y_ = 0.0f;
+ planet_equator_z_ = 0.0f;
+ eye_x_ = 0.0f;
+ eye_y_ = 0.0f;
+ eye_z_ = 0.0f;
+ light_x_ = 0.0f;
+ light_y_ = 0.0f;
+ light_z_ = 0.0f;
+ diffuse_r_ = 0.0f;
+ diffuse_g_ = 0.0f;
+ diffuse_b_ = 0.0f;
+ ambient_r_ = 0.0f;
+ ambient_g_ = 0.0f;
+ ambient_b_ = 0.0f;
+ planet_xyz_ = 0.0f;
+ planet_pole_x_equator_x_ = 0.0f;
+ planet_pole_x_equator_y_ = 0.0f;
+ planet_pole_x_equator_z_ = 0.0f;
+ planet_radius2_ = 0.0f;
+ planet_one_over_radius_ = 0.0f;
+ eye_xyz_ = 0.0f;
+ ui_zoom_ = 14.0f;
+ ui_light_ = 1.0f;
+ ui_spin_x_ = 0.01f;
+ ui_spin_y_ = 0.0f;
+
+ // Set up reasonable default values.
+ SetPlanetXYZR(0.0f, 0.0f, 48.0f, 4.0f);
+ SetEyeXYZ(0.0f, 0.0f, -ui_zoom_);
+ SetLightXYZ(-60.0f, -30.0f, 0.0f);
+ SetAmbientRGB(0.05f, 0.05f, 0.05f);
+ SetDiffuseRGB(0.8f, 0.8f, 0.8f);
+ SetPlanetPole(0.0f, 1.0f, 0.0f);
+ SetPlanetEquator(1.0f, 0.0f, 0.0f);
+ SetPlanetSpin(kPI / 2.0f, kPI / 2.0f);
+ SetZoom(ui_zoom_);
+ SetLight(ui_light_);
+
+ // Send UI values to JS to reset html sliders.
+ PostUpdateMessage("set_zoom", ui_zoom_);
+ PostUpdateMessage("set_light", ui_light_);
+}
+
+
+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_ = "";
+
+ Reset();
+
+ // By default, render from the dispatch thread.
+ num_threads_ = 0;
+ workers_ = new ThreadPool(num_threads_);
+}
+
+Planet::~Planet() {
+ delete workers_;
+ DestroyContext();
+}
+
+// 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;
+}
+
+
+inline uint32_t* Planet::wGetAddr(int x, int y) {
+ assert(pixel_buffer_);
+ return (pixel_buffer_ + y * stride_in_pixels_) + x;
+}
+
+// This is the meat of the ray tracer. Given a pixel span (x0, x1) on
+// scanline y, shoot rays into the scene and render what they hit. Use
+// scanline coherence to do a few optimizations
+void Planet::wRenderPixelSpan(int x0, int x1, int y) {
+ if (!base_tex_ || !night_tex_)
+ return;
+ 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 z1 = 0.0f;
+ float dy = (y1 - y0);
+ float dz = (z1 - z0);
+ float dy_dy_dz_dz = dy * dy + dz * dz;
+ float two_dy_y0_y_two_dz_z0_z = 2.0f * dy * (y0 - planet_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_;
+ uint32_t* pixels = this->wGetAddr(x0, y);
+ for (int x = x0; x <= x1; ++x) {
+ // scan normalized screen -1..1
+ float x1 = (static_cast<float>(x) * oowidth) * 2.0f - 1.0f;
+ // eye
+ float x0 = eye_x_;
+ // delta from screen to eye
+ float dx = (x1 - x0);
+ // build a, b, c
+ float a = dx * dx + dy_dy_dz_dz;
+ float b = 2.0f * dx * (x0 - planet_x_) + two_dy_y0_y_two_dz_z0_z;
+ float c = planet_xyz_eye_xyz +
+ -2.0f * (planet_x_ * x0 + y_y0_z_z0) - (planet_radius2_);
+ // calculate discriminant
+ float disc = b * b - 4.0f * a * c;
+
+ // Did ray hit the sphere?
+ if (disc < 0.0f) {
+ *pixels = kColorBlack;
+ ++pixels;
+ continue;
+ }
+
+ // calc parametric t value
+ float t = (-b - inline_sqrt(disc)) / (2.0f * a);
+ float px = x0 + t * dx;
+ float py = y0 + t * dy;
+ float pz = z0 + t * dz;
+ float nx = (px - planet_x_) * planet_one_over_radius_;
+ float ny = (py - planet_y_) * planet_one_over_radius_;
+ float nz = (pz - planet_z_) * planet_one_over_radius_;
+
+ // Misc raytrace calculations.
+ float Lx = (light_x_ - px);
+ float Ly = (light_y_ - py);
+ float Lz = (light_z_ - pz);
+ float Lq = 1.0f / inline_quick_sqrt(Lx * Lx + Ly * Ly + Lz * Lz);
+ Lx *= Lq;
+ Ly *= Lq;
+ Lz *= Lq;
+ float d = (Lx * nx + Ly * ny + Lz * nz);
+ float pr = (diffuse_r_ * d) + ambient_r_;
+ float pg = (diffuse_g_ * d) + ambient_g_;
+ float pb = (diffuse_b_ * d) + ambient_b_;
+ float ds = -(nx * planet_pole_x_ +
+ ny * planet_pole_y_ +
+ nz * planet_pole_z_);
+ float ang = acos_.TableLerp(ds);
+ float v = ang * kOneOverPI;
+ float dp = planet_equator_x_ * nx +
+ planet_equator_y_ * ny +
+ planet_equator_z_ * nz;
+ float w = dp / sin(ang);
+ if (w > 1.0f) w = 1.0f;
+ if (w < -1.0f) w = -1.0f;
+ float th = acos_.TableLerp(w) * kOneOver2PI;
+ float dps = planet_pole_x_equator_x_ * nx +
+ planet_pole_x_equator_y_ * ny +
+ planet_pole_x_equator_z_ * nz;
+ float u;
+ if (dps < 0.0f)
+ u = th;
+ else
+ u = 1.0f - th;
+
+ // Look up daylight texel.
+ int tx = static_cast<int>(u * base_tex_->width);
+ int ty = static_cast<int>(v * base_tex_->height);
+ int offset = tx + ty * base_tex_->width;
+ uint32_t base_texel = base_tex_->pixels[offset];
+ float tr = ExtractR(base_texel);
+ float tg = ExtractG(base_texel);
+ float tb = ExtractB(base_texel);
+
+ float ipr = 1.0f - pr;
+ if (ipr < 0.0f) ipr = 0.0f;
+ float ipg = 1.0f - pg;
+ if (ipg < 0.0f) ipg = 0.0f;
+ float ipb = 1.0f - pb;
+ if (ipb < 0.0f) ipb = 0.0f;
+
+ // Look up night texel.
+ int nix = static_cast<int>(u * night_tex_->width);
+ int niy = static_cast<int>(v * night_tex_->height);
+ int noffset = nix + niy * night_tex_->width;
+ uint32_t night_texel = night_tex_->pixels[noffset];
+ float nr = ExtractR(night_texel);
+ float ng = ExtractG(night_texel);
+ float nb = ExtractB(night_texel);
+
+ // Final color value is lerp between day and night texels.
+ unsigned int ir = Clamp255(pr * tr + nr * ipr);
+ unsigned int ig = Clamp255(pg * tg + ng * ipg);
+ unsigned int ib = Clamp255(pb * tb + nb * ipb);
+
+ unsigned int color = MakeRGBA(ir, ig, ib, 0xFF);
+
+ *pixels = color;
+ ++pixels;
+ }
+}
+
+// Renders a rectangular area of the screen, scan line at a time
+void Planet::wRenderRect(int x, int y, int w, int h) {
+ for (int j = y; j < (y + h); ++j) {
+ this->wRenderPixelSpan(x, x + w - 1, j);
+ }
+}
+
+// If multithreading, this function is only called by the worker threads.
+void Planet::wRenderRegion(int region) {
+ // convert region # into x0, y0, x1, y1 rectangle
+ int x, y, w, h;
+ wMakeRect(region, &x, &y, &w, &h);
+ // render this rectangle
+ wRenderRect(x, y, w, h);
+}
+
+// Entry point for worker thread. Can't pass a member function around, so we
+// have to do this little round-about.
+void Planet::wRenderRegionEntry(int region, void* thiz) {
+ static_cast<Planet*>(thiz)->wRenderRegion(region);
+}
+
+// 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);
+}
+
+// Pre-calculations to make inner loops faster.
+void Planet::CacheCalcs() {
+ planet_xyz_ = planet_x_ * planet_x_ +
+ planet_y_ * planet_y_ +
+ planet_z_ * planet_z_;
+ planet_radius2_ = planet_radius_ * planet_radius_;
+ planet_one_over_radius_ = 1.0f / planet_radius_;
+ eye_xyz_ = eye_x_ * eye_x_ + eye_y_ * eye_y_ + eye_z_ * eye_z_;
+ // spin vector from center->equator
+ planet_equator_x_ = cos(planet_spin_x_);
+ planet_equator_y_ = 0.0f;
+ planet_equator_z_ = sin(planet_spin_x_);
+
+ // cache cross product of pole & equator
+ planet_pole_x_equator_x_ = planet_pole_y_ * planet_equator_z_ -
+ planet_pole_z_ * planet_equator_y_;
+ planet_pole_x_equator_y_ = planet_pole_z_ * planet_equator_x_ -
+ planet_pole_x_ * planet_equator_z_;
+ planet_pole_x_equator_z_ = planet_pole_x_ * planet_equator_y_ -
+ planet_pole_y_ * planet_equator_x_;
+}
+
+void Planet::SetPlanetXYZR(float x, float y, float z, float r) {
+ planet_x_ = x;
+ planet_y_ = y;
+ planet_z_ = z;
+ planet_radius_ = r;
+ CacheCalcs();
+}
+
+void Planet::SetEyeXYZ(float x, float y, float z) {
+ eye_x_ = x;
+ eye_y_ = y;
+ eye_z_ = z;
+ CacheCalcs();
+}
+
+void Planet::SetLightXYZ(float x, float y, float z) {
+ light_x_ = x;
+ light_y_ = y;
+ light_z_ = z;
+ CacheCalcs();
+}
+
+void Planet::SetAmbientRGB(float r, float g, float b) {
+ ambient_r_ = r;
+ ambient_g_ = g;
+ ambient_b_ = b;
+ CacheCalcs();
+}
+
+void Planet::SetDiffuseRGB(float r, float g, float b) {
+ diffuse_r_ = r;
+ diffuse_g_ = g;
+ diffuse_b_ = b;
+ CacheCalcs();
+}
+
+void Planet::SetPlanetPole(float x, float y, float z) {
+ planet_pole_x_ = x;
+ planet_pole_y_ = y;
+ planet_pole_z_ = z;
+ CacheCalcs();
+}
+
+void Planet::SetPlanetEquator(float x, float y, float z) {
+ // This is really over-ridden by spin at the momenent.
+ planet_equator_x_ = x;
+ planet_equator_y_ = y;
+ planet_equator_z_ = z;
+ CacheCalcs();
+}
+
+void Planet::SetPlanetSpin(float x, float y) {
+ planet_spin_x_ = x;
+ planet_spin_y_ = y;
+ CacheCalcs();
+}
+
+// Run a simple sim to spin the planet. Update loop is run once per frame.
+// Called from the main thread only and only when the worker threads are idle.
+void Planet::UpdateSim() {
+ float x = planet_spin_x_ + ui_spin_x_;
+ float y = planet_spin_y_ + ui_spin_y_;
+ // keep in nice range
+ if (x > (kPI * 2.0f))
+ x = x - kPI * 2.0f;
+ else if (x < (-kPI * 2.0f))
+ x = x + kPI * 2.0f;
+ if (y > (kPI * 2.0f))
+ y = y - kPI * 2.0f;
+ else if (y < (-kPI * 2.0f))
+ y = y + kPI * 2.0f;
+ 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();
+ printf("Benchmark started...\n");
+ benchmark_frame_counter_ = kFramesToBenchmark;
+ benchmarking_ = true;
+ benchmark_start_time_ = getseconds();
+}
+
+void Planet::EndBenchmark() {
+ benchmark_end_time_ = getseconds();
+ printf("Benchmark ended... time: %2.5f\n",
+ benchmark_end_time_ - benchmark_start_time_);
+ benchmarking_ = false;
+ benchmark_frame_counter_ = 0;
+ double total_time = benchmark_end_time_ - benchmark_start_time_;
+ // Send benchmark result to JS.
+ PostUpdateMessage("benchmark_result", total_time);
+}
+
+void Planet::SetZoom(float zoom) {
+ ui_zoom_ = std::min(kZoomMax, std::max(kZoomMin, zoom));
+ SetEyeXYZ(0.0f, 0.0f, -ui_zoom_);
+}
+
+void Planet::SetLight(float light) {
+ ui_light_ = std::min(kLightMax, std::max(kLightMin, light));
+ SetDiffuseRGB(0.8f * ui_light_, 0.8f * ui_light_, 0.8f * ui_light_);
+ SetAmbientRGB(0.4f * ui_light_, 0.4f * ui_light_, 0.4f * ui_light_);
+}
+
+void Planet::SetTexture(const std::string& name, int width, int height,
+ uint32_t* pixels) {
+ if (pixels) {
+ if (name == "earth.jpg") {
+ delete base_tex_;
+ base_tex_ = new Texture(width, height, pixels);
+ } else if (name == "earthnight.jpg") {
+ delete night_tex_;
+ night_tex_ = new Texture(width, height, pixels);
+ }
+ }
+}
+
+// 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;
+ }
+ 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:
+ return false;
+ }
+ return true;
+}
+
+// PostUpdateMessage() helper function for sending small messages to JS.
+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));
+}
+
+void Planet::Update() {
+ // Don't call FlushPixelBuffer() when benchmarking - vsync is enabled by
+ // default, and will throttle the benchmark results.
+ do {
+ UpdateSim();
+ Render();
+ if (!benchmarking_) break;
+ --benchmark_frame_counter_;
+ } while (benchmark_frame_counter_ > 0);
+ 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() {}
+
+ // Create and return a Planet instance.
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new Planet(instance);
+ }
+};
+
+namespace pp {
+Module* CreateModule() {
+ return new PlanetModule();
+}
+} // namespace pp
+
diff --git a/native_client_sdk/src/examples/demo/earth/earth.jpg b/native_client_sdk/src/examples/demo/earth/earth.jpg
new file mode 100644
index 0000000000..82bd420a87
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/earth/earth.jpg
Binary files differ
diff --git a/native_client_sdk/src/examples/demo/earth/earthnight.jpg b/native_client_sdk/src/examples/demo/earth/earthnight.jpg
new file mode 100644
index 0000000000..301f152567
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/earth/earthnight.jpg
Binary files differ
diff --git a/native_client_sdk/src/examples/demo/earth/example.dsc b/native_client_sdk/src/examples/demo/earth/example.dsc
new file mode 100644
index 0000000000..21eb60c354
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/earth/example.dsc
@@ -0,0 +1,22 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
+ 'TARGETS': [
+ {
+ 'NAME' : 'earth',
+ 'TYPE' : 'main',
+ 'SOURCES' : [
+ 'earth.cc'
+ ],
+ 'LIBS': ['sdk_util', 'ppapi_cpp', 'ppapi', 'pthread']
+ }
+ ],
+ 'DATA': [
+ 'earth.jpg',
+ 'earthnight.jpg',
+ 'example.js',
+ ],
+ 'DEST': 'examples/demo',
+ 'NAME': 'earth',
+ 'TITLE': 'Multi-Threaded Earth Demo',
+ 'GROUP': 'Demo'
+}
diff --git a/native_client_sdk/src/examples/demo/earth/example.js b/native_client_sdk/src/examples/demo/earth/example.js
new file mode 100644
index 0000000000..34f6c1142c
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/earth/example.js
@@ -0,0 +1,88 @@
+// 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.
+
+function moduleDidLoad() {
+}
+
+function postThreadFunc(numThreads) {
+ return function () {
+ common.naclModule.postMessage({'message' : 'set_threads',
+ 'value' : numThreads});
+ }
+}
+
+// Add event listeners after the NaCl module has loaded. These listeners will
+// forward messages to the NaCl module via postMessage()
+function attachListeners() {
+ document.getElementById('benchmark').addEventListener('click',
+ function() {
+ common.naclModule.postMessage({'message' : 'run benchmark'});
+ common.updateStatus('BENCHMARKING... (please wait)');
+ });
+ var threads = [0, 1, 2, 4, 6, 8, 12, 16, 24, 32];
+ for (var i = 0; i < threads.length; i++) {
+ document.getElementById('radio'+i).addEventListener('click',
+ postThreadFunc(threads[i]));
+ }
+ document.getElementById('zoomRange').addEventListener('change',
+ function() {
+ var value = parseFloat(document.getElementById('zoomRange').value);
+ common.naclModule.postMessage({'message' : 'set_zoom',
+ 'value' : value});
+ });
+ document.getElementById('lightRange').addEventListener('change',
+ function() {
+ var value = parseFloat(document.getElementById('lightRange').value);
+ common.naclModule.postMessage({'message' : 'set_light',
+ 'value' : value});
+ });
+}
+
+// Load a texture and send pixel data down to NaCl module.
+function loadTexture(name) {
+ // Load image from jpg, decompress into canvas.
+ var img = new Image();
+ img.onload = function() {
+ var graph = document.createElement('canvas');
+ graph.width = img.width;
+ graph.height = img.height;
+ var context = graph.getContext('2d');
+ context.drawImage(img, 0, 0);
+ var imageData = context.getImageData(0, 0, img.width, img.height);
+ // Send NaCl module the raw image data obtained from canvas.
+ common.naclModule.postMessage({'message' : 'texture',
+ 'name' : name,
+ 'width' : img.width,
+ 'height' : img.height,
+ 'data' : imageData.data.buffer});
+ }
+ img.src = name;
+}
+
+// Handle a message coming from the NaCl module.
+function handleMessage(message_event) {
+ if (message_event.data['message'] == 'benchmark_result') {
+ // benchmark result
+ var result = message_event.data['value'];
+ console.log('Benchmark result:' + result);
+ result = (Math.round(result * 1000) / 1000).toFixed(3);
+ document.getElementById('result').textContent =
+ 'Result: ' + result + ' seconds';
+ common.updateStatus('SUCCESS');
+ } else if (message_event.data['message'] == 'set_zoom') {
+ // zoom slider
+ var zoom = message_event.data['value'];
+ document.getElementById('zoomRange').value = zoom;
+ } else if (message_event.data['message'] == 'set_light') {
+ // light slider
+ var light = message_event.data['value'];
+ document.getElementById('lightRange').value = light;
+ } else if (message_event.data['message'] == 'request_textures') {
+ // NaCl module is requesting a set of textures.
+ var names = message_event.data['names'];
+ for (var i = 0; i < names.length; i++)
+ loadTexture(names[i]);
+ }
+}
+
diff --git a/native_client_sdk/src/examples/demo/earth/index.html b/native_client_sdk/src/examples/demo/earth/index.html
new file mode 100644
index 0000000000..8ca4aa42aa
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/earth/index.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<!--
+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.
+-->
+<head>
+ <meta http-equiv="Pragma" content="no-cache">
+ <meta http-equiv="Expires" content="-1">
+ <meta charset="UTF-8">
+ <title>{{title}}</title>
+ <script type="text/javascript" src="common.js"></script>
+ <script type="text/javascript" src="example.js"></script>
+</head>
+<body {{attrs}} data-width="640" data-height="640">
+ <h1>{{title}}</h1>
+ <h2>Status: <code id="statusField">NO-STATUS</code></h2>
+ <div>
+ This demo renders a rotating globe using the Graphics2D interface.
+ Image Credit:
+ NASA Goddard Space Flight Center Image by Reto Stöckli (land surface,
+ shallow water, clouds). Enhancements by Robert Simmon (ocean color,
+ compositing, 3D globes, animation).
+ Data and technical support: MODIS Land Group; MODIS Science Data,
+ Support Team; MODIS Atmosphere Group; MODIS Ocean Group Additional data:
+ USGS EROS Data Center (topography); USGS Terrestrial Remote Sensing
+ Flagstaff Field Center (Antarctica); Defense Meteorological
+ Satellite Program (city lights).
+ <br>
+ Zoom:
+ <input type="range" id="zoomRange"
+ min="1.0" max="50.0" step="0.5" value="14.0" />
+ Light:
+ <input type="range" id="lightRange"
+ min="0.2" max="2.0" step=".01" value="1.0" />
+ <br>
+ Number of threads (0 is main thread):
+ <input type="radio" name="threadCount" id="radio0" value="0"
+ checked="checked">
+ <label for="radio0">0</label>
+ <input type="radio" name="threadCount" id="radio1" value="1">
+ <label for="radio1">1</label>
+ <input type="radio" name="threadCount" id="radio2" value="2">
+ <label for="radio2">2</label>
+ <input type="radio" name="threadCount" id="radio3" value="4">
+ <label for="radio3">4</label>
+ <input type="radio" name="threadCount" id="radio4" value="6">
+ <label for="radio4">6</label>
+ <input type="radio" name="threadCount" id="radio5" value="8">
+ <label for="radio5">8</label>
+ <input type="radio" name="threadCount" id="radio6" value="12">
+ <label for="radio6">12</label>
+ <input type="radio" name="threadCount" id="radio7" value="16">
+ <label for="radio7">16</label>
+ <input type="radio" name="threadCount" id="radio8" value="24">
+ <label for="radio8">24</label>
+ <input type="radio" name="threadCount" id="radio9" value="32">
+ <label for="radio9">32</label>
+ <br>
+ <input type="submit" id="benchmark" value="Run Benchmark">
+ <label id="result" name="result"> </label>
+ </div>
+ <!-- The NaCl plugin will be embedded inside the element with id "listener".
+ See common.js.-->
+ <div id="listener"></div>
+</body>
+</html>
diff --git a/native_client_sdk/src/examples/demo/flock/example.dsc b/native_client_sdk/src/examples/demo/flock/example.dsc
new file mode 100644
index 0000000000..50fdeeb462
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/example.dsc
@@ -0,0 +1,26 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
+ 'TARGETS': [
+ {
+ 'NAME' : 'flock',
+ 'TYPE' : 'main',
+ 'SOURCES' : [
+ 'flock.cc',
+ 'goose.cc',
+ 'goose.h',
+ 'sprite.cc',
+ 'sprite.h',
+ 'vector2.h'
+ ],
+ 'DEPS': ['ppapi_simple', 'nacl_io'],
+ 'LIBS': ['ppapi_cpp', 'ppapi', 'pthread']
+ }
+ ],
+ 'DATA': [
+ 'images/flock_green.raw'
+ ],
+ 'DEST': 'examples/demo',
+ 'NAME': 'flock',
+ 'TITLE': 'Flocking Geese',
+ 'GROUP': 'Demo'
+}
diff --git a/native_client_sdk/src/examples/demo/flock/flock.cc b/native_client_sdk/src/examples/demo/flock/flock.cc
new file mode 100644
index 0000000000..de23691149
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/flock.cc
@@ -0,0 +1,150 @@
+// 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "nacl_io/nacl_io.h"
+
+#include "ppapi/c/pp_rect.h"
+#include "ppapi/c/pp_size.h"
+
+#include "ppapi_simple/ps_context_2d.h"
+#include "ppapi_simple/ps_main.h"
+
+#include "goose.h"
+#include "sprite.h"
+#include "vector2.h"
+
+
+namespace {
+ // The goose sprites rotate in increments of 5 degrees.
+const double kGooseHeadingIncrement = (5.0 * M_PI) / 180.0;
+} // namespace
+
+struct ImageFormat {
+ int width;
+ int height;
+ int channels;
+};
+
+Sprite* g_goose_sprite;
+std::vector<Goose> g_geese;
+std::vector<Vector2> g_attractors;
+
+
+void ResetFlock(PSContext2D_t* ctx, size_t count) {
+ Vector2 center(0.5 * ctx->width, 0.5 * ctx->height);
+
+ g_geese.resize(count);
+ for (size_t i = 0; i < count; i++) {
+ double dx = (double) rand() / (double) RAND_MAX;
+ double dy = (double) rand() / (double) RAND_MAX;
+ g_geese[i] = Goose(center, Vector2(dx, dy));
+ }
+}
+
+void Render(PSContext2D_t* ctx) {
+ PSContext2DGetBuffer(ctx);
+ const size_t num_geese = g_geese.size();
+
+ if (NULL == g_goose_sprite) return;
+ if (NULL == ctx->data) return;
+
+ // Clear to WHITE
+ memset(ctx->data, 0xFF, ctx->stride * ctx->height);
+
+ int32_t sprite_side_length = g_goose_sprite->size().height();
+ pp::Rect sprite_src_rect(0, 0, sprite_side_length, sprite_side_length);
+ pp::Rect canvas_bounds(pp::Size(ctx->width, ctx->height));
+
+
+ // Run the simulation for each goose.
+ for (size_t i = 0; i < num_geese; i++) {
+ Goose& goose = g_geese[i];
+
+ // Update position and orientation
+ goose.SimulationTick(g_geese, g_attractors, canvas_bounds);
+ pp::Point dest_point(goose.location().x() - sprite_side_length / 2,
+ goose.location().y() - sprite_side_length / 2);
+
+ // Compute image to use
+ double heading = goose.velocity().Heading();
+ if (heading < 0.0)
+ heading = M_PI * 2.0 + heading;
+
+ int32_t sprite_index =
+ static_cast<int32_t>(heading / kGooseHeadingIncrement);
+
+ sprite_src_rect.set_x(sprite_index * sprite_side_length);
+ g_goose_sprite->CompositeFromRectToPoint(
+ sprite_src_rect,
+ ctx->data, canvas_bounds, 0,
+ dest_point);
+ }
+
+ PSContext2DSwapBuffer(ctx);
+}
+
+/*
+ * 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[]) {
+ ImageFormat fmt;
+ uint32_t* buffer;
+ size_t len;
+
+ PSEventSetFilter(PSE_ALL);
+
+ // Mount the images directory as an HTTP resource.
+ mount("images", "/images", "httpfs", 0, "");
+
+ FILE* fp = fopen("/images/flock_green.raw", "rb");
+ fread(&fmt, sizeof(fmt), 1, fp);
+
+ len = fmt.width * fmt.height * fmt.channels;
+ buffer = new uint32_t[len];
+ fread(buffer, 1, len, fp);
+ fclose(fp);
+
+ g_goose_sprite = new Sprite(buffer, pp::Size(fmt.width, fmt.height), 0);
+
+ PSContext2D_t* ctx = PSContext2DAllocate();
+ ResetFlock(ctx, 50);
+ while (1) {
+ PSEvent* event;
+
+ // Consume all available events
+ while ((event = PSEventTryAcquire()) != NULL) {
+ PSContext2DHandleEvent(ctx, event);
+ PSEventRelease(event);
+ }
+
+ if (ctx->bound) {
+ Render(ctx);
+ } else {
+ // If not bound, wait for an event which may signal a context becoming
+ // available, instead of spinning.
+ event = PSEventWaitAcquire();
+ if (PSContext2DHandleEvent(ctx, event))
+ ResetFlock(ctx, 50);
+ PSEventRelease(event);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * 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/flock/frame_counter.cc b/native_client_sdk/src/examples/demo/flock/frame_counter.cc
new file mode 100644
index 0000000000..e9e4c54534
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/frame_counter.cc
@@ -0,0 +1,43 @@
+// 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 <time.h>
+#include <limits>
+
+#include "nacl_app/flock.h"
+
+void FrameCounter::BeginFrame() {
+ struct timeval start_time;
+ gettimeofday(&start_time, NULL);
+ frame_start_ = start_time.tv_sec * kMicroSecondsPerSecond +
+ start_time.tv_usec;
+}
+
+void FrameCounter::EndFrame() {
+ struct timeval end_time;
+ gettimeofday(&end_time, NULL);
+ double frame_end = end_time.tv_sec * kMicroSecondsPerSecond +
+ end_time.tv_usec;
+ double dt = frame_end - frame_start_;
+ if (dt < 0)
+ return;
+ frame_duration_accumulator_ += dt;
+ frame_count_++;
+ if (frame_count_ > kFrameRateRefreshCount ||
+ frame_duration_accumulator_ >= kMicroSecondsPerSecond) {
+ double elapsed_time = frame_duration_accumulator_ /
+ kMicroSecondsPerSecond;
+ if (fabs(elapsed_time) > std::numeric_limits<double>::epsilon()) {
+ frames_per_second_ = frame_count_ / elapsed_time;
+ }
+ frame_duration_accumulator_ = 0;
+ frame_count_ = 0;
+ }
+}
+
+void FrameCounter::Reset() {
+ frames_per_second_ = 0;
+ frame_duration_accumulator_ = 0;
+ frame_count_ = 0;
+}
diff --git a/native_client_sdk/src/examples/demo/flock/frame_counter.h b/native_client_sdk/src/examples/demo/flock/frame_counter.h
new file mode 100644
index 0000000000..26a1b66288
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/frame_counter.h
@@ -0,0 +1,46 @@
+// 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 FRAME_COUNTER_H_
+#define FRAME_COUNTER_H_
+
+class FrameCounter {
+ public:
+ FrameCounter()
+ : frame_duration_accumulator_(0),
+ frame_count_(0),
+ frames_per_second_(0) {}
+ ~FrameCounter() {}
+
+ // Record the current time, which is used to compute the frame duration
+ // when EndFrame() is called.
+ void BeginFrame();
+
+ // Compute the delta since the last call to BeginFrame() and increment the
+ // frame count. Update the frame rate whenever the prescribed number of
+ // frames have been counted, or at least one second of simulator time has
+ // passed, whichever is less.
+ void EndFrame();
+
+ // Reset the frame counters back to 0.
+ void Reset();
+
+ // The current frame rate. Note that this is 0 for the first second in
+ // the accumulator, and is updated every 100 frames (and at least once
+ // every second of simulation time or so).
+ double frames_per_second() const {
+ return frames_per_second_;
+ }
+
+ private:
+ static const double kMicroSecondsPerSecond = 1000000.0;
+ static const int32_t kFrameRateRefreshCount = 100;
+
+ double frame_duration_accumulator_; // Measured in microseconds.
+ int32_t frame_count_;
+ double frame_start_;
+ double frames_per_second_;
+};
+
+#endif // FRAME_COUNTER_H_
diff --git a/native_client_sdk/src/examples/demo/flock/goose.cc b/native_client_sdk/src/examples/demo/flock/goose.cc
new file mode 100644
index 0000000000..f706134c65
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/goose.cc
@@ -0,0 +1,204 @@
+ // 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 "goose.h"
+
+namespace {
+// The maximum speed of a goose. Measured in meters/second.
+const double kMaxSpeed = 2.0;
+
+// The maximum force that can be applied to turn a goose when computing the
+// aligment. Measured in meters/second/second.
+const double kMaxTurningForce = 0.05;
+
+// The neighbour radius of a goose. Only geese within this radius will affect
+// the flocking computations of this goose. Measured in pixels.
+const double kNeighbourRadius = 64.0;
+
+// The minimum distance that a goose can be from this goose. If another goose
+// comes within this distance of this goose, the flocking algorithm tries to
+// move the geese apart. Measured in pixels.
+const double kPersonalSpace = 32.0;
+
+// The distance at which attractors have effect on a goose's direction.
+const double kAttractorRadius = 320.0;
+
+// The goose will try to turn towards geese within this distance (computed
+// during the cohesion phase). Measured in pixels.
+const double kMaxTurningDistance = 100.0;
+
+// The weights used when computing the weighted sum the three flocking
+// components.
+const double kSeparationWeight = 2.0;
+const double kAlignmentWeight = 1.0;
+const double kCohesionWeight = 1.0;
+
+} // namespace
+
+
+Goose::Goose() : location_(0, 0), velocity_(0, 0) {
+}
+
+Goose::Goose(const Vector2& location, const Vector2& velocity)
+ : location_(location),
+ velocity_(velocity) {
+}
+
+void Goose::SimulationTick(const std::vector<Goose>& geese,
+ const std::vector<Vector2>& attractors,
+ const pp::Rect& flock_box) {
+
+ Vector2 acceleration = DesiredVector(geese, attractors);
+ velocity_.Add(acceleration);
+
+ // Limit the velocity to a maximum speed.
+ velocity_.Clamp(kMaxSpeed);
+
+ location_.Add(velocity_);
+
+ // Wrap the goose location to the flock box.
+ if (!flock_box.IsEmpty()) {
+ while (location_.x() < flock_box.x())
+ location_.set_x(location_.x() + flock_box.width());
+
+ while (location_.x() >= flock_box.right())
+ location_.set_x(location_.x() - flock_box.width());
+
+ while (location_.y() < flock_box.y())
+ location_.set_y(location_.y() + flock_box.height());
+
+ while (location_.y() >= flock_box.bottom())
+ location_.set_y(location_.y() - flock_box.height());
+ }
+}
+
+Vector2 Goose::DesiredVector(const std::vector<Goose>& geese,
+ const std::vector<Vector2>& attractors) {
+ // Loop over all the neighbouring geese in the flock, accumulating
+ // the separation mean, the alignment mean and the cohesion mean.
+ int32_t separation_count = 0;
+ Vector2 separation;
+ int32_t align_count = 0;
+ Vector2 alignment;
+ int32_t cohesion_count = 0;
+ Vector2 cohesion;
+
+ for (std::vector<Goose>::const_iterator goose_it = geese.begin();
+ goose_it < geese.end();
+ ++goose_it) {
+ const Goose& goose = *goose_it;
+
+ // Compute the distance from this goose to its neighbour.
+ Vector2 goose_delta = Vector2::Difference(
+ location_, goose.location());
+ double distance = goose_delta.Magnitude();
+
+ separation_count = AccumulateSeparation(
+ distance, goose_delta, &separation, separation_count);
+
+ align_count = AccumulateAlignment(
+ distance, goose, &alignment, align_count);
+ cohesion_count = AccumulateCohesion(
+ distance, goose, &cohesion, cohesion_count);
+ }
+
+ // Compute the means and create a weighted sum. This becomes the goose's new
+ // acceleration.
+ if (separation_count > 0) {
+ separation.Scale(1.0 / static_cast<double>(separation_count));
+ }
+ if (align_count > 0) {
+ alignment.Scale(1.0 / static_cast<double>(align_count));
+ // Limit the effect that alignment has on the final acceleration. The
+ // alignment component can overpower the others if there is a big
+ // difference between this goose's velocity and its neighbours'.
+ alignment.Clamp(kMaxTurningForce);
+ }
+
+ // Compute the effect of the attractors and blend this in with the flock
+ // cohesion component. An attractor has to be within kAttractorRadius to
+ // effect the heading of a goose.
+ for (size_t i = 0; i < attractors.size(); ++i) {
+ Vector2 attractor_direction = Vector2::Difference(
+ attractors[i], location_);
+ double distance = attractor_direction.Magnitude();
+ if (distance < kAttractorRadius) {
+ attractor_direction.Scale(1000); // Each attractor acts like 1000 geese.
+ cohesion.Add(attractor_direction);
+ cohesion_count++;
+ }
+ }
+
+ // If there is a non-0 cohesion component, steer the goose so that it tries
+ // to follow the flock.
+ if (cohesion_count > 0) {
+ cohesion.Scale(1.0 / static_cast<double>(cohesion_count));
+ cohesion = TurnTowardsTarget(cohesion);
+ }
+ // Compute the weighted sum.
+ separation.Scale(kSeparationWeight);
+ alignment.Scale(kAlignmentWeight);
+ cohesion.Scale(kCohesionWeight);
+ Vector2 weighted_sum = cohesion;
+ weighted_sum.Add(alignment);
+ weighted_sum.Add(separation);
+ return weighted_sum;
+}
+
+Vector2 Goose::TurnTowardsTarget(const Vector2& target) {
+ Vector2 desired_direction = Vector2::Difference(target, location_);
+ double distance = desired_direction.Magnitude();
+ Vector2 new_direction;
+ if (distance > 0.0) {
+ desired_direction.Normalize();
+ // If the target is within the turning affinity distance, then make the
+ // desired direction based on distance to the target. Otherwise, base
+ // the desired direction on MAX_SPEED.
+ if (distance < kMaxTurningDistance) {
+ // Some pretty arbitrary dampening.
+ desired_direction.Scale(kMaxSpeed * distance / 100.0);
+ } else {
+ desired_direction.Scale(kMaxSpeed);
+ }
+ new_direction = Vector2::Difference(desired_direction, velocity_);
+ new_direction.Clamp(kMaxTurningForce);
+ }
+ return new_direction;
+}
+
+int32_t Goose::AccumulateSeparation(double distance,
+ const Vector2& goose_delta,
+ Vector2* separation, /* inout */
+ int32_t separation_count) {
+ if (distance > 0.0 && distance < kPersonalSpace) {
+ Vector2 weighted_direction = goose_delta;
+ weighted_direction.Normalize();
+ weighted_direction.Scale(1.0 / distance);
+ separation->Add(weighted_direction);
+ separation_count++;
+ }
+ return separation_count;
+}
+
+int32_t Goose::AccumulateAlignment(double distance,
+ const Goose& goose,
+ Vector2* alignment, /* inout */
+ int32_t align_count) {
+ if (distance > 0.0 && distance < kNeighbourRadius) {
+ alignment->Add(goose.velocity());
+ align_count++;
+ }
+ return align_count;
+}
+
+int32_t Goose::AccumulateCohesion(double distance,
+ const Goose& goose,
+ Vector2* cohesion, /* inout */
+ int32_t cohesion_count) {
+ if (distance > 0.0 && distance < kNeighbourRadius) {
+ cohesion->Add(goose.location());
+ cohesion_count++;
+ }
+ return cohesion_count;
+}
diff --git a/native_client_sdk/src/examples/demo/flock/goose.h b/native_client_sdk/src/examples/demo/flock/goose.h
new file mode 100644
index 0000000000..2bd5be0518
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/goose.h
@@ -0,0 +1,129 @@
+// 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 GOOSE_H_
+#define GOOSE_H_
+
+#include <vector>
+#include "ppapi/cpp/rect.h"
+
+#include "vector2.h"
+
+// A Goose. Each goose has a location and a velocity. Implements the
+// flocking algortihm described here:
+// http://processingjs.org/learning/topic/flocking with references to
+// http://harry.me/2011/02/17/neat-algorithms---flocking.
+class Goose {
+ public:
+ // Initialize a Goose at location (0, 0) no velocity.
+ Goose();
+
+ // Initialize a Goose at the given location with the specified velocity.
+ Goose(const Vector2& location, const Vector2& velocity);
+
+ // Run one tick of the simulation. Compute a new acceleration based on the
+ // flocking algorithm (see Goose.flock()) and update the goose's location
+ // by integrating acceleration and velocity.
+ // @param geese The list of all the geese in the flock.
+ // @param attractors The list of attractors. Geese have affinity for these
+ // points.
+ // @param flockBox The geese will stay inside of this box. If the flock_box
+ // is empty, the geese don't have boundaries.
+ void SimulationTick(const std::vector<Goose>& geese,
+ const std::vector<Vector2>& attractors,
+ const pp::Rect& flock_box);
+
+ // Implement the flocking algorithm in five steps:
+ // 1. Compute the separation component,
+ // 2. Compute the alignment component,
+ // 3. Compute the cohesion component.
+ // 4. Compute the effect of the attractors and blend this in with the
+ // cohesion component.
+ // 5. Create a weighted sum of the three components and use this as the
+ // new acceleration for the goose.
+ // This is an O(n^2) version of the algorithm. There are ways to speed this
+ // up using spatial coherence techniques, but this version is much simpler.
+ // @param geese The list of all the neighbouring geese (in this
+ // implementation, this is all the geese in the flock).
+ // @param attractors The list of attractors. Geese have affinity for these
+ // points.
+ // @return The acceleration vector for this goose based on the flocking
+ // algorithm.
+ Vector2 DesiredVector(const std::vector<Goose>& geese,
+ const std::vector<Vector2>& attractors);
+
+ // Turn the goose towards a target. The amount of turning force is clamped
+ // to |kMaxTurningForce|.
+ // @param target Turn the goose towards this target.
+ // @return A vector representing the new direction of the goose.
+ Vector2 TurnTowardsTarget(const Vector2& target);
+
+ // Accessors for location and velocoity.
+ Vector2 location() const {
+ return location_;
+ }
+ Vector2 velocity() const {
+ return velocity_;
+ }
+
+ private:
+ // Add a neighbouring goose's contribution to the separation mean. Only
+ // consider geese that have moved inside of this goose's personal space.
+ // Modifies the separation accumulator |separation| in-place.
+ // @param distance The distance from this goose to the neighbouring goose.
+ // @param gooseDirection The direction vector from this goose to the
+ // neighbour.
+ // @param separation The accumulated separation from all the neighbouring
+ // geese.
+ // @param separationCount The current number of geese that have contributed to
+ // the separation component so far.
+ // @return The new count of geese that contribute to the separation component.
+ // If the goose under consideration does not contribute, this value is the
+ // same as |separationCount|.
+ int32_t AccumulateSeparation(double distance,
+ const Vector2& goose_direction,
+ Vector2* separation, /* inout */
+ int32_t separation_count);
+
+ // Add a neighbouring goose's contribution to the alignment mean. Alignment
+ // is the average velocity of the neighbours. Only consider geese that are
+ // within |kNeighbourRadius|. Modifies the alignment accumulator |alignment|
+ // in-place.
+ // @param distance The distance from this goose to the neighbouring goose.
+ // @param goose The neighbouring goose under consideration.
+ // @param alignment The accumulated alignment from all the neighbouring geese.
+ // @param alignCount The current number of geese that have contributed to the
+ // alignment component so far.
+ // @return The new count of geese that contribute to the alignment component.
+ // If the goose under consideration does not contribute, this value is the
+ // same as |alignCount|.
+ int32_t AccumulateAlignment(double distance,
+ const Goose& goose,
+ Vector2* alignment, /* inout */
+ int32_t align_count);
+
+ // Add a neighbouring goose's contribution to the cohesion mean. Cohesion is
+ // based on the average location of the neighbours. The goose attempts to
+ // point to this average location. Only consider geese that are within
+ // |kNeighbourRadius|. Modifies the cohesion accumulator |cohesion| in-place.
+ // @param {!number} distance The distance from this goose to the neighbouring
+ // goose.
+ // @param {!Goose} goose The neighbouring goose under consideration.
+ // @param {!goog.math.Vec2} cohesion The accumulated cohesion from all the
+ // neighbouring geese.
+ // @param {!number} cohesionCount The current number of geese that have
+ // contributed to the cohesion component so far.
+ // @return {!number} The new count of geese that contribute to the cohesion
+ // component. If the goose under consideration does not contribute, this
+ // value is the same as |cohesionCount|.
+ int32_t AccumulateCohesion(double distance,
+ const Goose& goose,
+ Vector2* cohesion, /* inout */
+ int32_t cohesion_count);
+
+ Vector2 location_;
+ Vector2 velocity_;
+};
+
+#endif // GOOSE_H_
diff --git a/native_client_sdk/src/examples/demo/flock/index.html b/native_client_sdk/src/examples/demo/flock/index.html
new file mode 100644
index 0000000000..d20182dbaa
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/index.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<!--
+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.
+-->
+<head>
+ <meta http-equiv="Pragma" content="no-cache">
+ <meta http-equiv="Expires" content="-1">
+ <title>{{title}}</title>
+ <script type="text/javascript" src="common.js"></script>
+</head>
+<body data-width="800" data-height="800" {{attrs}}>
+ <h1>{{title}}</h1>
+ <h2>Status: <code id="statusField">NO-STATUS</code></h2>
+ <p> Simulates the swarming and avoiding flight behavior of a flock of
+ geese. This demo using the ppapi_simple library to automatically handle
+ creation and maintainence of the 2D graphics context, providing a pointer
+ and stride for a 32 bit (RGBA/ARGB) area in which the example draws
+ every frame.
+ </p>
+ <!-- The NaCl plugin will be embedded inside the element with id "listener".
+ See common.js.-->
+ <div id="listener"></div>
+</body>
+</html>
diff --git a/native_client_sdk/src/examples/demo/flock/sprite.cc b/native_client_sdk/src/examples/demo/flock/sprite.cc
new file mode 100644
index 0000000000..553fc55b83
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/sprite.cc
@@ -0,0 +1,91 @@
+// 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "sprite.h"
+
+namespace {
+
+inline uint32_t Blend(uint32_t src1, uint32_t src2) {
+ // Divide both sources by 2, then add them together using a mask
+ // to avoid overflow.
+ src1 = (src1 >> 1) & 0x7F7F7F7F;
+ src2 = (src2 >> 1) & 0x7F7F7F7F;
+ return src1 + src2;
+}
+
+} // namespace
+
+
+Sprite::Sprite(uint32_t* pixel_buffer,
+ const pp::Size& size,
+ int32_t row_bytes) {
+ SetPixelBuffer(pixel_buffer, size, row_bytes);
+}
+
+Sprite::~Sprite() {
+ delete[] pixel_buffer_;
+}
+
+void Sprite::SetPixelBuffer(uint32_t* pixel_buffer,
+ const pp::Size& size,
+ int32_t row_bytes) {
+ pixel_buffer_ = pixel_buffer;
+ pixel_buffer_size_ = size;
+ row_bytes_ = row_bytes ? row_bytes : size.width() * sizeof(uint32_t);
+}
+
+void Sprite::CompositeFromRectToPoint(const pp::Rect& src_rect,
+ uint32_t* dest_pixel_buffer,
+ const pp::Rect& dest_bounds,
+ int32_t dest_row_bytes,
+ const pp::Point& dest_point) const {
+ // Clip the source rect to the source image bounds.
+ pp::Rect src_bounds(pp::Point(), size());
+ pp::Rect src_rect_clipped(src_rect.Intersect(src_bounds));
+ if (src_rect_clipped.IsEmpty())
+ return;
+
+ // Create a clipped rect in the destination coordinate space that contains the
+ // final image.
+ pp::Rect draw_rect(dest_point, src_rect_clipped.size());
+ pp::Rect draw_rect_clipped(dest_bounds.Intersect(draw_rect));
+ if (draw_rect_clipped.IsEmpty())
+ return;
+ // Transform the dest rect to the source image coordinate system.
+ pp::Point src_offset(draw_rect_clipped.point());
+ src_offset -= dest_point;
+ src_rect_clipped.Offset(src_offset);
+ src_rect_clipped.set_size(draw_rect_clipped.size());
+ size_t src_byte_offset = src_rect_clipped.x() * sizeof(uint32_t) +
+ src_rect_clipped.y() * row_bytes_;
+ const uint8_t* src_pixels =
+ reinterpret_cast<const uint8_t*>(pixel_buffer_) + src_byte_offset;
+
+ if (dest_row_bytes == 0)
+ dest_row_bytes = dest_bounds.width() * sizeof(uint32_t);
+ size_t dest_byte_offset = draw_rect_clipped.point().x() * sizeof(uint32_t) +
+ draw_rect_clipped.point().y() * dest_row_bytes;
+ uint8_t* dest_pixels = reinterpret_cast<uint8_t*>(dest_pixel_buffer) +
+ dest_byte_offset;
+
+ for (int32_t y = 0; y < src_rect_clipped.height(); ++y) {
+ const uint32_t* src_scanline =
+ reinterpret_cast<const uint32_t*>(src_pixels);
+ uint32_t* dest_scanline = reinterpret_cast<uint32_t*>(dest_pixels);
+ for (int32_t x = 0; x < src_rect_clipped.width(); ++x) {
+ uint32_t src = *src_scanline++;
+ uint32_t dst = *dest_scanline;
+ *dest_scanline++ = Blend(dst, src);
+ }
+ src_pixels += row_bytes_;
+ dest_pixels += dest_row_bytes;
+ }
+}
+
diff --git a/native_client_sdk/src/examples/demo/flock/sprite.h b/native_client_sdk/src/examples/demo/flock/sprite.h
new file mode 100644
index 0000000000..b846768f56
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/sprite.h
@@ -0,0 +1,57 @@
+// 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 SPRITE_H_
+#define SPRITE_H_
+
+#include <vector>
+#include "ppapi/cpp/point.h"
+#include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/size.h"
+
+
+// A Sprite is a simple container of a pixel buffer. It knows how to
+// composite itself to another pixel buffer of the same format.
+class Sprite {
+ public:
+ // Initialize a Sprite to use the attached pixel buffer. The Sprite takes
+ // ownership of the pixel buffer, deleting it in the dtor. The pixel
+ // buffer is assumed to be 32-bit ARGB-8-8-8-8 pixel format, with pre-
+ // multiplied alpha. If |row_bytes| is 0, then the number of bytes per row
+ // is assumed to be size.width() * sizeof(uint32_t).
+ Sprite(uint32_t* pixel_buffer, const pp::Size& size, int32_t stride = 0);
+
+ // Delete the pixel buffer. It is assumed that the pixel buffer was created
+ // using malloc().
+ ~Sprite();
+
+ // Reset the internal pixel buffer to a new one. Deletes the old pixel
+ // buffer. Sprite takes ownership of the new pixel buffer. If |row_bytes|
+ // is 0, then the number of bytes per row is assumed to be size.width() *
+ // sizeof(uint32_t).
+ void SetPixelBuffer(uint32_t* pixel_buffer,
+ const pp::Size& size,
+ int32_t row_bytes);
+
+ // Composite the section of the Sprite contained in |src_rect| into the given
+ // pixel buffer at |dest_point|. Performs an average of the source and
+ // dest pixel, and all necessary clipping.
+ void CompositeFromRectToPoint(const pp::Rect& src_rect,
+ uint32_t* dest_pixel_buffer,
+ const pp::Rect& dest_bounds,
+ int32_t dest_row_bytes,
+ const pp::Point& dest_point) const;
+
+ // Accessors.
+ const pp::Size& size() const {
+ return pixel_buffer_size_;
+ }
+
+ private:
+ uint32_t* pixel_buffer_;
+ pp::Size pixel_buffer_size_;
+ int32_t row_bytes_;
+};
+
+#endif // SPRITE_H_
diff --git a/native_client_sdk/src/examples/demo/flock/vector2.h b/native_client_sdk/src/examples/demo/flock/vector2.h
new file mode 100644
index 0000000000..9d68178f6d
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/flock/vector2.h
@@ -0,0 +1,81 @@
+// 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 VECTOR2_H_
+#define VECTOR2_H_
+
+#include <stdlib.h>
+#include <cmath>
+#include <limits>
+
+// A small class that encapsulates a 2D vector. Provides a few simple
+// operations.
+
+class Vector2 {
+ public:
+ Vector2() : x_(0.0), y_(0.0) {}
+ Vector2(double x, double y) : x_(x), y_(y) {}
+ ~Vector2() {}
+
+ // Create a new vector that represents a - b.
+ static Vector2 Difference(const Vector2& a, const Vector2& b) {
+ Vector2 diff(a.x() - b.x(), a.y() - b.y());
+ return diff;
+ }
+
+ // The magnitude of this vector.
+ double Magnitude() const {
+ return sqrt(x_ * x_ + y_ * y_);
+ }
+
+ // Add |vec| to this vector. Works in-place.
+ void Add(const Vector2& vec) {
+ x_ += vec.x();
+ y_ += vec.y();
+ }
+
+ // Normalize this vector in-place. If the vector is degenerate (size 0)
+ // then do nothing.
+ void Normalize() {
+ double mag = Magnitude();
+ if (fabs(mag) < std::numeric_limits<double>::epsilon())
+ return;
+ Scale(1.0 / mag);
+ }
+
+ // Scale the vector in-place by |scale|.
+ void Scale(double scale) {
+ x_ *= scale;
+ y_ *= scale;
+ }
+
+ // Clamp a vector to a maximum magnitude. Works on the vector in-place.
+ // @param max_mag The maximum magnitude of the vector.
+ void Clamp(double max_mag) {
+ double mag = Magnitude();
+ if (mag > max_mag) {
+ Scale(max_mag / mag); // Does Normalize() followed by Scale(max_mag).
+ }
+ }
+
+ // Compute the "heading" of a vector - this is the angle in radians between
+ // the vector and the x-axis.
+ // @return {!number} The "heading" angle in radians.
+ double Heading() const {
+ double angle = atan2(y_, x_);
+ return angle;
+ }
+
+ // Accessors and mutators for the coordinate values.
+ double x() const { return x_; }
+ void set_x(double x) { x_ = x; }
+
+ double y() const { return y_; }
+ void set_y(double y) { y_ = y; }
+
+ double x_;
+ double y_;
+};
+
+#endif // VECTOR2_H_
diff --git a/native_client_sdk/src/examples/demo/life/index.html b/native_client_sdk/src/examples/demo/life/index.html
index 626f532b5b..6a5978fdd6 100644
--- a/native_client_sdk/src/examples/demo/life/index.html
+++ b/native_client_sdk/src/examples/demo/life/index.html
@@ -14,8 +14,6 @@ found in the LICENSE file.
<body data-width="640" data-height="640" {{attrs}}>
<h1>{{title}}</h1>
<h2>Status: <code id="statusField">NO-STATUS</code></h2>
- <p>
- </p>
<!-- The NaCl plugin will be embedded inside the element with id "listener".
See common.js.-->
<div id="listener"></div>
diff --git a/native_client_sdk/src/examples/demo/nacl_io/example.js b/native_client_sdk/src/examples/demo/nacl_io/example.js
index 5221e5d013..5a75f167b4 100644
--- a/native_client_sdk/src/examples/demo/nacl_io/example.js
+++ b/native_client_sdk/src/examples/demo/nacl_io/example.js
@@ -8,10 +8,10 @@ function moduleDidLoad() {
// Called by the common.js module.
function domContentLoaded(name, tc, config, width, height) {
- window.webkitStorageInfo.requestQuota(window.PERSISTENT, 1024*1024,
+ navigator.webkitPersistentStorage.requestQuota(1024 * 1024,
function(bytes) {
common.updateStatus(
- 'Allocated '+bytes+' bytes of persistant storage.');
+ 'Allocated ' + bytes + ' bytes of persistant storage.');
common.createNaClModule(name, tc, config, width, height);
common.attachDefaultListeners();
},
@@ -78,7 +78,7 @@ function fopen(e) {
function fopenResult(filename, filehandle) {
filehandle_map[filehandle] = filename;
- addFilenameToSelectElements(filehandle, filename)
+ addFilenameToSelectElements(filehandle, filename);
common.logMessage('File ' + filename + ' opened successfully.\n');
}
@@ -143,6 +143,7 @@ function statResult(filename, size) {
*
* @param {string} s The string to search.
* @param {string} prefix The prefix to search for in |s|.
+ * @return {boolean} Whether |s| starts with |prefix|.
*/
function startsWith(s, prefix) {
// indexOf would search the entire string, lastIndexOf(p, 0) only checks at
diff --git a/native_client_sdk/src/examples/demo/pi_generator/example.dsc b/native_client_sdk/src/examples/demo/pi_generator/example.dsc
index 99aefd0aab..e62adeed80 100644
--- a/native_client_sdk/src/examples/demo/pi_generator/example.dsc
+++ b/native_client_sdk/src/examples/demo/pi_generator/example.dsc
@@ -1,11 +1,11 @@
{
- 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win', 'linux'],
+ 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'],
'TARGETS': [
{
'NAME' : 'pi_generator',
'TYPE' : 'main',
'SOURCES' : ['pi_generator.cc'],
- 'LIBS': ['ppapi_cpp', 'ppapi', 'pthread']
+ 'LIBS': ['ppapi_simple', 'nacl_io', 'ppapi_cpp', 'ppapi', 'pthread']
}
],
'DATA': [
diff --git a/native_client_sdk/src/examples/demo/pi_generator/example.js b/native_client_sdk/src/examples/demo/pi_generator/example.js
index dfc77467a4..0afee49e50 100644
--- a/native_client_sdk/src/examples/demo/pi_generator/example.js
+++ b/native_client_sdk/src/examples/demo/pi_generator/example.js
@@ -2,15 +2,6 @@
// 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() {
- setInterval(postPaintMessage, 5);
-}
-
-function postPaintMessage() {
- common.naclModule.postMessage('paint');
-}
-
// Handle a message coming from the NaCl module. The message payload is
// assumed to contain the current estimated value of Pi. Update the Pi
// text display with this value.
diff --git a/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc b/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
index 6259f0bb67..9b1f472ba9 100644
--- a/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
+++ b/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
@@ -3,333 +3,54 @@
// found in the LICENSE file.
#include <math.h>
-#include <pthread.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string>
-
-#include "ppapi/cpp/graphics_2d.h"
-#include "ppapi/cpp/image_data.h"
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/rect.h"
-#include "ppapi/cpp/size.h"
-#include "ppapi/cpp/var.h"
-#include "ppapi/utility/completion_callback_factory.h"
+#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"
#ifdef WIN32
#undef PostMessage
-// Allow 'this' in initializer list
-#pragma warning(disable : 4355)
#endif
namespace {
-const int kPthreadMutexSuccess = 0;
-const char* const kPaintMethodId = "paint";
-const double kInvalidPiValue = -1.0;
+
const int kMaxPointCount = 1000000000; // The total number of points to draw.
+const double kSecsPerFrame = 0.005; // How long to draw points before swapping.
const uint32_t kOpaqueColorMask = 0xff000000; // Opaque pixels.
const uint32_t kRedMask = 0xff0000;
const uint32_t kBlueMask = 0xff;
const uint32_t kRedShift = 16;
const uint32_t kBlueShift = 0;
-} // namespace
-
-class PiGeneratorInstance : public pp::Instance {
- public:
- explicit PiGeneratorInstance(PP_Instance instance);
- virtual ~PiGeneratorInstance();
-
- // Start up the ComputePi() thread.
- virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
-
- // Update the graphics context to the new size, and regenerate |pixel_buffer_|
- // to fit the new size as well.
- virtual void DidChangeView(const pp::View& view);
-
- // Called by the browser to handle the postMessage() call in Javascript.
- // The message in this case is expected to contain the string 'paint', and
- // if so this invokes the Paint() function. If |var_message| is not a string
- // type, or contains something other than 'paint', this method posts an
- // invalid value for Pi (-1.0) back to the browser.
- virtual void HandleMessage(const pp::Var& var_message);
-
- // Return a pointer to the pixels represented by |pixel_buffer_|. When this
- // method returns, the underlying |pixel_buffer_| object is locked. This
- // call must have a matching UnlockPixels() or various threading errors
- // (e.g. deadlock) will occur.
- uint32_t* LockPixels();
- // Release the image lock acquired by LockPixels().
- void UnlockPixels() const;
-
- // Flushes its contents of |pixel_buffer_| to the 2D graphics context. The
- // ComputePi() thread fills in |pixel_buffer_| pixels as it computes Pi.
- // This method is called by HandleMessage when a message containing 'paint'
- // is received. Echos the current value of pi as computed by the Monte Carlo
- // method by posting the value back to the browser.
- void Paint();
-
- bool quit() const { return quit_; }
-
- // |pi_| is computed in the ComputePi() thread.
- double pi() const { return pi_; }
-
- int width() const {
- return pixel_buffer_ ? pixel_buffer_->size().width() : 0;
- }
- int height() const {
- return pixel_buffer_ ? pixel_buffer_->size().height() : 0;
- }
-
- // Indicate whether a flush is pending. This can only be called from the
- // main thread; it is not thread safe.
- bool flush_pending() const { return flush_pending_; }
- void set_flush_pending(bool flag) { flush_pending_ = flag; }
-
- private:
- // Create and initialize the 2D context used for drawing.
- void CreateContext(const pp::Size& size, float device_scale);
- // Destroy the 2D drawing context.
- void DestroyContext();
- // Push the pixels to the browser, then attempt to flush the 2D context. If
- // there is a pending flush on the 2D context, then update the pixels only
- // and do not flush.
- void FlushPixelBuffer();
-
- void FlushCallback(int32_t result);
-
- bool IsContextValid() const { return graphics_2d_context_ != NULL; }
-
- pp::CompletionCallbackFactory<PiGeneratorInstance> callback_factory_;
- mutable pthread_mutex_t pixel_buffer_mutex_;
- pp::Graphics2D* graphics_2d_context_;
- pp::ImageData* pixel_buffer_;
- bool flush_pending_;
- bool quit_;
- pthread_t compute_pi_thread_;
- int thread_create_result_;
- double pi_;
- float device_scale_;
-
- // ComputePi() estimates Pi using Monte Carlo method and it is executed by a
- // separate thread created in SetWindow(). ComputePi() puts kMaxPointCount
- // points inside the square whose length of each side is 1.0, and calculates
- // the ratio of the number of points put inside the inscribed quadrant divided
- // by the total number of random points to get Pi/4.
- static void* ComputePi(void* param);
-};
-
-// A small helper RAII class that implements a scoped pthread_mutex lock.
-class ScopedMutexLock {
- public:
- explicit ScopedMutexLock(pthread_mutex_t* mutex) : mutex_(mutex) {
- if (pthread_mutex_lock(mutex_) != kPthreadMutexSuccess) {
- mutex_ = NULL;
- }
- }
- ~ScopedMutexLock() {
- if (mutex_)
- pthread_mutex_unlock(mutex_);
- }
- bool is_valid() const { return mutex_ != NULL; }
-
- private:
- pthread_mutex_t* mutex_; // Weak reference.
-};
-
-// A small helper RAII class used to acquire and release the pixel lock.
-class ScopedPixelLock {
- public:
- explicit ScopedPixelLock(PiGeneratorInstance* image_owner)
- : image_owner_(image_owner), pixels_(image_owner->LockPixels()) {}
-
- ~ScopedPixelLock() {
- pixels_ = NULL;
- image_owner_->UnlockPixels();
- }
-
- uint32_t* pixels() const { return pixels_; }
-
- private:
- PiGeneratorInstance* image_owner_; // Weak reference.
- uint32_t* pixels_; // Weak reference.
-};
-
-PiGeneratorInstance::PiGeneratorInstance(PP_Instance instance)
- : pp::Instance(instance),
- callback_factory_(this),
- graphics_2d_context_(NULL),
- pixel_buffer_(NULL),
- flush_pending_(false),
- quit_(false),
- thread_create_result_(0),
- pi_(0.0),
- device_scale_(1.0) {
- pthread_mutex_init(&pixel_buffer_mutex_, NULL);
-}
-
-PiGeneratorInstance::~PiGeneratorInstance() {
- quit_ = true;
- if (thread_create_result_ == 0) {
- pthread_join(compute_pi_thread_, NULL);
- }
- DestroyContext();
- // The ComputePi() thread should be gone by now, so there is no need to
- // acquire the mutex for |pixel_buffer_|.
- delete pixel_buffer_;
- pthread_mutex_destroy(&pixel_buffer_mutex_);
-}
-
-void PiGeneratorInstance::DidChangeView(const pp::View& view) {
- pp::Size size = view.GetRect().size();
- float device_scale = view.GetDeviceScale();
- size.set_width(static_cast<int>(size.width() * device_scale));
- size.set_height(static_cast<int>(size.height() * device_scale));
- if (pixel_buffer_ && size == pixel_buffer_->size() &&
- device_scale == device_scale_)
- return; // Size and scale didn't change, no need to update anything.
-
- // Create a new device context with the new size and scale.
- DestroyContext();
- device_scale_ = device_scale;
- CreateContext(size, device_scale_);
- // Delete the old pixel buffer and create a new one.
- ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
- delete pixel_buffer_;
- pixel_buffer_ = NULL;
- if (graphics_2d_context_ != NULL) {
- pixel_buffer_ = new pp::ImageData(this,
- PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- graphics_2d_context_->size(),
- false);
- }
-}
-
-bool PiGeneratorInstance::Init(uint32_t argc,
- const char* argn[],
- const char* argv[]) {
- thread_create_result_ =
- pthread_create(&compute_pi_thread_, NULL, ComputePi, this);
- return thread_create_result_ == 0;
-}
-
-uint32_t* PiGeneratorInstance::LockPixels() {
- void* pixels = NULL;
- // Do not use a ScopedMutexLock here, since the lock needs to be held until
- // the matching UnlockPixels() call.
- if (pthread_mutex_lock(&pixel_buffer_mutex_) == kPthreadMutexSuccess) {
- if (pixel_buffer_ != NULL && !pixel_buffer_->is_null()) {
- pixels = pixel_buffer_->data();
- }
- }
- return reinterpret_cast<uint32_t*>(pixels);
-}
-
-void PiGeneratorInstance::HandleMessage(const pp::Var& var_message) {
- if (!var_message.is_string()) {
- PostMessage(pp::Var(kInvalidPiValue));
- }
- std::string message = var_message.AsString();
- if (message == kPaintMethodId) {
- Paint();
- } else {
- PostMessage(pp::Var(kInvalidPiValue));
- }
-}
-
-void PiGeneratorInstance::UnlockPixels() const {
- pthread_mutex_unlock(&pixel_buffer_mutex_);
-}
-
-void PiGeneratorInstance::Paint() {
- ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
- if (!scoped_mutex.is_valid()) {
- return;
- }
- FlushPixelBuffer();
- // Post the current estimate of Pi back to the browser.
- pp::Var pi_estimate(pi());
- // Paint() is called on the main thread, so no need for CallOnMainThread()
- // here. It's OK to just post the message.
- PostMessage(pi_estimate);
-}
-
-void PiGeneratorInstance::CreateContext(const pp::Size& size,
- float device_scale) {
- ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
- if (!scoped_mutex.is_valid()) {
- return;
- }
- if (IsContextValid())
- return;
- graphics_2d_context_ = new pp::Graphics2D(this, size, false);
- // Scale the contents of the graphics context down by the inverse of the
- // device scale. This makes each pixel in the context represent a single
- // physical pixel on the device when running on high-DPI displays.
- // See pp::Graphics2D::SetScale for more details.
- graphics_2d_context_->SetScale(1.0 / device_scale);
- if (!BindGraphics(*graphics_2d_context_)) {
- printf("Couldn't bind the device context\n");
- }
-}
-void PiGeneratorInstance::DestroyContext() {
- ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
- if (!scoped_mutex.is_valid()) {
- return;
- }
- if (!IsContextValid())
- return;
- delete graphics_2d_context_;
- graphics_2d_context_ = NULL;
-}
+int g_points_in_circle = 0;
+int g_total_points = 0;
+double g_pi = 0;
-void PiGeneratorInstance::FlushPixelBuffer() {
- if (!IsContextValid())
- return;
- // Note that the pixel lock is held while the buffer is copied into the
- // device context and then flushed.
- graphics_2d_context_->PaintImageData(*pixel_buffer_, pp::Point());
- if (flush_pending())
- return;
- set_flush_pending(true);
- graphics_2d_context_->Flush(
- callback_factory_.NewCallback(&PiGeneratorInstance::FlushCallback));
-}
+} // namespace
-// This is called by the browser when the 2D context has been flushed to the
-// browser window.
-void PiGeneratorInstance::FlushCallback(int32_t result) {
- set_flush_pending(false);
-}
+bool Render(PSContext2D_t* ctx) {
+ PSContext2DGetBuffer(ctx);
-void* PiGeneratorInstance::ComputePi(void* param) {
- int count = 0; // The number of points put inside the inscribed quadrant.
- unsigned int seed = 1;
- srand(seed);
+ if (NULL == ctx->data)
+ return true;
- PiGeneratorInstance* pi_generator = static_cast<PiGeneratorInstance*>(param);
- for (int i = 1; i <= kMaxPointCount && !pi_generator->quit(); ++i) {
- ScopedPixelLock scoped_pixel_lock(pi_generator);
- uint32_t* pixel_bits = scoped_pixel_lock.pixels();
- if (pixel_bits == NULL) {
- // Note that if the pixel buffer never gets initialized, this won't ever
- // paint anything. Which is probably the right thing to do. Also, this
- // clause means that the image will not get the very first few Pi dots,
- // since it's possible that this thread starts before the pixel buffer is
- // initialized.
- continue;
- }
+ PP_TimeTicks start_time = PSInterfaceCore()->GetTimeTicks();
+ while (PSInterfaceCore()->GetTimeTicks() - start_time < kSecsPerFrame) {
double x = static_cast<double>(rand()) / RAND_MAX;
double y = static_cast<double>(rand()) / RAND_MAX;
double distance = sqrt(x * x + y * y);
- int px = x * pi_generator->width();
- int py = (1.0 - y) * pi_generator->height();
- uint32_t color = pixel_bits[pi_generator->width() * py + px];
+ int px = x * ctx->width;
+ int py = (1.0 - y) * ctx->height;
+ uint32_t color = ctx->data[ctx->width * py + px];
+
+ ++g_total_points;
if (distance < 1.0) {
+ ++g_points_in_circle;
+ g_pi = 4.0 * g_points_in_circle / g_total_points;
// Set color to blue.
- ++count;
- pi_generator->pi_ = 4.0 * count / i;
color += 4 << kBlueShift;
color &= kBlueMask;
} else {
@@ -337,21 +58,48 @@ void* PiGeneratorInstance::ComputePi(void* param) {
color += 4 << kRedShift;
color &= kRedMask;
}
- pixel_bits[pi_generator->width() * py + px] = color | kOpaqueColorMask;
+ ctx->data[ctx->width * py + px] = color | kOpaqueColorMask;
}
- return 0;
+
+ PSContext2DSwapBuffer(ctx);
+ return g_total_points != kMaxPointCount;
}
-class PiGeneratorModule : public pp::Module {
- public:
- PiGeneratorModule() : pp::Module() {}
- virtual ~PiGeneratorModule() {}
+/*
+ * 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[]) {
+ unsigned int seed = 1;
+ srand(seed);
+
+ PSEventSetFilter(PSE_ALL);
+
+ PSContext2D_t* ctx = PSContext2DAllocate();
+ bool running = true;
+ while (running) {
+ PSEvent* event;
+
+ // Consume all available events
+ while ((event = PSEventTryAcquire()) != NULL) {
+ PSContext2DHandleEvent(ctx, event);
+ PSEventRelease(event);
+ }
+
+ if (ctx->bound) {
+ running = Render(ctx);
+ }
- virtual pp::Instance* CreateInstance(PP_Instance instance) {
- return new PiGeneratorInstance(instance);
+ // Send the current PI value to JavaScript.
+ PP_Var var = PP_MakeDouble(g_pi);
+ PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), var);
}
-};
-namespace pp {
-Module* CreateModule() { return new PiGeneratorModule(); }
-} // namespace pp
+ return 0;
+}
+
+/*
+ * 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/voronoi/example.js b/native_client_sdk/src/examples/demo/voronoi/example.js
index aa02f38049..1807831141 100644
--- a/native_client_sdk/src/examples/demo/voronoi/example.js
+++ b/native_client_sdk/src/examples/demo/voronoi/example.js
@@ -7,7 +7,8 @@ function moduleDidLoad() {
function postThreadFunc(numThreads) {
return function () {
- common.naclModule.postMessage('threads: ' + numThreads);
+ common.naclModule.postMessage({'message' : 'set_threads',
+ 'value' : numThreads});
}
}
@@ -16,34 +17,31 @@ function postThreadFunc(numThreads) {
function attachListeners() {
document.getElementById('benchmark').addEventListener('click',
function() {
- common.naclModule.postMessage('run benchmark');
+ common.naclModule.postMessage({'message' : 'run_benchmark'});
common.updateStatus('BENCHMARKING... (please wait)');
});
document.getElementById('drawPoints').addEventListener('click',
function() {
var checked = document.getElementById('drawPoints').checked;
- if (checked)
- common.naclModule.postMessage('with points');
- else
- common.naclModule.postMessage('without points');
+ common.naclModule.postMessage({'message' : 'draw_points',
+ 'value' : checked});
});
document.getElementById('drawInteriors').addEventListener('click',
function() {
var checked = document.getElementById('drawInteriors').checked;
- if (checked)
- common.naclModule.postMessage('with interiors');
- else
- common.naclModule.postMessage('without interiors');
+ common.naclModule.postMessage({'message' : 'draw_interiors',
+ 'value' : checked});
});
var threads = [0, 1, 2, 4, 6, 8, 12, 16, 24, 32];
for (var i = 0; i < threads.length; i++) {
- document.getElementById('radio'+i).addEventListener('click',
+ document.getElementById('radio' + i).addEventListener('click',
postThreadFunc(threads[i]));
}
document.getElementById('pointRange').addEventListener('change',
function() {
- var value = document.getElementById('pointRange').value;
- common.naclModule.postMessage('points: ' + value);
+ var value = parseFloat(document.getElementById('pointRange').value);
+ common.naclModule.postMessage({'message' : 'set_points',
+ 'value' : value});
document.getElementById('pointCount').textContent = value + ' points';
});
}
@@ -51,9 +49,11 @@ function attachListeners() {
// Handle a message coming from the NaCl module.
// In the Voronoi example, the only message will be the benchmark result.
function handleMessage(message_event) {
- var x = (Math.round(message_event.data * 1000) / 1000).toFixed(3);
- document.getElementById('result').textContent =
- 'Result: ' + x + ' seconds';
- common.updateStatus('SUCCESS')
+ if (message_event.data['message'] == 'benchmark_result') {
+ var x = (Math.round(message_event.data['value'] * 1000) / 1000).toFixed(3);
+ document.getElementById('result').textContent =
+ 'Result: ' + x + ' seconds';
+ common.updateStatus('SUCCESS')
+ }
}
diff --git a/native_client_sdk/src/examples/demo/voronoi/voronoi.cc b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
index d4e1025181..870ffae359 100644
--- a/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
+++ b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
@@ -13,6 +13,7 @@
#include <ppapi/cpp/rect.h>
#include <ppapi/cpp/size.h>
#include <ppapi/cpp/var.h>
+#include <ppapi/cpp/var_dictionary.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
@@ -133,6 +134,8 @@ class Voronoi : public pp::Instance {
// 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.
@@ -466,8 +469,8 @@ void Voronoi::EndBenchmark() {
benchmark_end_time_ - benchmark_start_time_);
benchmarking_ = false;
benchmark_frame_counter_ = 0;
- pp::Var result(benchmark_end_time_ - benchmark_start_time_);
- PostMessage(result);
+ double result = benchmark_end_time_ - benchmark_start_time_;
+ PostUpdateMessage("benchmark_result", result);
}
// Handle input events from the user.
@@ -488,30 +491,35 @@ bool Voronoi::HandleInputEvent(const pp::InputEvent& event) {
}
// Handle messages sent from Javascript.
-void Voronoi::HandleMessage(const pp::Var& message) {
- if (message.is_string()) {
- std::string message_string = message.AsString();
- if (message_string == "run benchmark" && !benchmarking_)
+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_string == "with points")
- draw_points_ = true;
- else if (message_string == "without points")
- draw_points_ = false;
- else if (message_string == "with interiors")
- draw_interiors_ = true;
- else if (message_string == "without interiors")
- draw_interiors_ = false;
- else if (strstr(message_string.c_str(), "points:")) {
- int num_points = atoi(strstr(message_string.c_str(), " "));
+ 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 (strstr(message_string.c_str(), "threads:")) {
- int thread_count = atoi(strstr(message_string.c_str(), " "));
+ } else if (message == "set_threads") {
+ int thread_count = dictionary.Get("value").AsInt();
delete workers_;
workers_ = new ThreadPool(thread_count);
}
}
}
+// PostUpdateMessage() helper function for sendimg small messages to JS.
+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();
}
diff --git a/native_client_sdk/src/examples/getting_started/hello_world/index.html b/native_client_sdk/src/examples/getting_started/hello_world/index.html
index 4ed29868dd..32da7732cc 100644
--- a/native_client_sdk/src/examples/getting_started/hello_world/index.html
+++ b/native_client_sdk/src/examples/getting_started/hello_world/index.html
@@ -17,8 +17,8 @@ found in the LICENSE file.
<h2>Status: <code id="statusField">NO-STATUS</code></h2>
<p>The Hello World In C example demonstrates the basic structure of all
Native Client applications. This example loads a Native Client module. The
- page tracks the status of the module as it load. On a successful load, the
- module will post a message containing the string "Hello World" back to
+ page tracks the status of the module as it loads. On a successful load,
+ the module will post a message containing the string "Hello World" back to
JavaScript which will display it as an alert.</p>
<h2>Output:</h2>
<pre id="log" style="font-weight: bold"></pre>
diff --git a/native_client_sdk/src/examples/getting_started/simple_hello_world/index.html b/native_client_sdk/src/examples/getting_started/simple_hello_world/index.html
index c6a4aa1ef4..5e2965ff93 100644
--- a/native_client_sdk/src/examples/getting_started/simple_hello_world/index.html
+++ b/native_client_sdk/src/examples/getting_started/simple_hello_world/index.html
@@ -16,7 +16,7 @@ found in the LICENSE file.
<h1>{{title}}</h1>
<h2>Status: <code id="statusField">NO-STATUS</code></h2>
<p>The Hello World Stdio example is the simplest one in the SDK. It uses the
- ppapi_main library which creates an Module and Instance, using default
+ ppapi_main library which creates a Module and an Instance, using default
values to simplify setup and communication with the PPAPI system. In
addition, it uses the nacl_io library to remap IO to the Pepper API. This
simplifies IO by providing a standard blocking API and allowing STDERR to
diff --git a/native_client_sdk/src/examples/tutorial/dlopen/index.html b/native_client_sdk/src/examples/tutorial/dlopen/index.html
index 0e535b4c66..95bc51d58e 100644
--- a/native_client_sdk/src/examples/tutorial/dlopen/index.html
+++ b/native_client_sdk/src/examples/tutorial/dlopen/index.html
@@ -15,7 +15,7 @@ found in the LICENSE file.
<body {{attrs}}>
<h1>{{title}}</h1>
<h2>Status: <code id="statusField">NO-STATUS</code></h2>
- <p>The dlopen example demonstrates how build dynamic libraries and then
+ <p>The dlopen example demonstrates how to build dynamic libraries and then
open and use them at runtime. When the page loads, type in a question and
hit enter or click the ASK! button. The question and answer will be
displayed in the page under the text entry box. Shared libraries are only
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_event_listener.cc b/native_client_sdk/src/libraries/gtest_ppapi/gtest_event_listener.cc
deleted file mode 100644
index 3bc84a8494..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_event_listener.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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 "gtest_ppapi/gtest_event_listener.h"
-
-#include "ppapi/c/pp_macros.h"
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/module.h"
-#include "ppapi/cpp/var.h"
-
-#if defined(WIN32)
-#undef PostMessage
-#endif
-
-GTestEventListener::GTestEventListener(pp::Instance* instance)
- : instance_(instance),
- PP_ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {
- assert(pp::Module::Get()->core()->IsMainThread());
-}
-
-void GTestEventListener::OnTestProgramStart(
- const ::testing::UnitTest& unit_test) {
- std::stringstream msg;
- int num_tests = unit_test.test_to_run_count();
- int num_test_cases = unit_test.test_case_to_run_count();
-
- msg << "::start::" << num_tests << " test";
- if (num_tests > 1) msg << 's';
- msg << " from "<< num_test_cases << " test case";
- if (num_test_cases > 1) msg << 's';
- msg << '.';
- MyPostMessage(msg.str());
-}
-
-void GTestEventListener::OnTestCaseStart(
- const ::testing::TestCase& test_case) {
- // not currently used
-}
-
-void GTestEventListener::OnTestStart(const ::testing::TestInfo& test_info) {
- // not currently used
-}
-
-void GTestEventListener::OnTestPartResult(
- const ::testing::TestPartResult& test_part_result) {
- if (test_part_result.failed()) {
- std::stringstream msg;
- msg << "::test_failed::";
- if (test_part_result.file_name())
- msg << test_part_result.file_name();
- else
- msg << "<unknown filename>";
- msg << "::" << test_part_result.line_number() << "::";
- msg << test_part_result.summary();
- MyPostMessage(msg.str());
- }
-}
-
-void GTestEventListener::OnTestEnd(const ::testing::TestInfo& test_info) {
- std::stringstream msg;
- msg << "::test_end::";
- msg << test_info.test_case_name() << "." << test_info.name();
-
- msg << (test_info.result()->Failed() ? ": FAILED" : ": OK");
- MyPostMessage(msg.str());
-}
-
-void GTestEventListener::OnTestCaseEnd(
- const ::testing::TestCase& test_case) {
- // not used
-}
-
-void GTestEventListener::OnTestProgramEnd(
- const ::testing::UnitTest& unit_test) {
- // Print info about what test and test cases ran.
- int num_passed_tests = unit_test.successful_test_count();
- int num_failed_tests = unit_test.failed_test_count();
- std::stringstream msg;
- msg << "::Result::";
- msg << ((num_failed_tests > 0) ? "failed::" : "success::");
- msg << num_passed_tests << "::" << num_failed_tests << "::";
- MyPostMessage(msg.str());
-}
-
-void GTestEventListener::MyPostMessage(const std::string& str) {
- if (pp::Module::Get()->core()->IsMainThread()) {
- instance_->PostMessage(str);
- } else {
- pp::CompletionCallback cc = factory_.NewCallback(
- &GTestEventListener::MyPostMessageCallback, str);
- pp::Module::Get()->core()->CallOnMainThread(0, cc, PP_OK);
- }
-}
-
-void GTestEventListener::MyPostMessageCallback(int32_t result,
- const std::string& str) {
- instance_->PostMessage(str);
-}
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_event_listener.h b/native_client_sdk/src/libraries/gtest_ppapi/gtest_event_listener.h
deleted file mode 100644
index 90d5d0a71c..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_event_listener.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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 GTEST_PPAPI_GTEST_EVENT_LISTENER_H_
-#define GTEST_PPAPI_GTEST_EVENT_LISTENER_H_
-
-#include <string>
-
-#include "gtest/gtest.h"
-#include "ppapi/utility/completion_callback_factory.h"
-
-namespace pp {
-class Instance;
-} // namespace pp
-
-// GTestEventListener is a gtest event listener that performs two functions:
-// 1. It redirects output to PostMessage rather than printf, so that test events
-// are dispatched to JS.
-// 2. Channels post-message dispatches to the main thread via callbacks, so that
-// it can be used from any thread.
-//
-// GTestEventListener formats gtest event messages to be parsed by javascript
-// helper functions found in gtest_runner.js
-class GTestEventListener : public ::testing::EmptyTestEventListener {
- public:
- explicit GTestEventListener(pp::Instance* instance);
-
- // TestEventListener overrides.
- virtual void OnTestProgramStart(const ::testing::UnitTest& unit_test);
- virtual void OnTestCaseStart(const ::testing::TestCase& test_case);
- virtual void OnTestStart(const ::testing::TestInfo& test_info);
- virtual void OnTestPartResult(
- const ::testing::TestPartResult& test_part_result);
- virtual void OnTestEnd(const ::testing::TestInfo& test_info);
- virtual void OnTestCaseEnd(const ::testing::TestCase& test_case);
- virtual void OnTestProgramEnd(const ::testing::UnitTest& unit_test);
-
- private:
- // Called MyPostMessage as to not conflict with win32 macro PostMessage.
- void MyPostMessage(const std::string& str);
- void MyPostMessageCallback(int32_t result, const std::string& str);
-
- pp::Instance* instance_;
- pp::CompletionCallbackFactory<GTestEventListener> factory_;
-};
-
-#endif // GTEST_PPAPI_GTEST_EVENT_LISTENER_H_
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_instance.cc b/native_client_sdk/src/libraries/gtest_ppapi/gtest_instance.cc
deleted file mode 100644
index dc5e1a72c8..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_instance.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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 "gtest_ppapi/gtest_instance.h"
-#include "gtest_ppapi/gtest_runner.h"
-#include "ppapi/cpp/var.h"
-
-#if defined(WIN32)
-#undef PostMessage
-#endif
-
-GTestInstance::GTestInstance(PP_Instance instance)
- : pp::Instance(instance) {
-}
-
-GTestInstance::~GTestInstance() {
-}
-
-bool GTestInstance::Init(uint32_t /* argc */, const char* /* argn */[],
- const char* /* argv */[]) {
- // Create a GTestRunner thread/singleton.
- int local_argc = 0;
- GTestRunner::CreateGTestRunnerThread(this, local_argc, NULL);
- return true;
-}
-
-void GTestInstance::HandleMessage(const pp::Var& var_message) {
- if (!var_message.is_string()) {
- PostMessage("Invalid message");
- return;
- }
-
- std::string message = var_message.AsString();
- if (message == "RunGTest") {
- // This is our signal to start running the tests. Results from the tests
- // are posted through GTestEventListener.
- GTestRunner::gtest_runner()->RunAllTests();
- } else {
- std::string return_var;
- return_var = "Unknown message ";
- return_var += message;
- PostMessage(return_var);
- }
-}
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_instance.h b/native_client_sdk/src/libraries/gtest_ppapi/gtest_instance.h
deleted file mode 100644
index 152f3bea7b..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_instance.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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 GTEST_PPAPI_GTEST_INSTANCE_H_
-#define GTEST_PPAPI_GTEST_INSTANCE_H_
-
-#include "ppapi/cpp/instance.h"
-
-// GTestInstance is a NaCl instance specifically dedicated to running
-// gtest-based unit tests. It creates a GTestRunner thread/singleton pair as
-// part of its Init function and runs all registered gtests once it
-// receives a 'RunGTest' message in its post-message handler. Results from the
-// test are posted back to JS through GTestEventListener.
-//
-// All tests are run from a background thread and must be written accordingly.
-// Although that may complicate the test code a little, it allows the tests
-// to be synchronized. I.e. Each test is launched and the thread is blocked
-// until the outcome is known and reported.
-class GTestInstance : public pp::Instance {
- public:
- explicit GTestInstance(PP_Instance instance);
- virtual ~GTestInstance();
-
- // pp::Instance overrides.
- virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
- virtual void HandleMessage(const pp::Var& var_message);
-};
-
-#endif // GTEST_PPAPI_GTEST_INSTANCE_H_
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_module.cc b/native_client_sdk/src/libraries/gtest_ppapi/gtest_module.cc
deleted file mode 100644
index bda434cb7a..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_module.cc
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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 "gtest_ppapi/gtest_module.h"
-#include "gtest_ppapi/gtest_instance.h"
-
-pp::Instance* GTestModule::CreateInstance(PP_Instance instance) {
- return new GTestInstance(instance);
-}
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_module.h b/native_client_sdk/src/libraries/gtest_ppapi/gtest_module.h
deleted file mode 100644
index b08b90aa56..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_module.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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 GTEST_PPAPI_GTEST_MODULE_H_
-#define GTEST_PPAPI_GTEST_MODULE_H_
-#include "ppapi/cpp/module.h"
-
-// GTestModule is a NaCl module dedicated to running gtest-based unit tests.
-// It creates an NaCl instance based on GTestInstance.
-class GTestModule : public pp::Module {
- public:
- GTestModule() : pp::Module() {}
- ~GTestModule() {}
-
- virtual pp::Instance* CreateInstance(PP_Instance instance);
-};
-
-#endif // GTEST_PPAPI_GTEST_MODULE_H_
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_nacl_environment.cc b/native_client_sdk/src/libraries/gtest_ppapi/gtest_nacl_environment.cc
deleted file mode 100644
index 5cc51ec15c..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_nacl_environment.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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 "gtest_ppapi/gtest_nacl_environment.h"
-
-pp::Instance* GTestNaclEnvironment::global_instance_ = NULL;
-
-void GTestNaclEnvironment::SetUp() {
- // Check that the global instance is set before running the tests.
- assert(global_instance_ != NULL);
-}
-
-void GTestNaclEnvironment::TearDown() {
-}
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_nacl_environment.h b/native_client_sdk/src/libraries/gtest_ppapi/gtest_nacl_environment.h
deleted file mode 100644
index 759b775d2e..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_nacl_environment.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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 GTEST_PPAPI_GTEST_NACL_ENVIRONMENT_H_
-#define GTEST_PPAPI_GTEST_NACL_ENVIRONMENT_H_
-
-#include <cassert>
-#include "gtest/gtest.h"
-
-namespace pp {
-class Instance;
-} // namespace pp
-
-// A custom environment for NaCl gtest.
-class GTestNaclEnvironment : public ::testing::Environment {
- public:
- // Set the global NaCl instance that will be shared by all the tests.
- static void set_global_instance(pp::Instance* instance) {
- global_instance_ = instance;
- }
-
- // Get the global NaCl instance.
- static pp::Instance* global_instance() { return global_instance_; }
-
- // Environment overrides.
- virtual void SetUp();
- virtual void TearDown();
-
- private:
- static pp::Instance* global_instance_;
-};
-
-#endif // GTEST_PPAPI_GTEST_NACL_ENVIRONMENT_H_
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_runner.cc b/native_client_sdk/src/libraries/gtest_ppapi/gtest_runner.cc
deleted file mode 100644
index d8ce6dc04b..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_runner.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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 "gtest_ppapi/gtest_runner.h"
-
-#include <cassert>
-
-#include "gtest/gtest.h"
-#include "gtest_ppapi/gtest_event_listener.h"
-#include "gtest_ppapi/gtest_nacl_environment.h"
-
-pthread_t GTestRunner::g_test_runner_thread_;
-GTestRunner* GTestRunner::gtest_runner_ = NULL;
-
-void GTestRunner::CreateGTestRunnerThread(pp::Instance* instance,
- int argc, char** argv) {
- assert(!gtest_runner_);
- if (!gtest_runner_) {
- gtest_runner_ = new GTestRunner();
- gtest_runner_->Init(instance, argc, argv);
- pthread_create(&g_test_runner_thread_, NULL, ThreadFunc, NULL);
- }
-}
-
-void GTestRunner::RunAllTests() {
- status_signal_.Lock();
- assert(status_ == kIdle);
- status_ = kRunTests;
- status_signal_.Signal();
- status_signal_.Unlock();
-}
-
-void* GTestRunner::ThreadFunc(void* param) {
- gtest_runner_->RunLoop();
- delete gtest_runner_;
- gtest_runner_ = NULL;
- return NULL;
-}
-
-GTestRunner::GTestRunner() : status_(kIdle) { }
-
-void GTestRunner::Init(pp::Instance* instance, int argc, char** argv) {
- // Init gtest.
- testing::InitGoogleTest(&argc, argv);
-
- // Add GTestEventListener to the list of listeners. That will cause the
- // test output to go to nacltest.js through PostMessage.
- ::testing::TestEventListeners& listeners =
- ::testing::UnitTest::GetInstance()->listeners();
- delete listeners.Release(listeners.default_result_printer());
- listeners.Append(new GTestEventListener(instance));
-
- // We use our own gtest environment, mainly to make the nacl instance
- // available to the individual unit tests.
- GTestNaclEnvironment* test_env = new GTestNaclEnvironment();
- test_env->set_global_instance(instance);
- ::testing::AddGlobalTestEnvironment(test_env);
-}
-
-void GTestRunner::RunLoop() {
- // Stay idle until RunAlltests is called.
- status_signal_.Lock();
- while (status_ == kIdle) {
- status_signal_.Wait();
- }
-
- assert(status_ == kRunTests);
- status_signal_.Unlock();
- int result = RUN_ALL_TESTS();
- (void)result;
-}
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/gtest_runner.h b/native_client_sdk/src/libraries/gtest_ppapi/gtest_runner.h
deleted file mode 100644
index b7e489c048..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/gtest_runner.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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 GTEST_PPAPI_GTEST_RUNNER_H_
-#define GTEST_PPAPI_GTEST_RUNNER_H_
-
-#include <pthread.h>
-#include "gtest_ppapi/thread_condition.h"
-
-namespace pp {
-class Instance;
-} // namespace pp
-
-// GTestRunner is a threaded singleton for running gtest-based unit tests.
-class GTestRunner {
- public:
- // Factory function to create the background gtest thread and associated
- // GTestRunner singleton. It is an error to call the factory function more
- // than once that raises an assert in debug mode.
- //
- // Parameters:
- // instance: the NaCl instance.
- // argc: arg count from pp::Instance::Init.
- // argv: the arguments from pp::Instance::Init.
- static void CreateGTestRunnerThread(pp::Instance* instance,
- int argc, char** argv);
-
- // Get the GTestRunner singleton.
- // @return A pointer to the GTestRunner singleton.
- static GTestRunner* gtest_runner() { return gtest_runner_; }
-
- // Tell the GTestRunner to run all gtest unit tests.
- void RunAllTests();
-
- protected:
- // The pthread thread function.
- static void* ThreadFunc(void* param);
-
- // Don't try to create instances directly. Use the factory function instead.
- GTestRunner();
- void Init(pp::Instance* instance, int argc, char** argv);
-
- // The thread run loop exits once all test have run.
- void RunLoop();
-
- private:
- // The status and associated status signal are used to control the state of
- // the thread run loop.
- enum Status { kIdle, kRunTests };
- ThreadCondition status_signal_;
- Status status_;
-
- static pthread_t g_test_runner_thread_;
- static GTestRunner* gtest_runner_;
-};
-
-#endif // GTEST_PPAPI_GTEST_RUNNER_H_
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/library.dsc b/native_client_sdk/src/libraries/gtest_ppapi/library.dsc
deleted file mode 100644
index 01aa35067b..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/library.dsc
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win', 'linux'],
- 'TARGETS': [
- {
- 'NAME' : 'gtest_ppapi',
- # gtest-typed-test.h:239:47: error: anonymous variadic macros were introduced in C99 [-Werror=variadic-macros]
- 'CXXFLAGS': ['-Wno-variadic-macros'],
- 'TYPE' : 'lib',
- 'SOURCES' : [
- "gtest_event_listener.cc",
- "gtest_instance.cc",
- "gtest_module.cc",
- "gtest_nacl_environment.cc",
- "gtest_runner.cc",
- ],
- }
- ],
- 'HEADERS': [
- {
- 'FILES': [
- "gtest_event_listener.h",
- "gtest_instance.h",
- "gtest_module.h",
- "gtest_nacl_environment.h",
- "gtest_runner.h",
- "thread_condition.h",
- ],
- 'DEST': 'include/gtest_ppapi',
- },
- ],
- 'DEST': 'testlibs',
- 'NAME': 'gtest_ppapi',
-}
diff --git a/native_client_sdk/src/libraries/gtest_ppapi/thread_condition.h b/native_client_sdk/src/libraries/gtest_ppapi/thread_condition.h
deleted file mode 100644
index d7af353349..0000000000
--- a/native_client_sdk/src/libraries/gtest_ppapi/thread_condition.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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 GTEST_PPAPI_THREAD_CONDITION_H_
-#define GTEST_PPAPI_THREAD_CONDITION_H_
-
-#include <pthread.h>
-
-struct timespec;
-
-// A wrapper class for condition signaling. Contains a mutex and condition
-// pair.
-class ThreadCondition {
- public:
- // Initialize the mutex and the condition.
- ThreadCondition() {
- pthread_mutex_init(&cond_mutex_, NULL);
- pthread_cond_init(&condition_, NULL);
- }
-
- virtual ~ThreadCondition() {
- pthread_cond_destroy(&condition_);
- pthread_mutex_destroy(&cond_mutex_);
- }
-
- // Lock the mutex, do this before signalling the condition.
- void Lock() {
- pthread_mutex_lock(&cond_mutex_);
- }
-
- // Unlock the mutex, do this after raising a signal or after returning from
- // Wait().
- void Unlock() {
- pthread_mutex_unlock(&cond_mutex_);
- }
-
- // Signal the condition. This will cause Wait() to return.
- void Signal() {
- pthread_cond_broadcast(&condition_);
- }
-
- // Wait for a Signal(). Note that this can spuriously return, so you should
- // have a guard bool to see if the condition is really true. E.g., in the
- // calling thread:
- // cond_lock->Lock();
- // cond_true = true;
- // cond_lock->Signal();
- // cond_lock->Unlock();
- // In the worker thread:
- // cond_lock->Lock();
- // while (!cond_true) {
- // cond_lock->Wait();
- // }
- // cond_lock->Unlock();
- void Wait() {
- pthread_cond_wait(&condition_, &cond_mutex_);
- }
-
- private:
- pthread_mutex_t cond_mutex_;
- pthread_cond_t condition_;
-};
-
-#endif // GTEST_PPAPI_THREAD_CONDITION_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/ioctl.h b/native_client_sdk/src/libraries/nacl_io/ioctl.h
new file mode 100644
index 0000000000..0a730e8568
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/ioctl.h
@@ -0,0 +1,25 @@
+/* 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_IO_IOCTL_H_
+#define LIBRARIES_NACL_IO_IOCTL_H_
+
+/* ioctl to tell a tty mount to prefix every message with a particular
+ * null-terminated string. Accepts a pointer to a C string which will
+ * be the prefix.
+ */
+#define TIOCNACLPREFIX 0xadcd01
+
+/* ioctl to feed input to a tty mount. Accepts a pointer to the following
+ * struct (tioc_nacl_input_string), which contains a pointer to an array
+ * of characters.
+ */
+#define TIOCNACLINPUT 0xadcd02
+
+struct tioc_nacl_input_string {
+ size_t length;
+ const char* buffer;
+};
+
+#endif // LIBRARIES_NACL_IO_NACL_IO_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc b/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
index a943894595..322bd9e4af 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
@@ -8,16 +8,15 @@
#include <fcntl.h>
#include <pthread.h>
-#ifndef WIN32
-// Needed for SEEK_SET/SEEK_CUR/SEEK_END.
-#include <unistd.h>
-#endif
-
#include "nacl_io/mount.h"
#include "nacl_io/mount_node.h"
+#include "nacl_io/osunistd.h"
// It is only legal to construct a handle while the kernel lock is held.
-KernelHandle::KernelHandle(Mount* mnt, MountNode* node)
+KernelHandle::KernelHandle()
+ : mount_(NULL), node_(NULL), offs_(0) {}
+
+KernelHandle::KernelHandle(const ScopedMount& mnt, const ScopedMountNode& node)
: mount_(mnt), node_(node), offs_(0) {}
Error KernelHandle::Init(int open_mode) {
@@ -71,3 +70,4 @@ Error KernelHandle::Seek(off_t offset, int whence, off_t* out_offset) {
*out_offset = offs_ = new_offset;
return 0;
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_handle.h b/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
index ab7b7cd699..d24533d5ff 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
@@ -8,37 +8,37 @@
#include <pthread.h>
#include "nacl_io/error.h"
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_node.h"
#include "nacl_io/ostypes.h"
+
#include "sdk_util/macros.h"
#include "sdk_util/ref_object.h"
-
-class Mount;
-class MountNode;
+#include "sdk_util/scoped_ref.h"
// KernelHandle provides a reference counted container for the open
// file information, such as it's mount, node, access type and offset.
// KernelHandle can only be referenced when the KernelProxy lock is held.
class KernelHandle : public RefObject {
public:
- // Assumes |mnt| and |node| are non-NULL.
- KernelHandle(Mount* mnt, MountNode* node);
+ KernelHandle();
+ KernelHandle(const ScopedMount& mnt, const ScopedMountNode& node);
Error Init(int open_flags);
+
// Assumes |out_offset| is non-NULL.
Error Seek(off_t offset, int whence, off_t* out_offset);
- Mount* mount_;
- MountNode* node_;
+ ScopedRef<Mount> mount_;
+ ScopedRef<MountNode> node_;
size_t offs_;
private:
- // May only be called by the KernelProxy when the Kernel's
- // lock is held.
friend class KernelObject;
friend class KernelProxy;
- void Acquire() { RefObject::Acquire(); }
- bool Release() { return RefObject::Release(); }
DISALLOW_COPY_AND_ASSIGN(KernelHandle);
};
+typedef ScopedRef<KernelHandle> ScopedKernelHandle;
+
#endif // LIBRARIES_NACL_IO_KERNEL_HANDLE_H_
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 9615dde48b..b237221b3f 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
@@ -172,3 +172,23 @@ int ki_munmap(void* addr, size_t length) {
int ki_open_resource(const char* file) {
return s_kp->open_resource(file);
}
+
+int ki_ioctl(int d, int request, char* argp) {
+ return s_kp->ioctl(d, request, argp);
+}
+
+int ki_chown(const char* path, uid_t owner, gid_t group) {
+ return s_kp->chown(path, owner, group);
+}
+
+int ki_fchown(int fd, uid_t owner, gid_t group) {
+ return s_kp->fchown(fd, owner, group);
+}
+
+int ki_lchown(const char* path, uid_t owner, gid_t group) {
+ return s_kp->lchown(path, owner, group);
+}
+
+int ki_utime(const char* filename, const struct utimbuf* times) {
+ return s_kp->utime(filename, times);
+}
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 c4b658dfd4..de9e98e33c 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
@@ -8,6 +8,7 @@
#include <ppapi/c/ppb.h>
#include <ppapi/c/pp_instance.h>
#include "nacl_io/ostypes.h"
+#include "nacl_io/osutime.h"
#include "sdk_util/macros.h"
EXTERN_C_BEGIN
@@ -56,8 +57,12 @@ void* ki_mmap(void* addr, size_t length, int prot, int flags, int fd,
off_t offset);
int ki_munmap(void* addr, size_t length);
int ki_open_resource(const char* file);
+int ki_ioctl(int d, int request, char* argp);
+int ki_chown(const char* path, uid_t owner, gid_t group);
+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);
EXTERN_C_END
#endif // LIBRARIES_NACL_IO_KERNEL_INTERCEPT_H_
-
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
index 6be3c9779b..f593d21ce2 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
@@ -17,7 +17,10 @@
#include "nacl_io/kernel_handle.h"
#include "nacl_io/mount.h"
#include "nacl_io/mount_node.h"
+
#include "sdk_util/auto_lock.h"
+#include "sdk_util/ref_object.h"
+#include "sdk_util/scoped_ref.h"
KernelObject::KernelObject() {
pthread_mutex_init(&kernel_lock_, NULL);
@@ -32,11 +35,11 @@ KernelObject::~KernelObject() {
// Uses longest prefix to find the mount for the give path, then
// acquires the mount and returns it with a relative path.
Error KernelObject::AcquireMountAndPath(const std::string& relpath,
- Mount** out_mount,
+ ScopedMount* out_mount,
Path* out_path) {
- *out_mount = NULL;
- *out_path = Path();
+ out_mount->reset(NULL);
+ *out_path = Path();
Path abs_path;
{
AutoLock lock(&process_lock_);
@@ -44,7 +47,6 @@ Error KernelObject::AcquireMountAndPath(const std::string& relpath,
}
AutoLock lock(&kernel_lock_);
- Mount* mount = NULL;
// Find longest prefix
size_t max = abs_path.Size();
@@ -53,66 +55,32 @@ Error KernelObject::AcquireMountAndPath(const std::string& relpath,
if (it != mounts_.end()) {
out_path->Set("/");
out_path->Append(abs_path.Range(max - len, max));
- mount = it->second;
- break;
+
+ *out_mount = it->second;
+ return 0;
}
}
- if (NULL == mount)
- return ENOTDIR;
-
- // Acquire the mount while we hold the proxy lock
- mount->Acquire();
- *out_mount = mount;
- return 0;
-}
-
-void KernelObject::ReleaseMount(Mount* mnt) {
- AutoLock lock(&kernel_lock_);
- mnt->Release();
+ return ENOTDIR;
}
-Error KernelObject::AcquireHandle(int fd, KernelHandle** out_handle) {
- *out_handle = NULL;
+Error KernelObject::AcquireHandle(int fd, ScopedKernelHandle* out_handle) {
+ out_handle->reset(NULL);
AutoLock lock(&process_lock_);
if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
return EBADF;
- KernelHandle* handle = handle_map_[fd];
- if (NULL == handle)
- return EBADF;
-
- // Ref count while holding parent mutex
- handle->Acquire();
-
- lock.Unlock();
- if (handle->node_)
- handle->mount_->AcquireNode(handle->node_);
-
- *out_handle = handle;
- return 0;
-}
-
-void KernelObject::ReleaseHandle(KernelHandle* handle) {
- // The handle must already be held before taking the
- // kernel lock.
- if (handle->node_)
- handle->mount_->ReleaseNode(handle->node_);
+ *out_handle = handle_map_[fd];
+ if (out_handle) return 0;
- AutoLock lock(&process_lock_);
- handle->Release();
+ return EBADF;
}
-int KernelObject::AllocateFD(KernelHandle* handle) {
+int KernelObject::AllocateFD(const ScopedKernelHandle& handle) {
AutoLock lock(&process_lock_);
int id;
- // Acquire the handle and its mount since we are about to track it with
- // this FD.
- handle->Acquire();
- handle->mount_->Acquire();
-
// If we can recycle and FD, use that first
if (free_fds_.size()) {
id = free_fds_.front();
@@ -127,28 +95,16 @@ int KernelObject::AllocateFD(KernelHandle* handle) {
return id;
}
-void KernelObject::FreeAndReassignFD(int fd, KernelHandle* handle) {
+void KernelObject::FreeAndReassignFD(int fd, const ScopedKernelHandle& handle) {
if (NULL == handle) {
FreeFD(fd);
} else {
AutoLock lock(&process_lock_);
- // Acquire the new handle first in case they are the same.
- if (handle) {
- handle->Acquire();
- handle->mount_->Acquire();
- }
-
// If the required FD is larger than the current set, grow the set
- if (fd >= handle_map_.size()) {
- handle_map_.resize(fd + 1);
- } else {
- KernelHandle* old_handle = handle_map_[fd];
- if (NULL != old_handle) {
- old_handle->mount_->Release();
- old_handle->Release();
- }
- }
+ if (fd >= handle_map_.size())
+ handle_map_.resize(fd + 1, ScopedRef<KernelHandle>());
+
handle_map_[fd] = handle;
}
}
@@ -156,14 +112,9 @@ void KernelObject::FreeAndReassignFD(int fd, KernelHandle* handle) {
void KernelObject::FreeFD(int fd) {
AutoLock lock(&process_lock_);
- // Release the mount and handle since we no longer
- // track them with this FD.
- KernelHandle* handle = handle_map_[fd];
- handle->Release();
- handle->mount_->Release();
-
- handle_map_[fd] = NULL;
+ handle_map_[fd].reset(NULL);
free_fds_.push_back(fd);
+
// Force lower numbered FD to be available first.
std::push_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
}
@@ -171,6 +122,7 @@ void KernelObject::FreeFD(int fd) {
Path KernelObject::GetAbsPathLocked(const std::string& path) {
// Generate absolute path
Path abs_path(cwd_);
+
if (path[0] == '/') {
abs_path = path;
} else {
@@ -180,3 +132,4 @@ Path KernelObject::GetAbsPathLocked(const std::string& path) {
return abs_path;
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.h b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
index eb4c8ac041..6dc695999a 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
@@ -12,10 +12,10 @@
#include <vector>
#include "nacl_io/error.h"
+#include "nacl_io/kernel_handle.h"
+#include "nacl_io/mount.h"
#include "nacl_io/path.h"
-class KernelHandle;
-class Mount;
// KernelObject provides basic functionality for threadsafe
// access to kernel objects such as file descriptors and
@@ -23,8 +23,8 @@ class Mount;
// path resolution.
class KernelObject {
public:
- typedef std::vector<KernelHandle*> HandleMap_t;
- typedef std::map<std::string, Mount*> MountMap_t;
+ typedef std::vector<ScopedKernelHandle> HandleMap_t;
+ typedef std::map<std::string, ScopedMount> MountMap_t;
KernelObject();
virtual ~KernelObject();
@@ -32,23 +32,20 @@ class KernelObject {
// Find the mount for the given path, and acquires it.
// Assumes |out_mount| and |out_path| are non-NULL.
Error AcquireMountAndPath(const std::string& relpath,
- Mount** out_mount,
+ ScopedMount* out_mount,
Path* out_path);
- // Assumes |mnt| is non-NULL.
- void ReleaseMount(Mount* mnt);
// Convert from FD to KernelHandle, and acquire the handle.
// Assumes |out_handle| is non-NULL.
- Error AcquireHandle(int fd, KernelHandle** out_handle);
- // Assumes |handle| is non-NULL.
- void ReleaseHandle(KernelHandle* handle);
+ Error AcquireHandle(int fd, ScopedKernelHandle* out_handle);
// Allocate a new fd and assign the handle to it, while
// ref counting the handle and associated mount.
// Assumes |handle| is non-NULL;
- int AllocateFD(KernelHandle* handle);
+ int AllocateFD(const ScopedKernelHandle& handle);
+
// Assumes |handle| is non-NULL;
- void FreeAndReassignFD(int fd, KernelHandle* handle);
+ void FreeAndReassignFD(int fd, const ScopedKernelHandle& handle);
void FreeFD(int fd);
protected:
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 2f49395ee0..8d5655ab59 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -25,6 +25,7 @@
#include "nacl_io/osstat.h"
#include "nacl_io/path.h"
#include "nacl_io/pepper_interface.h"
+#include "nacl_io/typed_mount_factory.h"
#include "sdk_util/auto_lock.h"
#include "sdk_util/ref_object.h"
@@ -38,18 +39,27 @@
KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL) {}
-KernelProxy::~KernelProxy() { delete ppapi_; }
+KernelProxy::~KernelProxy() {
+ // Clean up the MountFactories.
+ for (MountFactoryMap_t::iterator i = factories_.begin();
+ i != factories_.end();
+ ++i) {
+ delete i->second;
+ }
+
+ delete ppapi_;
+}
void KernelProxy::Init(PepperInterface* ppapi) {
ppapi_ = ppapi;
cwd_ = "/";
dev_ = 1;
- factories_["memfs"] = MountMem::Create<MountMem>;
- factories_["dev"] = MountDev::Create<MountDev>;
- factories_["html5fs"] = MountHtml5Fs::Create<MountHtml5Fs>;
- factories_["httpfs"] = MountHttp::Create<MountHttp>;
- factories_["passthroughfs"] = MountPassthrough::Create<MountPassthrough>;
+ factories_["memfs"] = new TypedMountFactory<MountMem>;
+ factories_["dev"] = new TypedMountFactory<MountDev>;
+ factories_["html5fs"] = new TypedMountFactory<MountHtml5Fs>;
+ factories_["httpfs"] = new TypedMountFactory<MountHttp>;
+ factories_["passthroughfs"] = new TypedMountFactory<MountPassthrough>;
int result;
result = mount("", "/", "passthroughfs", 0, NULL);
@@ -67,75 +77,52 @@ void KernelProxy::Init(PepperInterface* ppapi) {
int KernelProxy::open(const char* path, int oflags) {
Path rel;
- Mount* mnt;
+ ScopedMount mnt;
Error error = AcquireMountAndPath(path, &mnt, &rel);
if (error) {
errno = error;
return -1;
}
- MountNode* node = NULL;
+ ScopedMountNode node;
error = mnt->Open(rel, oflags, &node);
if (error) {
errno = error;
- ReleaseMount(mnt);
return -1;
}
- KernelHandle* handle = new KernelHandle(mnt, node);
+ ScopedKernelHandle handle(new KernelHandle(mnt, node));
error = handle->Init(oflags);
if (error) {
errno = error;
- ReleaseMount(mnt);
return -1;
}
- int fd = AllocateFD(handle);
- mnt->AcquireNode(node);
-
- ReleaseHandle(handle);
- ReleaseMount(mnt);
-
- return fd;
+ return AllocateFD(handle);
}
int KernelProxy::close(int fd) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
- Mount* mount = handle->mount_;
- // Acquire the mount to ensure FreeFD doesn't prematurely destroy it.
- mount->Acquire();
-
- // FreeFD will release the handle/mount held by this fd.
+ // Remove the FD from the process open file descriptor map
FreeFD(fd);
-
- // If this handle is the last reference to its node, releasing it will close
- // the node.
- ReleaseHandle(handle);
-
- // Finally, release the mount.
- mount->Release();
-
return 0;
}
int KernelProxy::dup(int oldfd) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(oldfd, &handle);
if (error) {
errno = error;
return -1;
}
- int newfd = AllocateFD(handle);
- ReleaseHandle(handle);
-
- return newfd;
+ return AllocateFD(handle);
}
int KernelProxy::dup2(int oldfd, int newfd) {
@@ -143,7 +130,7 @@ int KernelProxy::dup2(int oldfd, int newfd) {
if (oldfd == newfd)
return newfd;
- KernelHandle* old_handle;
+ ScopedKernelHandle old_handle;
Error error = AcquireHandle(oldfd, &old_handle);
if (error) {
errno = error;
@@ -151,7 +138,6 @@ int KernelProxy::dup2(int oldfd, int newfd) {
}
FreeAndReassignFD(newfd, old_handle);
- ReleaseHandle(old_handle);
return newfd;
}
@@ -190,7 +176,7 @@ char* KernelProxy::getwd(char* buf) {
}
int KernelProxy::chmod(const char* path, mode_t mode) {
- int fd = KernelProxy::open(path, O_RDWR);
+ int fd = KernelProxy::open(path, O_RDONLY);
if (-1 == fd)
return -1;
@@ -199,8 +185,24 @@ int KernelProxy::chmod(const char* path, mode_t mode) {
return result;
}
+int KernelProxy::chown(const char* path, uid_t owner, gid_t group) {
+ return 0;
+}
+
+int KernelProxy::fchown(int fd, uid_t owner, gid_t group) {
+ return 0;
+}
+
+int KernelProxy::lchown(const char* path, uid_t owner, gid_t group) {
+ return 0;
+}
+
+int KernelProxy::utime(const char* filename, const struct utimbuf* times) {
+ return 0;
+}
+
int KernelProxy::mkdir(const char* path, mode_t mode) {
- Mount* mnt;
+ ScopedMount mnt;
Path rel;
Error error = AcquireMountAndPath(path, &mnt, &rel);
if (error) {
@@ -208,19 +210,17 @@ int KernelProxy::mkdir(const char* path, mode_t mode) {
return -1;
}
- int result = 0;
error = mnt->Mkdir(rel, mode);
if (error) {
errno = error;
- result = -1;
+ return -1;
}
- ReleaseMount(mnt);
- return result;
+ return 0;
}
int KernelProxy::rmdir(const char* path) {
- Mount* mnt;
+ ScopedMount mnt;
Path rel;
Error error = AcquireMountAndPath(path, &mnt, &rel);
if (error) {
@@ -228,15 +228,13 @@ int KernelProxy::rmdir(const char* path) {
return -1;
}
- int result = 0;
error = mnt->Rmdir(rel);
if (error) {
errno = error;
- result = -1;
+ return -1;
}
- ReleaseMount(mnt);
- return result;
+ return 0;
}
int KernelProxy::stat(const char* path, struct stat* buf) {
@@ -313,14 +311,13 @@ int KernelProxy::mount(const char* source,
free(str);
}
- Mount* mnt = NULL;
- Error error = factory->second(dev_++, smap, ppapi_, &mnt);
+ Error error =
+ factory->second->CreateMount(dev_++, smap, ppapi_, &mounts_[abs_targ]);
if (error) {
errno = error;
return -1;
}
- mounts_[abs_targ] = mnt;
return 0;
}
@@ -346,13 +343,12 @@ int KernelProxy::umount(const char* path) {
return -1;
}
- it->second->Release();
mounts_.erase(it);
return 0;
}
ssize_t KernelProxy::read(int fd, void* buf, size_t nbytes) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
@@ -362,18 +358,19 @@ ssize_t KernelProxy::read(int fd, void* buf, size_t nbytes) {
AutoLock lock(&handle->lock_);
int cnt = 0;
error = handle->node_->Read(handle->offs_, buf, nbytes, &cnt);
- if (error)
+ if (error) {
errno = error;
+ return -1;
+ }
if (cnt > 0)
handle->offs_ += cnt;
- ReleaseHandle(handle);
return cnt;
}
ssize_t KernelProxy::write(int fd, const void* buf, size_t nbytes) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
@@ -383,37 +380,36 @@ ssize_t KernelProxy::write(int fd, const void* buf, size_t nbytes) {
AutoLock lock(&handle->lock_);
int cnt = 0;
error = handle->node_->Write(handle->offs_, buf, nbytes, &cnt);
- if (error)
+ if (error) {
errno = error;
+ return -1;
+ }
if (cnt > 0)
handle->offs_ += cnt;
- ReleaseHandle(handle);
return cnt;
}
int KernelProxy::fstat(int fd, struct stat* buf) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
- int result = 0;
error = handle->node_->GetStat(buf);
if (error) {
errno = error;
- result = -1;
+ return -1;
}
- ReleaseHandle(handle);
- return result;
+ return 0;
}
int KernelProxy::getdents(int fd, void* buf, unsigned int count) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
@@ -430,69 +426,79 @@ int KernelProxy::getdents(int fd, void* buf, unsigned int count) {
if (cnt > 0)
handle->offs_ += cnt;
- ReleaseHandle(handle);
return cnt;
}
int KernelProxy::ftruncate(int fd, off_t length) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
- int result = 0;
error = handle->node_->FTruncate(length);
if (error) {
errno = error;
- result = -1;
+ return -1;
}
- ReleaseHandle(handle);
- return result;
+ return 0;
}
int KernelProxy::fsync(int fd) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
- int result = 0;
error = handle->node_->FSync();
if (error) {
errno = error;
- result = -1;
+ return -1;
}
- ReleaseHandle(handle);
- return result;
+ return 0;
}
int KernelProxy::isatty(int fd) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
return -1;
}
- int result = 0;
error = handle->node_->IsaTTY();
if (error) {
errno = error;
- result = -1;
+ return -1;
}
- ReleaseHandle(handle);
- return result;
+ return 0;
+}
+
+int KernelProxy::ioctl(int d, int request, char* argp) {
+ ScopedKernelHandle handle;
+ Error error = AcquireHandle(d, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ error = handle->node_->Ioctl(request, argp);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ return 0;
}
off_t KernelProxy::lseek(int fd, off_t offset, int whence) {
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
@@ -504,15 +510,14 @@ off_t KernelProxy::lseek(int fd, off_t offset, int whence) {
error = handle->Seek(offset, whence, &new_offset);
if (error) {
errno = error;
- new_offset = -1;
+ return -1;
}
- ReleaseHandle(handle);
return new_offset;
}
int KernelProxy::unlink(const char* path) {
- Mount* mnt;
+ ScopedMount mnt;
Path rel;
Error error = AcquireMountAndPath(path, &mnt, &rel);
if (error) {
@@ -520,19 +525,17 @@ int KernelProxy::unlink(const char* path) {
return -1;
}
- int result = 0;
error = mnt->Unlink(rel);
if (error) {
errno = error;
- result = -1;
+ return -1;
}
- ReleaseMount(mnt);
- return result;
+ return 0;
}
int KernelProxy::remove(const char* path) {
- Mount* mnt;
+ ScopedMount mnt;
Path rel;
Error error = AcquireMountAndPath(path, &mnt, &rel);
if (error) {
@@ -540,28 +543,46 @@ int KernelProxy::remove(const char* path) {
return -1;
}
- int result = 0;
error = mnt->Remove(rel);
if (error) {
errno = error;
- result = -1;
+ return -1;
}
- ReleaseMount(mnt);
- return result;
+ return 0;
}
// TODO(noelallen): Needs implementation.
int KernelProxy::fchmod(int fd, int mode) {
- errno = EINVAL;
- return -1;
+ ScopedKernelHandle handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ return 0;
}
int KernelProxy::access(const char* path, int amode) {
- errno = EINVAL;
- return -1;
+ Path rel;
+
+ ScopedMount mnt;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ error = mnt->Access(rel, amode);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
}
+// TODO(noelallen): Needs implementation.
int KernelProxy::link(const char* oldpath, const char* newpath) {
errno = EINVAL;
return -1;
@@ -582,7 +603,7 @@ void* KernelProxy::mmap(void* addr,
assert((flags & MAP_ANONYMOUS) == 0);
assert(fd != -1);
- KernelHandle* handle;
+ ScopedKernelHandle handle;
Error error = AcquireHandle(fd, &handle);
if (error) {
errno = error;
@@ -590,17 +611,13 @@ void* KernelProxy::mmap(void* addr,
}
void* new_addr;
- {
- AutoLock lock(&handle->lock_);
- error = handle->node_->MMap(addr, length, prot, flags, offset, &new_addr);
- if (error) {
- errno = error;
- ReleaseHandle(handle);
- return MAP_FAILED;
- }
+ AutoLock lock(&handle->lock_);
+ error = handle->node_->MMap(addr, length, prot, flags, offset, &new_addr);
+ if (error) {
+ errno = error;
+ return MAP_FAILED;
}
- ReleaseHandle(handle);
return new_addr;
}
@@ -640,7 +657,7 @@ int KernelProxy::munmap(void* addr, size_t length) {
}
int KernelProxy::open_resource(const char* path) {
- Mount* mnt;
+ ScopedMount mnt;
Path rel;
Error error = AcquireMountAndPath(path, &mnt, &rel);
if (error) {
@@ -648,31 +665,24 @@ int KernelProxy::open_resource(const char* path) {
return -1;
}
- MountNode* node = NULL;
+ ScopedMountNode node;
error = mnt->OpenResource(rel, &node);
if (error) {
// OpenResource failed, try Open().
error = mnt->Open(rel, O_RDONLY, &node);
if (error) {
errno = error;
- ReleaseMount(mnt);
return -1;
}
}
- KernelHandle* handle = new KernelHandle(mnt, node);
+ ScopedKernelHandle handle(new KernelHandle(mnt, node));
error = handle->Init(O_RDONLY);
if (error) {
errno = error;
- ReleaseMount(mnt);
return -1;
}
- int fd = AllocateFD(handle);
- mnt->AcquireNode(node);
-
- ReleaseHandle(handle);
- ReleaseMount(mnt);
-
- return fd;
+ return AllocateFD(handle);
}
+
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 e8c251a32a..554a75ca4c 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
@@ -5,21 +5,14 @@
#ifndef LIBRARIES_NACL_IO_KERNEL_PROXY_H_
#define LIBRARIES_NACL_IO_KERNEL_PROXY_H_
-#include <ppapi/c/pp_instance.h>
-#include <ppapi/c/ppb.h>
-#include <pthread.h>
#include <map>
#include <string>
-#include <vector>
#include "nacl_io/kernel_object.h"
-#include "nacl_io/mount.h"
+#include "nacl_io/mount_factory.h"
#include "nacl_io/ostypes.h"
-#include "nacl_io/path.h"
+#include "nacl_io/osutime.h"
-class KernelHandle;
-class Mount;
-class MountNode;
class PepperInterface;
// KernelProxy provide one-to-one mapping for libc kernel calls. Calls to the
@@ -29,9 +22,7 @@ class PepperInterface;
// other classes should return Error (as defined by nacl_io/error.h).
class KernelProxy : protected KernelObject {
public:
- typedef Error (*MountFactory_t)(int, StringMap_t&, PepperInterface*, Mount**);
- typedef std::map<std::string, std::string> StringMap_t;
- typedef std::map<std::string, MountFactory_t> MountFactoryMap_t;
+ typedef std::map<std::string, MountFactory*> MountFactoryMap_t;
KernelProxy();
virtual ~KernelProxy();
@@ -40,7 +31,7 @@ class KernelProxy : protected KernelObject {
virtual void Init(PepperInterface* ppapi);
// KernelHandle and FD allocation and manipulation functions.
- virtual int open(const char *path, int oflag);
+ virtual int open(const char* path, int oflag);
virtual int close(int fd);
virtual int dup(int fd);
virtual int dup2(int fd, int newfd);
@@ -53,6 +44,12 @@ class KernelProxy : protected KernelObject {
const char *filesystemtype, unsigned long mountflags, const void *data);
virtual int umount(const char *path);
+ // Stub system calls that don't do anything (yet), handled by KernelProxy.
+ virtual int chown(const char* path, uid_t owner, gid_t group);
+ virtual int fchown(int fd, uid_t owner, gid_t group);
+ virtual int lchown(const char* path, uid_t owner, gid_t group);
+ virtual int utime(const char* filename, const struct utimbuf* times);
+
// System calls that take a path as an argument:
// The kernel proxy will look for the Node associated to the path. To
// find the node, the kernel proxy calls the corresponding mount's GetNode()
@@ -76,6 +73,7 @@ class KernelProxy : protected KernelObject {
virtual int ftruncate(int fd, off_t length);
virtual int fsync(int fd);
virtual int isatty(int fd);
+ virtual int ioctl(int d, int request, char *argp);
// lseek() relies on the mount's Stat() to determine whether or not the
// file handle corresponding to fd is a directory
@@ -93,7 +91,11 @@ class KernelProxy : protected KernelObject {
virtual int link(const char* oldpath, const char* newpath);
virtual int symlink(const char* oldpath, const char* newpath);
- virtual void* mmap(void* addr, size_t length, int prot, int flags, int fd,
+ virtual void* mmap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ int fd,
size_t offset);
virtual int munmap(void* addr, size_t length);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
index 322fe72154..ca1ada6af6 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
@@ -7,6 +7,8 @@
#include <sys/types.h>
#include <stdlib.h>
+#include "nacl_io/ostypes.h"
+#include "nacl_io/osutime.h"
#include "sdk_util/macros.h"
#if defined(__GLIBC__)
@@ -37,9 +39,11 @@ void kernel_wrap_init();
int NAME(access)(const char* path, int amode) NOTHROW;
int NAME(chdir)(const char* path) NOTHROW;
int NAME(chmod)(const char* path, chmod_mode_t mode) NOTHROW;
+int chown(const char* path, uid_t owner, gid_t group);
int NAME(close)(int fd);
int NAME(dup)(int oldfd) NOTHROW;
int NAME(dup2)(int oldfd, int newfd) NOTHROW;
+int fchown(int fd, uid_t owner, gid_t group);
#if defined(WIN32)
int _fstat32(int fd, struct _stat32* buf);
int _fstat64(int fd, struct _stat64* buf);
@@ -54,7 +58,9 @@ int ftruncate(int fd, off_t length) NOTHROW;
char* NAME(getcwd)(char* buf, getcwd_size_t size) NOTHROW;
char* getwd(char* buf) NOTHROW;
int getdents(int fd, void* buf, unsigned int count) NOTHROW;
+int ioctl(int d, int request, char* argp) NOTHROW;
int NAME(isatty)(int fd) NOTHROW;
+int lchown(const char* path, uid_t owner, gid_t group);
int link(const char* oldpath, const char* newpath) NOTHROW;
off_t NAME(lseek)(int fd, off_t offset, int whence) NOTHROW;
#if defined(WIN32)
@@ -82,6 +88,7 @@ int stat(const char* path, struct stat* buf) NOTHROW;
int symlink(const char* oldpath, const char* newpath) NOTHROW;
int umount(const char* path) NOTHROW;
int NAME(unlink)(const char* path) NOTHROW;
+int utime(const char* filename, const struct utimbuf* times);
read_ssize_t NAME(write)(int fd, const void* buf, size_t nbyte);
EXTERN_C_END
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 efa765b075..2de85f800c 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
@@ -138,6 +138,10 @@ int WRAP(chdir) (const char* pathname) {
return (ki_chdir(pathname)) ? errno : 0;
}
+int chown(const char* path, uid_t owner, gid_t group) {
+ return ki_chown(path, owner, group);
+}
+
int WRAP(close)(int fd) {
return (ki_close(fd) < 0) ? errno : 0;
}
@@ -151,6 +155,10 @@ int WRAP(dup2)(int fd, int newfd) NOTHROW {
return (ki_dup2(fd, newfd) < 0) ? errno : 0;
}
+int fchown(int fd, uid_t owner, gid_t group) {
+ return ki_fchown(fd, owner, group);
+}
+
int WRAP(fstat)(int fd, struct nacl_abi_stat *nacl_buf) {
struct stat buf;
memset(&buf, 0, sizeof(struct stat));
@@ -215,10 +223,18 @@ int WRAP(getdents)(int fd, dirent* nacl_buf, size_t nacl_count, size_t *nread) {
return 0;
}
+int ioctl(int d, int request, char* argp) NOTHROW {
+ return ki_ioctl(d, request, argp);
+}
+
int isatty(int fd) NOTHROW {
return ki_isatty(fd);
}
+int lchown(const char* path, uid_t owner, gid_t group) {
+ return ki_lchown(path, owner, group);
+}
+
int link(const char* oldpath, const char* newpath) NOTHROW {
return ki_link(oldpath, newpath);
}
@@ -310,7 +326,11 @@ int unlink(const char* path) NOTHROW {
return ki_unlink(path);
}
-int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) {
+int utime(const char* filename, const struct utimbuf* times) {
+ return ki_utime(filename, times);
+}
+
+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);
@@ -326,7 +346,7 @@ 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) {
struct nacl_abi_stat st;
int err = REAL(fstat)(fd, &st);
if (err) {
@@ -338,7 +358,7 @@ int _real_fstat(int fd, struct stat *buf) {
return 0;
}
-int _real_getdents(int fd, void* buf, size_t count, size_t *nread) {
+int _real_getdents(int fd, void* buf, size_t count, size_t* nread) {
// "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s).
// See WRAP(getdents) above.
char* nacl_buf = (char*)alloca(count);
@@ -434,3 +454,4 @@ EXTERN_C_END
#endif // defined(__native_client__) && defined(__GLIBC__)
+
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 722d54ef6f..d2f824253b 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
@@ -63,6 +63,10 @@ int chmod(const char* path, mode_t mode) {
return ki_chmod(path, mode);
}
+int chown(const char* path, uid_t owner, gid_t group) {
+ return ki_chown(path, owner, group);
+}
+
int WRAP(close)(int fd) {
return (ki_close(fd) < 0) ? errno : 0;
}
@@ -77,7 +81,11 @@ int WRAP(dup2)(int fd, int newfd) {
return (newfd < 0) ? errno : 0;
}
-int WRAP(fstat)(int fd, struct stat *buf) {
+int fchown(int fd, uid_t owner, gid_t group) {
+ return ki_fchown(fd, owner, group);
+}
+
+int WRAP(fstat)(int fd, struct stat* buf) {
return (ki_fstat(fd, buf) < 0) ? errno : 0;
}
@@ -101,14 +109,22 @@ int getdents(int fd, void* buf, unsigned int count) {
return ki_getdents(fd, buf, count);
}
-int WRAP(getdents)(int fd, dirent* buf, size_t count, size_t *nread) {
+int WRAP(getdents)(int fd, dirent* buf, size_t count, size_t* nread) {
return (ki_getdents(fd, buf, count) < 0) ? errno : 0;
}
+int ioctl(int d, int request, char* argp) {
+ return ki_ioctl(d, request, argp);
+}
+
int isatty(int fd) {
return ki_isatty(fd);
}
+int lchown(const char* path, uid_t owner, gid_t group) {
+ return ki_lchown(path, owner, group);
+}
+
int link(const char* oldpath, const char* newpath) {
return ki_link(oldpath, newpath);
}
@@ -143,7 +159,7 @@ int WRAP(open)(const char* pathname, int oflag, mode_t cmode, int* newfd) {
return (*newfd < 0) ? errno : 0;
}
-int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) {
+int WRAP(read)(int fd, void* buf, size_t count, size_t* nread) {
if (!ki_is_initialized())
return REAL(read)(fd, buf, count, nread);
@@ -181,6 +197,10 @@ int unlink(const char* path) {
return ki_unlink(path);
}
+int utime(const char *filename, const struct utimbuf* times) {
+ return ki_utime(filename, times);
+}
+
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);
@@ -268,3 +288,4 @@ EXTERN_C_END
#endif // defined(__native_client__) && !defined(__GLIBC__)
+
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc
index 79dfa879b1..85bfd0cf06 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc
@@ -55,6 +55,10 @@ int _chmod(const char* path, mode_t mode) {
return ki_chmod(path, mode);
}
+int chown(const char* path, uid_t owner, gid_t group) {
+ return ki_chown(path, owner, group);
+}
+
int _close(int fd) {
return ki_close(fd);
}
@@ -71,6 +75,10 @@ int _dup2(int oldfd, int newfd) {
return ki_dup2(oldfd, newfd);
}
+int fchown(int fd, uid_t owner, gid_t group) {
+ return ki_fchown(fd, owner, group);
+}
+
int _fstat32(int fd, struct _stat32* buf) {
struct stat ki_buf;
int res = ki_fstat(fd, &ki_buf);
@@ -119,10 +127,18 @@ int getdents(int fd, void* buf, unsigned int count) {
return ki_getdents(fd, buf, count);
}
+int ioctl(int d, int request, char* argp) {
+ return ki_ioctl(d, request, argp);
+}
+
int _isatty(int fd) {
return ki_isatty(fd);
}
+int lchown(const char* path, uid_t owner, gid_t group) {
+ return ki_lchown(path, owner, group);
+}
+
int link(const char* oldpath, const char* newpath) {
return ki_link(oldpath, newpath);
}
@@ -226,6 +242,10 @@ int _unlink(const char* path) {
return ki_unlink(path);
}
+int _utime(const char* filename, const struct utimbuf* times) {
+ return ki_utime(filename, times);
+}
+
int _write(int fd, const void* buf, size_t nbyte) {
if (!ki_is_initialized())
return 0;
@@ -294,3 +314,4 @@ void kernel_wrap_init() {
EXTERN_C_END
#endif // defined(WIN32)
+
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 81d621cfa2..eef0ac62ee 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -39,6 +39,7 @@
'FILES': [
"error.h",
"inode_pool.h",
+ "ioctl.h",
"kernel_handle.h",
"kernel_intercept.h",
"kernel_object.h",
@@ -47,6 +48,7 @@
"kernel_wrap_real.h",
"mount.h",
"mount_dev.h",
+ "mount_factory.h",
"mount_html5fs.h",
"mount_http.h",
"mount_mem.h",
@@ -62,9 +64,12 @@
"osmman.h",
"osstat.h",
"ostypes.h",
+ "osunistd.h",
+ "osutime.h",
"path.h",
"pepper_interface.h",
"real_pepper_interface.h",
+ "typed_mount_factory.h",
],
'DEST': 'include/nacl_io',
},
diff --git a/native_client_sdk/src/libraries/nacl_io/mount.cc b/native_client_sdk/src/libraries/nacl_io/mount.cc
index 76fe3a7848..d944ac96bd 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount.cc
@@ -32,18 +32,8 @@ Error Mount::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
void Mount::Destroy() {}
-void Mount::AcquireNode(MountNode* node) {
- AutoLock lock(&lock_);
- node->Acquire();
-}
-
-void Mount::ReleaseNode(MountNode* node) {
- AutoLock lock(&lock_);
- node->Release();
-}
-
-Error Mount::OpenResource(const Path& path, MountNode** out_node) {
- *out_node = NULL;
+Error Mount::OpenResource(const Path& path, ScopedMountNode* out_node) {
+ out_node->reset(NULL);
return EINVAL;
}
@@ -69,3 +59,4 @@ void Mount::OnNodeDestroyed(MountNode* node) {
if (node->stat_.st_ino)
inode_pool_.Release(node->stat_.st_ino);
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/mount.h b/native_client_sdk/src/libraries/nacl_io/mount.h
index ddf1fd5c76..58cf1a4ed1 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount.h
@@ -12,12 +12,16 @@
#include "nacl_io/inode_pool.h"
#include "nacl_io/mount_node.h"
#include "nacl_io/path.h"
+
#include "sdk_util/macros.h"
#include "sdk_util/ref_object.h"
+#include "sdk_util/scoped_ref.h"
+class Mount;
class MountNode;
class PepperInterface;
+typedef ScopedRef<Mount> ScopedMount;
typedef std::map<std::string, std::string> StringMap_t;
// NOTE: The KernelProxy is the only class that should be setting errno. All
@@ -36,31 +40,25 @@ class Mount : public RefObject {
virtual void Destroy();
public:
- template <class M>
- // Assumes that |out_mount| is non-NULL.
- static Error Create(int dev,
- StringMap_t& args,
- PepperInterface* ppapi,
- Mount** out_mount);
-
PepperInterface* ppapi() { return ppapi_; }
- // Assumes that |node| is non-NULL.
- void AcquireNode(MountNode* node);
- // Assumes that |node| is non-NULL.
- void ReleaseNode(MountNode* node);
-
// All paths in functions below are expected to containing a leading "/".
+ // Test whether a file or directory at a given path can be accessed.
+ // Returns 0 on success, or an appropriate errno value on failure.
+ virtual Error Access(const Path& path, int a_mode) = 0;
+
// Open a node at |path| with the specified open flags. The resulting
// MountNode is created with a ref count of 1.
// Assumes that |out_node| is non-NULL.
- virtual Error Open(const Path& path, int o_flags, MountNode** out_node) = 0;
+ virtual Error Open(const Path& path,
+ int o_flags,
+ ScopedMountNode* out_node) = 0;
// OpenResource is only used to read files from the NaCl NMF file. No mount
// except MountPassthrough should implement it.
// Assumes that |out_node| is non-NULL.
- virtual Error OpenResource(const Path& path, MountNode** out_node);
+ virtual Error OpenResource(const Path& path, ScopedMountNode* out_node);
// Unlink, Mkdir, Rmdir will affect the both the RefCount
// and the nlink number in the stat object.
@@ -74,6 +72,7 @@ class Mount : public RefObject {
// Assumes that |node| is non-NULL.
void OnNodeCreated(MountNode* node);
+
// Assumes that |node| is non-NULL.
void OnNodeDestroyed(MountNode* node);
@@ -88,28 +87,7 @@ class Mount : public RefObject {
// lock is held, so we make it private.
friend class KernelObject;
friend class KernelProxy;
- void Acquire() { RefObject::Acquire(); }
- bool Release() { return RefObject::Release(); }
-
DISALLOW_COPY_AND_ASSIGN(Mount);
};
-/*static*/
-template <class M>
-Error Mount::Create(int dev,
- StringMap_t& args,
- PepperInterface* ppapi,
- Mount** out_mount) {
- Mount* mnt = new M();
- Error error = mnt->Init(dev, args, ppapi);
- if (error) {
- delete mnt;
- *out_mount = NULL;
- return error;
- }
-
- *out_mount = mnt;
- return 0;
-}
-
#endif // LIBRARIES_NACL_IO_MOUNT_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
index 11893ea09e..78b5916fd5 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+/* 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.
*/
@@ -8,11 +8,17 @@
#include <errno.h>
#include <fcntl.h>
+#include <pthread.h>
#include <string.h>
+
+#include <deque>
+
+#include "nacl_io/ioctl.h"
#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/mount_dev.h"
#include "nacl_io/mount_node.h"
#include "nacl_io/mount_node_dir.h"
+#include "nacl_io/osunistd.h"
#include "nacl_io/pepper_interface.h"
#include "sdk_util/auto_lock.h"
@@ -66,11 +72,25 @@ class ConsoleNode : public NullNode {
class TtyNode : public NullNode {
public:
explicit TtyNode(Mount* mount);
+ ~TtyNode();
+
+ virtual Error Ioctl(int request,
+ char* arg);
+
+ virtual Error Read(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes);
virtual Error Write(size_t offs,
const void* buf,
size_t count,
int* out_bytes);
+
+ private:
+ std::deque<char> input_buffer_;
+ pthread_cond_t is_readable_;
+ std::string prefix_;
};
class ZeroNode : public MountNode {
@@ -175,7 +195,14 @@ Error ConsoleNode::Write(size_t offs,
return 0;
}
-TtyNode::TtyNode(Mount* mount) : NullNode(mount) {}
+TtyNode::TtyNode(Mount* mount) : NullNode(mount) {
+ prefix_ = "_default_:";
+ pthread_cond_init(&is_readable_, NULL);
+}
+
+TtyNode::~TtyNode() {
+ pthread_cond_destroy(&is_readable_);
+}
Error TtyNode::Write(size_t offs,
const void* buf,
@@ -189,15 +216,68 @@ Error TtyNode::Write(size_t offs,
if (!(var_intr && msg_intr))
return ENOSYS;
+ // We append the prefix_ to the data in buf, then package it up
+ // and post it as a message.
const char* data = static_cast<const char*>(buf);
- uint32_t len = static_cast<uint32_t>(count);
- struct PP_Var val = var_intr->VarFromUtf8(data, len);
+ std::string message;
+ {
+ AutoLock lock(&lock_);
+ message = prefix_;
+ }
+ message.append(data, count);
+ uint32_t len = static_cast<uint32_t>(message.size());
+ struct PP_Var val = var_intr->VarFromUtf8(message.data(), len);
msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val);
-
*out_bytes = count;
return 0;
}
+Error TtyNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ AutoLock lock(&lock_);
+ while (input_buffer_.size() <= 0) {
+ pthread_cond_wait(&is_readable_, &lock_);
+ }
+
+ // Copies data from the input buffer into buf.
+ size_t bytes_to_copy = std::min(count, input_buffer_.size());
+ std::copy(input_buffer_.begin(), input_buffer_.begin() + bytes_to_copy,
+ static_cast<char*>(buf));
+ *out_bytes = bytes_to_copy;
+ input_buffer_.erase(input_buffer_.begin(),
+ input_buffer_.begin() + bytes_to_copy);
+ return 0;
+}
+
+Error TtyNode::Ioctl(int request, char* arg) {
+ if (request == TIOCNACLPREFIX) {
+ // This ioctl is used to change the prefix for this tty node.
+ // The prefix is used to distinguish messages intended for this
+ // tty node from all the other messages cluttering up the
+ // javascript postMessage() channel.
+ AutoLock lock(&lock_);
+ prefix_ = arg;
+ return 0;
+ } else if (request == TIOCNACLINPUT) {
+ // This ioctl is used to deliver data from the user to this tty node's
+ // input buffer. We check if the prefix in the input data matches the
+ // prefix for this node, and only deliver the data if so.
+ struct tioc_nacl_input_string* message =
+ reinterpret_cast<struct tioc_nacl_input_string*>(arg);
+ AutoLock lock(&lock_);
+ if (message->length >= prefix_.size() &&
+ strncmp(message->buffer, prefix_.data(), prefix_.size()) == 0) {
+ input_buffer_.insert(input_buffer_.end(),
+ message->buffer + prefix_.size(),
+ message->buffer + message->length);
+ pthread_cond_broadcast(&is_readable_);
+ return 0;
+ }
+ return ENOTTY;
+ } else {
+ return EINVAL;
+ }
+}
+
ZeroNode::ZeroNode(Mount* mount) : MountNode(mount) { stat_.st_mode = S_IFCHR; }
Error ZeroNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
@@ -269,23 +349,28 @@ Error UrandomNode::Write(size_t offs,
} // namespace
-Error MountDev::Open(const Path& path, int mode, MountNode** out_node) {
- *out_node = NULL;
+Error MountDev::Access(const Path& path, int a_mode) {
+ ScopedMountNode node;
+ int error = root_->FindChild(path.Join(), &node);
+ if (error)
+ return error;
+
+ // Don't allow execute access.
+ if (a_mode & X_OK)
+ return EACCES;
+ return 0;
+}
+
+Error MountDev::Open(const Path& path, int mode, ScopedMountNode* out_node) {
+ out_node->reset(NULL);
AutoLock lock(&lock_);
// Don't allow creating any files.
if (mode & O_CREAT)
return EINVAL;
- MountNode* node = NULL;
- int error = root_->FindChild(path.Join(), &node);
- if (error)
- return error;
-
- node->Acquire();
- *out_node = node;
- return 0;
+ return root_->FindChild(path.Join(), out_node);
}
Error MountDev::Unlink(const Path& path) { return EINVAL; }
@@ -298,14 +383,14 @@ Error MountDev::Remove(const Path& path) { return EINVAL; }
MountDev::MountDev() {}
-#define INITIALIZE_DEV_NODE(path, klass) \
- error = root_->AddChild(path, new klass(this)); \
- if (error) \
+#define INITIALIZE_DEV_NODE(path, klass) \
+ error = root_->AddChild(path, ScopedMountNode(new klass(this))); \
+ if (error) \
return error;
-#define INITIALIZE_DEV_NODE_1(path, klass, arg) \
- error = root_->AddChild(path, new klass(this, arg)); \
- if (error) \
+#define INITIALIZE_DEV_NODE_1(path, klass, arg) \
+ error = root_->AddChild(path, ScopedMountNode(new klass(this, arg))); \
+ if (error) \
return error;
Error MountDev::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
@@ -313,7 +398,7 @@ Error MountDev::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
if (error)
return error;
- root_ = new MountNodeDir(this);
+ root_.reset(new MountNodeDir(this));
INITIALIZE_DEV_NODE("/null", NullNode);
INITIALIZE_DEV_NODE("/zero", ZeroNode);
@@ -330,8 +415,3 @@ Error MountDev::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
return 0;
}
-void MountDev::Destroy() {
- if (root_)
- root_->Release();
- root_ = NULL;
-}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_dev.h b/native_client_sdk/src/libraries/nacl_io/mount_dev.h
index 7ad7daa3b9..5d47838b62 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_dev.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.h
@@ -6,13 +6,14 @@
#define LIBRARIES_NACL_IO_MOUNT_DEV_H_
#include "nacl_io/mount.h"
+#include "nacl_io/typed_mount_factory.h"
class MountNode;
class MountDev : public Mount {
public:
- virtual Error Open(const Path& path, int mode, MountNode** out_node);
-
+ virtual Error Access(const Path& path, int a_mode);
+ virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node);
virtual Error Unlink(const Path& path);
virtual Error Mkdir(const Path& path, int permissions);
virtual Error Rmdir(const Path& path);
@@ -22,12 +23,12 @@ class MountDev : public Mount {
MountDev();
virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
- virtual void Destroy();
private:
- MountNode* root_;
+ ScopedMountNode root_;
- friend class Mount;
+ friend class TypedMountFactory<MountDev>;
+ DISALLOW_COPY_AND_ASSIGN(MountDev);
};
#endif // LIBRARIES_NACL_IO_MOUNT_DEV_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_factory.h b/native_client_sdk/src/libraries/nacl_io/mount_factory.h
new file mode 100644
index 0000000000..35f77d7609
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_factory.h
@@ -0,0 +1,29 @@
+/* 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_MOUNT_FACTORY_H_
+#define LIBRARIES_NACL_IO_MOUNT_FACTORY_H_
+
+#include <map>
+#include <string>
+
+#include "nacl_io/error.h"
+#include "sdk_util/scoped_ref.h"
+
+class PepperInterface;
+class Mount;
+
+typedef std::map<std::string, std::string> StringMap_t;
+
+class MountFactory {
+ public:
+ virtual ~MountFactory() {}
+ virtual Error CreateMount(int dev,
+ StringMap_t& args,
+ PepperInterface* ppapi,
+ ScopedRef<Mount>* out_mount) = 0;
+};
+
+#endif // LIBRARIES_NACL_IO_MOUNT_FACTORY_H_
+
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
index 0008284253..edac8f4c05 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
@@ -6,6 +6,7 @@
#include "nacl_io/mount_html5fs.h"
#include <errno.h>
+#include <fcntl.h>
#include <ppapi/c/pp_completion_callback.h>
#include <ppapi/c/pp_errors.h>
#include <stdlib.h>
@@ -24,9 +25,21 @@ int64_t strtoull(const char* nptr, char** endptr, int base) {
} // namespace
-Error MountHtml5Fs::Open(const Path& path, int mode, MountNode** out_node) {
- *out_node = NULL;
+Error MountHtml5Fs::Access(const Path& path, int a_mode) {
+ // a_mode is unused, since all files are readable, writable and executable.
+ ScopedMountNode node;
+ Error error = Open(path, O_RDONLY, &node);
+ if (error)
+ return error;
+
+ node->Release();
+ return 0;
+}
+Error MountHtml5Fs::Open(const Path& path,
+ int mode,
+ ScopedMountNode* out_node) {
+ out_node->reset(NULL);
Error error = BlockUntilFilesystemOpen();
if (error)
return error;
@@ -34,14 +47,12 @@ Error MountHtml5Fs::Open(const Path& path, int mode, MountNode** out_node) {
PP_Resource fileref = ppapi()->GetFileRefInterface()
->Create(filesystem_resource_, path.Join().c_str());
if (!fileref)
- return ENOSYS;
+ return ENOENT;
- MountNodeHtml5Fs* node = new MountNodeHtml5Fs(this, fileref);
+ ScopedMountNode node(new MountNodeHtml5Fs(this, fileref));
error = node->Init(mode);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
*out_node = node;
return 0;
@@ -59,7 +70,7 @@ Error MountHtml5Fs::Mkdir(const Path& path, int permissions) {
ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
path.Join().c_str()));
if (!fileref_resource.pp_resource())
- return EIO;
+ return ENOENT;
int32_t result = ppapi()->GetFileRefInterface()->MakeDirectory(
fileref_resource.pp_resource(), PP_FALSE, PP_BlockUntilComplete());
@@ -81,7 +92,7 @@ Error MountHtml5Fs::Remove(const Path& path) {
ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
path.Join().c_str()));
if (!fileref_resource.pp_resource())
- return ENOSYS;
+ return ENOENT;
int32_t result = ppapi()->GetFileRefInterface()
->Delete(fileref_resource.pp_resource(), PP_BlockUntilComplete());
@@ -178,3 +189,4 @@ void MountHtml5Fs::FilesystemOpenCallback(int32_t result) {
filesystem_open_error_ = PPErrorToErrno(result);
pthread_cond_signal(&filesystem_open_cond_);
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
index e872dae353..d2e1b083ee 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
@@ -6,14 +6,17 @@
#define LIBRARIES_NACL_IO_MOUNT_HTML5FS_H_
#include <pthread.h>
+
#include "nacl_io/mount.h"
#include "nacl_io/pepper_interface.h"
+#include "nacl_io/typed_mount_factory.h"
class MountNode;
class MountHtml5Fs : public Mount {
public:
- virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error Access(const Path& path, int a_mode);
+ virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node);
virtual Error Unlink(const Path& path);
virtual Error Mkdir(const Path& path, int permissions);
virtual Error Rmdir(const Path& path);
@@ -38,7 +41,7 @@ class MountHtml5Fs : public Mount {
Error filesystem_open_error_; // protected by lock_.
pthread_cond_t filesystem_open_cond_;
- friend class Mount;
+ friend class TypedMountFactory<MountHtml5Fs>;
};
#endif // LIBRARIES_NACL_IO_MOUNT_HTML5FS_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_http.cc b/native_client_sdk/src/libraries/nacl_io/mount_http.cc
index 15c32e6231..9638746b03 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_http.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_http.cc
@@ -21,7 +21,7 @@
#include "nacl_io/mount_node_dir.h"
#include "nacl_io/mount_node_http.h"
#include "nacl_io/osinttypes.h"
-#include "sdk_util/auto_lock.h"
+#include "nacl_io/osunistd.h"
namespace {
@@ -54,9 +54,32 @@ std::string NormalizeHeaderKey(const std::string& s) {
return result;
}
-Error MountHttp::Open(const Path& path, int mode, MountNode** out_node) {
- *out_node = NULL;
+Error MountHttp::Access(const Path& path, int a_mode) {
+ assert(url_root_.empty() || url_root_[url_root_.length() - 1] == '/');
+
+ NodeMap_t::iterator iter = node_cache_.find(path.Join());
+ if (iter == node_cache_.end()) {
+ // If we can't find the node in the cache, fetch it
+ std::string url = MakeUrl(path);
+ ScopedMountNode node(new MountNodeHttp(this, url, cache_content_));
+ Error error = node->Init(O_RDONLY);
+ if (error)
+ return error;
+
+ error = node->GetStat(NULL);
+ if (error)
+ return error;
+ }
+
+ // Don't allow write or execute access.
+ if (a_mode & (W_OK | X_OK))
+ return EACCES;
+
+ return 0;
+}
+Error MountHttp::Open(const Path& path, int mode, ScopedMountNode* out_node) {
+ out_node->reset(NULL);
assert(url_root_.empty() || url_root_[url_root_.length() - 1] == '/');
NodeMap_t::iterator iter = node_cache_.find(path.Join());
@@ -66,37 +89,26 @@ Error MountHttp::Open(const Path& path, int mode, MountNode** out_node) {
}
// If we can't find the node in the cache, create it
- std::string url = url_root_ + (path.IsAbsolute() ? path.Range(1, path.Size())
- : path.Join());
-
- MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_);
+ std::string url = MakeUrl(path);
+ ScopedMountNode node(new MountNodeHttp(this, url, cache_content_));
Error error = node->Init(mode);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
error = node->GetStat(NULL);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
- MountNodeDir* parent;
+ ScopedMountNode parent;
error = FindOrCreateDir(path.Parent(), &parent);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
error = parent->AddChild(path.Basename(), node);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
node_cache_[path.Join()] = node;
-
*out_node = node;
return 0;
}
@@ -241,43 +253,36 @@ Error MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
void MountHttp::Destroy() {}
-Error MountHttp::FindOrCreateDir(const Path& path, MountNodeDir** out_node) {
- *out_node = NULL;
-
+Error MountHttp::FindOrCreateDir(const Path& path,
+ ScopedMountNode* out_node) {
+ out_node->reset(NULL);
std::string strpath = path.Join();
NodeMap_t::iterator iter = node_cache_.find(strpath);
if (iter != node_cache_.end()) {
- *out_node = static_cast<MountNodeDir*>(iter->second);
+ *out_node = iter->second;
return 0;
}
// If the node does not exist, create it.
- MountNodeDir* node = new MountNodeDir(this);
+ ScopedMountNode node(new MountNodeDir(this));
Error error = node->Init(S_IREAD);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
// If not the root node, find the parent node and add it to the parent
if (!path.Top()) {
- MountNodeDir* parent;
+ ScopedMountNode parent;
error = FindOrCreateDir(path.Parent(), &parent);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
error = parent->AddChild(path.Basename(), node);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
}
// Add it to the node cache.
node_cache_[strpath] = node;
-
*out_node = node;
return 0;
}
@@ -337,31 +342,24 @@ Error MountHttp::ParseManifest(char* text) {
}
Path path(name);
- std::string url =
- url_root_ +
- (path.IsAbsolute() ? path.Range(1, path.Size()) : path.Join());
+ std::string url = MakeUrl(path);
+
+ MountNodeHttp* http_node = new MountNodeHttp(this, url, cache_content_);
+ ScopedMountNode node(http_node);
- MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_);
Error error = node->Init(mode);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
+ http_node->SetCachedSize(atoi(lenstr));
- node->SetCachedSize(atoi(lenstr));
-
- MountNodeDir* dir_node;
+ ScopedMountNode dir_node;
error = FindOrCreateDir(path.Parent(), &dir_node);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
error = dir_node->AddChild(path.Basename(), node);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
std::string pname = path.Join();
node_cache_[pname] = node;
@@ -374,7 +372,7 @@ Error MountHttp::ParseManifest(char* text) {
Error MountHttp::LoadManifest(const std::string& manifest_name,
char** out_manifest) {
Path manifest_path(manifest_name);
- MountNode* manifest_node = NULL;
+ ScopedMountNode manifest_node;
*out_manifest = NULL;
int error = Open(manifest_path, O_RDONLY, &manifest_node);
@@ -383,22 +381,21 @@ Error MountHttp::LoadManifest(const std::string& manifest_name,
size_t size;
error = manifest_node->GetSize(&size);
- if (error) {
- manifest_node->Release();
+ if (error)
return error;
- }
char* text = new char[size + 1];
int len;
error = manifest_node->Read(0, text, size, &len);
- if (error) {
- manifest_node->Release();
+ if (error)
return error;
- }
- manifest_node->Release();
text[len] = 0;
-
*out_manifest = text;
return 0;
}
+
+std::string MountHttp::MakeUrl(const Path& path) {
+ return url_root_ +
+ (path.IsAbsolute() ? path.Range(1, path.Size()) : path.Join());
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_http.h b/native_client_sdk/src/libraries/nacl_io/mount_http.h
index e10f1afcfe..e804f37d5a 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_http.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_http.h
@@ -9,19 +9,19 @@
#include <string>
#include "nacl_io/mount.h"
#include "nacl_io/pepper_interface.h"
+#include "nacl_io/typed_mount_factory.h"
class MountNode;
-class MountNodeDir;
-class MountNodeHttp;
class MountHttpMock;
std::string NormalizeHeaderKey(const std::string& s);
class MountHttp : public Mount {
public:
- typedef std::map<std::string, MountNode*> NodeMap_t;
+ typedef std::map<std::string, ScopedMountNode> NodeMap_t;
- virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error Access(const Path& path, int a_mode);
+ virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node);
virtual Error Unlink(const Path& path);
virtual Error Mkdir(const Path& path, int permissions);
virtual Error Rmdir(const Path& path);
@@ -36,11 +36,15 @@ class MountHttp : public Mount {
virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
- Error FindOrCreateDir(const Path& path, MountNodeDir** out_node);
+ Error FindOrCreateDir(const Path& path, ScopedMountNode* out_node);
Error LoadManifest(const std::string& path, char** out_manifest);
Error ParseManifest(char *text);
private:
+ // Gets the URL to fetch for |path|.
+ // |path| is relative to the mount point for the HTTP filesystem.
+ std::string MakeUrl(const Path& path);
+
std::string url_root_;
StringMap_t headers_;
NodeMap_t node_cache_;
@@ -49,7 +53,7 @@ class MountHttp : public Mount {
bool cache_stat_;
bool cache_content_;
- friend class Mount;
+ friend class TypedMountFactory<MountHttp>;
friend class MountNodeHttp;
friend class MountHttpMock;
};
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_mem.cc b/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
index 356600b4ec..41e0fddef9 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+/* Copyright (c) 2012 The hromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+
#include <string>
#include "nacl_io/mount.h"
@@ -13,35 +14,32 @@
#include "nacl_io/mount_node_dir.h"
#include "nacl_io/mount_node_mem.h"
#include "nacl_io/osstat.h"
+#include "nacl_io/osunistd.h"
#include "nacl_io/path.h"
#include "sdk_util/auto_lock.h"
#include "sdk_util/ref_object.h"
-MountMem::MountMem() : root_(NULL), max_ino_(0) {}
+MountMem::MountMem() : root_(NULL) {}
Error MountMem::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
Error error = Mount::Init(dev, args, ppapi);
if (error)
return error;
- root_ = new MountNodeDir(this);
+ root_.reset(new MountNodeDir(this));
error = root_->Init(S_IREAD | S_IWRITE);
if (error) {
- root_->Release();
+ root_.reset(NULL);
return error;
}
-
return 0;
}
-void MountMem::Destroy() {
- if (root_)
- root_->Release();
- root_ = NULL;
-}
-
-Error MountMem::FindNode(const Path& path, int type, MountNode** out_node) {
- MountNode* node = root_;
+Error MountMem::FindNode(const Path& path,
+ int type,
+ ScopedMountNode* out_node) {
+ out_node->reset(NULL);
+ ScopedMountNode node = root_;
// If there is no root there, we have an error.
if (node == NULL)
@@ -76,38 +74,47 @@ Error MountMem::FindNode(const Path& path, int type, MountNode** out_node) {
return 0;
}
-Error MountMem::Open(const Path& path, int mode, MountNode** out_node) {
- AutoLock lock(&lock_);
- MountNode* node = NULL;
- *out_node = NULL;
-
+Error MountMem::Access(const Path& path, int a_mode) {
+ ScopedMountNode node;
Error error = FindNode(path, 0, &node);
+ if (error)
+ return error;
+
+ int obj_mode = node->GetMode();
+ if (((a_mode & R_OK) && !(obj_mode & S_IREAD)) ||
+ ((a_mode & W_OK) && !(obj_mode & S_IWRITE)) ||
+ ((a_mode & X_OK) && !(obj_mode & S_IEXEC))) {
+ return EACCES;
+ }
+
+ return 0;
+}
+
+Error MountMem::Open(const Path& path, int mode, ScopedMountNode* out_node) {
+ out_node->reset(NULL);
+ ScopedMountNode node;
+
+ Error error = FindNode(path, 0, &node);
if (error) {
// If the node does not exist and we can't create it, fail
if ((mode & O_CREAT) == 0)
return ENOENT;
// Now first find the parent directory to see if we can add it
- MountNode* parent = NULL;
+ ScopedMountNode parent;
error = FindNode(path.Parent(), S_IFDIR, &parent);
if (error)
return error;
- // Create it with a single reference
- node = new MountNodeMem(this);
+ node.reset(new MountNodeMem(this));
error = node->Init(OpenModeToPermission(mode));
- if (error) {
- node->Release();
+ if (error)
return error;
- }
error = parent->AddChild(path.Basename(), node);
- if (error) {
- // Or if it fails, release it
- node->Release();
+ if (error)
return error;
- }
*out_node = node;
return 0;
@@ -127,15 +134,11 @@ Error MountMem::Open(const Path& path, int mode, MountNode** out_node) {
if ((obj_mode & req_mode) != req_mode)
return EACCES;
- // We opened it, so ref count it before passing it back.
- node->Acquire();
*out_node = node;
return 0;
}
Error MountMem::Mkdir(const Path& path, int mode) {
- AutoLock lock(&lock_);
-
// We expect a Mount "absolute" path
if (!path.IsAbsolute())
return ENOENT;
@@ -144,12 +147,12 @@ Error MountMem::Mkdir(const Path& path, int mode) {
if (path.Size() == 1)
return EEXIST;
- MountNode* parent = NULL;
+ ScopedMountNode parent;
int error = FindNode(path.Parent(), S_IFDIR, &parent);
if (error)
return error;
- MountNode* node = NULL;
+ ScopedMountNode node;
error = parent->FindChild(path.Basename(), &node);
if (!error)
return EEXIST;
@@ -160,21 +163,12 @@ Error MountMem::Mkdir(const Path& path, int mode) {
// Allocate a node, with a RefCount of 1. If added to the parent
// it will get ref counted again. In either case, release the
// recount we have on exit.
- node = new MountNodeDir(this);
+ node.reset(new MountNodeDir(this));
error = node->Init(S_IREAD | S_IWRITE);
- if (error) {
- node->Release();
- return error;
- }
-
- error = parent->AddChild(path.Basename(), node);
- if (error) {
- node->Release();
+ if (error)
return error;
- }
- node->Release();
- return 0;
+ return parent->AddChild(path.Basename(), node);
}
Error MountMem::Unlink(const Path& path) {
@@ -190,7 +184,6 @@ Error MountMem::Remove(const Path& path) {
}
Error MountMem::RemoveInternal(const Path& path, int remove_type) {
- AutoLock lock(&lock_);
bool dir_only = remove_type == REMOVE_DIR;
bool file_only = remove_type == REMOVE_FILE;
bool remove_dir = (remove_type & REMOVE_DIR) != 0;
@@ -205,13 +198,13 @@ Error MountMem::RemoveInternal(const Path& path, int remove_type) {
return EEXIST;
}
- MountNode* parent = NULL;
+ ScopedMountNode parent;
int error = FindNode(path.Parent(), S_IFDIR, &parent);
if (error)
return error;
// Verify we find a child which is a directory.
- MountNode* child = NULL;
+ ScopedMountNode child;
error = parent->FindChild(path.Basename(), &child);
if (error)
return error;
@@ -227,3 +220,4 @@ Error MountMem::RemoveInternal(const Path& path, int remove_type) {
return parent->RemoveChild(path.Basename());
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_mem.h b/native_client_sdk/src/libraries/nacl_io/mount_mem.h
index 930e9c734a..9bd679dba5 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_mem.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_mem.h
@@ -5,17 +5,14 @@
#ifndef LIBRARIES_NACL_IO_MOUNT_MEM_H_
#define LIBRARIES_NACL_IO_MOUNT_MEM_H_
-#include <map>
-#include <string>
-
#include "nacl_io/mount.h"
+#include "nacl_io/typed_mount_factory.h"
class MountMem : public Mount {
protected:
MountMem();
virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
- virtual void Destroy();
// The protected functions are only used internally and will not
// acquire or release the mount's lock themselves. The caller is
@@ -26,10 +23,11 @@ class MountMem : public Mount {
void FreeINO(int ino);
// Find a Node specified node optionally failing if type does not match.
- virtual Error FindNode(const Path& path, int type, MountNode** out_node);
+ virtual Error FindNode(const Path& path, int type, ScopedMountNode* out_node);
public:
- virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error Access(const Path& path, int a_mode);
+ virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node);
virtual Error Unlink(const Path& path);
virtual Error Mkdir(const Path& path, int perm);
virtual Error Rmdir(const Path& path);
@@ -42,10 +40,9 @@ private:
Error RemoveInternal(const Path& path, int remove_type);
- MountNode* root_;
- size_t max_ino_;
+ ScopedMountNode root_;
- friend class Mount;
+ friend class TypedMountFactory<MountMem>;
DISALLOW_COPY_AND_ASSIGN(MountMem);
};
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 34de7a8164..424df70e7c 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
@@ -8,6 +8,8 @@
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
+
+#include <algorithm>
#include <string>
#include "nacl_io/kernel_wrap_real.h"
@@ -46,9 +48,7 @@ void MountNode::Destroy() {
Error MountNode::FSync() { return 0; }
-Error MountNode::FTruncate(off_t length) {
- return EINVAL;
-}
+Error MountNode::FTruncate(off_t length) { return EINVAL; }
Error MountNode::GetDents(size_t offs,
struct dirent* pdir,
@@ -64,9 +64,7 @@ Error MountNode::GetStat(struct stat* pstat) {
return 0;
}
-Error MountNode::Ioctl(int request, char* arg) {
- return EINVAL;
-}
+Error MountNode::Ioctl(int request, char* arg) { return EINVAL; }
Error MountNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
*out_bytes = 0;
@@ -133,29 +131,21 @@ bool MountNode::IsaFile() { return (stat_.st_mode & S_IFREG) != 0; }
bool MountNode::IsaTTY() { return (stat_.st_mode & S_IFCHR) != 0; }
-Error MountNode::AddChild(const std::string& name, MountNode* node) {
+Error MountNode::AddChild(const std::string& name,
+ const ScopedMountNode& node) {
return ENOTDIR;
}
-Error MountNode::RemoveChild(const std::string& name) {
- return ENOTDIR;
-}
+Error MountNode::RemoveChild(const std::string& name) { return ENOTDIR; }
-Error MountNode::FindChild(const std::string& name, MountNode** out_node) {
- *out_node = NULL;
+Error MountNode::FindChild(const std::string& name, ScopedMountNode* out_node) {
+ out_node->reset(NULL);
return ENOTDIR;
}
-int MountNode::ChildCount() {
- return 0;
-}
+int MountNode::ChildCount() { return 0; }
-void MountNode::Link() {
- Acquire();
- stat_.st_nlink++;
-}
+void MountNode::Link() { stat_.st_nlink++; }
+
+void MountNode::Unlink() { stat_.st_nlink--; }
-void MountNode::Unlink() {
- stat_.st_nlink--;
- Release();
-}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.h b/native_client_sdk/src/libraries/nacl_io/mount_node.h
index 0acce66f80..fb0f14f2c5 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.h
@@ -9,11 +9,17 @@
#include "nacl_io/error.h"
#include "nacl_io/osstat.h"
+
#include "sdk_util/ref_object.h"
+#include "sdk_util/scoped_ref.h"
struct dirent;
struct stat;
+
class Mount;
+class MountNode;
+
+typedef ScopedRef<MountNode> ScopedMountNode;
// NOTE: The KernelProxy is the only class that should be setting errno. All
// other classes should return Error (as defined by nacl_io/error.h).
@@ -63,24 +69,26 @@ class MountNode : public RefObject {
virtual int GetMode();
virtual int GetType();
// Assume that |out_size| is non-NULL.
- virtual Error GetSize(size_t *out_size);
+ virtual Error GetSize(size_t* out_size);
virtual bool IsaDir();
virtual bool IsaFile();
virtual bool IsaTTY();
+ // Number of children for this node (directory)
+ virtual int ChildCount();
+
protected:
// Directory operations on the node are done by the Mount. The mount's lock
// must be held while these calls are made.
// Adds or removes a directory entry updating the link numbers and refcount
// Assumes that |node| is non-NULL.
- virtual Error AddChild(const std::string& name, MountNode* node);
+ virtual Error AddChild(const std::string& name, const ScopedMountNode& node);
virtual Error RemoveChild(const std::string& name);
// Find a child and return it without updating the refcount
// Assumes that |out_node| is non-NULL.
- virtual Error FindChild(const std::string& name, MountNode** out_node);
- virtual int ChildCount();
+ virtual Error FindChild(const std::string& name, ScopedMountNode* out_node);
// Update the link count
virtual void Link();
@@ -88,6 +96,11 @@ class MountNode : public RefObject {
protected:
struct stat stat_;
+
+ // We use a pointer directly to avoid cycles in the ref count.
+ // TODO(noelallen) We should change this so it's unnecessary for the node
+ // to track it's parent. When a node is unlinked, the mount should do
+ // any cleanup it needs.
Mount* mount_;
friend class Mount;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc
index 6f7feab44a..5aa39f966c 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc
@@ -73,7 +73,8 @@ Error MountNodeDir::GetDents(size_t offs,
return 0;
}
-Error MountNodeDir::AddChild(const std::string& name, MountNode* node) {
+Error MountNodeDir::AddChild(const std::string& name,
+ const ScopedMountNode& node) {
AutoLock lock(&lock_);
if (name.empty())
@@ -104,8 +105,9 @@ Error MountNodeDir::RemoveChild(const std::string& name) {
return ENOENT;
}
-Error MountNodeDir::FindChild(const std::string& name, MountNode** out_node) {
- *out_node = NULL;
+Error MountNodeDir::FindChild(const std::string& name,
+ ScopedMountNode* out_node) {
+ out_node->reset(NULL);
AutoLock lock(&lock_);
MountNodeMap_t::iterator it = map_.find(name);
@@ -131,9 +133,8 @@ void MountNodeDir::BuildCache() {
cache_ = (struct dirent*)malloc(sizeof(struct dirent) * map_.size());
MountNodeMap_t::iterator it = map_.begin();
for (size_t index = 0; it != map_.end(); it++, index++) {
- MountNode* node = it->second;
size_t len = it->first.length();
- cache_[index].d_ino = node->stat_.st_ino;
+ cache_[index].d_ino = it->second->stat_.st_ino;
cache_[index].d_off = sizeof(struct dirent);
cache_[index].d_reclen = sizeof(struct dirent);
cache_[index].d_name[len] = 0;
@@ -141,3 +142,4 @@ void MountNodeDir::BuildCache() {
}
}
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_dir.h b/native_client_sdk/src/libraries/nacl_io/mount_node_dir.h
index a2ab67ecfa..dd635fe50b 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_dir.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_dir.h
@@ -16,6 +16,9 @@ class MountDev;
class MountHtml5Fs;
class MountHttp;
class MountMem;
+class MountNodeDir;
+
+typedef ScopedRef<MountNodeDir> ScopedMountNodeDir;
class MountNodeDir : public MountNode {
protected:
@@ -23,7 +26,7 @@ class MountNodeDir : public MountNode {
virtual ~MountNodeDir();
public:
- typedef std::map<std::string, MountNode*> MountNodeMap_t;
+ typedef std::map<std::string, ScopedMountNode> MountNodeMap_t;
virtual Error FTruncate(off_t size);
virtual Error GetDents(size_t offs,
@@ -34,9 +37,9 @@ class MountNodeDir : public MountNode {
virtual Error Write(size_t offs, void *buf, size_t count, int* out_bytes);
// Adds a finds or adds a directory entry as an INO, updating the refcount
- virtual Error AddChild(const std::string& name, MountNode *node);
+ virtual Error AddChild(const std::string& name, const ScopedMountNode& node);
virtual Error RemoveChild(const std::string& name);
- virtual Error FindChild(const std::string& name, MountNode** out_node);
+ virtual Error FindChild(const std::string& name, ScopedMountNode* out_node);
virtual int ChildCount();
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc
index 8be2a4f74b..a6bfc9b12b 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc
@@ -268,10 +268,12 @@ Error MountNodeHtml5Fs::Init(int perm) {
// First query the FileRef to see if it is a file or directory.
PP_FileInfo file_info;
- mount_->ppapi()->GetFileRefInterface()->Query(fileref_resource_, &file_info,
- PP_BlockUntilComplete());
+ int32_t query_result =
+ mount_->ppapi()->GetFileRefInterface()->Query(fileref_resource_,
+ &file_info,
+ PP_BlockUntilComplete());
// If this is a directory, do not get a FileIO.
- if (file_info.type == PP_FILETYPE_DIRECTORY)
+ if (query_result == PP_OK && file_info.type == PP_FILETYPE_DIRECTORY)
return 0;
fileio_resource_ = mount_->ppapi()->GetFileIoInterface()
@@ -302,3 +304,4 @@ void MountNodeHtml5Fs::Destroy() {
fileref_resource_ = 0;
MountNode::Destroy();
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_http.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_http.cc
index 5005ff48d3..02303953ae 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_http.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_http.cc
@@ -27,6 +27,8 @@ namespace {
const size_t MAX_READ_BUFFER_SIZE = 64 * 1024;
const int32_t STATUSCODE_OK = 200;
const int32_t STATUSCODE_PARTIAL_CONTENT = 206;
+const int32_t STATUSCODE_FORBIDDEN = 403;
+const int32_t STATUSCODE_NOT_FOUND = 404;
StringMap_t ParseHeaders(const char* headers, int32_t headers_length) {
enum State {
@@ -124,6 +126,22 @@ bool ParseContentRange(const StringMap_t& headers,
return false;
}
+// Maps an HTTP |status_code| onto the appropriate errno code.
+int HTTPStatusCodeToErrno(int status_code) {
+ switch (status_code) {
+ case STATUSCODE_OK:
+ case STATUSCODE_PARTIAL_CONTENT:
+ return 0;
+ case STATUSCODE_FORBIDDEN:
+ return EACCES;
+ case STATUSCODE_NOT_FOUND:
+ return ENOENT;
+ }
+ if (status_code >= 400 && status_code < 500)
+ return EINVAL;
+ return EIO;
+}
+
} // namespace
void MountNodeHttp::SetCachedSize(off_t size) {
@@ -298,10 +316,9 @@ Error MountNodeHttp::OpenUrl(const char* method,
*out_statuscode = statuscode.value.as_int;
// Only accept OK or Partial Content.
- if (*out_statuscode != STATUSCODE_OK &&
- *out_statuscode != STATUSCODE_PARTIAL_CONTENT) {
- return EINVAL;
- }
+ Error error = HTTPStatusCodeToErrno(*out_statuscode);
+ if (error)
+ return error;
// Get response headers.
PP_Var response_headers_var = response_interface->GetProperty(
@@ -521,3 +538,4 @@ Error MountNodeHttp::DownloadToBuffer(PP_Resource loader,
*out_bytes = count;
return 0;
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc
index d324079700..fb403d5cb3 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc
@@ -43,7 +43,6 @@ Error MountNodeMem::Write(size_t offs,
size_t count,
int* out_bytes) {
*out_bytes = 0;
-
AutoLock lock(&lock_);
if (count == 0)
@@ -77,7 +76,7 @@ Error MountNodeMem::FTruncate(off_t new_size) {
if (newdata != NULL) {
// Zero out new space.
if (new_size > old_size)
- memset(newdata + old_size, 0, new_size - old_size);
+ memset(newdata + old_size, 0, need - old_size);
data_ = newdata;
capacity_ = need;
@@ -93,3 +92,4 @@ Error MountNodeMem::FTruncate(off_t new_size) {
stat_.st_size = static_cast<off_t>(new_size);
return EIO;
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
index 268cbea7a5..32cde000b2 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
@@ -108,29 +108,33 @@ Error MountPassthrough::Init(int dev,
void MountPassthrough::Destroy() {}
-Error MountPassthrough::Open(const Path& path, int mode, MountNode** out_node) {
- *out_node = NULL;
+Error MountPassthrough::Access(const Path& path, int a_mode) {
+ // There is no underlying 'access' syscall in NaCl. It just returns ENOSYS.
+ return ENOSYS;
+}
+Error MountPassthrough::Open(const Path& path,
+ int mode,
+ ScopedMountNode* out_node) {
+ out_node->reset(NULL);
int real_fd;
int error = _real_open(path.Join().c_str(), mode, 0666, &real_fd);
if (error)
return error;
- MountNodePassthrough* node = new MountNodePassthrough(this, real_fd);
- *out_node = node;
+ out_node->reset(new MountNodePassthrough(this, real_fd));
return 0;
}
-Error MountPassthrough::OpenResource(const Path& path, MountNode** out_node) {
- *out_node = NULL;
-
+Error MountPassthrough::OpenResource(const Path& path,
+ ScopedMountNode* out_node) {
int real_fd;
+ out_node->reset(NULL);
int error = _real_open_resource(path.Join().c_str(), &real_fd);
if (error)
return error;
- MountNodePassthrough* node = new MountNodePassthrough(this, real_fd);
- *out_node = node;
+ out_node->reset(new MountNodePassthrough(this, real_fd));
return 0;
}
@@ -151,3 +155,4 @@ Error MountPassthrough::Remove(const Path& path) {
// Not implemented by NaCl.
return ENOSYS;
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
index b143abf007..4d441a0ba7 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
@@ -6,6 +6,7 @@
#define LIBRARIES_NACL_IO_MOUNT_PASSTHROUGH_H_
#include "nacl_io/mount.h"
+#include "nacl_io/typed_mount_factory.h"
class MountPassthrough : public Mount {
protected:
@@ -15,16 +16,17 @@ class MountPassthrough : public Mount {
virtual void Destroy();
public:
- virtual Error Open(const Path& path, int mode, MountNode** out_node);
- virtual Error OpenResource(const Path& path, MountNode** out_node);
+ virtual Error Access(const Path& path, int a_mode);
+ virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node);
+ virtual Error OpenResource(const Path& path, ScopedMountNode* out_node);
virtual Error Unlink(const Path& path);
virtual Error Mkdir(const Path& path, int perm);
virtual Error Rmdir(const Path& path);
virtual Error Remove(const Path& path);
private:
- friend class Mount;
- DISALLOW_COPY_AND_ASSIGN(MountPassthrough);
+ friend class TypedMountFactory<MountPassthrough>;
+ DISALLOW_COPY_AND_ASSIGN(MountPassthrough);
};
#endif // LIBRARIES_NACL_IO_MOUNT_PASSTHROUGH_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/nacl_io.cc b/native_client_sdk/src/libraries/nacl_io/nacl_io.cc
index 9750cd858d..29371c9561 100644
--- a/native_client_sdk/src/libraries/nacl_io/nacl_io.cc
+++ b/native_client_sdk/src/libraries/nacl_io/nacl_io.cc
@@ -16,3 +16,4 @@ void nacl_io_init_ppapi(PP_Instance instance,
PPB_GetInterface get_interface) {
ki_init_ppapi(NULL, instance, get_interface);
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/ostypes.h b/native_client_sdk/src/libraries/nacl_io/ostypes.h
index 5adc6fe5bd..084ec3319f 100644
--- a/native_client_sdk/src/libraries/nacl_io/ostypes.h
+++ b/native_client_sdk/src/libraries/nacl_io/ostypes.h
@@ -13,6 +13,8 @@
typedef int mode_t;
typedef SSIZE_T ssize_t;
+typedef int uid_t;
+typedef int gid_t;
#endif
diff --git a/native_client_sdk/src/libraries/nacl_io/osunistd.h b/native_client_sdk/src/libraries/nacl_io/osunistd.h
new file mode 100644
index 0000000000..c5da0efe0a
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/osunistd.h
@@ -0,0 +1,22 @@
+/* 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_OSUNISTD_H_
+#define LIBRARIES_NACL_IO_OSUNISTD_H_
+
+#if defined(WIN32)
+
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#define F_OK 0
+
+#else
+
+#include <unistd.h>
+
+#endif
+
+#endif // LIBRARIES_NACL_IO_OSUNISTD_H_
+
diff --git a/native_client_sdk/src/libraries/nacl_io/osutime.h b/native_client_sdk/src/libraries/nacl_io/osutime.h
new file mode 100644
index 0000000000..03d98b99a2
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/osutime.h
@@ -0,0 +1,15 @@
+/* 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_IO_OSUTIME_H_
+#define LIBRARIES_NACL_IO_OSUTIME_H_
+
+#if defined(WIN32)
+#define utimbuf _utimbuf
+#endif
+
+struct utimbuf;
+
+#endif // LIBRARIES_NACL_IO_OSUTIME_H_
+
diff --git a/native_client_sdk/src/libraries/nacl_io/path.cc b/native_client_sdk/src/libraries/nacl_io/path.cc
index 6cab36a441..88b6413589 100644
--- a/native_client_sdk/src/libraries/nacl_io/path.cc
+++ b/native_client_sdk/src/libraries/nacl_io/path.cc
@@ -201,3 +201,4 @@ Path& Path::operator =(const Path& p) {
Path& Path::operator =(const std::string& p) {
return Set(p);
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc
index ea74756f0d..861649d1c3 100644
--- a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc
+++ b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc
@@ -136,3 +136,4 @@ int32_t RealPepperInterface::InitializeMessageLoop() {
return PP_OK;
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/typed_mount_factory.h b/native_client_sdk/src/libraries/nacl_io/typed_mount_factory.h
new file mode 100644
index 0000000000..c859b0bb46
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/typed_mount_factory.h
@@ -0,0 +1,29 @@
+/* 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_TYPED_MOUNT_FACTORY_H_
+#define LIBRARIES_NACL_IO_TYPED_MOUNT_FACTORY_H_
+
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_factory.h"
+
+template <typename T>
+class TypedMountFactory : public MountFactory {
+ public:
+ virtual Error CreateMount(int dev,
+ StringMap_t& args,
+ PepperInterface* ppapi,
+ ScopedRef<Mount>* out_mount) {
+ ScopedRef<T> mnt(new T());
+ Error error = mnt->Init(dev, args, ppapi);
+ if (error)
+ return error;
+
+ *out_mount = mnt;
+ return 0;
+ }
+};
+
+#endif // LIBRARIES_NACL_IO_TYPED_MOUNT_FACTORY_H_
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/example.dsc b/native_client_sdk/src/libraries/nacl_io_test/example.dsc
index df934a56a2..b26cd7cd29 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/example.dsc
+++ b/native_client_sdk/src/libraries/nacl_io_test/example.dsc
@@ -13,20 +13,24 @@
'kernel_proxy_mock.h',
'kernel_proxy_test.cc',
'kernel_wrap_test.cc',
+ 'main.cc',
'mock_util.h',
- 'module.cc',
- 'mount_node_test.cc',
'mount_html5fs_test.cc',
'mount_http_test.cc',
+ 'mount_mock.cc',
+ 'mount_mock.h',
+ 'mount_node_mock.cc',
+ 'mount_node_mock.h',
+ 'mount_node_test.cc',
'mount_test.cc',
'path_test.cc',
'pepper_interface_mock.cc',
'pepper_interface_mock.h',
],
- 'DEPS': ['nacl_io'],
+ 'DEPS': ['ppapi_simple', 'nacl_io'],
# Order matters here: gtest has a "main" function that will be used if
# referenced before ppapi.
- 'LIBS': ['gtest_ppapi', 'gmock', 'ppapi_cpp', 'ppapi', 'gtest', 'pthread'],
+ 'LIBS': ['gmock', 'ppapi_cpp', 'ppapi', 'gtest', 'pthread'],
'INCLUDES': ['$(NACL_SDK_ROOT)/include/gtest/internal'],
}
],
diff --git a/native_client_sdk/src/libraries/nacl_io_test/example.js b/native_client_sdk/src/libraries/nacl_io_test/example.js
index 2d93739d0f..bd175944b9 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/example.js
+++ b/native_client_sdk/src/libraries/nacl_io_test/example.js
@@ -6,19 +6,80 @@ function moduleDidLoad() {
// The module is not hidden by default so we can easily see if the plugin
// failed to load.
common.hideModule();
- common.naclModule.postMessage('RunGTest');
+}
+
+var currentTestEl = null;
+
+function startCommand(testName) {
+ var testListEl = document.getElementById('tests');
+ var testEl = document.createElement('li');
+ var testRowEl = document.createElement('div');
+ var testNameEl = document.createElement('span');
+ var testResultEl = document.createElement('span');
+ testRowEl.classList.add('row');
+ testNameEl.classList.add('name');
+ testNameEl.textContent = testName;
+ testResultEl.classList.add('result');
+ testRowEl.appendChild(testNameEl);
+ testRowEl.appendChild(testResultEl);
+ testEl.appendChild(testRowEl);
+ testListEl.appendChild(testEl);
+
+ currentTestEl = testEl;
+}
+
+function failCommand(fileName, lineNumber, summary) {
+ var testMessageEl = document.createElement('pre');
+ testMessageEl.textContent += fileName + ':' + lineNumber + ': ' + summary;
+ currentTestEl.appendChild(testMessageEl);
+}
+
+function endCommand(testName, testResult) {
+ var testRowEl = currentTestEl.querySelector('.row');
+ var testResultEl = currentTestEl.querySelector('.result');
+ testRowEl.classList.add(testResult);
+ testResultEl.textContent = testResult;
}
function handleMessage(event) {
- var logEl = document.getElementById('log');
var msg = event.data;
+ var firstColon = msg.indexOf(':');
+ var cmd = msg.substr(0, firstColon);
+ var cmdFunctionName = cmd + 'Command';
+ var cmdFunction = window[cmdFunctionName];
+
+ if (typeof(cmdFunction) !== 'function') {
+ console.log('Unknown command: ' + cmd);
+ console.log(' message: ' + msg);
+ return;
+ }
+
+ var argCount = cmdFunction.length;
+
+ // Don't use split, because it will split all commas (for example any commas
+ // in the test failure summary).
+ var argList = msg.substr(firstColon + 1);
+ args = [];
+ for (var i = 0; i < argCount - 1; ++i) {
+ var arg;
+ var comma = argList.indexOf(',');
+ if (comma === -1) {
+ if (i !== argCount - 1) {
+ console.log('Bad arg count to command "' + cmd + '", expected ' +
+ argCount);
+ console.log(' message: ' + msg);
+ } else {
+ arg = argList;
+ }
+ } else {
+ arg = argList.substr(0, comma);
+ argList = argList.substr(comma + 1);
+ }
+ args.push(arg);
+ }
- // Perform some basic escaping.
- msg = msg.replace(/&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;')
- .replace(/"/g, '&quot;')
- .replace(/'/g, '&apos;');
+ // Last argument is the rest of the message.
+ args.push(argList);
- logEl.innerHTML += msg + '\n';
+ cmdFunction.apply(null, args);
}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/index.html b/native_client_sdk/src/libraries/nacl_io_test/index.html
index 424f557e13..ba54317929 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/index.html
+++ b/native_client_sdk/src/libraries/nacl_io_test/index.html
@@ -11,6 +11,11 @@ found in the LICENSE file.
<title>{{title}}</title>
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript" src="example.js"></script>
+ <style>
+ .result { padding-left: 10px; }
+ .ok { background-color: #0f0; }
+ .failed { background-color: #f00; }
+ </style>
</head>
<body {{attrs}}>
<h1>{{title}}</h1>
@@ -18,6 +23,6 @@ found in the LICENSE file.
<!-- The NaCl plugin will be embedded inside the element with id "listener".
See common.js.-->
<div id="listener"></div>
- <pre id="log"></pre>
+ <ul id="tests" style="list-style:none;"></ul>
</body>
</html>
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc
index 9e6f4832a7..7f7f7eadd6 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc
@@ -20,178 +20,172 @@
namespace {
-class MountRefMock : public Mount {
+class MountNodeRefMock : public MountNode {
public:
- MountRefMock(int* mount_count, int* handle_count)
- : mount_count(mount_count), handle_count(handle_count) {
- (*mount_count)++;
- }
+ MountNodeRefMock(Mount* mnt) : MountNode(mnt) {}
+};
- ~MountRefMock() { (*mount_count)--; }
+class MountRefMock : public Mount {
+ public:
+ MountRefMock() {}
+ ~MountRefMock() {}
public:
- Error Open(const Path& path, int mode, MountNode** out_node) {
- *out_node = NULL;
+ Error Access(const Path& path, int a_mode) { return ENOSYS; }
+ Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
+ out_node->reset(NULL);
return ENOSYS;
}
Error Unlink(const Path& path) { return 0; }
Error Mkdir(const Path& path, int permissions) { return 0; }
Error Rmdir(const Path& path) { return 0; }
Error Remove(const Path& path) { return 0; }
-
- public:
- int* mount_count;
- int* handle_count;
};
class KernelHandleRefMock : public KernelHandle {
public:
- KernelHandleRefMock(Mount* mnt, MountNode* node)
- : KernelHandle(mnt, node) {
- MountRefMock* mock_mount = static_cast<MountRefMock*>(mnt);
- (*mock_mount->handle_count)++;
- }
+ KernelHandleRefMock(const ScopedMount& mnt, const ScopedMountNode& node)
+ : KernelHandle(mnt, node) {}
- ~KernelHandleRefMock() {
- MountRefMock* mock_mount = static_cast<MountRefMock*>(mount_);
- (*mock_mount->handle_count)--;
- }
+ ~KernelHandleRefMock() {}
};
class KernelObjectTest : public ::testing::Test {
public:
- KernelObjectTest() : mount_count(0), handle_count(0) {
+ KernelObjectTest() {
proxy = new KernelObject;
- mnt = new MountRefMock(&mount_count, &handle_count);
+ mnt.reset(new MountRefMock());
+ node.reset(new MountNodeRefMock(mnt.get()));
}
~KernelObjectTest() {
// mnt is ref-counted, it doesn't need to be explicitly deleted.
+ node.reset(NULL);
+ mnt.reset(NULL);
delete proxy;
}
KernelObject* proxy;
- MountRefMock* mnt;
- int mount_count;
- int handle_count;
+ ScopedMount mnt;
+ ScopedMountNode node;
};
} // namespace
-TEST_F(KernelObjectTest, Referencing) {
- KernelHandle* handle = new KernelHandleRefMock(mnt, NULL);
- KernelHandle* handle2 = new KernelHandleRefMock(mnt, NULL);
- KernelHandle* result_handle = NULL;
+#include <nacl_io/mount_mem.h>
+#include <nacl_io/mount_http.h>
- // Objects should have one ref when we start
+TEST_F(KernelObjectTest, Referencing) {
+ // The mount and node should have 1 ref count at this point
EXPECT_EQ(1, mnt->RefCount());
- EXPECT_EQ(1, handle->RefCount());
+ EXPECT_EQ(1, node->RefCount());
- // Objects should have two refs when we get here
- int fd1 = proxy->AllocateFD(handle);
+ // Pass the mount and node into a KernelHandle
+ KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
+ ScopedKernelHandle handle_a(raw_handle);
+
+ // The mount and node should have 1 ref count at this point
+ EXPECT_EQ(1, handle_a->RefCount());
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
+
+ ScopedKernelHandle handle_b = handle_a;
+
+ // There should be two references to the KernelHandle, the mount and node
+ // should be unchanged.
+ EXPECT_EQ(2, handle_a->RefCount());
+ EXPECT_EQ(2, handle_b->RefCount());
+ EXPECT_EQ(handle_a.get(), handle_b.get());
EXPECT_EQ(2, mnt->RefCount());
- EXPECT_EQ(2, handle->RefCount());
+ EXPECT_EQ(2, node->RefCount());
- // If we "dup" the handle, we should bump the refs
- int fd2 = proxy->AllocateFD(handle);
- EXPECT_EQ(3, mnt->RefCount());
- EXPECT_EQ(3, handle->RefCount());
+ // Allocating an FD should cause the KernelProxy to ref the handle and
+ // the node and mount should be unchanged.
+ int fd1 = proxy->AllocateFD(handle_a);
+ EXPECT_EQ(3, handle_a->RefCount());
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
- // If use a new handle with the same values... bump the refs
- int fd3 = proxy->AllocateFD(handle2);
- EXPECT_EQ(4, mnt->RefCount());
- EXPECT_EQ(2, handle2->RefCount());
+ // If we "dup" the handle, we should bump the ref count on the handle
+ int fd2 = proxy->AllocateFD(handle_b);
+ EXPECT_EQ(4, handle_a->RefCount());
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
// Handles are expected to come out in order
EXPECT_EQ(0, fd1);
EXPECT_EQ(1, fd2);
- EXPECT_EQ(2, fd3);
+
+ // Now we "free" the handles, since the proxy should hold them.
+ handle_a.reset(NULL);
+ handle_b.reset(NULL);
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
// We should find the handle by either fd
- EXPECT_EQ(0, proxy->AcquireHandle(fd1, &result_handle));
- EXPECT_EQ(handle, result_handle);
- EXPECT_EQ(0, proxy->AcquireHandle(fd2, &result_handle));
- EXPECT_EQ(handle, result_handle);
-
- // A non existent fd should fail
- EXPECT_EQ(EBADF, proxy->AcquireHandle(-1, &result_handle));
- EXPECT_EQ(NULL, result_handle);
- EXPECT_EQ(EBADF, proxy->AcquireHandle(100, &result_handle));
- EXPECT_EQ(NULL, result_handle);
-
- // Acquiring the handle, should have ref'd it
- EXPECT_EQ(4, mnt->RefCount());
- EXPECT_EQ(5, handle->RefCount());
-
- // Release the handle for each call to acquire
- proxy->ReleaseHandle(handle);
- proxy->ReleaseHandle(handle);
-
- // Release the handle for each time we constructed something
- proxy->ReleaseHandle(handle);
- proxy->ReleaseHandle(handle2);
- proxy->ReleaseMount(mnt);
-
- // We should now only have references used by the KernelProxy
- EXPECT_EQ(2, handle->RefCount());
- EXPECT_EQ(1, handle2->RefCount());
- EXPECT_EQ(3, mnt->RefCount());
-
- EXPECT_EQ(2, handle_count);
- EXPECT_EQ(1, mount_count);
+ EXPECT_EQ(0, proxy->AcquireHandle(fd1, &handle_a));
+ EXPECT_EQ(0, proxy->AcquireHandle(fd2, &handle_b));
+ EXPECT_EQ(raw_handle, handle_a.get());
+ EXPECT_EQ(raw_handle, handle_b.get());
- proxy->FreeFD(fd1);
- EXPECT_EQ(2, handle_count);
- EXPECT_EQ(1, mount_count);
+ EXPECT_EQ(4, handle_a->RefCount());
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
+
+ // A non existent fd should fail, and handleA should decrement as handleB
+ // is released by the call.
+ EXPECT_EQ(EBADF, proxy->AcquireHandle(-1, &handle_b));
+ EXPECT_EQ(NULL, handle_b.get());
+ EXPECT_EQ(3, handle_a->RefCount());
+
+ EXPECT_EQ(EBADF, proxy->AcquireHandle(100, &handle_b));
+ EXPECT_EQ(NULL, handle_b.get());
- proxy->FreeFD(fd3);
- EXPECT_EQ(1, handle_count);
- EXPECT_EQ(1, mount_count);
+ // Now only the KernelProxy should reference the KernelHandle in the
+ // FD to KernelHandle Map.
+ handle_a.reset();
+ handle_b.reset();
+ EXPECT_EQ(2, raw_handle->RefCount());
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
proxy->FreeFD(fd2);
- EXPECT_EQ(0, handle_count);
- EXPECT_EQ(0, mount_count);
+ EXPECT_EQ(1, raw_handle->RefCount());
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
+
+ proxy->FreeFD(fd1);
+ EXPECT_EQ(1, mnt->RefCount());
+ EXPECT_EQ(1, node->RefCount());
}
TEST_F(KernelObjectTest, FreeAndReassignFD) {
- KernelHandle* result_handle = NULL;
-
- EXPECT_EQ(0, handle_count);
-
- KernelHandle* handle = new KernelHandleRefMock(mnt, NULL);
-
- EXPECT_EQ(1, handle_count);
- EXPECT_EQ(1, handle->RefCount());
-
- // Assign to a non-existent FD
- proxy->FreeAndReassignFD(2, handle);
- EXPECT_EQ(EBADF, proxy->AcquireHandle(0, &result_handle));
- EXPECT_EQ(NULL, result_handle);
- EXPECT_EQ(EBADF, proxy->AcquireHandle(1, &result_handle));
- EXPECT_EQ(NULL, result_handle);
- EXPECT_EQ(0, proxy->AcquireHandle(2, &result_handle));
- EXPECT_EQ(handle, result_handle);
- proxy->ReleaseHandle(handle);
-
- EXPECT_EQ(1, handle_count);
- EXPECT_EQ(2, handle->RefCount());
-
- proxy->FreeAndReassignFD(0, handle);
- EXPECT_EQ(0, proxy->AcquireHandle(0, &result_handle));
- EXPECT_EQ(handle, result_handle);
- EXPECT_EQ(EBADF, proxy->AcquireHandle(1, &result_handle));
- EXPECT_EQ(NULL, result_handle);
- EXPECT_EQ(0, proxy->AcquireHandle(2, &result_handle));
- EXPECT_EQ(handle, result_handle);
- proxy->ReleaseHandle(handle);
- proxy->ReleaseHandle(handle);
-
- EXPECT_EQ(1, handle_count);
- EXPECT_EQ(3, handle->RefCount());
-
- proxy->FreeFD(0);
- proxy->FreeFD(2);
- proxy->ReleaseHandle(handle); // handle is constructed with a refcount of 1.
-
- EXPECT_EQ(0, handle_count);
+ // The mount and node should have 1 ref count at this point
+ EXPECT_EQ(1, mnt->RefCount());
+ EXPECT_EQ(1, node->RefCount());
+
+ KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
+ ScopedKernelHandle handle(raw_handle);
+
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
+ EXPECT_EQ(1, raw_handle->RefCount());
+
+ int fd1 = proxy->AllocateFD(handle);
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
+ EXPECT_EQ(2, raw_handle->RefCount());
+
+ proxy->FreeAndReassignFD(5, handle);
+ EXPECT_EQ(2, mnt->RefCount());
+ EXPECT_EQ(2, node->RefCount());
+ EXPECT_EQ(3, raw_handle->RefCount());
+
+ handle.reset();
+ EXPECT_EQ(2, raw_handle->RefCount());
+
+ proxy->AcquireHandle(5, &handle);
+ EXPECT_EQ(3, raw_handle->RefCount());
+ EXPECT_EQ(raw_handle, handle.get());
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc
index 5c4db1d905..367569ef13 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc
@@ -6,11 +6,11 @@
#include "kernel_proxy_mock.h"
#include "nacl_io/kernel_intercept.h"
-KernelProxyMock::KernelProxyMock() {
-}
+KernelProxyMock::KernelProxyMock() {}
KernelProxyMock::~KernelProxyMock() {
// Uninitialize the kernel proxy so wrapped functions passthrough to their
// unwrapped versions.
ki_uninit();
}
+
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 d74e886bc8..defd7deb41 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
@@ -20,16 +20,20 @@ class KernelProxyMock : public KernelProxy {
MOCK_METHOD2(access, int(const char*, int));
MOCK_METHOD1(chdir, int(const char*));
MOCK_METHOD2(chmod, int(const char*, mode_t));
+ MOCK_METHOD3(chown, int(const char*, uid_t, gid_t));
MOCK_METHOD1(close, int(int));
MOCK_METHOD1(dup, int(int));
MOCK_METHOD2(dup2, int(int, int));
+ MOCK_METHOD3(fchown, int(int, uid_t, gid_t));
MOCK_METHOD2(ftruncate, int(int, off_t));
MOCK_METHOD2(fstat, int(int, struct stat*));
MOCK_METHOD1(fsync, int(int));
MOCK_METHOD2(getcwd, char*(char*, size_t));
MOCK_METHOD3(getdents, int(int, void*, unsigned int));
MOCK_METHOD1(getwd, char*(char*));
+ MOCK_METHOD3(ioctl, int(int, int, char*));
MOCK_METHOD1(isatty, int(int));
+ MOCK_METHOD3(lchown, int(const char*, uid_t, gid_t));
MOCK_METHOD3(lseek, off_t(int, off_t, int));
MOCK_METHOD2(mkdir, int(const char*, mode_t));
MOCK_METHOD5(mount, int(const char*, const char*, const char*, unsigned long,
@@ -41,6 +45,7 @@ class KernelProxyMock : public KernelProxy {
MOCK_METHOD2(stat, int(const char*, struct stat*));
MOCK_METHOD1(umount, int(const char*));
MOCK_METHOD1(unlink, int(const char*));
+ MOCK_METHOD2(utime, int(const char*, const struct utimbuf*));
MOCK_METHOD3(write, ssize_t(int, const void*, size_t));
MOCK_METHOD2(link, int(const char*, const char*));
MOCK_METHOD2(symlink, int(const char*, const char*));
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
index 40f4ef7a15..70e76e17b9 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
@@ -11,19 +11,39 @@
#include <map>
#include <string>
-#include "nacl_io/kernel_handle.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "mount_mock.h"
+#include "mount_node_mock.h"
+
#include "nacl_io/kernel_intercept.h"
#include "nacl_io/kernel_proxy.h"
#include "nacl_io/mount.h"
#include "nacl_io/mount_mem.h"
#include "nacl_io/osmman.h"
#include "nacl_io/path.h"
+#include "nacl_io/typed_mount_factory.h"
-#include "gtest/gtest.h"
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
+using ::testing::StrEq;
+using ::testing::WithArgs;
+
+namespace {
+
+class KernelProxyFriend : public KernelProxy {
+ public:
+ Mount* RootMount() { return mounts_["/"].get(); }
+};
class KernelProxyTest : public ::testing::Test {
public:
- KernelProxyTest() : kp_(new KernelProxy) {
+ KernelProxyTest() : kp_(new KernelProxyFriend) {
ki_init(kp_);
// Unmount the passthrough FS and mount a memfs.
EXPECT_EQ(0, kp_->umount("/"));
@@ -35,10 +55,36 @@ class KernelProxyTest : public ::testing::Test {
delete kp_;
}
- private:
- KernelProxy* kp_;
+ protected:
+ KernelProxyFriend* kp_;
};
+} // namespace
+
+TEST_F(KernelProxyTest, FileLeak) {
+ const size_t buffer_size = 1024;
+ char filename[128];
+ int file_num;
+ int garbage[buffer_size];
+
+ MountMem* mount = (MountMem*)kp_->RootMount();
+ ScopedMountNode root;
+
+ EXPECT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root));
+ EXPECT_EQ(0, root->ChildCount());
+
+ for (file_num = 0; file_num < 4096; file_num++) {
+ sprintf(filename, "/foo%i.tmp", file_num++);
+ FILE* f = fopen(filename, "w");
+ EXPECT_NE((FILE*)0, f);
+ EXPECT_EQ(1, root->ChildCount());
+ EXPECT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f));
+ fclose(f);
+ EXPECT_EQ(0, remove(filename));
+ }
+ EXPECT_EQ(0, root->ChildCount());
+}
+
TEST_F(KernelProxyTest, WorkingDirectory) {
char text[1024];
@@ -151,6 +197,7 @@ TEST_F(KernelProxyTest, MemMountLseek) {
char buffer[4];
memset(&buffer[0], 0xfe, 4);
EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END));
+ EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
EXPECT_EQ(4, ki_read(fd, &buffer[0], 4));
EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
}
@@ -197,6 +244,8 @@ TEST_F(KernelProxyTest, MemMountDup) {
// fd, new_fd, dup_fd -> "/bar"
}
+namespace {
+
StringMap_t g_StringMap;
class MountMockInit : public MountMem {
@@ -207,13 +256,14 @@ class MountMockInit : public MountMem {
return EINVAL;
return 0;
}
- ;
+
+ friend class TypedMountFactory<MountMockInit>;
};
class KernelProxyMountMock : public KernelProxy {
virtual void Init(PepperInterface* ppapi) {
KernelProxy::Init(NULL);
- factories_["initfs"] = MountMockInit::Create<MountMockInit>;
+ factories_["initfs"] = new TypedMountFactory<MountMockInit>;
}
};
@@ -230,6 +280,8 @@ class KernelProxyMountTest : public ::testing::Test {
KernelProxy* kp_;
};
+} // namespace
+
TEST_F(KernelProxyMountTest, MountInit) {
int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
@@ -282,26 +334,28 @@ class MountNodeMockMMap : public MountNode {
class MountMockMMap : public Mount {
public:
- virtual Error Open(const Path& path, int mode, MountNode** out_node) {
- MountNodeMockMMap* node = new MountNodeMockMMap(this);
- *out_node = node;
+ virtual Error Access(const Path& path, int a_mode) { return 0; }
+ virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
+ out_node->reset(new MountNodeMockMMap(this));
return 0;
}
- virtual Error OpenResource(const Path& path, MountNode** out_node) {
- *out_node = NULL;
+ virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) {
+ out_node->reset(NULL);
return ENOSYS;
}
virtual Error Unlink(const Path& path) { return ENOSYS; }
virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
virtual Error Rmdir(const Path& path) { return ENOSYS; }
virtual Error Remove(const Path& path) { return ENOSYS; }
+
+ friend class TypedMountFactory<MountMockMMap>;
};
class KernelProxyMockMMap : public KernelProxy {
virtual void Init(PepperInterface* ppapi) {
KernelProxy::Init(NULL);
- factories_["mmapfs"] = MountMockInit::Create<MountMockMMap>;
+ factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>;
}
};
@@ -345,3 +399,104 @@ TEST_F(KernelProxyMMapTest, MMap) {
// We don't track regions, so the mmap count hasn't changed.
EXPECT_EQ(3, g_MMapCount);
}
+
+namespace {
+
+class SingletonMountFactory : public MountFactory {
+ public:
+ SingletonMountFactory(const ScopedMount& mount) : mount_(mount) {}
+
+ virtual Error CreateMount(int dev,
+ StringMap_t& args,
+ PepperInterface* ppapi,
+ ScopedMount* out_mount) {
+ *out_mount = mount_;
+ return 0;
+ }
+
+ private:
+ ScopedMount mount_;
+};
+
+class KernelProxyError : public KernelProxy {
+ public:
+ KernelProxyError() : mnt_(new MountMock) {}
+
+ virtual void Init(PepperInterface* ppapi) {
+ KernelProxy::Init(ppapi);
+ factories_["testfs"] = new SingletonMountFactory(mnt_);
+
+ EXPECT_CALL(*mnt_, Destroy()).Times(1);
+ }
+
+ ScopedRef<MountMock> mnt() { return mnt_; }
+
+ private:
+ ScopedRef<MountMock> mnt_;
+};
+
+class KernelProxyErrorTest : public ::testing::Test {
+ public:
+ KernelProxyErrorTest() : kp_(new KernelProxyError) {
+ ki_init(kp_);
+ // Unmount the passthrough FS and mount a testfs.
+ EXPECT_EQ(0, kp_->umount("/"));
+ EXPECT_EQ(0, kp_->mount("", "/", "testfs", 0, NULL));
+ }
+
+ ~KernelProxyErrorTest() {
+ ki_uninit();
+ delete kp_;
+ }
+
+ ScopedRef<MountMock> mnt() { return kp_->mnt(); }
+
+ private:
+ KernelProxyError* kp_;
+};
+
+} // namespace
+
+TEST_F(KernelProxyErrorTest, WriteError) {
+ ScopedRef<MountMock> mock_mnt(mnt());
+ ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
+ EXPECT_CALL(*mock_mnt, Open(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
+
+ EXPECT_CALL(*mock_node, Write(_, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(0), // Wrote 0 bytes.
+ Return(1234))); // Returned error 1234.
+
+ EXPECT_CALL(*mock_node, Destroy()).Times(1);
+
+ int fd = ki_open("/dummy", O_WRONLY);
+ EXPECT_NE(0, fd);
+
+ char buf[20];
+ EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
+ // The Mount should be able to return whatever error it wants and have it
+ // propagate through.
+ EXPECT_EQ(1234, errno);
+}
+
+TEST_F(KernelProxyErrorTest, ReadError) {
+ ScopedRef<MountMock> mock_mnt(mnt());
+ ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
+ EXPECT_CALL(*mock_mnt, Open(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
+
+ EXPECT_CALL(*mock_node, Read(_, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(0), // Read 0 bytes.
+ Return(1234))); // Returned error 1234.
+
+ EXPECT_CALL(*mock_node, Destroy()).Times(1);
+
+ int fd = ki_open("/dummy", O_RDONLY);
+ EXPECT_NE(0, fd);
+
+ char buf[20];
+ EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
+ // The Mount should be able to return whatever error it wants and have it
+ // propagate through.
+ EXPECT_EQ(1234, errno);
+}
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 34d8472ff2..53856a46dd 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+/* 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.
*/
@@ -73,6 +73,9 @@ void MakeDummyStatbuf(struct stat* statbuf) {
statbuf->st_ctime = 11;
}
+const uid_t kDummyUid = 1001;
+const gid_t kDummyGid = 1002;
+
class KernelWrapTest : public ::testing::Test {
public:
KernelWrapTest() {
@@ -114,6 +117,13 @@ TEST_F(KernelWrapTest, chmod) {
chmod("chmod", 23);
}
+TEST_F(KernelWrapTest, chown) {
+ uid_t uid = kDummyUid;
+ gid_t gid = kDummyGid;
+ EXPECT_CALL(mock, chown(StrEq("chown"), uid, gid)).Times(1);
+ chown("chown", uid, gid);
+}
+
TEST_F(KernelWrapTest, close) {
EXPECT_CALL(mock, close(34)).Times(1);
close(34);
@@ -129,6 +139,13 @@ TEST_F(KernelWrapTest, dup2) {
dup2(123, 234);
}
+TEST_F(KernelWrapTest, fchown) {
+ uid_t uid = kDummyUid;
+ gid_t gid = kDummyGid;
+ EXPECT_CALL(mock, fchown(123, uid, gid)).Times(1);
+ fchown(123, uid, gid);
+}
+
TEST_F(KernelWrapTest, fstat) {
struct stat in_statbuf;
MakeDummyStatbuf(&in_statbuf);
@@ -174,11 +191,24 @@ TEST_F(KernelWrapTest, getwd) {
#pragma GCC diagnostic warning "-Wdeprecated-declarations"
#endif
+TEST_F(KernelWrapTest, ioctl) {
+ char buffer[] = "ioctl";
+ EXPECT_CALL(mock, ioctl(012, 345, StrEq("ioctl"))).Times(1);
+ ioctl(012, 345, buffer);
+}
+
TEST_F(KernelWrapTest, isatty) {
EXPECT_CALL(mock, isatty(678)).Times(1);
isatty(678);
}
+TEST_F(KernelWrapTest, lchown) {
+ uid_t uid = kDummyUid;
+ gid_t gid = kDummyGid;
+ EXPECT_CALL(mock, lchown(StrEq("lchown"), uid, gid)).Times(1);
+ lchown("lchown", uid, gid);
+}
+
TEST_F(KernelWrapTest, lseek) {
EXPECT_CALL(mock, lseek(789, 891, 912)).Times(1);
lseek(789, 891, 912);
@@ -242,7 +272,14 @@ TEST_F(KernelWrapTest, unlink) {
unlink("unlink");
}
+TEST_F(KernelWrapTest, utime) {
+ const struct utimbuf* times;
+ EXPECT_CALL(mock, utime(StrEq("utime"), times));
+ utime("utime", times);
+}
+
TEST_F(KernelWrapTest, write) {
EXPECT_CALL(mock, write(6789, NULL, 7891)).Times(1);
write(6789, NULL, 7891);
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/main.cc b/native_client_sdk/src/libraries/nacl_io_test/main.cc
new file mode 100644
index 0000000000..f9adc0d594
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io_test/main.cc
@@ -0,0 +1,55 @@
+// 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 <string>
+
+#include "gtest/gtest.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi_simple/ps_main.h"
+
+#if defined(WIN32)
+#include <Windows.h>
+#undef PostMessage
+#endif
+
+class GTestEventListener : public ::testing::EmptyTestEventListener {
+ public:
+ // TestEventListener overrides.
+ virtual void OnTestStart(const ::testing::TestInfo& test_info) {
+ std::stringstream msg;
+ msg << "start:" << test_info.test_case_name() << "." << test_info.name();
+ pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+ }
+
+ virtual void OnTestPartResult(
+ const ::testing::TestPartResult& test_part_result) {
+ if (test_part_result.failed()) {
+ std::stringstream msg;
+ msg << "fail:" << test_part_result.file_name() << ","
+ << test_part_result.line_number() << ","
+ << test_part_result.summary();
+ pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+ }
+ }
+
+ virtual void OnTestEnd(const ::testing::TestInfo& test_info) {
+ std::stringstream msg;
+ msg << "end:" << test_info.test_case_name() << "." << test_info.name()
+ << "," << (test_info.result()->Failed() ? "failed" : "ok");
+ pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+ }
+};
+
+int example_main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners()
+ .Append(new GTestEventListener());
+ return RUN_ALL_TESTS();
+}
+
+// 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_test/module.cc b/native_client_sdk/src/libraries/nacl_io_test/module.cc
deleted file mode 100644
index 0eee65f108..0000000000
--- a/native_client_sdk/src/libraries/nacl_io_test/module.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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 "gtest_ppapi/gtest_module.h"
-
-namespace pp {
-
-Module* CreateModule() {
- return new GTestModule();
-}
-
-} // namespace pp
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc
index e92a20aa5d..a14ef0fae0 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc
@@ -18,6 +18,7 @@
#include "mock_util.h"
#include "nacl_io/mount_html5fs.h"
#include "nacl_io/osdirent.h"
+#include "nacl_io/osunistd.h"
#include "pepper_interface_mock.h"
using ::testing::_;
@@ -37,9 +38,7 @@ class MountHtml5FsMock : public MountHtml5Fs {
Init(1, map, ppapi);
}
- ~MountHtml5FsMock() {
- Destroy();
- }
+ ~MountHtml5FsMock() {}
};
class MountHtml5FsTest : public ::testing::Test {
@@ -99,8 +98,8 @@ class MountHtml5FsNodeTest : public MountHtml5FsTest {
void InitNode();
protected:
- MountHtml5FsMock* mnt_;
- MountNode* node_;
+ ScopedRef<MountHtml5FsMock> mnt_;
+ ScopedMountNode node_;
FileRefInterfaceMock* fileref_;
FileIoInterfaceMock* fileio_;
@@ -114,9 +113,7 @@ class MountHtml5FsNodeTest : public MountHtml5FsTest {
const char MountHtml5FsNodeTest::path_[] = "/foo";
MountHtml5FsNodeTest::MountHtml5FsNodeTest()
- : mnt_(NULL),
- node_(NULL),
- fileref_(NULL),
+ : fileref_(NULL),
fileio_(NULL) {
}
@@ -126,10 +123,8 @@ void MountHtml5FsNodeTest::SetUp() {
}
void MountHtml5FsNodeTest::TearDown() {
- if (mnt_) {
- mnt_->ReleaseNode(node_);
- delete mnt_;
- }
+ node_.reset();
+ mnt_.reset();
}
void MountHtml5FsNodeTest::SetUpNodeExpectations(PP_FileType file_type) {
@@ -162,12 +157,12 @@ void MountHtml5FsNodeTest::SetUpNodeExpectations(PP_FileType file_type) {
void MountHtml5FsNodeTest::InitFilesystem() {
StringMap_t map;
- mnt_ = new MountHtml5FsMock(map, ppapi_);
+ mnt_.reset(new MountHtml5FsMock(map, ppapi_));
}
void MountHtml5FsNodeTest::InitNode() {
ASSERT_EQ(0, mnt_->Open(Path(path_), O_CREAT | O_RDWR, &node_));
- ASSERT_NE((MountNode*)NULL, node_);
+ ASSERT_NE((MountNode*)NULL, node_.get());
}
// Node test where the filesystem is opened synchronously; that is, the
@@ -316,7 +311,78 @@ TEST_F(MountHtml5FsTest, FilesystemType) {
StringMap_t map;
map["type"] = "PERSISTENT";
map["expected_size"] = "100";
- MountHtml5FsMock mnt(map, ppapi_);
+ ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
+}
+
+TEST_F(MountHtml5FsTest, Access) {
+ const char path[] = "/foo";
+ const PP_Resource fileref_resource = 235;
+ const PP_Resource fileio_resource = 236;
+
+ // These are the default values.
+ SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
+
+ FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
+ FileIoInterfaceMock* fileio = ppapi_->GetFileIoInterface();
+
+ EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
+ .WillOnce(Return(fileref_resource));
+ PP_FileInfo info;
+ memset(&info, 0, sizeof(PP_FileInfo));
+ info.type = PP_FILETYPE_REGULAR;
+ EXPECT_CALL(*fileref, Query(fileref_resource, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(info),
+ Return(int32_t(PP_OK))));
+ EXPECT_CALL(*fileio, Create(instance_)).WillOnce(Return(fileio_resource));
+ int32_t open_flags = PP_FILEOPENFLAG_READ;
+ EXPECT_CALL(*fileio,
+ Open(fileio_resource, fileref_resource, open_flags, _))
+ .WillOnce(Return(int32_t(PP_OK)));
+ EXPECT_CALL(*fileio, Close(fileio_resource));
+ EXPECT_CALL(*fileio, Flush(fileio_resource, _));
+ EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource));
+ EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
+
+ ASSERT_EQ(0, mnt->Access(Path(path), R_OK | W_OK | X_OK));
+}
+
+TEST_F(MountHtml5FsTest, AccessFileNotFound) {
+ const char path[] = "/foo";
+ const PP_Resource fileref_resource = 235;
+ const PP_Resource fileio_resource = 236;
+
+ // These are the default values.
+ SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
+
+ FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
+ FileIoInterfaceMock* fileio = ppapi_->GetFileIoInterface();
+
+ // Report the file as missing.
+ EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
+ .WillOnce(Return(fileref_resource));
+ PP_FileInfo info;
+ memset(&info, 0, sizeof(PP_FileInfo));
+ info.type = PP_FILETYPE_REGULAR;
+ EXPECT_CALL(*fileref, Query(fileref_resource, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(info),
+ Return(int32_t(PP_ERROR_FILENOTFOUND))));
+ EXPECT_CALL(*fileio, Create(instance_)).WillOnce(Return(fileio_resource));
+ int32_t open_flags = PP_FILEOPENFLAG_READ;
+ EXPECT_CALL(*fileio,
+ Open(fileio_resource, fileref_resource, open_flags, _))
+ .WillOnce(Return(int32_t(PP_ERROR_FILENOTFOUND)));
+ EXPECT_CALL(*fileio, Close(fileio_resource));
+ EXPECT_CALL(*fileio, Flush(fileio_resource, _));
+ EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource));
+ EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
+
+ ASSERT_EQ(ENOENT, mnt->Access(Path(path), F_OK));
}
TEST_F(MountHtml5FsTest, Mkdir) {
@@ -335,10 +401,10 @@ TEST_F(MountHtml5FsTest, Mkdir) {
EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
StringMap_t map;
- MountHtml5FsMock mnt(map, ppapi_);
+ ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
const int permissions = 0; // unused.
- int32_t result = mnt.Mkdir(Path(path), permissions);
+ int32_t result = mnt->Mkdir(Path(path), permissions);
ASSERT_EQ(0, result);
}
@@ -358,9 +424,9 @@ TEST_F(MountHtml5FsTest, Remove) {
EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
StringMap_t map;
- MountHtml5FsMock mnt(map, ppapi_);
+ ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
- int32_t result = mnt.Remove(Path(path));
+ int32_t result = mnt->Remove(Path(path));
ASSERT_EQ(0, result);
}
@@ -558,3 +624,4 @@ TEST_F(MountHtml5FsNodeSyncDirTest, GetDents) {
EXPECT_EQ(sizeof(dirent), dirents[1].d_reclen);
EXPECT_STREQ(fileref_name_cstr_2, dirents[1].d_name);
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc
index 1bc75068f1..2c77c508fa 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc
@@ -16,6 +16,7 @@
#include "nacl_io/mount_http.h"
#include "nacl_io/mount_node_dir.h"
#include "nacl_io/osdirent.h"
+#include "nacl_io/osunistd.h"
#include "pepper_interface_mock.h"
using ::testing::_;
@@ -130,26 +131,27 @@ TEST_F(MountHttpTest, ParseManifest) {
char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
EXPECT_EQ(0, mnt_->ParseManifest(manifest));
- MountNodeDir* root = NULL;
+ ScopedMountNode root;
EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/"), &root));
- ASSERT_NE((MountNode*)NULL, root);
+ ASSERT_NE((MountNode*)NULL, root.get());
EXPECT_EQ(2, root->ChildCount());
- MountNodeDir* dir = NULL;
+ ScopedMountNode dir;
EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/mydir"), &dir));
- ASSERT_NE((MountNode*)NULL, dir);
+ ASSERT_NE((MountNode*)NULL, dir.get());
EXPECT_EQ(1, dir->ChildCount());
- MountNode* node = mnt_->GetMap()["/mydir/foo"];
+ MountNode* node = mnt_->GetMap()["/mydir/foo"].get();
EXPECT_NE((MountNode*)NULL, node);
EXPECT_EQ(0, node->GetSize(&result_size));
EXPECT_EQ(123, result_size);
// Since these files are cached thanks to the manifest, we can open them
// without accessing the PPAPI URL API.
- MountNode* foo = NULL;
+ ScopedMountNode foo;
EXPECT_EQ(0, mnt_->Open(Path("/mydir/foo"), O_RDONLY, &foo));
- MountNode* bar = NULL;
+
+ ScopedMountNode bar;
EXPECT_EQ(0, mnt_->Open(Path("/thatdir/bar"), O_RDWR, &bar));
struct stat sfoo;
@@ -176,12 +178,15 @@ class MountHttpNodeTest : public MountHttpTest {
void ExpectHeaders(const char* headers);
void OpenNode();
void SetResponse(int status_code, const char* headers);
+ // Set a response code, but expect the request to fail. Certain function calls
+ // expected by SetResponse are not expected here.
+ void SetResponseExpectFail(int status_code, const char* headers);
void SetResponseBody(const char* body);
void ResetMocks();
protected:
MountHttpMock* mnt_;
- MountNode* node_;
+ ScopedMountNode node_;
VarInterfaceMock* var_;
URLLoaderInterfaceMock* loader_;
@@ -283,6 +288,18 @@ void MountHttpNodeTest::SetResponse(int status_code, const char* headers) {
Return(headers)));
}
+void MountHttpNodeTest::SetResponseExpectFail(int status_code,
+ const char* headers) {
+ ON_CALL(*response_, GetProperty(response_resource_, _))
+ .WillByDefault(Return(PP_MakeUndefined()));
+
+ PP_Var var_headers = MakeString(348);
+ EXPECT_CALL(*response_,
+ GetProperty(response_resource_,
+ PP_URLRESPONSEPROPERTY_STATUSCODE))
+ .WillOnce(Return(PP_MakeInt32(status_code)));
+}
+
ACTION_P3(ReadResponseBodyAction, offset, body, body_length) {
char* buf = static_cast<char*>(arg1);
size_t read_length = arg2;
@@ -310,7 +327,7 @@ void MountHttpNodeTest::SetResponseBody(const char* body) {
void MountHttpNodeTest::OpenNode() {
ASSERT_EQ(0, mnt_->Open(Path(path_), O_RDONLY, &node_));
- ASSERT_NE((MountNode*)NULL, node_);
+ ASSERT_NE((MountNode*)NULL, node_.get());
}
void MountHttpNodeTest::ResetMocks() {
@@ -322,8 +339,7 @@ void MountHttpNodeTest::ResetMocks() {
}
void MountHttpNodeTest::TearDown() {
- if (node_)
- mnt_->ReleaseNode(node_);
+ node_.reset();
delete mnt_;
}
@@ -337,6 +353,70 @@ TEST_F(MountHttpNodeTest, OpenAndCloseNoCache) {
OpenNode();
}
+TEST_F(MountHttpNodeTest, OpenAndCloseNotFound) {
+ StringMap_t smap;
+ smap["cache_content"] = "false";
+ SetMountArgs(StringMap_t());
+ ExpectOpen("HEAD");
+ ExpectHeaders("");
+ SetResponseExpectFail(404, "");
+ ASSERT_EQ(ENOENT, mnt_->Open(Path(path_), O_RDONLY, &node_));
+}
+
+TEST_F(MountHttpNodeTest, OpenAndCloseServerError) {
+ StringMap_t smap;
+ smap["cache_content"] = "false";
+ SetMountArgs(StringMap_t());
+ ExpectOpen("HEAD");
+ ExpectHeaders("");
+ SetResponseExpectFail(500, "");
+ ASSERT_EQ(EIO, mnt_->Open(Path(path_), O_RDONLY, &node_));
+}
+
+TEST_F(MountHttpNodeTest, GetStat) {
+ StringMap_t smap;
+ smap["cache_content"] = "false";
+ SetMountArgs(StringMap_t());
+ ExpectOpen("HEAD");
+ ExpectHeaders("");
+ SetResponse(200, "Content-Length: 42\n");
+ OpenNode();
+
+ struct stat stat;
+ EXPECT_EQ(0, node_->GetStat(&stat));
+ EXPECT_EQ(42, stat.st_size);
+}
+
+TEST_F(MountHttpNodeTest, Access) {
+ StringMap_t smap;
+ smap["cache_content"] = "false";
+ SetMountArgs(StringMap_t());
+ ExpectOpen("HEAD");
+ ExpectHeaders("");
+ SetResponse(200, "");
+ ASSERT_EQ(0, mnt_->Access(Path(path_), R_OK));
+}
+
+TEST_F(MountHttpNodeTest, AccessWrite) {
+ StringMap_t smap;
+ smap["cache_content"] = "false";
+ SetMountArgs(StringMap_t());
+ ExpectOpen("HEAD");
+ ExpectHeaders("");
+ SetResponse(200, "");
+ ASSERT_EQ(EACCES, mnt_->Access(Path(path_), W_OK));
+}
+
+TEST_F(MountHttpNodeTest, AccessNotFound) {
+ StringMap_t smap;
+ smap["cache_content"] = "false";
+ SetMountArgs(StringMap_t());
+ ExpectOpen("HEAD");
+ ExpectHeaders("");
+ SetResponseExpectFail(404, "");
+ ASSERT_EQ(ENOENT, mnt_->Access(Path(path_), R_OK));
+}
+
TEST_F(MountHttpNodeTest, ReadCached) {
size_t result_size = 0;
int result_bytes = 0;
@@ -527,3 +607,4 @@ TEST_F(MountHttpNodeTest, ReadPartialNoServerSupport) {
EXPECT_EQ(sizeof(buf) - 1, result_bytes);
EXPECT_STREQ("abcdefghi", &buf[0]);
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_mock.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_mock.cc
new file mode 100644
index 0000000000..4b69108e21
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_mock.cc
@@ -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 "mount_mock.h"
+
+MountMock::MountMock() {}
+
+MountMock::~MountMock() {}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_mock.h b/native_client_sdk/src/libraries/nacl_io_test/mount_mock.h
new file mode 100644
index 0000000000..7ceebc47b9
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_mock.h
@@ -0,0 +1,30 @@
+/* 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_TEST_MOUNT_MOCK_H_
+#define LIBRARIES_NACL_IO_TEST_MOUNT_MOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "nacl_io/mount.h"
+
+class MountMock : public Mount {
+ public:
+ MountMock();
+ virtual ~MountMock();
+
+ MOCK_METHOD3(Init, Error(int, StringMap_t&, PepperInterface*));
+ MOCK_METHOD0(Destroy, void());
+ MOCK_METHOD2(Access, Error(const Path&, int));
+ MOCK_METHOD3(Open, Error(const Path&, int, ScopedMountNode*));
+ MOCK_METHOD2(OpenResource, Error(const Path&, ScopedMountNode*));
+ MOCK_METHOD1(Unlink, Error(const Path&));
+ MOCK_METHOD2(Mkdir, Error(const Path&, int));
+ MOCK_METHOD1(Rmdir, Error(const Path&));
+ MOCK_METHOD1(Remove, Error(const Path&));
+};
+
+#endif // LIBRARIES_NACL_IO_TEST_MOUNT_MOCK_H_
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.cc
new file mode 100644
index 0000000000..b925b56633
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.cc
@@ -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 "mount_node_mock.h"
+
+MountNodeMock::MountNodeMock(Mount* mount) : MountNode(mount) {}
+
+MountNodeMock::~MountNodeMock() {}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.h b/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.h
new file mode 100644
index 0000000000..dbbfda1497
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.h
@@ -0,0 +1,44 @@
+/* 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_TEST_MOUNT_NODE_MOCK_H_
+#define LIBRARIES_NACL_IO_TEST_MOUNT_NODE_MOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "nacl_io/mount.h"
+
+class MountNodeMock : public MountNode {
+ public:
+ explicit MountNodeMock(Mount*);
+ virtual ~MountNodeMock();
+
+ MOCK_METHOD1(Init, Error(int));
+ MOCK_METHOD0(Destroy, void());
+ MOCK_METHOD0(FSync, Error());
+ MOCK_METHOD1(FTruncate, Error(off_t));
+ MOCK_METHOD4(GetDents, Error(size_t, struct dirent*, size_t, int*));
+ MOCK_METHOD1(GetStat, Error(struct stat*));
+ MOCK_METHOD2(Ioctl, Error(int, char*));
+ MOCK_METHOD4(Read, Error(size_t, void*, size_t, int*));
+ MOCK_METHOD4(Write, Error(size_t, const void*, size_t, int*));
+ MOCK_METHOD6(MMap, Error(void*, size_t, int, int, size_t, void**));
+ MOCK_METHOD0(GetLinks, int());
+ MOCK_METHOD0(GetMode, int());
+ MOCK_METHOD0(GetType, int());
+ MOCK_METHOD1(GetSize, Error(size_t*));
+ MOCK_METHOD0(IsaDir, bool());
+ MOCK_METHOD0(IsaFile, bool());
+ MOCK_METHOD0(IsaTTY, bool());
+ MOCK_METHOD0(ChildCount, int());
+ MOCK_METHOD2(AddChild, Error(const std::string&, const ScopedMountNode&));
+ MOCK_METHOD1(RemoveChild, Error(const std::string&));
+ MOCK_METHOD2(FindChild, Error(const std::string&, ScopedMountNode*));
+ MOCK_METHOD0(Link, void());
+ MOCK_METHOD0(Unlink, void());
+};
+
+#endif // LIBRARIES_NACL_IO_TEST_MOUNT_NODE_MOCK_H_
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc
index bc6fa65ed6..794bbdfbf4 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc
@@ -7,7 +7,9 @@
#include <fcntl.h>
#include "nacl_io/error.h"
+#include "nacl_io/ioctl.h"
#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/mount_dev.h"
#include "nacl_io/mount_node.h"
#include "nacl_io/mount_node_dir.h"
#include "nacl_io/mount_node_mem.h"
@@ -26,13 +28,13 @@ class MockMemory : public MountNodeMem {
~MockMemory() { s_AllocNum--; }
Error Init(int mode) { return MountNodeMem::Init(mode); }
- Error AddChild(const std::string& name, MountNode* node) {
+ Error AddChild(const std::string& name, const ScopedMountNode& node) {
return MountNodeMem::AddChild(name, node);
}
Error RemoveChild(const std::string& name) {
return MountNodeMem::RemoveChild(name);
}
- Error FindChild(const std::string& name, MountNode** out_node) {
+ Error FindChild(const std::string& name, ScopedMountNode* out_node) {
return MountNodeMem::FindChild(name, out_node);
}
void Link() { MountNodeMem::Link(); }
@@ -49,13 +51,13 @@ class MockDir : public MountNodeDir {
~MockDir() { s_AllocNum--; }
Error Init(int mode) { return MountNodeDir::Init(mode); }
- Error AddChild(const std::string& name, MountNode* node) {
+ Error AddChild(const std::string& name, const ScopedMountNode& node) {
return MountNodeDir::AddChild(name, node);
}
Error RemoveChild(const std::string& name) {
return MountNodeDir::RemoveChild(name);
}
- Error FindChild(const std::string& name, MountNode** out_node) {
+ Error FindChild(const std::string& name, ScopedMountNode* out_node) {
return MountNodeDir::FindChild(name, out_node);
}
void Link() { MountNodeDir::Link(); }
@@ -67,7 +69,7 @@ class MockDir : public MountNodeDir {
TEST(MountNodeTest, File) {
MockMemory* file = new MockMemory;
- MountNode* result_node = NULL;
+ ScopedMountNode result_node;
size_t result_size = 0;
int result_bytes = 0;
@@ -80,7 +82,7 @@ TEST(MountNodeTest, File) {
EXPECT_FALSE(file->IsaDir());
EXPECT_TRUE(file->IsaFile());
EXPECT_FALSE(file->IsaTTY());
- EXPECT_EQ(1, file->RefCount());
+ EXPECT_EQ(0, file->RefCount());
// Test IO
char buf1[1024];
@@ -111,17 +113,17 @@ TEST(MountNodeTest, File) {
// Directory operations should fail
struct dirent d;
EXPECT_EQ(ENOTDIR, file->GetDents(0, &d, sizeof(d), &result_bytes));
- EXPECT_EQ(ENOTDIR, file->AddChild("", file));
+ EXPECT_EQ(ENOTDIR, file->AddChild("", result_node));
EXPECT_EQ(ENOTDIR, file->RemoveChild(""));
EXPECT_EQ(ENOTDIR, file->FindChild("", &result_node));
- EXPECT_EQ(NULL_NODE, result_node);
+ EXPECT_EQ(NULL_NODE, result_node.get());
delete file;
}
TEST(MountNodeTest, Directory) {
MockDir* root = new MockDir();
- MountNode* result_node = NULL;
+ ScopedMountNode result_node;
size_t result_size = 0;
int result_bytes = 0;
@@ -134,7 +136,7 @@ TEST(MountNodeTest, Directory) {
EXPECT_TRUE(root->IsaDir());
EXPECT_FALSE(root->IsaFile());
EXPECT_FALSE(root->IsaTTY());
- EXPECT_EQ(1, root->RefCount());
+ EXPECT_EQ(0, root->RefCount());
// IO operations should fail
char buf1[1024];
@@ -144,10 +146,11 @@ TEST(MountNodeTest, Directory) {
EXPECT_EQ(EISDIR, root->Write(0, buf1, sizeof(buf1), &result_bytes));
// Test directory operations
- MockMemory* file = new MockMemory;
- EXPECT_EQ(0, file->Init(S_IREAD | S_IWRITE));
+ MockMemory* raw_file = new MockMemory;
+ EXPECT_EQ(0, raw_file->Init(S_IREAD | S_IWRITE));
+ ScopedMountNode file(raw_file);
- EXPECT_EQ(1, root->RefCount());
+ EXPECT_EQ(0, root->RefCount());
EXPECT_EQ(1, file->RefCount());
EXPECT_EQ(0, root->AddChild("F1", file));
EXPECT_EQ(1, file->GetLinks());
@@ -169,14 +172,15 @@ TEST(MountNodeTest, Directory) {
EXPECT_EQ(3, file->RefCount());
EXPECT_EQ(EEXIST, root->AddChild("F1", file));
EXPECT_EQ(2, file->GetLinks());
+ EXPECT_EQ(3, file->RefCount());
EXPECT_EQ(2, s_AllocNum);
EXPECT_EQ(0, root->FindChild("F1", &result_node));
- EXPECT_NE(NULL_NODE, result_node);
+ EXPECT_NE(NULL_NODE, result_node.get());
EXPECT_EQ(0, root->FindChild("F2", &result_node));
- EXPECT_NE(NULL_NODE, result_node);
+ EXPECT_NE(NULL_NODE, result_node.get());
EXPECT_EQ(ENOENT, root->FindChild("F3", &result_node));
- EXPECT_EQ(NULL_NODE, result_node);
+ EXPECT_EQ(NULL_NODE, result_node.get());
EXPECT_EQ(2, s_AllocNum);
EXPECT_EQ(0, root->RemoveChild("F1"));
@@ -187,9 +191,6 @@ TEST(MountNodeTest, Directory) {
EXPECT_EQ(1, file->RefCount());
EXPECT_EQ(2, s_AllocNum);
- file->Release();
+ file.reset();
EXPECT_EQ(1, s_AllocNum);
- root->Release();
- EXPECT_EQ(0, s_AllocNum);
}
-
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc
index 245d13daf4..d9bb876070 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+/* 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.
*/
@@ -6,15 +6,16 @@
#include <errno.h>
#include <fcntl.h>
#include <string.h>
-#include <string>
#include <sys/stat.h>
+#include <string>
+#include "gtest/gtest.h"
+#include "nacl_io/ioctl.h"
#include "nacl_io/mount.h"
#include "nacl_io/mount_dev.h"
#include "nacl_io/mount_mem.h"
#include "nacl_io/osdirent.h"
-
-#include "gtest/gtest.h"
+#include "nacl_io/osunistd.h"
namespace {
@@ -43,35 +44,48 @@ class MountDevMock : public MountDev {
TEST(MountTest, Sanity) {
MountMemMock* mnt = new MountMemMock();
- MountNode* file;
- MountNode* root;
- MountNode* result_node;
+
+ ScopedMountNode file;
+ ScopedMountNode root;
+ ScopedMountNode result_node;
+
size_t result_size = 0;
int result_bytes = 0;
-
char buf1[1024];
// A memory mount starts with one directory node: the root.
EXPECT_EQ(1, mnt->num_nodes());
// Fail to open non existent file
+ EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), R_OK | W_OK));
EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &result_node));
- EXPECT_EQ(NULL, result_node);
+ EXPECT_EQ(NULL, result_node.get());
+ EXPECT_EQ(1, mnt->num_nodes());
// Create a file
EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &file));
- EXPECT_NE(NULL_NODE, file);
+ EXPECT_NE(NULL_NODE, file.get());
if (file == NULL)
return;
- EXPECT_EQ(2, file->RefCount());
+
+ // We now have a directory and a file. The file has a two references
+ // one returned to the test, one for the name->inode map.
EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(2, file->RefCount());
+ EXPECT_EQ(0, mnt->Access(Path("/foo"), R_OK | W_OK));
+ EXPECT_EQ(EACCES, mnt->Access(Path("/foo"), X_OK));
+ // Write access should be allowed on the root directory.
+ EXPECT_EQ(0, mnt->Access(Path("/"), R_OK | W_OK));
+ EXPECT_EQ(EACCES, mnt->Access(Path("/"), X_OK));
// Open the root directory for write should fail.
EXPECT_EQ(EISDIR, mnt->Open(Path("/"), O_RDWR, &root));
+ EXPECT_EQ(2, mnt->num_nodes());
- // Open the root directory
+ // Open the root directory, should not create a new file
EXPECT_EQ(0, mnt->Open(Path("/"), O_RDONLY, &root));
- EXPECT_NE(NULL_NODE, root);
+ EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_NE(NULL_NODE, root.get());
if (NULL != root) {
struct dirent dirs[2];
int len;
@@ -82,11 +96,12 @@ TEST(MountTest, Sanity) {
// Fail to re-create the same file
EXPECT_EQ(EEXIST,
mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
- EXPECT_EQ(NULL_NODE, result_node);
+ EXPECT_EQ(NULL_NODE, result_node.get());
EXPECT_EQ(2, mnt->num_nodes());
// Fail to create a directory with the same name
EXPECT_EQ(EEXIST, mnt->Mkdir(Path("/foo"), O_RDWR));
+ EXPECT_EQ(2, mnt->num_nodes());
// Attempt to READ/WRITE
EXPECT_EQ(0, file->GetSize(&result_size));
@@ -97,76 +112,108 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(sizeof(buf1), result_size);
EXPECT_EQ(0, file->Read(0, buf1, sizeof(buf1), &result_bytes));
EXPECT_EQ(sizeof(buf1), result_bytes);
+ EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(2, file->RefCount());
- // Attempt to open the same file
+ // Attempt to open the same file, create another ref to it, but does not
+ // create a new file.
EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
- EXPECT_EQ(file, result_node);
- EXPECT_EQ(0, file->GetSize(&result_size));
- EXPECT_EQ(sizeof(buf1), result_size);
EXPECT_EQ(3, file->RefCount());
EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(file.get(), result_node.get());
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(sizeof(buf1), result_size);
- // Attempt to close and delete the file
- mnt->ReleaseNode(file);
+ // Remove our references so that only the Mount holds it
+ file.reset();
+ result_node.reset();
EXPECT_EQ(2, mnt->num_nodes());
+
+ // This should have deleted the object
EXPECT_EQ(0, mnt->Unlink(Path("/foo")));
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(1, mnt->num_nodes());
+
+ // We should fail to find it
EXPECT_EQ(ENOENT, mnt->Unlink(Path("/foo")));
- EXPECT_EQ(2, mnt->num_nodes());
- mnt->ReleaseNode(file);
EXPECT_EQ(1, mnt->num_nodes());
// Recreate foo as a directory
EXPECT_EQ(0, mnt->Mkdir(Path("/foo"), O_RDWR));
+ EXPECT_EQ(2, mnt->num_nodes());
// Create a file (exclusively)
EXPECT_EQ(0, mnt->Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
- EXPECT_NE(NULL_NODE, file);
+ EXPECT_NE(NULL_NODE, file.get());
if (NULL == file)
return;
+ EXPECT_EQ(2, file->RefCount());
+ EXPECT_EQ(3, mnt->num_nodes());
- // Attempt to delete the directory
+ // Attempt to delete the directory and fail
EXPECT_EQ(ENOTEMPTY, mnt->Rmdir(Path("/foo")));
+ EXPECT_EQ(2, root->RefCount());
+ EXPECT_EQ(2, file->RefCount());
+ EXPECT_EQ(3, mnt->num_nodes());
- // Unlink the file, then delete the directory
+ // Unlink the file, we should have the only file ref at this point.
EXPECT_EQ(0, mnt->Unlink(Path("/foo/bar")));
- EXPECT_EQ(0, mnt->Rmdir(Path("/foo")));
+ EXPECT_EQ(2, root->RefCount());
+ EXPECT_EQ(1, file->RefCount());
+ EXPECT_EQ(3, mnt->num_nodes());
+
+
+ // Deref the file, to make it go away
+ file.reset();
EXPECT_EQ(2, mnt->num_nodes());
- mnt->ReleaseNode(file);
+
+ // Deref the directory
+ EXPECT_EQ(0, mnt->Rmdir(Path("/foo")));
EXPECT_EQ(1, mnt->num_nodes());
// Verify the directory is gone
+ EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK));
EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &file));
- EXPECT_EQ(NULL_NODE, file);
+ EXPECT_EQ(NULL_NODE, file.get());
}
TEST(MountTest, MemMountRemove) {
MountMemMock* mnt = new MountMemMock();
- MountNode* file;
- MountNode* result_node;
+ ScopedMountNode file;
+ ScopedMountNode result_node;
EXPECT_EQ(0, mnt->Mkdir(Path("/dir"), O_RDWR));
EXPECT_EQ(0, mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
- EXPECT_NE(NULL_NODE, file);
- mnt->ReleaseNode(file);
+ EXPECT_NE(NULL_NODE, file.get());
+ EXPECT_EQ(3, mnt->num_nodes());
+ file.reset();
EXPECT_EQ(0, mnt->Remove(Path("/dir")));
+ EXPECT_EQ(2, mnt->num_nodes());
EXPECT_EQ(0, mnt->Remove(Path("/file")));
+ EXPECT_EQ(1, mnt->num_nodes());
EXPECT_EQ(ENOENT,
mnt->Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
- EXPECT_EQ(NULL_NODE, result_node);
+ EXPECT_EQ(NULL_NODE, result_node.get());
EXPECT_EQ(ENOENT, mnt->Open(Path("/file"), O_RDONLY, &result_node));
- EXPECT_EQ(NULL_NODE, result_node);
+ EXPECT_EQ(NULL_NODE, result_node.get());
+}
+
+TEST(MountTest, DevAccess) {
+ // Should not be able to open non-existent file.
+ MountDevMock* mnt = new MountDevMock();
+ ASSERT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK));
}
TEST(MountTest, DevNull) {
MountDevMock* mnt = new MountDevMock();
- MountNode* dev_null = NULL;
+ ScopedMountNode dev_null;
int result_bytes = 0;
+ ASSERT_EQ(0, mnt->Access(Path("/null"), R_OK | W_OK));
+ ASSERT_EQ(EACCES, mnt->Access(Path("/null"), X_OK));
ASSERT_EQ(0, mnt->Open(Path("/null"), O_RDWR, &dev_null));
- ASSERT_NE(NULL_NODE, dev_null);
+ ASSERT_NE(NULL_NODE, dev_null.get());
// Writing to /dev/null should write everything.
const char msg[] = "Dummy test message.";
@@ -178,16 +225,17 @@ TEST(MountTest, DevNull) {
char buffer[kBufferLength];
EXPECT_EQ(0, dev_null->Read(0, &buffer[0], kBufferLength, &result_bytes));
EXPECT_EQ(0, result_bytes);
- mnt->ReleaseNode(dev_null);
}
TEST(MountTest, DevZero) {
MountDevMock* mnt = new MountDevMock();
- MountNode* dev_zero = NULL;
+ ScopedMountNode dev_zero;
int result_bytes = 0;
+ ASSERT_EQ(0, mnt->Access(Path("/zero"), R_OK | W_OK));
+ ASSERT_EQ(EACCES, mnt->Access(Path("/zero"), X_OK));
ASSERT_EQ(0, mnt->Open(Path("/zero"), O_RDWR, &dev_zero));
- ASSERT_NE(NULL_NODE, dev_zero);
+ ASSERT_NE(NULL_NODE, dev_zero.get());
// Writing to /dev/zero should write everything.
const char msg[] = "Dummy test message.";
@@ -205,16 +253,17 @@ TEST(MountTest, DevZero) {
char zero_buffer[kBufferLength];
memset(&zero_buffer[0], 0, kBufferLength);
EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength));
- mnt->ReleaseNode(dev_zero);
}
TEST(MountTest, DevUrandom) {
MountDevMock* mnt = new MountDevMock();
- MountNode* dev_urandom = NULL;
+ ScopedMountNode dev_urandom;
int result_bytes = 0;
+ ASSERT_EQ(0, mnt->Access(Path("/urandom"), R_OK | W_OK));
+ ASSERT_EQ(EACCES, mnt->Access(Path("/urandom"), X_OK));
ASSERT_EQ(0, mnt->Open(Path("/urandom"), O_RDWR, &dev_urandom));
- ASSERT_NE(NULL_NODE, dev_urandom);
+ ASSERT_NE(NULL_NODE, dev_urandom.get());
// Writing to /dev/urandom should write everything.
const char msg[] = "Dummy test message.";
@@ -250,3 +299,68 @@ TEST(MountTest, DevUrandom) {
// Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom.
EXPECT_LE(chi_squared, 293.24);
}
+
+
+TEST(MountTest, DevTty) {
+ MountDevMock* mnt = new MountDevMock();
+ ScopedMountNode dev_tty;
+
+ ASSERT_EQ(0, mnt->Access(Path("/tty"), R_OK | W_OK));
+ ASSERT_EQ(EACCES, mnt->Access(Path("/tty"), X_OK));
+ ASSERT_EQ(0, mnt->Open(Path("/tty"), O_RDWR, &dev_tty));
+ ASSERT_NE(NULL_NODE, dev_tty.get());
+
+ // 123 is not a valid ioctl request.
+ EXPECT_EQ(EINVAL, dev_tty->Ioctl(123, NULL));
+
+ // TIOCNACLPREFIX is, it should set the prefix.
+ std::string prefix("__my_awesome_prefix__");
+ EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLPREFIX,
+ const_cast<char*>(prefix.c_str())));
+
+ // Now let's try sending some data over.
+ // First we create the message.
+ std::string content("hello, how are you?");
+ std::string message = prefix.append(content);
+ struct tioc_nacl_input_string packaged_message;
+ packaged_message.length = message.size();
+ packaged_message.buffer = message.data();
+
+ // Now we make buffer we'll read into.
+ // We fill the buffer and a backup buffer with arbitrary data
+ // and compare them after reading to make sure read doesn't
+ // clobber parts of the buffer it shouldn't.
+ int bytes_read;
+ char buffer[100];
+ char backup_buffer[100];
+ memset(buffer, 'a', 100);
+ memset(backup_buffer, 'a', 100);
+
+ // Now we actually send the data
+ EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLINPUT,
+ reinterpret_cast<char*>(&packaged_message)));
+
+ // We read a small chunk first to ensure it doesn't give us
+ // more than we ask for.
+ EXPECT_EQ(0, dev_tty->Read(0, buffer, 5, &bytes_read));
+ EXPECT_EQ(bytes_read, 5);
+ EXPECT_EQ(0, memcmp(content.data(), buffer, 5));
+ EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95));
+
+ // Now we ask for more data than is left in the tty, to ensure
+ // it doesn't give us more than is there.
+ EXPECT_EQ(0, dev_tty->Read(0, buffer + 5, 95, &bytes_read));
+ EXPECT_EQ(bytes_read, content.size() - 5);
+ EXPECT_EQ(0, memcmp(content.data(), buffer, content.size()));
+ EXPECT_EQ(0, memcmp(buffer + content.size(),
+ backup_buffer + content.size(),
+ 100 - content.size()));
+
+ // Now we try to send something with an invalid prefix
+ std::string bogus_message("Woah there, this message has no valid prefix");
+ struct tioc_nacl_input_string bogus_pack;
+ bogus_pack.length = bogus_message.size();
+ bogus_pack.buffer = bogus_message.data();
+ EXPECT_EQ(ENOTTY, dev_tty->Ioctl(TIOCNACLINPUT,
+ reinterpret_cast<char*>(&bogus_pack)));
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/path_test.cc b/native_client_sdk/src/libraries/nacl_io_test/path_test.cc
index 3f8c91803e..9a8d980b34 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/path_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/path_test.cc
@@ -256,3 +256,4 @@ TEST(PathTest, Range) {
EXPECT_EQ("an/absolute", p.Range(1, 3));
EXPECT_EQ("absolute", p.Range(2, 3));
}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc b/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc
index 95699256ae..a3418a6d34 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc
@@ -49,3 +49,4 @@ PP_Instance PepperInterfaceMock::GetInstance() {
BaseClass##Mock::~BaseClass##Mock() { \
}
#include "nacl_io/pepper/all_interfaces.h"
+
diff --git a/native_client_sdk/src/libraries/ppapi/library.dsc b/native_client_sdk/src/libraries/ppapi/library.dsc
index 6b35983beb..7e2f240595 100644
--- a/native_client_sdk/src/libraries/ppapi/library.dsc
+++ b/native_client_sdk/src/libraries/ppapi/library.dsc
@@ -1,5 +1,11 @@
{
- 'TOOLS': ['win', 'linux'],
+ 'TOOLS': ['win', 'linux', 'mac'],
+ 'SEARCH': [
+ '.',
+ '../../../../ppapi/c',
+ '../../../../ppapi/c/dev',
+ '../../../../ppapi/c/extensions/dev',
+ ],
'TARGETS': [
{
'NAME' : 'ppapi',
@@ -9,6 +15,130 @@
],
}
],
+ 'HEADERS': [
+ {
+ 'FILES': [
+ 'pp_array_output.h',
+ 'ppb_audio_config.h',
+ 'ppb_audio.h',
+ 'ppb_console.h',
+ 'ppb_core.h',
+ 'ppb_file_io.h',
+ 'ppb_file_ref.h',
+ 'ppb_file_system.h',
+ 'ppb_fullscreen.h',
+ 'ppb_gamepad.h',
+ 'ppb_graphics_2d.h',
+ 'ppb_graphics_3d.h',
+ 'ppb.h',
+ 'ppb_host_resolver.h',
+ 'ppb_image_data.h',
+ 'ppb_input_event.h',
+ 'ppb_instance.h',
+ 'ppb_message_loop.h',
+ 'ppb_messaging.h',
+ 'ppb_mouse_cursor.h',
+ 'ppb_mouse_lock.h',
+ 'ppb_net_address.h',
+ 'ppb_network_proxy.h',
+ 'pp_bool.h',
+ 'ppb_opengles2.h',
+ 'ppb_tcp_socket.h',
+ 'ppb_udp_socket.h',
+ 'ppb_url_loader.h',
+ 'ppb_url_request_info.h',
+ 'ppb_url_response_info.h',
+ 'ppb_var_array_buffer.h',
+ 'ppb_var_array.h',
+ 'ppb_var_dictionary.h',
+ 'ppb_var.h',
+ 'ppb_view.h',
+ 'ppb_websocket.h',
+ 'pp_completion_callback.h',
+ 'pp_directory_entry.h',
+ 'pp_errors.h',
+ 'pp_file_info.h',
+ 'pp_graphics_3d.h',
+ 'pp_input_event.h',
+ 'pp_instance.h',
+ 'pp_macros.h',
+ 'pp_module.h',
+ 'ppp_graphics_3d.h',
+ 'ppp.h',
+ 'ppp_input_event.h',
+ 'ppp_instance.h',
+ 'ppp_messaging.h',
+ 'ppp_mouse_lock.h',
+ 'pp_point.h',
+ 'pp_rect.h',
+ 'pp_resource.h',
+ 'pp_size.h',
+ 'pp_stdint.h',
+ 'pp_time.h',
+ 'pp_touch_point.h',
+ 'pp_var.h',
+ ],
+ 'DEST': 'include/ppapi/c',
+ },
+ {
+ 'FILES': [
+ 'deprecated_bool.h',
+ 'ppb_audio_input_dev.h',
+ 'ppb_buffer_dev.h',
+ 'ppb_char_set_dev.h',
+ 'ppb_crypto_dev.h',
+ 'ppb_cursor_control_dev.h',
+ 'ppb_device_ref_dev.h',
+ 'ppb_file_chooser_dev.h',
+ 'ppb_find_dev.h',
+ 'ppb_font_dev.h',
+ 'ppb_gles_chromium_texture_mapping_dev.h',
+ 'ppb_graphics_2d_dev.h',
+ 'ppb_ime_input_event_dev.h',
+ 'ppb_keyboard_input_event_dev.h',
+ 'ppb_memory_dev.h',
+ 'ppb_opengles2ext_dev.h',
+ 'ppb_printing_dev.h',
+ 'ppb_resource_array_dev.h',
+ 'ppb_scrollbar_dev.h',
+ 'ppb_testing_dev.h',
+ 'ppb_text_input_dev.h',
+ 'ppb_trace_event_dev.h',
+ 'ppb_truetype_font_dev.h',
+ 'ppb_url_util_dev.h',
+ 'ppb_var_deprecated.h',
+ 'ppb_video_capture_dev.h',
+ 'ppb_video_decoder_dev.h',
+ 'ppb_view_dev.h',
+ 'ppb_widget_dev.h',
+ 'ppb_zoom_dev.h',
+ 'pp_cursor_type_dev.h',
+ 'ppp_class_deprecated.h',
+ 'ppp_find_dev.h',
+ 'ppp_network_state_dev.h',
+ 'ppp_printing_dev.h',
+ 'pp_print_settings_dev.h',
+ 'ppp_scrollbar_dev.h',
+ 'ppp_selection_dev.h',
+ 'ppp_text_input_dev.h',
+ 'ppp_video_capture_dev.h',
+ 'ppp_video_decoder_dev.h',
+ 'ppp_widget_dev.h',
+ 'ppp_zoom_dev.h',
+ 'pp_video_capture_dev.h',
+ 'pp_video_dev.h',
+ ],
+ 'DEST': 'include/ppapi/c/dev',
+ },
+ {
+ 'FILES': [
+ 'ppb_ext_alarms_dev.h',
+ 'ppb_ext_events_dev.h',
+ 'ppb_ext_socket_dev.h',
+ ],
+ 'DEST': 'include/ppapi/c/extensions/dev',
+ },
+ ],
'DEST': 'src',
'NAME': 'ppapi',
}
diff --git a/native_client_sdk/src/libraries/ppapi_cpp/library.dsc b/native_client_sdk/src/libraries/ppapi_cpp/library.dsc
index e6ffb6c26c..061685c46d 100644
--- a/native_client_sdk/src/libraries/ppapi_cpp/library.dsc
+++ b/native_client_sdk/src/libraries/ppapi_cpp/library.dsc
@@ -3,6 +3,9 @@
'SEARCH': [
'.',
'../../../../ppapi/cpp',
+ '../../../../ppapi/cpp/dev',
+ '../../../../ppapi/cpp/extensions',
+ '../../../../ppapi/cpp/extensions/dev',
'../../../../ppapi/utility',
'../../../../ppapi/utility/graphics',
'../../../../ppapi/utility/threading',
@@ -13,46 +16,232 @@
'NAME' : 'ppapi_cpp',
'TYPE' : 'lib',
'SOURCES' : [
- 'ppp_entrypoints.cc',
- 'array_output.cc',
- 'audio.cc',
- 'audio_config.cc',
- 'core.cc',
- 'directory_entry.cc',
- 'file_io.cc',
- 'file_ref.cc',
- 'file_system.cc',
- 'fullscreen.cc',
- 'graphics_2d.cc',
- 'graphics_3d.cc',
- 'graphics_3d_client.cc',
- 'image_data.cc',
- 'input_event.cc',
- 'instance.cc',
- 'instance_handle.cc',
- 'lock.cc',
- 'message_loop.cc',
- 'module.cc',
- 'mouse_cursor.cc',
- 'mouse_lock.cc',
- 'rect.cc',
- 'resource.cc',
- 'url_loader.cc',
- 'url_request_info.cc',
- 'url_response_info.cc',
- 'var.cc',
- 'var_array_buffer.cc',
- 'view.cc',
- 'websocket.cc',
+ # ppapi/cpp
+ 'array_output.cc',
+ 'audio.cc',
+ 'audio_config.cc',
+ 'core.cc',
+ 'directory_entry.cc',
+ 'file_io.cc',
+ 'file_ref.cc',
+ 'file_system.cc',
+ 'fullscreen.cc',
+ 'graphics_2d.cc',
+ 'graphics_3d.cc',
+ 'graphics_3d_client.cc',
+ 'host_resolver.cc',
+ 'image_data.cc',
+ 'input_event.cc',
+ 'instance.cc',
+ 'instance_handle.cc',
+ 'message_loop.cc',
+ 'module.cc',
+ 'mouse_cursor.cc',
+ 'mouse_lock.cc',
+ 'net_address.cc',
+ 'network_proxy.cc',
+ 'ppp_entrypoints.cc',
+ 'rect.cc',
+ 'resource.cc',
+ 'tcp_socket.cc',
+ 'udp_socket.cc',
+ 'url_loader.cc',
+ 'url_request_info.cc',
+ 'url_response_info.cc',
+ 'var_array_buffer.cc',
+ 'var_array.cc',
+ 'var.cc',
+ 'var_dictionary.cc',
+ 'view.cc',
+ 'websocket.cc',
- # Utility sources.
- 'paint_aggregator.cc',
- 'paint_manager.cc',
- 'simple_thread.cc',
- 'websocket_api.cc',
+ # ppapi/cpp/dev
+ 'widget_client_dev.cc',
+ 'resource_array_dev.cc',
+ 'video_capture_client_dev.cc',
+ 'video_decoder_client_dev.cc',
+ 'crypto_dev.cc',
+ 'selection_dev.cc',
+ 'buffer_dev.cc',
+ 'url_util_dev.cc',
+ 'video_capture_dev.cc',
+ 'zoom_dev.cc',
+ 'ime_input_event_dev.cc',
+ 'text_input_dev.cc',
+ 'font_dev.cc',
+ 'find_dev.cc',
+ 'view_dev.cc',
+ 'memory_dev.cc',
+ 'truetype_font_dev.cc',
+ 'file_chooser_dev.cc',
+ 'video_decoder_dev.cc',
+ 'cursor_control_dev.cc',
+ 'device_ref_dev.cc',
+ 'printing_dev.cc',
+ 'scriptable_object_deprecated.cc',
+ 'audio_input_dev.cc',
+ 'scrollbar_dev.cc',
+ 'graphics_2d_dev.cc',
+ 'widget_dev.cc',
+
+ # ppapi/cpp/extensions
+ 'event_base.cc',
+
+ # ppapi/cpp/extensions/dev
+ 'alarms_dev.cc',
+ 'events_dev.cc',
+ 'socket_dev.cc',
+
+ # ppapi/utility/graphics
+ 'paint_aggregator.cc',
+ 'paint_manager.cc',
+
+ # ppapi/utility/websocket
+ 'websocket_api.cc',
+
+ # ppapi/utility/threading
+ 'lock.cc',
+ 'simple_thread.cc',
],
}
],
+ 'HEADERS': [
+ {
+ 'FILES': [
+ 'array_output.h',
+ 'audio_config.h',
+ 'audio.h',
+ 'completion_callback.h',
+ 'core.h',
+ 'directory_entry.h',
+ 'file_io.h',
+ 'file_ref.h',
+ 'file_system.h',
+ 'fullscreen.h',
+ 'graphics_2d.h',
+ 'graphics_3d_client.h',
+ 'graphics_3d.h',
+ 'host_resolver.h',
+ 'image_data.h',
+ 'input_event.h',
+ 'instance.h',
+ 'instance_handle.h',
+ 'logging.h',
+ 'message_loop.h',
+ 'module_embedder.h',
+ 'module.h',
+ 'module_impl.h',
+ 'mouse_cursor.h',
+ 'mouse_lock.h',
+ 'net_address.h',
+ 'network_proxy.h',
+ 'output_traits.h',
+ 'pass_ref.h',
+ 'point.h',
+ 'rect.h',
+ 'resource.h',
+ 'size.h',
+ 'tcp_socket.h',
+ 'touch_point.h',
+ 'udp_socket.h',
+ 'url_loader.h',
+ 'url_request_info.h',
+ 'url_response_info.h',
+ 'var_array_buffer.h',
+ 'var_array.h',
+ 'var_dictionary.h',
+ 'var.h',
+ 'view.h',
+ 'websocket.h',
+ ],
+ 'DEST': 'include/ppapi/cpp',
+ },
+ {
+ 'FILES': [
+ 'audio_input_dev.h',
+ 'buffer_dev.h',
+ 'crypto_dev.h',
+ 'cursor_control_dev.h',
+ 'device_ref_dev.h',
+ 'file_chooser_dev.h',
+ 'find_dev.h',
+ 'font_dev.h',
+ 'graphics_2d_dev.h',
+ 'ime_input_event_dev.h',
+ 'memory_dev.h',
+ 'printing_dev.h',
+ 'resource_array_dev.h',
+ 'scriptable_object_deprecated.h',
+ 'scrollbar_dev.h',
+ 'selection_dev.h',
+ 'text_input_dev.h',
+ 'truetype_font_dev.h',
+ 'url_util_dev.h',
+ 'video_capture_client_dev.h',
+ 'video_capture_dev.h',
+ 'video_decoder_client_dev.h',
+ 'video_decoder_dev.h',
+ 'view_dev.h',
+ 'widget_client_dev.h',
+ 'widget_dev.h',
+ 'zoom_dev.h',
+ ],
+ 'DEST': 'include/ppapi/cpp/dev',
+ },
+ {
+ 'FILES': [
+ 'dict_field.h',
+ 'event_base.h',
+ 'ext_output_traits.h',
+ 'from_var_converter.h',
+ 'optional.h',
+ 'to_var_converter.h',
+ ],
+ 'DEST': 'include/ppapi/cpp/extensions',
+ },
+ {
+ 'FILES': [
+ 'alarms_dev.h',
+ 'events_dev.h',
+ 'socket_dev.h',
+ ],
+ 'DEST': 'include/ppapi/cpp/extensions/dev',
+ },
+ {
+ 'FILES': [
+ 'completion_callback_factory.h',
+ 'completion_callback_factory_thread_traits.h',
+ ],
+ 'DEST': 'include/ppapi/utility',
+ },
+ {
+ 'FILES': [
+ 'paint_aggregator.h',
+ 'paint_manager.h',
+ ],
+ 'DEST': 'include/ppapi/utility/graphics',
+ },
+ {
+ 'FILES': [
+ 'paint_aggregator.h',
+ 'paint_manager.h',
+ ],
+ 'DEST': 'include/ppapi/utility/graphics',
+ },
+ {
+ 'FILES': [
+ 'websocket_api.h',
+ ],
+ 'DEST': 'include/ppapi/utility/websocket',
+ },
+ {
+ 'FILES': [
+ 'lock.h',
+ 'simple_thread.h',
+ ],
+ 'DEST': 'include/ppapi/utility/threading',
+ },
+ ],
'DEST': 'src',
'NAME': 'ppapi_cpp',
}
diff --git a/native_client_sdk/src/libraries/ppapi_cpp_private/library.dsc b/native_client_sdk/src/libraries/ppapi_cpp_private/library.dsc
index 8646c3a110..058d79bc5c 100644
--- a/native_client_sdk/src/libraries/ppapi_cpp_private/library.dsc
+++ b/native_client_sdk/src/libraries/ppapi_cpp_private/library.dsc
@@ -1,6 +1,7 @@
{
'TOOLS': ['newlib', 'glibc', 'pnacl', 'win', 'linux'],
'SEARCH': [
+ '../../../../ppapi/c/private',
'../../../../ppapi/cpp/private',
],
'TARGETS': [
@@ -20,6 +21,40 @@
],
}
],
+ 'HEADERS': [
+ # ppapi/c/private
+ {
+ 'FILES': [
+ 'ppb_ext_crx_file_system_private.h',
+ 'ppb_file_io_private.h',
+ 'ppb_file_ref_private.h',
+ 'ppb_host_resolver_private.h',
+ 'ppb_net_address_private.h',
+ 'ppb_tcp_server_socket_private.h',
+ 'ppb_tcp_socket_private.h',
+ 'ppb_udp_socket_private.h',
+ 'ppb_x509_certificate_private.h',
+ 'pp_file_handle.h',
+ ],
+ 'DEST': 'include/ppapi/c/private',
+ },
+
+ # ppapi/cpp/private
+ {
+ 'FILES': [
+ 'ext_crx_file_system_private.h',
+ 'file_io_private.h',
+ 'host_resolver_private.h',
+ 'net_address_private.h',
+ 'pass_file_handle.h',
+ 'tcp_server_socket_private.h',
+ 'tcp_socket_private.h',
+ 'udp_socket_private.h',
+ 'x509_certificate_private.h',
+ ],
+ 'DEST': 'include/ppapi/cpp/private',
+ },
+ ],
'DEST': 'src',
'NAME': 'ppapi_cpp_private',
}
diff --git a/native_client_sdk/src/libraries/ppapi_gles2/library.dsc b/native_client_sdk/src/libraries/ppapi_gles2/library.dsc
index ccf23bd769..bddf8c66b1 100644
--- a/native_client_sdk/src/libraries/ppapi_gles2/library.dsc
+++ b/native_client_sdk/src/libraries/ppapi_gles2/library.dsc
@@ -1,8 +1,10 @@
{
'TOOLS': ['newlib', 'glibc', 'pnacl', 'linux', 'win'],
'SEARCH' : [
- '.',
- '../../../../ppapi/lib/gl/gles2'
+ '../../../../ppapi/lib/gl/gles2',
+ '../../../../ppapi/lib/gl/include/EGL',
+ '../../../../ppapi/lib/gl/include/GLES2',
+ '../../../../ppapi/lib/gl/include/KHR'
],
'TARGETS': [
{
@@ -14,6 +16,38 @@
],
}
],
+ 'HEADERS': [
+ # ppapi/lib/gl/include/KHR
+ {
+ 'FILES': [
+ 'khrplatform.h'
+ ],
+ 'DEST': 'include/KHR',
+ },
+
+ # ppapi/lib/gl/include/GLES2
+ {
+ 'FILES': [
+ 'gl2.h',
+ 'gl2ext.h',
+ 'gl2platform.h',
+ ],
+ 'DEST': 'include/GLES2',
+ },
+
+ # ppapi/lib/gl/gles2
+ {
+ 'FILES': [ 'gl2ext_ppapi.h' ],
+ 'DEST': 'include/ppapi/gles2',
+ },
+
+ # Create a duplicate copy of this header
+ # TODO(sbc), remove this copy once we find a way to build gl2ext_ppapi.c.
+ {
+ 'FILES': [ 'gl2ext_ppapi.h' ],
+ 'DEST': 'include/ppapi/lib/gl/gles2',
+ },
+ ],
'DEST': 'src',
'NAME': 'ppapi_gles2',
}
diff --git a/native_client_sdk/src/libraries/ppapi_simple/library.dsc b/native_client_sdk/src/libraries/ppapi_simple/library.dsc
index 613a585227..841aeedf8f 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/library.dsc
+++ b/native_client_sdk/src/libraries/ppapi_simple/library.dsc
@@ -1,13 +1,15 @@
{
- 'TOOLS': ['newlib', 'glibc', 'pnacl'],
+ 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'],
'TARGETS': [
{
'NAME' : 'ppapi_simple',
'TYPE' : 'lib',
'SOURCES' : [
"ps.cc",
+ "ps_context_2d.cc",
"ps_event.cc",
"ps_instance.cc",
+ "ps_interface.cc",
"ps_main.cc",
],
}
@@ -16,8 +18,10 @@
{
'FILES': [
"ps.h",
+ "ps_context_2d.h",
"ps_event.h",
"ps_instance.h",
+ "ps_interface.h",
"ps_main.h",
],
'DEST': 'include/ppapi_simple',
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps.h b/native_client_sdk/src/libraries/ppapi_simple/ps.h
index 1d7b2543ae..fe5205b36a 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps.h
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps.h
@@ -85,12 +85,34 @@ extern void* PSUserCreateInstance(PP_Instance inst);
* configuration information and optional extra arguments which are passed to
* the 'main' function. See the appropriate ppapi_simple_main(XX).h header.
*/
+#if defined(WIN32)
+
+/* In MSVC, ##__VA_ARGS does not remove the following comma, only the
+ * previous one. As a result, passing no extra arguments to
+ * PPAPI_SIMPLE_USE_MAIN yields:
+ *
+ * static const char* params[] = { , NULL, NULL };
+ *
+ * We work around this by always preceding it with a "NULL,". That way the
+ * previous comma is removed and the following comma takes its place. We then
+ * skip this initial bogus value when passing the array to the factory.
+ */
+#define PPAPI_SIMPLE_USE_MAIN(factory, func, ...) \
+void* PSUserCreateInstance(PP_Instance inst) { \
+ PPAPI_SIMPLE_DECLARE_PARAMS(params, NULL, ##__VA_ARGS__, NULL, NULL) \
+ return factory(inst, func, params + 1); \
+}
+
+#else
+
#define PPAPI_SIMPLE_USE_MAIN(factory, func, ...) \
void* PSUserCreateInstance(PP_Instance inst) { \
PPAPI_SIMPLE_DECLARE_PARAMS(params, ##__VA_ARGS__, NULL, NULL) \
return factory(inst, func, params); \
}
+#endif
+
/**
* PPAPI_SIMPLE_USE_CLASS
@@ -109,5 +131,4 @@ void* PSUserCreateInstance(PP_Instance inst) { \
EXTERN_C_END
-#endif // PPAPI_SIMPLE_PPAPI_SIMPLE_H
-
+#endif // PPAPI_SIMPLE_PS_H_
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc
new file mode 100644
index 0000000000..743dabea96
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc
@@ -0,0 +1,134 @@
+// 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.auto
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ppapi/c/pp_rect.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/pp_size.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_graphics_2d.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_view.h"
+#include "ppapi/cpp/image_data.h"
+
+#include "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_context_2d.h"
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_instance.h"
+#include "ppapi_simple/ps_interface.h"
+
+PSContext2D_t* PSContext2DAllocate() {
+ PSContext2D_t* ctx = (PSContext2D_t*) malloc(sizeof(PSContext2D_t));
+ memset(ctx, 0, sizeof(PSContext2D_t));
+
+ ctx->format = PSInterfaceImageData()->GetNativeImageDataFormat();
+ return ctx;
+}
+
+void PSContext2DFree(PSContext2D_t* ctx) {
+ if (ctx->graphic_2d) {
+ PSInterfaceCore()->ReleaseResource(ctx->graphic_2d);
+ ctx->graphic_2d = 0;
+ }
+ if (ctx->image) {
+ PSInterfaceCore()->ReleaseResource(ctx->image);
+ ctx->image = 0;
+ }
+ free(ctx);
+}
+
+// Update the 2D context if the message is appropriate, returning non-zero
+// if the event was consumed.
+int PSContext2DHandleEvent(PSContext2D_t* ctx, PSEvent* event) {
+ switch(event->type) {
+ case PSE_INSTANCE_DIDCHANGEVIEW: {
+ struct PP_Rect rect;
+
+ PSInterfaceView()->GetRect(event->as_resource, &rect);
+ PSInterfaceCore()->ReleaseResource(ctx->graphic_2d);
+ ctx->bound = 0;
+ ctx->width = rect.size.width;
+ ctx->height = rect.size.height;
+
+ // Create an opaque graphic context of the specified size.
+ ctx->graphic_2d =
+ PSInterfaceGraphics2D()->Create(PSGetInstanceId(), &rect.size,
+ PP_TRUE);
+
+ // Bind the context to so that draws will be visible.
+ if (ctx->graphic_2d) {
+ ctx->bound =
+ PSInterfaceInstance()->BindGraphics(PSGetInstanceId(),
+ ctx->graphic_2d);
+ }
+
+ // Typically this resource would not be allocated yet, but just in case
+ // throw it away, to force a new allocation when GetBuffer is called.
+ if (ctx->image) {
+ PSInterfaceCore()->ReleaseResource(ctx->image);
+ ctx->image = 0;
+ }
+
+ return 1;
+ }
+ default: break;
+ }
+
+ return 0;
+}
+
+
+// Allocates (if needed) a new image context which will be swapped in when
+// drawing is complete. PSContextGetBuffer and PSContext2DSwapBuffer
+// implemented the suggested image/graphic_2d use specified in the
+// ppb_graphics_2d header.
+int PSContext2DGetBuffer(PSContext2D_t* ctx) {
+ if (!ctx->bound) return 0;
+
+ // Check if we are already holding an image
+ if (ctx->image) return 1;
+
+ PP_Size size;
+ size.width = ctx->width;
+ size.height = ctx->height;
+
+ // Allocate a new image resource with the specified size and format, but
+ // do not ZERO out the buffer first since we will fill it.
+ PP_Resource image =
+ PSInterfaceImageData()->Create(PSGetInstanceId(), ctx->format, &size,
+ PP_FALSE);
+
+ if (0 == image) {
+ PSInstance::GetInstance()->Error("Unable to create 2D image.\n");
+ return 0;
+ }
+
+ // Get the stride
+ struct PP_ImageDataDesc desc;
+ PSInterfaceImageData()->Describe(image, &desc);
+
+ ctx->image = image;
+ ctx->data = static_cast<uint32_t*>(PSInterfaceImageData()->Map(image));
+ ctx->stride = desc.stride;
+ return 1;
+}
+
+int PSContext2DSwapBuffer(PSContext2D_t* ctx) {
+ if (ctx->bound && ctx->image) {
+ PSInterfaceImageData()->Unmap(ctx->image);
+ PSInterfaceGraphics2D()->ReplaceContents(ctx->graphic_2d, ctx->image);
+ PSInterfaceGraphics2D()->Flush(ctx->graphic_2d, PP_BlockUntilComplete());
+ PSInterfaceCore()->ReleaseResource(ctx->image);
+
+ ctx->image = 0;
+ ctx->stride = 0;
+ ctx->data = NULL;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h
new file mode 100644
index 0000000000..30d0cf9cc7
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h
@@ -0,0 +1,67 @@
+/* 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 PPAPI_SIMPLE_PS_CONTEXT_2D_H_
+#define PPAPI_SIMPLE_PS_CONTEXT_2D_H_
+
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/ppb_graphics_2d.h"
+#include "ppapi/c/ppb_image_data.h"
+
+#include "ppapi_simple/ps_event.h"
+
+#include "sdk_util/macros.h"
+
+EXTERN_C_BEGIN
+
+typedef struct {
+ int bound;
+ int32_t width;
+ int32_t height;
+ uint32_t stride;
+ uint32_t* data;
+ PP_ImageDataFormat format;
+ PP_Resource graphic_2d;
+ PP_Resource image;
+} PSContext2D_t;
+
+
+/*
+ * PSContext2DAllocate
+ *
+ * Allocate or free a 2D context object which the library can use to perform
+ * various PPAPI operations on the developer's behalf, such as processing view
+ * change events, swapping buffers, etc...
+ */
+PSContext2D_t* PSContext2DAllocate();
+void PSContext2DFree(PSContext2D_t* ctx);
+
+/*
+ * PSContext2DHandleEvent
+ *
+ * Updates the context such as allocating, freeing, or sizing graphics and
+ * image resources in response to events.
+ */
+int PSContext2DHandleEvent(PSContext2D_t* ctx, PSEvent* event);
+
+/*
+ * PSContext2DGetBuffer
+ *
+ * Points the data member of the context to the raw pixels of the image for
+ * writing to the screen. The image will become visible after a swap.
+ */
+int PSContext2DGetBuffer(PSContext2D_t* ctx);
+
+/*
+ * PSContext2DSwapBuffer
+ *
+ * Swaps out the currently visible graphics with the data stored in the image
+ * buffer making it visible. The old image resource will no longer be
+ * available after this call.
+ */
+int PSContext2DSwapBuffer(PSContext2D_t* ctx);
+
+EXTERN_C_END
+
+#endif /* PPAPI_SIMPLE_PS_CONTEXT_2D_H_ */
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_event.h b/native_client_sdk/src/libraries/ppapi_simple/ps_event.h
index 563832c703..731f053b13 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_event.h
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_event.h
@@ -1,7 +1,6 @@
-// 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.
-
+/* 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 PPAPI_SIMPLE_PS_EVENT_H_
#define PPAPI_SIMPLE_PS_EVENT_H_
@@ -91,5 +90,4 @@ void PSEventPostResource(PSEventType type, PP_Resource resource);
EXTERN_C_END
-#endif // PPAPI_SIMPLE_PS_EVENT_H_
-
+#endif /* PPAPI_SIMPLE_PS_EVENT_H_ */
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
index 251876430b..4612a52cfd 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
-#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -16,6 +16,7 @@
#include <string>
#include <vector>
+#include "nacl_io/ioctl.h"
#include "nacl_io/kernel_wrap.h"
#include "nacl_io/nacl_io.h"
@@ -31,8 +32,14 @@
#include "ppapi_simple/ps_event.h"
#include "ppapi_simple/ps_instance.h"
+#include "ppapi_simple/ps_interface.h"
#include "ppapi_simple/ps_main.h"
+#if defined(WIN32)
+#define open _open
+#define dup2 _dup2
+#endif
+
static PSInstance* s_InstanceObject = NULL;
PSInstance* PSInstance::GetInstance() {
@@ -49,7 +56,7 @@ struct StartInfo {
// The starting point for 'main'. We create this thread to hide the real
// main pepper thread which must never be blocked.
void* PSInstance::MainThreadThunk(void *info) {
- s_InstanceObject->Log("Got MainThreadThunk.\n");
+ s_InstanceObject->Trace("Got MainThreadThunk.\n");
StartInfo* si = static_cast<StartInfo*>(info);
si->inst_->main_loop_ = new pp::MessageLoop(si->inst_);
si->inst_->main_loop_->AttachToCurrentThread();
@@ -61,31 +68,38 @@ void* PSInstance::MainThreadThunk(void *info) {
delete[] si->argv_;
delete si;
+ // Exit the entire process once the 'main' thread returns.
+ // The error code will be available to javascript via
+ // the exitcode paramater of the crash event.
+ exit(ret);
return NULL;
}
// The default implementation supports running a 'C' main.
int PSInstance::MainThread(int argc, char *argv[]) {
- if (main_cb_) {
- Log("Starting MAIN.\n");
- int ret = main_cb_(argc, argv);
- Log("Main thread returned with %d.\n", ret);
- return ret;
+ if (!main_cb_) {
+ Error("No main defined.\n");
+ return 0;
}
- Error("No main defined.\n");
- return 0;
+ Trace("Starting MAIN.\n");
+ int ret = main_cb_(argc, argv);
+ Log("Main thread returned with %d.\n", ret);
+ return ret;
}
PSInstance::PSInstance(PP_Instance instance, const char *argv[])
: pp::Instance(instance),
+ pp::MouseLock(this),
+ pp::Graphics3DClient(this),
main_loop_(NULL),
- verbosity_(PSV_LOG),
- events_enabled_(PSE_NONE) {
+ verbosity_(PSV_WARN),
+ events_enabled_(PSE_NONE),
+ fd_tty_(-1) {
// Set the single Instance object
s_InstanceObject = this;
-#ifdef DEBUG
+#ifdef NACL_SDK_DEBUG
SetVerbosity(PSV_LOG);
#endif
@@ -100,15 +114,6 @@ PSInstance::PSInstance(PP_Instance instance, const char *argv[])
PP_INPUTEVENT_CLASS_KEYBOARD |
PP_INPUTEVENT_CLASS_WHEEL |
PP_INPUTEVENT_CLASS_TOUCH);
-
- ppb_core_ = static_cast<const PPB_Core*>(
- pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
-
- ppb_var_ = static_cast<const PPB_Var*>(
- pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE));
-
- ppb_view_ = static_cast<const PPB_View*>(
- pp::Module::Get()->GetBrowserInterface(PPB_VIEW_INTERFACE));
}
PSInstance::~PSInstance() {}
@@ -128,13 +133,7 @@ bool PSInstance::Init(uint32_t arg,
si->argv_[0] = NULL;
// Process arguments passed into Module INIT from JavaScript
- for (uint32_t i=0; i < arg; i++) {
- if (argv[i]) {
- Log("ARG %s=%s\n", argn[i], argv[i]);
- } else {
- Log("ARG %s\n", argn[i]);
- }
-
+ for (uint32_t i = 0; i < arg; i++) {
// If we start with PM prefix set the instance argument map
if (0 == strncmp(argn[i], "ps_", 3)) {
std::string key = argn[i];
@@ -143,25 +142,33 @@ bool PSInstance::Init(uint32_t arg,
continue;
}
+ // Chrome passed @dev as an internal extra attribute in
+ // some cases. Ignore this.
+ if (0 == strcmp(argn[i], "@dev")) {
+ continue;
+ }
+
// If this is the 'src' tag, then get the NMF name.
if (!strcmp("src", argn[i])) {
char *name = new char[strlen(argv[i]) + 1];
strcpy(name, argv[i]);
si->argv_[0] = name;
- }
- else {
- // Otherwise turn it into arguments
- char *key = new char[strlen(argn[i]) + 3];
- key[0] = '-';
- key[1] = '-';
- strcpy(&key[2], argn[i]);
-
- si->argv_[si->argc_++] = key;
- if (argv[i] && argv[i][0]) {
- char *val = new char[strlen(argv[i]) + 1];
- strcpy(val, argv[i]);
- si->argv_[si->argc_++] = val;
- }
+ } else {
+ // Otherwise turn html tag attributes into arguments
+ // that get passed to the main funciton. Attributes
+ // without values get transformed into "--name" and
+ // attributes with values become "--name=value".
+ int arglen = strlen(argn[i]) + 3;
+ if (argv[i] && argv[i][0])
+ arglen += strlen(argv[i]) + 1;
+
+ char* arg = new char[arglen];
+ if (argv[i] && argv[i][0])
+ sprintf(arg, "--%s=%s", argn[i], argv[i]);
+ else
+ sprintf(arg, "--%s", argn[i]);
+
+ si->argv_[si->argc_++] = arg;
}
}
@@ -172,15 +179,33 @@ bool PSInstance::Init(uint32_t arg,
si->argv_[0] = name;
}
- if (ProcessProperties()) {
- pthread_t main_thread;
- int ret = pthread_create(&main_thread, NULL, MainThreadThunk, si);
- Log("Created thread: %d.\n", ret);
- return ret == 0;
+ PSInterfaceInit();
+ bool props_processed = ProcessProperties();
+
+ // Log arg values only once ProcessProperties has been
+ // called so that the ps_verbosity attribute will be in
+ // effect.
+ for (uint32_t i = 0; i < arg; i++) {
+ if (argv[i]) {
+ Trace("attribs[%d] '%s=%s'\n", i, argn[i], argv[i]);
+ } else {
+ Trace("attribs[%d] '%s'\n", i, argn[i]);
+ }
}
- Log("Skipping create thread.\n");
- return false;
+ for (uint32_t i = 0; i < si->argc_; i++) {
+ Trace("argv[%d] '%s'\n", i, si->argv_[i]);
+ }
+
+ if (!props_processed) {
+ Warn("Skipping create thread.\n");
+ return false;
+ }
+
+ pthread_t main_thread;
+ int ret = pthread_create(&main_thread, NULL, MainThreadThunk, si);
+ Trace("Created thread: %d.\n", ret);
+ return ret == 0;
}
const char* PSInstance::GetProperty(const char* key, const char* def) {
@@ -191,7 +216,7 @@ const char* PSInstance::GetProperty(const char* key, const char* def) {
return def;
}
-// Processes the properties passed fixed at compile time via the
+// Processes the properties set at compile time via the
// initialization macro, or via dynamically set embed attributes
// through instance DidCreate.
bool PSInstance::ProcessProperties() {
@@ -200,6 +225,7 @@ bool PSInstance::ProcessProperties() {
const char* stdout_path = GetProperty("ps_stdout", "/dev/stdout");
const char* stderr_path = GetProperty("ps_stderr", "/dev/console3");
const char* verbosity = GetProperty("ps_verbosity", NULL);
+ const char* tty_prefix = GetProperty("ps_tty_prefix", NULL);
// Reset verbosity if passed in
if (verbosity) SetVerbosity(static_cast<Verbosity>(atoi(verbosity)));
@@ -215,9 +241,20 @@ bool PSInstance::ProcessProperties() {
int fd2 = open(stderr_path, O_WRONLY);
dup2(fd2, 2);
+ if (tty_prefix) {
+ fd_tty_ = open("/dev/tty", O_WRONLY);
+ if (fd_tty_ >= 0) {
+ ioctl(fd_tty_, TIOCNACLPREFIX, const_cast<char*>(tty_prefix));
+ } else {
+ Error("Failed to open /dev/tty.\n");
+ }
+ }
+
// Set line buffering on stdout and stderr
+#if !defined(WIN32)
setvbuf(stderr, NULL, _IOLBF, 0);
setvbuf(stdout, NULL, _IOLBF, 0);
+#endif
return true;
}
@@ -225,28 +262,39 @@ void PSInstance::SetVerbosity(Verbosity verbosity) {
verbosity_ = verbosity;
}
-void PSInstance::Log(const char *fmt, ...) {
- if (verbosity_ >= PSV_LOG) {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stdout, fmt, ap);
+void PSInstance::VALog(Verbosity verbosity, const char *fmt, va_list args) {
+ if (verbosity <= verbosity_) {
+ fprintf(stderr, "ps: ");
+ vfprintf(stderr, fmt, args);
}
}
+void PSInstance::Trace(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ VALog(PSV_TRACE, fmt, ap);
+ va_end(ap);
+}
+
+void PSInstance::Log(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ VALog(PSV_LOG, fmt, ap);
+ va_end(ap);
+}
+
void PSInstance::Warn(const char *fmt, ...) {
- if (verbosity_ >= PSV_WARN) {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stdout, fmt, ap);
- }
+ va_list ap;
+ va_start(ap, fmt);
+ VALog(PSV_WARN, fmt, ap);
+ va_end(ap);
}
void PSInstance::Error(const char *fmt, ...) {
- if (verbosity_ >= PSV_ERROR) {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- }
+ va_list ap;
+ va_start(ap, fmt);
+ VALog(PSV_ERROR, fmt, ap);
+ va_end(ap);
}
void PSInstance::SetEnabledEvents(uint32_t mask) {
@@ -283,7 +331,7 @@ void PSInstance::PostEvent(PSEventType type, PP_Resource resource) {
if (events_enabled_ & type) {
if (resource) {
- ppb_core_->AddRefResource(resource);
+ PSInterfaceCore()->AddRefResource(resource);
}
PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent));
memset(env, 0, sizeof(*env));
@@ -296,8 +344,32 @@ void PSInstance::PostEvent(PSEventType type, PP_Resource resource) {
void PSInstance::PostEvent(PSEventType type, const PP_Var& var) {
assert(PSE_INSTANCE_HANDLEMESSAGE == type);
+ // If the user has specified a tty_prefix_ (using ioctl), then we'll give the
+ // tty node a chance to vacuum up any messages beginning with that prefix. If
+ // the message does not start with the prefix, the ioctl call will return
+ // ENOENT and we'll pass the message through to the event queue.
+ if (fd_tty_ >= 0 && var.type == PP_VARTYPE_STRING) {
+ uint32_t message_len;
+ const char* message = PSInterfaceVar()->VarToUtf8(var, &message_len);
+ std::string message_str(message, message + message_len);
+
+ // Since our message may contain null characters, we can't send it as a
+ // naked C string, so we package it up in this struct before sending it
+ // to the ioctl.
+ struct tioc_nacl_input_string ioctl_message;
+ ioctl_message.length = message_len;
+ ioctl_message.buffer = message_str.data();
+ int ret =
+ ioctl(fd_tty_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message));
+ if (ret != ENOTTY) {
+ Error("ioctl returned unexpected error: %d.\n", ret);
+ }
+
+ return;
+ }
+
if (events_enabled_ & type) {
- ppb_var_->AddRef(var);
+ PSInterfaceVar()->AddRef(var);
PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent));
memset(env, 0, sizeof(*env));
env->type = type;
@@ -318,12 +390,12 @@ void PSInstance::ReleaseEvent(PSEvent* event) {
if (event) {
switch(event->type) {
case PSE_INSTANCE_HANDLEMESSAGE:
- ppb_var_->Release(event->as_var);
+ PSInterfaceVar()->Release(event->as_var);
break;
case PSE_INSTANCE_HANDLEINPUT:
case PSE_INSTANCE_DIDCHANGEVIEW:
if (event->as_resource) {
- ppb_core_->ReleaseResource(event->as_resource);
+ PSInterfaceCore()->ReleaseResource(event->as_resource);
}
break;
default:
@@ -334,12 +406,11 @@ void PSInstance::ReleaseEvent(PSEvent* event) {
}
void PSInstance::HandleMessage(const pp::Var& message) {
- Log("Got Message\n");
+ Trace("Got Message\n");
PostEvent(PSE_INSTANCE_HANDLEMESSAGE, message.pp_var());
}
bool PSInstance::HandleInputEvent(const pp::InputEvent& event) {
- Log("Got Input\n");
PostEvent(PSE_INSTANCE_HANDLEINPUT, event.pp_resource());
return true;
}
@@ -355,3 +426,12 @@ void PSInstance::DidChangeFocus(bool focus) {
PostEvent(PSE_INSTANCE_DIDCHANGEFOCUS, focus ? PP_TRUE : PP_FALSE);
}
+void PSInstance::Graphics3DContextLost() {
+ Log("Graphics3DContextLost\n");
+ PostEvent(PSE_GRAPHICS3D_GRAPHICS3DCONTEXTLOST);
+}
+
+void PSInstance::MouseLockLost() {
+ Log("MouseLockLost\n");
+ PostEvent(PSE_MOUSELOCK_MOUSELOCKLOST);
+}
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
index bf9fbe4a9e..f02d574d5c 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
@@ -5,6 +5,7 @@
#ifndef PPAPI_SIMPLE_PS_INSTANCE_H_
#define PPAPI_SIMPLE_PS_INSTANCE_H_
+#include <stdarg.h>
#include <map>
#include "ppapi/c/pp_instance.h"
@@ -14,6 +15,7 @@
#include "ppapi/c/ppb_view.h"
#include "ppapi/cpp/fullscreen.h"
+#include "ppapi/cpp/graphics_3d_client.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/message_loop.h"
#include "ppapi/cpp/mouse_lock.h"
@@ -28,13 +30,18 @@
typedef std::map<std::string, std::string> PropertyMap_t;
-class PSInstance : public pp::Instance {
+// The basic instance class which also inherits the MouseLock and
+// Graphics3DClient interfaces.
+class PSInstance : public pp::Instance, pp::MouseLock, pp::Graphics3DClient {
public:
+ // Verbosity levels, ecplicitly numbered since we pass these
+ // in from html attributes as numberic values.
enum Verbosity {
- PSV_SILENT,
- PSV_ERROR,
- PSV_WARN,
- PSV_LOG,
+ PSV_SILENT = 0,
+ PSV_ERROR = 1,
+ PSV_WARN = 2,
+ PSV_LOG = 3,
+ PSV_TRACE = 4,
};
// Returns a pointer to the global instance
@@ -56,6 +63,7 @@ class PSInstance : public pp::Instance {
// Logging Functions
void SetVerbosity(Verbosity verbosity);
+ void Trace(const char *fmt, ...);
void Log(const char *fmt, ...);
void Warn(const char *fmt, ...);
void Error(const char *fmt, ...);
@@ -81,6 +89,10 @@ class PSInstance : public pp::Instance {
// This function will create a new thread which will run the pseudo main.
virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
+ // Output log message to stderr if the current verbosity is set
+ // at or above the given verbosity.
+ void VALog(Verbosity verbosity, const char *fmt, va_list args);
+
// Called whenever the in-browser window changes size, it will pass a
// context change request to whichever thread is handling rendering.
virtual void DidChangeView(const pp::View& view);
@@ -95,6 +107,12 @@ class PSInstance : public pp::Instance {
// and can later be processed on a sperate processing thread.
virtual bool HandleInputEvent(const pp::InputEvent& event);
+ // Called by the browser when the 3D context is lost.
+ virtual void Graphics3DContextLost();
+
+ // Called by the browser when the mouselock is lost.
+ virtual void MouseLockLost();
+
// Called by Init to processes default and embed tag arguments prior to
// launching the 'ppapi_main' thread.
virtual bool ProcessProperties();
@@ -109,13 +127,16 @@ class PSInstance : public pp::Instance {
ThreadSafeQueue<PSEvent> event_queue_;
uint32_t events_enabled_;
Verbosity verbosity_;
+ int fd_tty_;
PSMainFunc_t main_cb_;
const PPB_Core* ppb_core_;
const PPB_Var* ppb_var_;
const PPB_View* ppb_view_;
+
+ friend class PSGraphics3DClient;
+ friend class PSMouseLock;
};
#endif // PPAPI_MAIN_PS_INSTANCE_H_
-
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_interface.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_interface.cc
new file mode 100644
index 0000000000..43988e2996
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_interface.cc
@@ -0,0 +1,64 @@
+// 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 "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_interface.h"
+
+#define DEFINE_INTERFACE_FUNC(Name) \
+ static const PPB_##Name* s_##Name; \
+ const PPB_##Name* PSInterface##Name() { return s_##Name; }
+
+DEFINE_INTERFACE_FUNC(Audio)
+DEFINE_INTERFACE_FUNC(AudioConfig)
+DEFINE_INTERFACE_FUNC(Console)
+DEFINE_INTERFACE_FUNC(Core)
+DEFINE_INTERFACE_FUNC(FileIO)
+DEFINE_INTERFACE_FUNC(FileRef)
+DEFINE_INTERFACE_FUNC(FileSystem)
+DEFINE_INTERFACE_FUNC(Fullscreen)
+DEFINE_INTERFACE_FUNC(Gamepad)
+DEFINE_INTERFACE_FUNC(Graphics2D)
+DEFINE_INTERFACE_FUNC(Graphics3D)
+DEFINE_INTERFACE_FUNC(ImageData)
+DEFINE_INTERFACE_FUNC(Instance)
+DEFINE_INTERFACE_FUNC(Messaging)
+DEFINE_INTERFACE_FUNC(MessageLoop)
+DEFINE_INTERFACE_FUNC(MouseCursor)
+DEFINE_INTERFACE_FUNC(URLLoader)
+DEFINE_INTERFACE_FUNC(URLRequestInfo)
+DEFINE_INTERFACE_FUNC(URLResponseInfo)
+DEFINE_INTERFACE_FUNC(Var)
+DEFINE_INTERFACE_FUNC(VarArrayBuffer)
+DEFINE_INTERFACE_FUNC(View)
+DEFINE_INTERFACE_FUNC(WebSocket)
+
+
+#define REQUEST_INTERFACE(x, y) \
+ s_##x = static_cast<const PPB_##x*>(PSGetInterface(PPB_ ## y ##_INTERFACE));
+
+void PSInterfaceInit() {
+ REQUEST_INTERFACE(Audio, AUDIO)
+ REQUEST_INTERFACE(AudioConfig, AUDIO_CONFIG)
+ REQUEST_INTERFACE(Console, CONSOLE)
+ REQUEST_INTERFACE(Core, CORE)
+ REQUEST_INTERFACE(FileIO, FILEIO)
+ REQUEST_INTERFACE(FileRef, FILEREF)
+ REQUEST_INTERFACE(FileSystem, FILESYSTEM)
+ REQUEST_INTERFACE(Fullscreen, FULLSCREEN)
+ REQUEST_INTERFACE(Gamepad, GAMEPAD)
+ REQUEST_INTERFACE(Graphics2D, GRAPHICS_2D)
+ REQUEST_INTERFACE(Graphics3D, GRAPHICS_3D)
+ REQUEST_INTERFACE(ImageData, IMAGEDATA)
+ REQUEST_INTERFACE(Instance, INSTANCE)
+ REQUEST_INTERFACE(Messaging, MESSAGING)
+ REQUEST_INTERFACE(MessageLoop, MESSAGELOOP)
+ REQUEST_INTERFACE(MouseCursor, MOUSECURSOR)
+ REQUEST_INTERFACE(URLLoader, URLLOADER)
+ REQUEST_INTERFACE(URLRequestInfo, URLREQUESTINFO)
+ REQUEST_INTERFACE(URLResponseInfo, URLRESPONSEINFO)
+ REQUEST_INTERFACE(Var, VAR)
+ REQUEST_INTERFACE(VarArrayBuffer, VAR_ARRAY_BUFFER)
+ REQUEST_INTERFACE(View, VIEW)
+ REQUEST_INTERFACE(WebSocket, WEBSOCKET)
+}
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_interface.h b/native_client_sdk/src/libraries/ppapi_simple/ps_interface.h
new file mode 100644
index 0000000000..ad818f06e5
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_interface.h
@@ -0,0 +1,72 @@
+/* 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 PPAPI_SIMPLE_PS_INTERFACE_H_
+#define PPAPI_SIMPLE_PS_INTERFACE_H_
+
+#include "ppapi/c/pp_bool.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/pp_var.h"
+
+
+#include "ppapi/c/ppb_audio.h"
+#include "ppapi/c/ppb_audio_config.h"
+#include "ppapi/c/ppb_console.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_file_io.h"
+#include "ppapi/c/ppb_file_ref.h"
+#include "ppapi/c/ppb_file_system.h"
+#include "ppapi/c/ppb_fullscreen.h"
+#include "ppapi/c/ppb_gamepad.h"
+#include "ppapi/c/ppb_graphics_2d.h"
+#include "ppapi/c/ppb_graphics_3d.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_message_loop.h"
+#include "ppapi/c/ppb_messaging.h"
+#include "ppapi/c/ppb_mouse_cursor.h"
+#include "ppapi/c/ppb_mouse_lock.h"
+#include "ppapi/c/ppb_url_loader.h"
+#include "ppapi/c/ppb_url_request_info.h"
+#include "ppapi/c/ppb_url_response_info.h"
+#include "ppapi/c/ppb_var.h"
+#include "ppapi/c/ppb_var_array_buffer.h"
+#include "ppapi/c/ppb_view.h"
+#include "ppapi/c/ppb_websocket.h"
+
+#include "sdk_util/macros.h"
+
+EXTERN_C_BEGIN
+
+const PPB_Audio* PSInterfaceAudio();
+const PPB_AudioConfig* PSInterfaceAudioConfig();
+const PPB_Console* PSInterfaceConsole();
+const PPB_Core* PSInterfaceCore();
+const PPB_FileIO* PSInterfaceFileIO();
+const PPB_FileRef* PSInterfaceFileRef();
+const PPB_FileSystem* PSInterfaceFileSystem();
+const PPB_Fullscreen* PSInterfaceFullscreen();
+const PPB_Gamepad* PSInterfaceGamepad();
+const PPB_Graphics2D* PSInterfaceGraphics2D();
+const PPB_Graphics3D* PSInterfaceGraphics3D();
+const PPB_ImageData* PSInterfaceImageData();
+const PPB_Instance* PSInterfaceInstance();
+const PPB_Messaging* PSInterfaceMessaging();
+const PPB_MessageLoop* PSInterfaceMessageLoop();
+const PPB_MouseCursor* PSInterfaceMouseCursor();
+const PPB_URLLoader* PSInterfaceURLLoader();
+const PPB_URLRequestInfo* PSInterfaceURLRequestInfo();
+const PPB_URLResponseInfo* PSInterfaceURLResponseInfo();
+const PPB_Var* PSInterfaceVar();
+const PPB_VarArrayBuffer* PSInterfaceVarArrayBuffer();
+const PPB_View* PSInterfaceView();
+const PPB_WebSocket* PSInterfaceWebSocket();
+
+
+/* Initializes the Interface module which fetches the above interfaces. */
+void PSInterfaceInit();
+
+EXTERN_C_END
+
+#endif /* PPAPI_SIMPLE_PS_INTERFACE_H */
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_main.h b/native_client_sdk/src/libraries/ppapi_simple/ps_main.h
index c37ac5dba3..9e18edf9e4 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_main.h
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_main.h
@@ -1,6 +1,6 @@
-// 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.
+/* 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 PPAPI_SIMPLE_PS_MAIN_H_
#define PPAPI_SIMPLE_PS_MAIN_H_
@@ -34,5 +34,4 @@ void* PSMainCreate(PP_Instance inst, PSMainFunc_t func, const char **argv);
EXTERN_C_END
-#endif /* PPAPI_SIMPLE_PPAPI_SIMPLE_MAIN_H_ */
-
+#endif /* PPAPI_SIMPLE_PS_MAIN_H_ */
diff --git a/native_client_sdk/src/libraries/sdk_util/atomicops.h b/native_client_sdk/src/libraries/sdk_util/atomicops.h
new file mode 100644
index 0000000000..80d62d2157
--- /dev/null
+++ b/native_client_sdk/src/libraries/sdk_util/atomicops.h
@@ -0,0 +1,44 @@
+/* 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_SDK_UTIL_ATOMICOPS_H_
+#define LIBRARIES_SDK_UTIL_ATOMICOPS_H_
+
+#ifndef WIN32
+
+#include <stdint.h>
+typedef int32_t Atomic32;
+
+#ifndef __llvm__
+static inline void MemoryBarrier() {
+ __sync_synchronize();
+}
+#endif
+
+inline Atomic32 AtomicAddFetch(volatile Atomic32* ptr, Atomic32 value) {
+ return __sync_add_and_fetch(ptr, value);
+}
+
+#else
+
+#include <windows.h>
+
+/* Undefine many Windows.h macros that we almost certainly do not want. */
+#undef min
+#undef max
+#undef PostMessage
+#undef interface
+
+typedef long Atomic32;
+
+/* Windows.h already defines a MemoryBarrier macro. */
+
+inline Atomic32 AtomicAddFetch(volatile Atomic32* ptr, Atomic32 value) {
+ return InterlockedExchangeAdd(ptr, value);
+}
+#endif
+
+
+#endif /* LIBRARIES_SDK_UTIL_ATOMICOPS_H_ */
diff --git a/native_client_sdk/src/libraries/sdk_util/library.dsc b/native_client_sdk/src/libraries/sdk_util/library.dsc
index 0491d980ea..71a51481d7 100644
--- a/native_client_sdk/src/libraries/sdk_util/library.dsc
+++ b/native_client_sdk/src/libraries/sdk_util/library.dsc
@@ -15,9 +15,11 @@
'HEADERS': [
{
'FILES': [
+ 'atomicops.h',
'auto_lock.h',
'macros.h',
'ref_object.h',
+ 'scoped_ref.h',
'thread_pool.h',
'thread_safe_queue.h'
],
diff --git a/native_client_sdk/src/libraries/sdk_util/ref_object.h b/native_client_sdk/src/libraries/sdk_util/ref_object.h
index 4e81f32df6..e446e80141 100644
--- a/native_client_sdk/src/libraries/sdk_util/ref_object.h
+++ b/native_client_sdk/src/libraries/sdk_util/ref_object.h
@@ -9,21 +9,48 @@
#include <stdlib.h>
#include "pthread.h"
+#include "sdk_util/atomicops.h"
+
+class ScopedRefBase;
+
+/*
+ * RefObject
+ *
+ * A reference counted object with a lock. The lock protects the data within
+ * the object, but not the reference counting which happens through atomic
+ * operations. RefObjects should only be handled by ScopedRef objects.
+ *
+ * When the object is first created, it has a reference count of zero. It's
+ * first incremented when it gets assigned to a ScopedRef. When the last
+ * ScopedRef is reset or destroyed the object will get released.
+ */
+
class RefObject {
public:
RefObject() {
- ref_count_ = 1;
+ ref_count_ = 0;
pthread_mutex_init(&lock_, NULL);
}
+ /*
+ * RefCount
+ *
+ * RefCount returns an instantaneous snapshot of the RefCount, which may
+ * change immediately after it is fetched. This is only stable when all
+ * pointers to the object are scoped pointers (ScopedRef), and the value
+ * is one implying the current thread is the only one, with visibility to
+ * the object.
+ */
int RefCount() const { return ref_count_; }
+ protected:
void Acquire() {
- ref_count_++;
+ AtomicAddFetch(&ref_count_, 1);
}
bool Release() {
- if (--ref_count_ == 0) {
+ Atomic32 val = AtomicAddFetch(&ref_count_, -1);
+ if (val == 0) {
Destroy();
delete this;
return false;
@@ -31,18 +58,18 @@ class RefObject {
return true;
}
- protected:
virtual ~RefObject() {
pthread_mutex_destroy(&lock_);
}
// Override to clean up object when last reference is released.
virtual void Destroy() {}
-
pthread_mutex_t lock_;
private:
- int ref_count_;
+ Atomic32 ref_count_;
+
+ friend class ScopedRefBase;
};
#endif // LIBRARIES_SDK_UTIL_REF_OBJECT
diff --git a/native_client_sdk/src/libraries/sdk_util/scoped_ref.h b/native_client_sdk/src/libraries/sdk_util/scoped_ref.h
new file mode 100644
index 0000000000..0bbba713d5
--- /dev/null
+++ b/native_client_sdk/src/libraries/sdk_util/scoped_ref.h
@@ -0,0 +1,91 @@
+/* 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_SDK_UTIL_SCOPED_REF_H_
+#define LIBRARIES_SDK_UTIL_SCOPED_REF_H_
+
+#include <stdlib.h>
+
+#include "sdk_util/macros.h"
+#include "sdk_util/ref_object.h"
+
+class ScopedRefBase {
+ protected:
+ ScopedRefBase() : ptr_(NULL) {}
+ ~ScopedRefBase() { reset(NULL); }
+
+ void reset(RefObject* obj) {
+ if (obj) {
+ obj->Acquire();
+ }
+ if (ptr_) {
+ ptr_->Release();
+ }
+ ptr_ = obj;
+ }
+
+ protected:
+ RefObject* ptr_;
+};
+
+template <class T>
+class ScopedRef : public ScopedRefBase {
+ public:
+ ScopedRef() {}
+ ScopedRef(const ScopedRef& ptr) { reset(ptr.get()); }
+ explicit ScopedRef(T* ptr) { reset(ptr); }
+
+ ScopedRef& operator=(const ScopedRef& ptr) {
+ reset(ptr.get());
+ return *this;
+ }
+
+ template <typename U>
+ ScopedRef(const ScopedRef<U>& ptr) {
+ reset(ptr.get());
+ }
+
+ template <typename U>
+ ScopedRef& operator=(const ScopedRef<U>& ptr) {
+ reset(ptr.get());
+ return *this;
+ }
+
+ void reset(T* obj = NULL) { ScopedRefBase::reset(obj); }
+ T* get() const { return static_cast<T*>(ptr_); }
+
+ template <typename U>
+ bool operator==(const ScopedRef<U>& p) const {
+ return get() == p.get();
+ }
+
+ template <typename U>
+ bool operator!=(const ScopedRef<U>& p) const {
+ return get() != p.get();
+ }
+
+ public:
+ T& operator*() const { return *get(); }
+ T* operator->() const { return get(); }
+
+#ifndef __llvm__
+ private:
+ typedef void (ScopedRef::*bool_as_func_ptr)() const;
+ void bool_as_func_impl() const {};
+
+ public:
+ operator bool_as_func_ptr() const {
+ return (ptr_ != NULL) ? &ScopedRef::bool_as_func_impl : 0;
+ }
+#else
+ /*
+ * TODO Remove when bug 3514 is fixed see:
+ * https://code.google.com/p/nativeclient/issues/detail?id=3514
+ */
+ operator T*() const { return get(); }
+#endif
+};
+
+#endif // LIBRARIES_SDK_UTIL_SCOPED_REF_H_
diff --git a/native_client_sdk/src/libraries/xray/demangle.c b/native_client_sdk/src/libraries/xray/demangle.c
new file mode 100644
index 0000000000..9871bd3ad8
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/demangle.c
@@ -0,0 +1,26 @@
+/* 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 "xray/xray_priv.h"
+
+/* Note name demangling requires linking against libstdc++ */
+/* If your platform does not support __cxa_demangle, re-compile XRay with: */
+/* -DXRAY_NO_DEMANGLE */
+
+#if !defined(XRAY_NO_DEMANGLE)
+extern
+char* __cxa_demangle(const char* __mangled_name, char* __output_buffer,
+ size_t* __length, int* __status);
+#endif
+
+const char* XRayDemangle(char* demangle, size_t size, const char* symbol) {
+#if !defined(XRAY_NO_DEMANGLE)
+ int stat;
+ __cxa_demangle(symbol, demangle, &size, &stat);
+ if (stat == 0)
+ return demangle;
+#endif
+ return symbol;
+}
diff --git a/native_client_sdk/src/libraries/xray/hashtable.c b/native_client_sdk/src/libraries/xray/hashtable.c
new file mode 100644
index 0000000000..9166cfe2e3
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/hashtable.c
@@ -0,0 +1,201 @@
+/* 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.
+ */
+
+
+/* Hashtable for XRay */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xray/xray_priv.h"
+
+#if defined(XRAY)
+
+struct XRayHashTableEntry {
+ void* data;
+ uint32_t key;
+};
+
+
+struct XRayHashTable {
+ int size;
+ int count;
+ struct XRayHashTableEntry* array;
+};
+
+
+XRAY_NO_INSTRUMENT void XRayHashTableGrow(struct XRayHashTable* table);
+XRAY_NO_INSTRUMENT uint32_t XRayHashTableHashKey(uint32_t key);
+XRAY_NO_INSTRUMENT void XRayHashTableInit(struct XRayHashTable* table,
+ int32_t size);
+
+#define HASH_HISTO 1024
+int g_hash_histo[HASH_HISTO];
+
+
+/* Hashes a 32bit key into a 32bit value. */
+uint32_t XRayHashTableHashKey(uint32_t x) {
+ uint32_t y = x * 7919;
+ uint32_t z;
+ size_t c;
+ uint8_t* s = (uint8_t*)&y;
+ /* based on djb2 hash function */
+ uint32_t h = 5381;
+ for (c = 0; c < sizeof(y); ++c) {
+ z = s[c];
+ h = ((h << 5) + h) + z;
+ }
+ return h;
+}
+
+
+int XRayHashTableGetSize(struct XRayHashTable* table) {
+ return table->size;
+}
+
+
+/* Looks up key in hashtable and returns blind data. */
+void* XRayHashTableLookup(struct XRayHashTable* table, uint32_t key) {
+ uint32_t h = XRayHashTableHashKey(key);
+ uint32_t m = table->size - 1;
+ uint32_t j = h & m;
+ uint32_t i;
+ int z = 1;
+ for (i = 0; i < m; ++i) {
+ /* An empty entry means the {key, data} isn't in the table. */
+ if (NULL == table->array[j].data) {
+ ++g_hash_histo[0];
+ return NULL;
+ }
+ /* Search for address */
+ if (table->array[j].key == key) {
+ if (z >= HASH_HISTO)
+ z = HASH_HISTO - 1;
+ ++g_hash_histo[z];
+ return table->array[j].data;
+ }
+ j = (j + 1) & m;
+ ++z;
+ }
+ /* Table was full, and there wasn't a match. */
+ return NULL;
+}
+
+
+/* Inserts key & data into hash table. No duplicates. */
+void* XRayHashTableInsert(struct XRayHashTable* table,
+ void* data, uint32_t key) {
+ uint32_t h = XRayHashTableHashKey(key);
+ uint32_t m = table->size - 1;
+ uint32_t j = h & m;
+ uint32_t i;
+ for (i = 0; i < m; ++i) {
+ /* Take the first empty entry. */
+ /* (the key,data isn't already in the table) */
+ if (NULL == table->array[j].data) {
+ void* ret;
+ float ratio;
+ table->array[j].data = data;
+ table->array[j].key = key;
+ ++table->count;
+ ret = data;
+ ratio = (float)table->count / (float)table->size;
+ /* Double the size of the symtable if we've hit the ratio. */
+ if (ratio > XRAY_SYMBOL_TABLE_MAX_RATIO)
+ XRayHashTableGrow(table);
+ return ret;
+ }
+ /* If the key is already present, return the data in the table. */
+ if (table->array[j].key == key) {
+ return table->array[j].data;
+ }
+ j = (j + 1) & m;
+ }
+ /* Table was full */
+ return NULL;
+}
+
+
+void* XRayHashTableAtIndex(struct XRayHashTable* table, int i) {
+ if ((i < 0) || (i >= table->size))
+ return NULL;
+ return table->array[i].data;
+}
+
+
+/* Grows the hash table by doubling its size, */
+/* then re-inserts all the elements into the new table. */
+void XRayHashTableGrow(struct XRayHashTable* table) {
+ struct XRayHashTableEntry* old_array = table->array;
+ int old_size = table->size;
+ int new_size = old_size * 2;
+ int i;
+ printf("XRay: Growing a hash table...\n");
+ XRayHashTableInit(table, new_size);
+ for (i = 0; i < old_size; ++i) {
+ void* data = old_array[i].data;
+ if (NULL != data) {
+ uint32_t key = old_array[i].key;
+ XRayHashTableInsert(table, data, key);
+ }
+ }
+ XRayFree(old_array);
+}
+
+
+void XRayHashTableInit(struct XRayHashTable* table, int32_t size) {
+ size_t bytes;
+ if (0 != (size & (size - 1))) {
+ printf("Xray: Hash table size should be a power of 2!\n");
+ /* Round size up to next power of 2 */
+ /* see http://aggregate.org/MAGIC/ */
+ size--;
+ size |= size >> 1;
+ size |= size >> 2;
+ size |= size >> 4;
+ size |= size >> 8;
+ size |= size >> 16;
+ size++;
+ }
+ bytes = sizeof(table->array[0]) * size;
+ table->size = size;
+ table->count = 0;
+ table->array = (struct XRayHashTableEntry*)XRayMalloc(bytes);
+}
+
+
+/* Creates & inializes hash table. */
+struct XRayHashTable* XRayHashTableCreate(int size) {
+ struct XRayHashTable* table;
+ table = (struct XRayHashTable*)XRayMalloc(sizeof(*table));
+ XRayHashTableInit(table, size);
+ memset(&g_hash_histo[0], 0, sizeof(g_hash_histo[0]) * HASH_HISTO);
+ return table;
+}
+
+
+/* Prints hash table performance to file; for debugging. */
+void XRayHashTableHisto(FILE* f) {
+ int i;
+ for (i = 0; i < HASH_HISTO; ++i) {
+ if (0 != g_hash_histo[i])
+ fprintf(f, "hash_iterations[%d] = %d\n", i, g_hash_histo[i]);
+ }
+}
+
+
+/* Frees hash table. */
+/* Note: Does not free what the hash table entries point to. */
+void XRayHashTableFree(struct XRayHashTable* table) {
+ XRayFree(table->array);
+ table->size = 0;
+ table->count = 0;
+ table->array = NULL;
+ XRayFree(table);
+}
+
+#endif /* XRAY */
+
diff --git a/native_client_sdk/src/libraries/xray/library.dsc b/native_client_sdk/src/libraries/xray/library.dsc
new file mode 100644
index 0000000000..26f6d8dbc1
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/library.dsc
@@ -0,0 +1,34 @@
+{
+ 'TOOLS': ['newlib', 'glibc'],
+ 'SEARCH': [
+ '.'
+ ],
+ 'TARGETS': [
+ {
+ 'NAME' : 'xray',
+ 'TYPE' : 'lib',
+ 'SOURCES' : [
+ 'demangle.c',
+ 'hashtable.c',
+ 'stringpool.c',
+ 'symtable.c',
+ 'xray.c'
+ ],
+ 'CCFLAGS': [
+ '-DXRAY -DXRAY_ANNOTATE -O2'
+ ]
+ }
+ ],
+ 'HEADERS': [
+ {
+ 'FILES': [
+ 'xray.h',
+ 'xray_priv.h'
+ ],
+ 'DEST': 'include/xray',
+ }
+ ],
+ 'DEST': 'src',
+ 'NAME': 'xray',
+ 'EXPERIMENTAL': True,
+}
diff --git a/native_client_sdk/src/libraries/xray/stringpool.c b/native_client_sdk/src/libraries/xray/stringpool.c
new file mode 100644
index 0000000000..4a63581a0c
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/stringpool.c
@@ -0,0 +1,92 @@
+/* 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.
+ */
+
+
+/* XRay string pool */
+
+/* String pool holds a large pile of strings. */
+/* It is up to higher level data structures to avoid duplicates. */
+/* It is up to higher level data structures to provide fast lookups. */
+
+#include <stdlib.h>
+#include <string.h>
+#include "xray/xray_priv.h"
+
+#if defined(XRAY)
+
+struct XRayStringPoolNode {
+ struct XRayStringPoolNode* next;
+ char strings[XRAY_STRING_POOL_NODE_SIZE];
+};
+
+
+struct XRayStringPool {
+ struct XRayStringPoolNode* head;
+ struct XRayStringPoolNode* current;
+ int index;
+};
+
+
+static struct XRayStringPoolNode* XRayStringPoolAllocNode() {
+ struct XRayStringPoolNode* s;
+ s = (struct XRayStringPoolNode *)XRayMalloc(sizeof(*s));
+ s->next = NULL;
+ return s;
+}
+
+
+static int XRayStringPoolCurrentNodeSpaceAvail(struct XRayStringPool* pool) {
+ int i = pool->index;
+ return (XRAY_STRING_POOL_NODE_SIZE - i) - 1;
+}
+
+
+/* Append a string to the string pool. */
+char* XRayStringPoolAppend(struct XRayStringPool* pool, const char* src) {
+ /* Add +1 to STRING_POOL_NODE_SIZE to detect large strings */
+ /* Add +1 to strnlen result to account for string termination */
+ int n = strnlen(src, XRAY_STRING_POOL_NODE_SIZE + 1) + 1;
+ int a = XRayStringPoolCurrentNodeSpaceAvail(pool);
+ char* dst;
+ /* Don't accept strings larger than the pool node. */
+ if (n >= (XRAY_STRING_POOL_NODE_SIZE - 1))
+ return NULL;
+ /* If string doesn't fit, alloc a new node. */
+ if (n > a) {
+ pool->current->next = XRayStringPoolAllocNode();
+ pool->current = pool->current->next;
+ pool->index = 0;
+ }
+ /* Copy string and return a pointer to copy. */
+ dst = &pool->current->strings[pool->index];
+ strcpy(dst, src);
+ pool->index += n;
+ return dst;
+}
+
+
+/* Create & initialize a string pool instance. */
+struct XRayStringPool* XRayStringPoolCreate() {
+ struct XRayStringPool* pool;
+ pool = (struct XRayStringPool*)XRayMalloc(sizeof(*pool));
+ pool->head = XRayStringPoolAllocNode();
+ pool->current = pool->head;
+ return pool;
+}
+
+
+/* Free a string pool. */
+void XRayStringPoolFree(struct XRayStringPool* pool) {
+ struct XRayStringPoolNode* n = pool->head;
+ while (NULL != n) {
+ struct XRayStringPoolNode* c = n;
+ n = n->next;
+ XRayFree(c);
+ }
+ XRayFree(pool);
+}
+
+#endif /* XRAY */
+
diff --git a/native_client_sdk/src/libraries/xray/symtable.c b/native_client_sdk/src/libraries/xray/symtable.c
new file mode 100644
index 0000000000..b285cb189a
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/symtable.c
@@ -0,0 +1,264 @@
+/* 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.
+ */
+
+/* XRay symbol table */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__GLIBC__)
+#include <dlfcn.h>
+#endif
+
+#include "xray/xray_priv.h"
+
+#if defined(XRAY)
+
+bool g_symtable_debug = false;
+
+struct XRayFrameInfo {
+ int times_called;
+ int total_ticks;
+};
+
+
+struct XRaySymbol {
+ const char* name;
+ struct XRayFrameInfo frames[XRAY_MAX_FRAMES];
+};
+
+
+struct XRaySymbolPoolNode {
+ struct XRaySymbolPoolNode* next;
+ struct XRaySymbol symbols[XRAY_SYMBOL_POOL_NODE_SIZE];
+};
+
+
+struct XRaySymbolPool {
+ struct XRaySymbolPoolNode* head;
+ struct XRaySymbolPoolNode* current;
+ int index;
+};
+
+
+struct XRaySymbolTable {
+ int num_symbols;
+ struct XRayHashTable* hash_table;
+ struct XRayStringPool* string_pool;
+ struct XRaySymbolPool* symbol_pool;
+};
+
+
+const char* XRaySymbolGetName(struct XRaySymbol* symbol) {
+ return (NULL == symbol) ? "(null)" : symbol->name;
+}
+
+
+struct XRaySymbol* XRaySymbolCreate(struct XRaySymbolPool* sympool,
+ const char* name)
+{
+ struct XRaySymbol* symbol;
+ symbol = XRaySymbolPoolAlloc(sympool);
+ symbol->name = name;
+ return symbol;
+}
+
+
+struct XRaySymbol* XRaySymbolPoolAlloc(struct XRaySymbolPool* sympool) {
+ struct XRaySymbol* symbol;
+ if (sympool->index >= XRAY_SYMBOL_POOL_NODE_SIZE) {
+ struct XRaySymbolPoolNode* new_pool;
+ new_pool = (struct XRaySymbolPoolNode*)XRayMalloc(sizeof(*new_pool));
+ sympool->current->next = new_pool;
+ sympool->current = new_pool;
+ sympool->index = 0;
+ }
+ symbol = &sympool->current->symbols[sympool->index];
+ ++sympool->index;
+ return symbol;
+}
+
+
+struct XRaySymbolPool* XRaySymbolPoolCreate() {
+ struct XRaySymbolPool* sympool;
+ struct XRaySymbolPoolNode* node;
+ sympool = (struct XRaySymbolPool*)XRayMalloc(sizeof(*sympool));
+ node = (struct XRaySymbolPoolNode*)XRayMalloc(sizeof(*node));
+ sympool->head = node;
+ sympool->current = node;
+ sympool->index = 0;
+ return sympool;
+}
+
+
+void XRaySymbolPoolFree(struct XRaySymbolPool* pool) {
+ struct XRaySymbolPoolNode* n = pool->head;
+ while (NULL != n) {
+ struct XRaySymbolPoolNode* c = n;
+ n = n->next;
+ XRayFree(c);
+ }
+ XRayFree(pool);
+}
+
+
+int XRaySymbolTableGetSize(struct XRaySymbolTable* symtab) {
+ return XRayHashTableGetSize(symtab->hash_table);
+}
+
+
+struct XRaySymbol* XRaySymbolTableAtIndex(struct XRaySymbolTable* symtab,
+ int i) {
+ return (struct XRaySymbol*)XRayHashTableAtIndex(symtab->hash_table, i);
+}
+
+struct XRaySymbol* XRaySymbolTableAdd(struct XRaySymbolTable* symtab,
+ struct XRaySymbol* symbol,
+ uint32_t addr) {
+ return (struct XRaySymbol*)
+ XRayHashTableInsert(symtab->hash_table, symbol, addr);
+}
+
+struct XRaySymbol* XRaySymbolTableAddByName(struct XRaySymbolTable* symtab,
+ const char* name, uint32_t addr) {
+ char* recorded_name;
+ struct XRaySymbol* symbol;
+ char buffer[XRAY_LINE_SIZE];
+ const char* demangled_name = XRayDemangle(buffer, XRAY_LINE_SIZE, name);
+ /* record the demangled symbol name into the string pool */
+ recorded_name = XRayStringPoolAppend(symtab->string_pool, demangled_name);
+ if (g_symtable_debug)
+ printf("adding symbol %s\n", recorded_name);
+ /* construct a symbol and put it in the symbol table */
+ symbol = XRaySymbolCreate(symtab->symbol_pool, recorded_name);
+ return XRaySymbolTableAdd(symtab, symbol, addr);
+}
+
+struct XRaySymbol* XRaySymbolTableLookup(struct XRaySymbolTable* symtab,
+ uint32_t addr) {
+ void *x = XRayHashTableLookup(symtab->hash_table, addr);
+ struct XRaySymbol* r = (struct XRaySymbol*)x;
+#if defined(__GLIBC__)
+ if (r == NULL) {
+ Dl_info info;
+ if (dladdr((const void*)addr, &info) != 0)
+ if (info.dli_sname)
+ r = XRaySymbolTableAddByName(symtab, info.dli_sname, addr);
+ }
+#endif
+ return r;
+}
+
+struct XRaySymbol* XRaySymbolTableCreateEntry(struct XRaySymbolTable* symtab,
+ const char* line) {
+ uint32_t addr;
+ unsigned int uiaddr;
+ char symbol_text[XRAY_LINE_SIZE];
+ char* parsed_symbol;
+ char* newln;
+ sscanf(line,"%x %s", &uiaddr, symbol_text);
+ if (uiaddr > 0x07FFFFFF) {
+ printf("While parsing the mapfile, XRay encountered:\n");
+ printf("%s\n", line);
+ printf("XRay only works with code addresses 0x00000000 - 0x07FFFFFF\n");
+ printf("All functions must reside in this address space.\n");
+ exit(-1);
+ }
+ addr = (uint32_t)uiaddr;
+ parsed_symbol = strstr(line, symbol_text);
+ newln = strstr(parsed_symbol, "\n");
+ if (NULL != newln) {
+ *newln = 0;
+ }
+ return XRaySymbolTableAddByName(symtab, parsed_symbol, addr);
+}
+
+
+void XRaySymbolTableParseMapfile(struct XRaySymbolTable* symtab,
+ const char* mapfile)
+{
+ FILE* f;
+ char line[XRAY_LINE_SIZE];
+ bool in_text = false;
+ bool in_link_once = false;
+ int in_link_once_counter = 0;
+ int num_symbols = 0;
+
+ printf("XRay: opening mapfile %s\n", mapfile);
+ f = fopen(mapfile, "rt");
+ if (0 != f) {
+ printf("XRay: parsing...\n");
+ while(NULL != fgets(line, XRAY_LINE_SIZE, f)) {
+ if (line == strstr(line, " .text ")) {
+ in_text = true;
+ continue;
+ }
+ if (line == strstr(line, " .gnu.linkonce.t.")) {
+ in_link_once = true;
+ in_link_once_counter = 0;
+ continue;
+ }
+ if (line == strstr(line, " .text.")) {
+ in_link_once = true;
+ in_link_once_counter = 0;
+ continue;
+ }
+ if (line == strstr(line, " 0x")) {
+ if (in_text) {
+ XRaySymbolTableCreateEntry(symtab, line);
+ ++num_symbols;
+ } else if (in_link_once) {
+ if (in_link_once_counter != 0) {
+ XRaySymbolTableCreateEntry(symtab, line);
+ ++num_symbols;
+ } else {
+ ++in_link_once_counter;
+ }
+ }
+ } else {
+ in_text = false;
+ in_link_once = false;
+ }
+ }
+ fclose(f);
+ printf("XRay: loaded %d symbols into symbol table\n", num_symbols);
+ } else {
+ printf("XRay: failed to open %s\n", mapfile);
+ }
+ symtab->num_symbols += num_symbols;
+}
+
+
+/* Returns total number of symbols in the table. */
+int XRaySymbolCount(struct XRaySymbolTable* symtab) {
+ return symtab->num_symbols;
+}
+
+
+/* Creates and inializes a symbol table. */
+struct XRaySymbolTable* XRaySymbolTableCreate(int size) {
+ struct XRaySymbolTable* symtab;
+ symtab = (struct XRaySymbolTable*)XRayMalloc(sizeof(*symtab));
+ symtab->num_symbols = 0;
+ symtab->string_pool = XRayStringPoolCreate();
+ symtab->hash_table = XRayHashTableCreate(size);
+ symtab->symbol_pool = XRaySymbolPoolCreate();
+ return symtab;
+}
+
+
+/* Frees a symbol table. */
+void XRaySymbolTableFree(struct XRaySymbolTable* symtab) {
+ XRayStringPoolFree(symtab->string_pool);
+ XRaySymbolPoolFree(symtab->symbol_pool);
+ XRayHashTableFree(symtab->hash_table);
+ symtab->num_symbols = 0;
+ XRayFree(symtab);
+}
+
+#endif /* XRAY */
diff --git a/native_client_sdk/src/libraries/xray/xray.c b/native_client_sdk/src/libraries/xray/xray.c
new file mode 100644
index 0000000000..6a3f3ae689
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/xray.c
@@ -0,0 +1,825 @@
+/* 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.
+ */
+
+
+/* XRay -- a simple profiler for Native Client */
+
+#include <alloca.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "xray/xray_priv.h"
+
+#if defined(XRAY)
+
+#define FORCE_INLINE __attribute__((always_inline))
+
+#if defined(__amd64__)
+FORCE_INLINE uint64_t RDTSC64() {
+ uint64_t a, d;
+ __asm__ __volatile__("rdtsc" : "=a" (a), "=d" (d));
+ return ((uint64_t)a) | (((uint64_t)d) << 32);
+}
+#define RDTSC(_x) _x = RDTSC64()
+#else
+#define RDTSC(_x) __asm__ __volatile__ ("rdtsc" : "=A" (_x));
+#endif
+
+
+/* Use a TLS variable for cheap thread uid. */
+volatile __thread int g_xray_thread_id;
+
+
+struct XRayTraceStackEntry {
+ uint32_t depth_addr;
+ uint64_t tsc;
+ uint32_t dest;
+ uint32_t annotation_index;
+};
+
+
+struct XRayTraceBufferEntry {
+ uint32_t depth_addr;
+ uint32_t annotation_index;
+ uint64_t ticks;
+};
+
+
+struct XRayTraceFrameEntry {
+ /* Indices into global tracebuffer */
+ int start;
+ int end;
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t total_ticks;
+ int annotation_count;
+ bool valid;
+};
+
+
+struct XRayTraceFrame {
+ struct XRayTraceFrameEntry* entry;
+ int head;
+ int tail;
+ int count;
+};
+
+
+struct XRayTotal {
+ int index;
+ int frame;
+ uint64_t ticks;
+};
+
+
+struct XRayTraceCapture {
+ /* Common variables share cache line */
+ volatile void* recording;
+ uint32_t stack_depth;
+ uint32_t max_stack_depth;
+ int buffer_index;
+ int buffer_size;
+ int disabled;
+ int annotation_count;
+ struct XRaySymbolTable* symbols;
+ bool initialized;
+ uint32_t annotation_filter;
+ uint32_t guard0;
+ struct XRayTraceStackEntry stack[XRAY_TRACE_STACK_SIZE] XRAY_ALIGN64;
+ uint32_t guard1;
+ char annotation[XRAY_ANNOTATION_STACK_SIZE] XRAY_ALIGN64;
+ uint32_t guard2;
+ struct XRayTraceBufferEntry* buffer;
+ struct XRayTraceFrame frame;
+} XRAY_ALIGN64;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+XRAY_NO_INSTRUMENT void __cyg_profile_func_enter(void* this_fn,
+ void* call_site);
+XRAY_NO_INSTRUMENT void __cyg_profile_func_exit(void* this_fn,
+ void* call_site);
+XRAY_NO_INSTRUMENT void __xray_profile_append_annotation(
+ struct XRayTraceStackEntry* se, struct XRayTraceBufferEntry* be);
+XRAY_NO_INSTRUMENT int XRayTraceBufferGetTraceCountForFrame(int frame);
+XRAY_NO_INSTRUMENT int XRayTraceBufferIncrementIndex(int i);
+XRAY_NO_INSTRUMENT int XRayTraceBufferDecrementIndex(int i);
+XRAY_NO_INSTRUMENT bool XRayTraceBufferIsAnnotation(int index);
+XRAY_NO_INSTRUMENT void XRayTraceBufferAppendString(char* src);
+XRAY_NO_INSTRUMENT int XRayTraceBufferCopyToString(int index, char* dst);
+XRAY_NO_INSTRUMENT int XRayTraceBufferSkipAnnotation(int index);
+XRAY_NO_INSTRUMENT int XRayTraceBufferNextEntry(int index);
+XRAY_NO_INSTRUMENT void XRayCheckGuards();
+XRAY_NO_INSTRUMENT void XRayFrameMakeLabel(int counter, char* label);
+XRAY_NO_INSTRUMENT int XRayFrameFindTail();
+
+#ifdef __cplusplus
+}
+#endif
+
+
+struct XRayTraceCapture g_xray = {
+ NULL, 0, 0, 0, 0, 0, 0, NULL, false, 0xFFFFFFFF
+};
+
+
+/* Increments the trace index, wrapping around if needed. */
+XRAY_FORCE_INLINE int XRayTraceBufferIncrementIndex(int index) {
+ ++index;
+ if (index >= g_xray.buffer_size)
+ index = 0;
+ return index;
+}
+
+
+/* Decrements the trace index, wrapping around if needed. */
+XRAY_FORCE_INLINE int XRayTraceBufferDecrementIndex(int index) {
+ --index;
+ if (index < 0)
+ index = g_xray.buffer_size - 1;
+ return index;
+}
+
+
+/* Returns true if the trace entry is an annotation string. */
+FORCE_INLINE bool XRayTraceBufferIsAnnotation(int index) {
+ struct XRayTraceBufferEntry* be = &g_xray.buffer[index];
+ char* dst = (char*)be;
+ return 0 == *dst;
+}
+
+
+/* Asserts that the guard values haven't changed. */
+void XRayCheckGuards() {
+ assert(g_xray.guard0 == XRAY_GUARD_VALUE);
+ assert(g_xray.guard1 == XRAY_GUARD_VALUE);
+ assert(g_xray.guard2 == XRAY_GUARD_VALUE);
+}
+
+
+/* Not very accurate, as the annotation strings will also
+** be counted as "entries" */
+int XRayTraceBufferGetTraceCountForFrame(int frame) {
+ assert(true == g_xray.initialized);
+ assert(frame >= 0);
+ assert(frame < g_xray.frame.count);
+ assert(NULL == g_xray.recording);
+ int start = g_xray.frame.entry[frame].start;
+ int end = g_xray.frame.entry[frame].end;
+ int num;
+ if (start < end)
+ num = end - start;
+ else
+ num = g_xray.buffer_size - (start - end);
+ return num;
+}
+
+
+/* Generic memory malloc for XRay */
+/* validates pointer returned by malloc */
+/* memsets memory block to zero */
+void* XRayMalloc(size_t t) {
+ void* data;
+ data = malloc(t);
+ if (NULL == data) {
+ printf("XRay: malloc(%d) failed, panic shutdown!\n", t);
+ exit(-1);
+ }
+ memset(data, 0, t);
+ return data;
+}
+
+
+/* Generic memory free for XRay */
+void XRayFree(void* data) {
+ assert(NULL != data);
+ free(data);
+}
+
+
+/* Append a string to trace buffer. */
+void XRayTraceBufferAppendString(char* src) {
+ int index = g_xray.buffer_index;
+ bool done = false;
+ int start_index = 1;
+ int s = 0;
+ int i;
+ char* dst = (char*)&g_xray.buffer[index];
+ const int num = sizeof(g_xray.buffer[index]);
+ dst[0] = 0;
+ while (!done) {
+ for (i = start_index; i < num; ++i) {
+ dst[i] = src[s];
+ if (0 == src[s]) {
+ dst[i] = 0;
+ done = true;
+ break;
+ }
+ ++s;
+ }
+ index = XRayTraceBufferIncrementIndex(index);
+ dst = (char*)&g_xray.buffer[index];
+ start_index = 0;
+ }
+ g_xray.buffer_index = index;
+}
+
+
+/* Copies annotation from trace buffer to output string. */
+int XRayTraceBufferCopyToString(int index, char* dst) {
+ assert(XRayTraceBufferIsAnnotation(index));
+ bool done = false;
+ int i;
+ int d = 0;
+ int start_index = 1;
+ while (!done) {
+ char* src = (char*) &g_xray.buffer[index];
+ const int num = sizeof(g_xray.buffer[index]);
+ for (i = start_index; i < num; ++i) {
+ dst[d] = src[i];
+ if (0 == src[i]) {
+ done = true;
+ break;
+ }
+ ++d;
+ }
+ index = XRayTraceBufferIncrementIndex(index);
+ start_index = 0;
+ }
+ return index;
+}
+
+
+/* Main profile capture function that is called at the start */
+/* of every instrumented function. This function is implicitly */
+/* called when code is compilied with the -finstrument-functions option */
+void __cyg_profile_func_enter(void* this_fn, void* call_site) {
+ if (&g_xray_thread_id == g_xray.recording) {
+ uint32_t depth = g_xray.stack_depth;
+ if (depth < g_xray.max_stack_depth) {
+ struct XRayTraceStackEntry* se = &g_xray.stack[depth];
+ uint32_t addr = (uint32_t)this_fn;
+ se->depth_addr = XRAY_PACK_DEPTH_ADDR(depth, addr);
+ se->dest = g_xray.buffer_index;
+ se->annotation_index = 0;
+ RDTSC(se->tsc);
+ g_xray.buffer_index =
+ XRayTraceBufferIncrementIndex(g_xray.buffer_index);
+ }
+ ++g_xray.stack_depth;
+ }
+}
+
+
+/* Main profile capture function that is called at the exit of */
+/* every instrumented function. This function is implicity called */
+/* when the code is compiled with the -finstrument-functions option */
+void __cyg_profile_func_exit(void* this_fn, void* call_site) {
+ if (&g_xray_thread_id == g_xray.recording) {
+ --g_xray.stack_depth;
+ if (g_xray.stack_depth < g_xray.max_stack_depth) {
+ uint32_t depth = g_xray.stack_depth;
+ struct XRayTraceStackEntry* se = &g_xray.stack[depth];
+ uint32_t buffer_index = se->dest;
+ uint64_t tsc;
+ struct XRayTraceBufferEntry* be = &g_xray.buffer[buffer_index];
+ RDTSC(tsc);
+ be->depth_addr = se->depth_addr;
+ be->ticks = tsc - se->tsc;
+ be->annotation_index = 0;
+ if (0 != se->annotation_index)
+ __xray_profile_append_annotation(se, be);
+ }
+ }
+}
+
+
+/* Special case appending annotation string to trace buffer */
+/* this function should only ever be called from __cyg_profile_func_exit() */
+void __xray_profile_append_annotation(struct XRayTraceStackEntry* se,
+ struct XRayTraceBufferEntry* be) {
+ struct XRayTraceStackEntry* parent = se - 1;
+ int start = parent->annotation_index;
+ be->annotation_index = g_xray.buffer_index;
+ char* str = &g_xray.annotation[start];
+ XRayTraceBufferAppendString(str);
+ *str = 0;
+ ++g_xray.annotation_count;
+}
+
+
+
+/* Annotates the trace buffer. no filtering. */
+void __XRayAnnotate(const char* fmt, ...) {
+ va_list args;
+ /* Only annotate functions recorded in the trace buffer. */
+ if (true == g_xray.initialized) {
+ if (0 == g_xray.disabled) {
+ if (&g_xray_thread_id == g_xray.recording) {
+ char buffer[1024];
+ int r;
+ va_start(args, fmt);
+ r = vsnprintf(buffer, sizeof(buffer), fmt, args);
+ va_end(args);
+ {
+ /* Get current string ptr */
+ int depth = g_xray.stack_depth - 1;
+ struct XRayTraceStackEntry* se = &g_xray.stack[depth];
+ if (0 == se->annotation_index) {
+ struct XRayTraceStackEntry* parent = se - 1;
+ se->annotation_index = parent->annotation_index;
+ }
+ char* dst = &g_xray.annotation[se->annotation_index];
+ strcpy(dst, buffer);
+ int len = strlen(dst);
+ se->annotation_index += len;
+ }
+ }
+ }
+ }
+}
+
+
+/* Annotates the trace buffer with user strings. Can be filtered. */
+void __XRayAnnotateFiltered(const uint32_t filter, const char* fmt, ...) {
+ va_list args;
+ if (true == g_xray.initialized) {
+ if (0 != (filter & g_xray.annotation_filter)) {
+ if (0 == g_xray.disabled) {
+ if (&g_xray_thread_id == g_xray.recording) {
+ char buffer[1024];
+ int r;
+ va_start(args, fmt);
+ r = vsnprintf(buffer, sizeof(buffer), fmt, args);
+ va_end(args);
+ {
+ /* get current string ptr */
+ int depth = g_xray.stack_depth - 1;
+ struct XRayTraceStackEntry* se = &g_xray.stack[depth];
+ if (0 == se->annotation_index) {
+ struct XRayTraceStackEntry* parent = se - 1;
+ se->annotation_index = parent->annotation_index;
+ }
+ char* dst = &g_xray.annotation[se->annotation_index];
+ strcpy(dst, buffer);
+ int len = strlen(dst);
+ se->annotation_index += len;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/* Allows user to specify annotation filter value, a 32 bit mask. */
+void XRaySetAnnotationFilter(uint32_t filter) {
+ g_xray.annotation_filter = filter;
+}
+
+
+/* Reset xray profiler. */
+void XRayReset() {
+ assert(true == g_xray.initialized);
+ assert(NULL == g_xray.recording);
+ g_xray.buffer_index = 0;
+ g_xray.stack_depth = 0;
+ g_xray.disabled = 0;
+ g_xray.frame.head = 0;
+ g_xray.frame.tail = 0;
+ memset(g_xray.frame.entry, 0,
+ sizeof(g_xray.frame.entry[0]) * g_xray.frame.count);
+ memset(&g_xray.stack, 0,
+ sizeof(g_xray.stack[0]) * XRAY_TRACE_STACK_SIZE);
+ XRayCheckGuards();
+}
+
+
+/* Change the maximum stack depth captures are made. */
+void XRaySetMaxStackDepth(int stack_depth) {
+ assert(true == g_xray.initialized);
+ assert(NULL == g_xray.recording);
+ if (stack_depth < 1)
+ stack_depth = 1;
+ if (stack_depth >= XRAY_TRACE_STACK_SIZE)
+ stack_depth = (XRAY_TRACE_STACK_SIZE - 1);
+ g_xray.max_stack_depth = stack_depth;
+}
+
+
+int XRayFramePrev(int i) {
+ i = i - 1;
+ if (i < 0)
+ i = g_xray.frame.count - 1;
+ return i;
+}
+
+
+int XRayFrameNext(int i) {
+ i = i + 1;
+ if (i >= g_xray.frame.count)
+ i = 0;
+ return i;
+}
+
+
+void XRayFrameMakeLabel(int counter, char* label) {
+ snprintf(label, XRAY_MAX_LABEL, "@@@frame%d", counter);
+}
+
+
+/* Scans the ring buffer going backwards to find last valid complete frame. */
+int XRayFrameFindTail() {
+ int head = g_xray.frame.head;
+ int index = XRayFramePrev(head);
+ int total_capture = 0;
+ int last_valid_frame = index;
+ /* Check for no captures */
+ if (g_xray.frame.head == g_xray.frame.tail)
+ return g_xray.frame.head;
+ /* Go back and invalidate all captures that have been stomped. */
+ while (index != head) {
+ bool valid = g_xray.frame.entry[index].valid;
+ if (valid) {
+ total_capture += XRayTraceBufferGetTraceCountForFrame(index) + 1;
+ if (total_capture < g_xray.buffer_size) {
+ last_valid_frame = index;
+ g_xray.frame.entry[index].valid = true;
+ } else {
+ g_xray.frame.entry[index].valid = false;
+ }
+ }
+ index = XRayFramePrev(index);
+ }
+ return last_valid_frame;
+}
+
+
+/* Starts a new frame and enables capturing, */
+/* must be paired with XRayEndFrame() */
+void XRayStartFrame() {
+ int i = g_xray.frame.head;
+ assert(true == g_xray.initialized);
+ assert(NULL == g_xray.recording);
+ XRayCheckGuards();
+ /* Add a trace entry marker so we can detect wrap around stomping */
+ struct XRayTraceBufferEntry* be = &g_xray.buffer[g_xray.buffer_index];
+ be->depth_addr = XRAY_FRAME_MARKER;
+ g_xray.buffer_index = XRayTraceBufferIncrementIndex(g_xray.buffer_index);
+ /* Set start of the frame we're about to trace */
+ g_xray.frame.entry[i].start = g_xray.buffer_index;
+ g_xray.disabled = 0;
+ g_xray.stack_depth = 1;
+ /* The trace stack[0] is reserved */
+ memset(&g_xray.stack[0], 0, sizeof(g_xray.stack[0]));
+ /* Annotation index 0 is reserved to indicate no annotation */
+ g_xray.stack[0].annotation_index = 1;
+ g_xray.annotation[0] = 0;
+ g_xray.annotation[1] = 0;
+ g_xray.annotation_count = 0;
+ g_xray.recording = &g_xray_thread_id;
+ RDTSC(g_xray.frame.entry[i].start_tsc);
+}
+
+
+/* Ends a frame and disables capturing. */
+/* Must be paired with XRayStartFrame() */
+/* Advances to the next frame. */
+void XRayEndFrame() {
+ int i = g_xray.frame.head;
+ assert(true == g_xray.initialized);
+ assert(NULL != g_xray.recording);
+ assert(0 == g_xray.disabled);
+ assert(1 == g_xray.stack_depth);
+ RDTSC(g_xray.frame.entry[i].end_tsc);
+ g_xray.frame.entry[i].total_ticks =
+ g_xray.frame.entry[i].end_tsc - g_xray.frame.entry[i].start_tsc;
+ g_xray.recording = NULL;
+ g_xray.frame.entry[i].end = g_xray.buffer_index;
+ g_xray.frame.entry[i].valid = true;
+ g_xray.frame.entry[i].annotation_count = g_xray.annotation_count;
+ g_xray.frame.head = XRayFrameNext(g_xray.frame.head);
+ /* If the table is filled, bump the tail. */
+ if (g_xray.frame.head == g_xray.frame.tail)
+ g_xray.frame.tail = XRayFrameNext(g_xray.frame.tail);
+ g_xray.frame.tail = XRayFrameFindTail();
+ /* Check that we didn't stomp over trace entry marker. */
+ int marker = XRayTraceBufferDecrementIndex(g_xray.frame.entry[i].start);
+ struct XRayTraceBufferEntry* be = &g_xray.buffer[marker];
+ if (be->depth_addr != XRAY_FRAME_MARKER) {
+ fprintf(stderr,
+ "XRay: XRayStopFrame() detects insufficient trace buffer size!\n");
+ XRayReset();
+ } else {
+ /* Replace marker with an empty annotation string. */
+ be->depth_addr = XRAY_NULL_ANNOTATION;
+ XRayCheckGuards();
+ }
+}
+
+
+/* Get the last frame captured. Do not call while capturing. */
+/* (ie call outside of XRayStartFrame() / XRayStopFrame() pair) */
+int XRayGetLastFrame() {
+ assert(true == g_xray.initialized);
+ assert(NULL == g_xray.recording);
+ assert(0 == g_xray.disabled);
+ assert(1 == g_xray.stack_depth);
+ int last_frame = XRayFramePrev(g_xray.frame.head);
+ return last_frame;
+}
+
+
+/* Disables capturing until a paired XRayEnableCapture() is called */
+/* This call can be nested, but must be paired with an enable */
+/* (If you need to just exclude a specific function and not its */
+/* children, the XRAY_NO_INSTRUMENT modifier might be better) */
+void XRayDisableCapture() {
+ assert(true == g_xray.initialized);
+ assert(NULL != g_xray.recording);
+ ++g_xray.disabled;
+ g_xray.recording = NULL;
+}
+
+
+/* Re-enables capture. Must be paired with XRayDisableCapture() */
+void XRayEnableCapture() {
+ assert(true == g_xray.initialized);
+ assert(NULL == g_xray.recording);
+ assert(0 < g_xray.disabled);
+ --g_xray.disabled;
+ if (0 == g_xray.disabled) {
+ g_xray.recording = &g_xray_thread_id;
+ }
+}
+
+
+/* The entry in the tracebuffer at index is an annotation string. */
+/* Calculate the next index value representing the next trace entry. */
+int XRayTraceBufferSkipAnnotation(int index) {
+ /* Annotations are strings embedded in the trace buffer. */
+ /* An annotation string can span multiple trace entries. */
+ /* Skip over the string by looking for zero termination. */
+ assert(XRayTraceBufferIsAnnotation(index));
+ bool done = false;
+ int start_index = 1;
+ int i;
+ while (!done) {
+ char* str = (char*) &g_xray.buffer[index];
+ const int num = sizeof(g_xray.buffer[index]);
+ for (i = start_index; i < num; ++i) {
+ if (0 == str[i]) {
+ done = true;
+ break;
+ }
+ }
+ index = XRayTraceBufferIncrementIndex(index);
+ start_index = 0;
+ }
+ return index;
+}
+
+
+/* Starting at index, return the index into the trace buffer */
+/* for the next trace entry. Index can wrap (ringbuffer) */
+int XRayTraceBufferNextEntry(int index) {
+ if (XRayTraceBufferIsAnnotation(index))
+ index = XRayTraceBufferSkipAnnotation(index);
+ else
+ index = XRayTraceBufferIncrementIndex(index);
+ return index;
+}
+
+
+/* Dumps the trace report for a given frame. */
+void XRayTraceReport(FILE* f, int frame, char* label,
+ float percent_cutoff, int ticks_cutoff) {
+ int index;
+ int start;
+ int end;
+ float total;
+ char space[257];
+ memset(space, ' ', 256);
+ space[256] = 0;
+ if (NULL == f) {
+ f = stdout;
+ }
+ fprintf(f,
+ "======================================================================\n");
+ if (NULL != label)
+ fprintf(f, "label %s\n", label);
+ fprintf(f, "\n");
+ fprintf(f,
+ " Address Ticks Percent Function <optional annotation>\n");
+ fprintf(f,
+ "----------------------------------------------------------------------\n");
+ start = g_xray.frame.entry[frame].start;
+ end = g_xray.frame.entry[frame].end;
+ total = (float)g_xray.frame.entry[frame].total_ticks;
+ index = start;
+ while (index != end) {
+ if (!XRayTraceBufferIsAnnotation(index)) {
+ const char* symbol_name;
+ char annotation[1024];
+ struct XRayTraceBufferEntry* e = &g_xray.buffer[index];
+ uint32_t depth = XRAY_EXTRACT_DEPTH(e->depth_addr);
+ uint32_t addr = XRAY_EXTRACT_ADDR(e->depth_addr);
+ uint32_t ticks = (e->ticks);
+ uint32_t annotation_index = (e->annotation_index);
+ float percent = 100.0f * (float)ticks / total;
+ if (percent >= percent_cutoff && ticks >= ticks_cutoff) {
+ struct XRaySymbol* symbol;
+ symbol = XRaySymbolTableLookup(g_xray.symbols, addr);
+ symbol_name = XRaySymbolGetName(symbol);
+ if (0 != annotation_index) {
+ XRayTraceBufferCopyToString(annotation_index, annotation);
+ } else {
+ strcpy(annotation, "");
+ }
+ fprintf(f, "0x%08X %10ld %5.1f %s%s %s\n",
+ (unsigned int)addr, (int64_t)ticks, percent,
+ &space[256 - depth], symbol_name, annotation);
+ }
+ }
+ index = XRayTraceBufferNextEntry(index);
+ }
+}
+
+
+int qcompare(const void* a, const void* b) {
+ struct XRayTotal* ia = (struct XRayTotal*)a;
+ struct XRayTotal* ib = (struct XRayTotal*)b;
+ return ib->ticks - ia->ticks;
+}
+
+
+/* Dumps a frame report */
+void XRayFrameReport(FILE* f) {
+ int i;
+ int head;
+ int frame;
+ int counter = 0;
+ int total_capture = 0;
+ struct XRayTotal* totals;
+ totals = (struct XRayTotal*)
+ alloca(g_xray.frame.count * sizeof(struct XRayTotal));
+ frame = g_xray.frame.tail;
+ head = g_xray.frame.head;
+ fprintf(f, "\n");
+ fprintf(f,
+ "Frame# Total Ticks Capture size Annotations Label\n");
+ fprintf(f,
+ "----------------------------------------------------------------------\n");
+ while (frame != head) {
+ int64_t total_ticks = g_xray.frame.entry[frame].total_ticks;
+ int capture_size = XRayTraceBufferGetTraceCountForFrame(frame);
+ int annotation_count = g_xray.frame.entry[frame].annotation_count;
+ bool valid = g_xray.frame.entry[frame].valid;
+ char label[XRAY_MAX_LABEL];
+ XRayFrameMakeLabel(counter, label);
+ fprintf(f, " %3d %s %10ld %10d %10d %s\n",
+ counter,
+ valid ? " " : "*",
+ (int64_t)total_ticks,
+ capture_size,
+ annotation_count,
+ label);
+ totals[counter].index = counter;
+ totals[counter].frame = frame;
+ totals[counter].ticks = total_ticks;
+ total_capture += capture_size;
+ frame = XRayFrameNext(frame);
+ ++counter;
+ }
+ fprintf(f,
+ "----------------------------------------------------------------------\n");
+ fprintf(f,
+ "XRay: %d frame(s) %d total capture(s)\n", counter, total_capture);
+ fprintf(f, "\n");
+ /* Sort and take average of the median cut */
+ qsort(totals, counter, sizeof(struct XRayTotal), qcompare);
+ fprintf(f, "\n");
+ fprintf(f, "Sorted by total ticks (most expensive first):\n");
+ fprintf(f, "\n");
+ fprintf(f,
+ "Frame# Total Ticks Capture size Annotations Label\n");
+ fprintf(f,
+ "----------------------------------------------------------------------\n");
+ for (i = 0; i < counter; ++i) {
+ int index = totals[i].index;
+ int frame = totals[i].frame;
+ int64_t total_ticks = g_xray.frame.entry[frame].total_ticks;
+ int capture_size = XRayTraceBufferGetTraceCountForFrame(frame);
+ int annotation_count = g_xray.frame.entry[frame].annotation_count;
+ char label[XRAY_MAX_LABEL];
+ XRayFrameMakeLabel(index, label);
+ fprintf(f, " %3d %10ld %10d %10d %s\n",
+ index,
+ (int64_t)total_ticks,
+ capture_size,
+ annotation_count,
+ label);
+ }
+}
+
+
+/* Dump a frame report followed by trace report(s) for each frame. */
+void XRayReport(FILE* f, float percent_cutoff, int ticks_cutoff) {
+ int head;
+ int index;
+ int counter = 0;
+ if (g_xray.symbols)
+ fprintf(f, "Number of symbols: %d\n", XRaySymbolCount(g_xray.symbols));
+ XRayFrameReport(f);
+ fprintf(f, "\n");
+ head = g_xray.frame.head;
+ index = g_xray.frame.tail;
+ while (index != head) {
+ char label[XRAY_MAX_LABEL];
+ fprintf(f, "\n");
+ XRayFrameMakeLabel(counter, label);
+ XRayTraceReport(f, index, label, percent_cutoff, ticks_cutoff);
+ index = XRayFrameNext(index);
+
+ ++counter;
+ }
+ fprintf(f,
+ "======================================================================\n");
+#if defined(XRAY_OUTPUT_HASH_COLLISIONS)
+ XRayHashTableHisto(f);
+#endif
+ fflush(f);
+}
+
+
+/* Write a profile report to text file. */
+void XRaySaveReport(const char* filename,
+ float percent_cutoff,
+ int ticks_cutoff) {
+ FILE* f;
+ f = fopen(filename, "wt");
+ if (NULL != f) {
+ XRayReport(f, percent_cutoff, ticks_cutoff);
+ fclose(f);
+ }
+}
+
+
+/* Initialize XRay */
+void XRayInit(int stack_depth, int buffer_size, int frame_count,
+ const char* mapfilename) {
+ int adj_frame_count = frame_count + 1;
+ assert(false == g_xray.initialized);
+ size_t buffer_size_in_bytes =
+ sizeof(g_xray.buffer[0]) * buffer_size;
+ size_t frame_size_in_bytes =
+ sizeof(g_xray.frame.entry[0]) * adj_frame_count;
+ g_xray.buffer =
+ (struct XRayTraceBufferEntry *)XRayMalloc(buffer_size_in_bytes);
+ g_xray.frame.entry =
+ (struct XRayTraceFrameEntry *)XRayMalloc(frame_size_in_bytes);
+
+ g_xray.buffer_size = buffer_size;
+ g_xray.frame.count = adj_frame_count;
+ g_xray.frame.head = 0;
+ g_xray.frame.tail = 0;
+ g_xray.disabled = 0;
+ g_xray.annotation_filter = 0xFFFFFFFF;
+ g_xray.guard0 = XRAY_GUARD_VALUE;
+ g_xray.guard1 = XRAY_GUARD_VALUE;
+ g_xray.guard2 = XRAY_GUARD_VALUE;
+ g_xray.initialized = true;
+ XRaySetMaxStackDepth(stack_depth);
+ XRayReset();
+
+ /* Mapfile is optional; we don't need it for captures, only for reports. */
+ g_xray.symbols = XRaySymbolTableCreate(XRAY_DEFAULT_SYMBOL_TABLE_SIZE);
+ if (NULL != mapfilename)
+ XRaySymbolTableParseMapfile(g_xray.symbols, mapfilename);
+}
+
+
+/* Shut down and free memory used by XRay. */
+void XRayShutdown() {
+ assert(true == g_xray.initialized);
+ assert(NULL == g_xray.recording);
+ XRayCheckGuards();
+ if (NULL != g_xray.symbols) {
+ XRaySymbolTableFree(g_xray.symbols);
+ }
+ XRayFree(g_xray.frame.entry);
+ XRayFree(g_xray.buffer);
+ g_xray.initialized = false;
+}
+
+#endif /* XRAY */
diff --git a/native_client_sdk/src/libraries/xray/xray.h b/native_client_sdk/src/libraries/xray/xray.h
new file mode 100644
index 0000000000..9039fdcc79
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/xray.h
@@ -0,0 +1,84 @@
+/* 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.
+ */
+
+/* XRay -- a simple profiler for Native Client */
+
+
+#ifndef LIBRARIES_XRAY_XRAY_H_
+#define LIBRARIES_XRAY_XRAY_H_
+
+#include <stdint.h>
+
+#if defined(__arm__)
+#undef XRAY
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define XRAY_NO_INSTRUMENT __attribute__((no_instrument_function))
+#define XRAY_INLINE __attribute__((always_inline, no_instrument_function))
+
+#if defined(XRAY)
+
+/* Do not call __XRayAnnotate* directly; instead use the */
+/* XRayAnnotate() macros below. */
+XRAY_NO_INSTRUMENT void __XRayAnnotate(const char* str, ...)
+ __attribute__ ((format(printf, 1, 2)));
+XRAY_NO_INSTRUMENT void __XRayAnnotateFiltered(const uint32_t filter,
+ const char* str, ...) __attribute__ ((format(printf, 2, 3)));
+
+/* This is the beginning of the public XRay API */
+
+/* Ok if mapfilename is NULL, no symbols will be loaded. On glibc builds,
+ * XRay will also attempt to populate the symbol table with dladdr()
+ */
+XRAY_NO_INSTRUMENT void XRayInit(int stack_size, int buffer_size,
+ int frame_count, const char* mapfilename);
+XRAY_NO_INSTRUMENT void XRayShutdown();
+XRAY_NO_INSTRUMENT void XRayStartFrame();
+XRAY_NO_INSTRUMENT void XRayEndFrame();
+XRAY_NO_INSTRUMENT void XRaySetAnnotationFilter(uint32_t filter);
+XRAY_NO_INSTRUMENT void XRaySaveReport(const char* filename,
+ float percent_cutoff,
+ int cycle_cutoff);
+XRAY_NO_INSTRUMENT void XRayReport(FILE* f,
+ float percent_cutoff,
+ int ticks_cutoff);
+#if defined(XRAY_ANNOTATE)
+#define XRayAnnotate(...) __XRayAnnotate(__VA_ARGS__)
+#define XRayAnnotateFiltered(...) __XRayAnnotateFiltered(__VA_ARGS__)
+#else
+#define XRayAnnotate(...)
+#define XRayAnnotateFiltered(...)
+#endif
+/* This is the end of the public XRay API */
+
+#else /* defined(XRAY) */
+
+/* Builds that don't define XRAY will use these 'null' functions instead. */
+
+#define XRayAnnotate(...)
+#define XRayAnnotateFiltered(...)
+
+inline void XRayInit(int stack_size, int buffer_size,
+ int frame_count, const char* mapfilename) {}
+inline void XRayShutdown() {}
+inline void XRayStartFrame() {}
+inline void XRayEndFrame() {}
+inline void XRaySetAnnotationFilter(uint32_t filter) {}
+inline void XRaySaveReport(const char* filename,
+ float percent_cutoff,
+ int cycle_cutoff) {}
+inline void XRayReport(FILE* f, float percent_cutoff, int ticks_cutoff);
+#endif /* defined(XRAY) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBRARIES_XRAY_XRAY_H_ */
+
diff --git a/native_client_sdk/src/libraries/xray/xray.html b/native_client_sdk/src/libraries/xray/xray.html
new file mode 100644
index 0000000000..6c249a2d1b
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/xray.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
+ <TITLE></TITLE>
+ <META NAME="GENERATOR" CONTENT="LibreOffice 3.5 (Linux)">
+ <META NAME="AUTHOR" CONTENT="Nicholas Fullagar">
+ <META NAME="CREATED" CONTENT="20130521;14423200">
+ <META NAME="CHANGEDBY" CONTENT="Nicholas Fullagar">
+ <META NAME="CHANGED" CONTENT="20130619;14414300">
+ <STYLE TYPE="text/css">
+ <!--
+ @page { margin: 0.79in }
+ P { margin-bottom: 0.08in }
+ -->
+ </STYLE>
+</HEAD>
+<BODY LANG="en-US" DIR="LTR">
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN STYLE="font-weight: normal">Guests,
+introduction.</SPAN></FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><BR>
+</P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN STYLE="font-weight: normal">Brief
+description of other PACC meetings.</SPAN></FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><BR>
+</P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN STYLE="font-weight: normal">Dan
+Hughes</SPAN></FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><BR>
+</P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3><SPAN STYLE="font-weight: normal">Dan
+attended Rochester Institute of Technology, studying advertising
+photography and specializing in digital engineering. After
+graduating, Dan worked as a commercial shooter, digital retoucher and
+ for a stint ran a fine art photography gallery, making and framing
+fine art prints. For the past three years, Dan has been organizing,
+creating and delivering photography education for Nik Software and
+now Google.</SPAN></FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><BR>
+</P>
+<P STYLE="margin-bottom: 0in"><BR>
+</P>
+<P STYLE="margin-bottom: 0in"><BR>
+</P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Nik
+Module Votes (*) </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>------------------------------
+-------------------- </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Sharpener:
+ XXXXXoooo:.. </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Silver
+Efex: XXXXoo:.. </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Dfine:
+ XXXo:::.... </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Viveza:
+ Xoo:... </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Color
+Efex: o::... </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>HDR
+Efex: X:.... </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3> </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>(*)
+key: X first o second : third . fourth+all </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3> </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3> </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3> </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Software
+ Votes (**) Total </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>------------------------------
+-------------------- </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Lightroom:
+ XXXXXoooo 9 </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Photoshop:
+ XXXooooe 8 </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Not
+stated: 3 </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3> </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>(**)
+key: X use primary o use both e Photoshop Elements </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3> </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3> </FONT></FONT></P>
+<P STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=3>Total
+replies: 16 </FONT></FONT></P>
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/native_client_sdk/src/libraries/xray/xray.odt b/native_client_sdk/src/libraries/xray/xray.odt
new file mode 100644
index 0000000000..75a9aaa927
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/xray.odt
Binary files differ
diff --git a/native_client_sdk/src/libraries/xray/xray_priv.h b/native_client_sdk/src/libraries/xray/xray_priv.h
new file mode 100644
index 0000000000..2f1150143b
--- /dev/null
+++ b/native_client_sdk/src/libraries/xray/xray_priv.h
@@ -0,0 +1,117 @@
+/* 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.
+ */
+
+
+/* XRay -- a simple profiler for Native Client */
+
+/* This header file is the private internal interface. */
+
+#ifndef LIBRARIES_XRAY_XRAY_PRIV_H_
+#define LIBRARIES_XRAY_XRAY_PRIV_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "xray/xray.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(XRAY)
+
+#define XRAY_FORCE_INLINE __attribute__((always_inline))
+
+#define XRAY_TRACE_STACK_SIZE (256)
+#define XRAY_TRACE_ANNOTATION_LENGTH (1024)
+#define XRAY_TRACE_BUFFER_SIZE (1048576)
+#define XRAY_ANNOTATION_STACK_SIZE ((XRAY_TRACE_STACK_SIZE) * \
+ (XRAY_TRACE_ANNOTATION_LENGTH))
+#define XRAY_STRING_POOL_NODE_SIZE (32768)
+#define XRAY_FRAME_MARKER (0xFFFFFFFF)
+#define XRAY_NULL_ANNOTATION (0x0)
+#define XRAY_FUNCTION_ALIGNMENT_BITS (4)
+#define XRAY_ADDR_MASK (0xFFFFFF00)
+#define XRAY_ADDR_SHIFT (4)
+#define XRAY_DEPTH_MASK (0x000000FF)
+#define XRAY_SYMBOL_TABLE_MAX_RATIO (0.66f)
+#define XRAY_LINE_SIZE (1024)
+#define XRAY_MAX_FRAMES (60)
+#define XRAY_MAX_LABEL (64)
+#define XRAY_DEFAULT_SYMBOL_TABLE_SIZE (4096)
+#define XRAY_SYMBOL_POOL_NODE_SIZE (1024)
+#define XRAY_GUARD_VALUE (0x12345678)
+#define XRAY_EXTRACT_ADDR(x) (((x) & XRAY_ADDR_MASK) >> XRAY_ADDR_SHIFT)
+#define XRAY_EXTRACT_DEPTH(x) ((x) & XRAY_DEPTH_MASK)
+#define XRAY_PACK_ADDR(x) (((x) << XRAY_ADDR_SHIFT) & XRAY_ADDR_MASK)
+#define XRAY_PACK_DEPTH(x) ((x) & XRAY_DEPTH_MASK)
+#define XRAY_PACK_DEPTH_ADDR(d, a) (XRAY_PACK_DEPTH(d) | XRAY_PACK_ADDR(a))
+#define XRAY_ALIGN64 __attribute((aligned(64)))
+
+struct XRayStringPool;
+struct XRayHashTable;
+struct XRaySymbolPool;
+struct XRaySymbol;
+struct XRaySymbolTable;
+
+/* Important: don't instrument xray itself, so use */
+/* XRAY_NO_INSTRUMENT on all xray functions */
+
+XRAY_NO_INSTRUMENT char* XRayStringPoolAppend(struct XRayStringPool* pool,
+ const char* src);
+XRAY_NO_INSTRUMENT struct XRayStringPool* XRayStringPoolCreate();
+XRAY_NO_INSTRUMENT void XRayStringPoolFree(struct XRayStringPool* pool);
+
+XRAY_NO_INSTRUMENT void* XRayHashTableLookup(struct XRayHashTable* table,
+ uint32_t addr);
+XRAY_NO_INSTRUMENT void* XRayHashTableInsert(struct XRayHashTable* table,
+ void* data, uint32_t addr);
+XRAY_NO_INSTRUMENT void* XRayHashTableAtIndex(
+ struct XRayHashTable* table, int i);
+XRAY_NO_INSTRUMENT int XRayHashTableGetSize(struct XRayHashTable* table);
+XRAY_NO_INSTRUMENT struct XRayHashTable* XRayHashTableCreate(int size);
+XRAY_NO_INSTRUMENT void XRayHashTableFree(struct XRayHashTable* table);
+XRAY_NO_INSTRUMENT void XRayHashTableHisto(FILE* f);
+
+XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolPoolAlloc(
+ struct XRaySymbolPool* sympool);
+XRAY_NO_INSTRUMENT struct XRaySymbolPool* XRaySymbolPoolCreate();
+XRAY_NO_INSTRUMENT void XRaySymbolPoolFree(struct XRaySymbolPool* sympool);
+
+XRAY_NO_INSTRUMENT const char* XRayDemangle(char* demangle, size_t buffersize,
+ const char* symbol);
+
+XRAY_NO_INSTRUMENT const char* XRaySymbolGetName(struct XRaySymbol* symbol);
+XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolCreate(
+ struct XRaySymbolPool* sympool, const char* name);
+XRAY_NO_INSTRUMENT void XRaySymbolFree(struct XRaySymbol* symbol);
+XRAY_NO_INSTRUMENT int XRaySymbolCount(struct XRaySymbolTable* symtab);
+
+XRAY_NO_INSTRUMENT void XRaySymbolTableParseMapfile(
+ struct XRaySymbolTable* symbols, const char* mapfilename);
+XRAY_NO_INSTRUMENT int XRaySymbolTableGetSize(struct XRaySymbolTable* symtab);
+XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolTableLookup(
+ struct XRaySymbolTable* symbols, uint32_t addr);
+XRAY_NO_INSTRUMENT struct XRaySymbol* XRaySymbolTableAtIndex(
+ struct XRaySymbolTable* symbols, int i);
+XRAY_NO_INSTRUMENT struct XRaySymbolTable* XRaySymbolTableCreate(int size);
+XRAY_NO_INSTRUMENT void XRaySymbolTableFree(struct XRaySymbolTable* symbtab);
+
+XRAY_NO_INSTRUMENT void* XRayMalloc(size_t t);
+XRAY_NO_INSTRUMENT void XRayFree(void* data);
+XRAY_NO_INSTRUMENT void XRaySetMaxStackDepth(int stack_depth);
+XRAY_NO_INSTRUMENT int XRayGetLastFrame();
+XRAY_NO_INSTRUMENT void XRayDisableCapture();
+XRAY_NO_INSTRUMENT void XRayEnableCapture();
+XRAY_NO_INSTRUMENT void XRayLoadMapfile(const char* mapfilename);
+
+#endif /* defined(XRAY) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBRARIES_XRAY_XRAY_PRIV_H_ */
diff --git a/native_client_sdk/src/project_templates/README b/native_client_sdk/src/project_templates/README
deleted file mode 100644
index 5aca398aba..0000000000
--- a/native_client_sdk/src/project_templates/README
+++ /dev/null
@@ -1,45 +0,0 @@
-Welcome to the Native Client SDK project_templates directory.
-
-Currently, this directory contains a mechanism to allow a developer to
-bootstrap a native client project and write a lot of the NaCl-specific code
-automatically, so the developer can add her own functionality quickly. The
-projects created are designed to be self-contained, meaning that they have
-everything they need to run, except a server.
-
-To start a project, run "./init_project.py" or "python init_project.py"
-depending on your system configuration. The script will give you usage
-information when run with -h or when insufficient or malformed arguments are
-provided.
-
-The result of the script is a project with the name you provide at a location
-of your choice. If you have your own server, you may create the project in
-a location it serves. Otherwise, you may create a project under the SDK
-examples directory and examples/httpd.py to serve your project quickly - at
-least temporarily.
-
-In the future, this directory is intended as a repository for useful stub code,
-code snippets, and code generators that can be used to facilitate rapid
-development. For now we support initial project setup via init_project.py, but
-any generically useful code can be added here if it follows a reasonable
-organization. The organization is as follows:
-
-project_templates:
- Contains any top-level scripting elements that apply or may come in useful
- for the generation of all NaCl/Pepper2 projects, common Makefile sections,
- and this README.
-project_templates/[language]:
- For any given language there should be a directory with a name that is
- commonly associated with that language.
-project_templates/[topic]
-project_templates/[language]/[topic]
- For any given programming topic, such as audio, 2d, or 3d programming, there
- should be a directory at the root level for any components that are not
- language specific and that may apply to that topic. For corresponding
- components that are language specific, a sub-directory for the topic may
- also be created under the language directory.
-
-Note that the layout in this directory does not reflect the layout of the
-projects that are created. It is merely a set of simple guidelines to help
-organize generic code and utilities so they can be managed here. How
-generated projects are laid out is left up to the design of the particular
-code-generator.
diff --git a/native_client_sdk/src/project_templates/c/build.scons b/native_client_sdk/src/project_templates/c/build.scons
deleted file mode 100644
index 6836f4ebcc..0000000000
--- a/native_client_sdk/src/project_templates/c/build.scons
+++ /dev/null
@@ -1,15 +0,0 @@
-#! -*- python -*-
-#
-# Copyright (c) 2011 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.
-
-import make_nacl_env
-import os
-
-nacl_env = make_nacl_env.NaClEnvironment(
- nacl_platform=os.getenv('NACL_TARGET_PLATFORM'))
-
-sources = ['<PROJECT_NAME>.c']
-
-nacl_env.AllNaClModules(sources, '<PROJECT_NAME>')
diff --git a/native_client_sdk/src/project_templates/c/project_file.c b/native_client_sdk/src/project_templates/c/project_file.c
deleted file mode 100644
index 7f25bd659e..0000000000
--- a/native_client_sdk/src/project_templates/c/project_file.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/** @file <PROJECT_NAME>.c
- * This example demonstrates loading, running and scripting a very simple
- * NaCl module.
- */
-#include <stdlib.h>
-#include <string.h>
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_var.h"
-#include "ppapi/c/ppb.h"
-#include "ppapi/c/ppb_instance.h"
-#include "ppapi/c/ppb_messaging.h"
-#include "ppapi/c/ppb_var.h"
-#include "ppapi/c/ppp.h"
-#include "ppapi/c/ppp_instance.h"
-#include "ppapi/c/ppp_messaging.h"
-
-static PP_Module module_id = 0;
-static struct PPB_Messaging* messaging_interface = NULL;
-static struct PPB_Var* var_interface = NULL;
-
-/**
- * Returns a mutable C string contained in the @a var or NULL if @a var is not
- * string. This makes a copy of the string in the @a var and adds a NULL
- * terminator. Note that VarToUtf8() does not guarantee the NULL terminator on
- * the returned string. See the comments for VarToUtf8() in ppapi/c/ppb_var.h
- * for more info. The caller is responsible for freeing the returned memory.
- * @param[in] var PP_Var containing string.
- * @return a mutable C string representation of @a var.
- * @note The caller is responsible for freeing the returned string.
- */
-/* TODO(sdk_user): 2. Uncomment this when you need it. It is commented out so
- * that the compiler doesn't complain about unused functions.
- */
-#if 0
-static char* AllocateCStrFromVar(struct PP_Var var) {
- uint32_t len = 0;
- if (var_interface != NULL) {
- const char* var_c_str = var_interface->VarToUtf8(var, &len);
- if (len > 0) {
- char* c_str = (char*)malloc(len + 1);
- memcpy(c_str, var_c_str, len);
- c_str[len] = '\0';
- return c_str;
- }
- }
- return NULL;
-}
-#endif
-
-/**
- * Creates a new string PP_Var from C string. The resulting object will be a
- * refcounted string object. It will be AddRef()ed for the caller. When the
- * caller is done with it, it should be Release()d.
- * @param[in] str C string to be converted to PP_Var
- * @return PP_Var containing string.
- */
-/* TODO(sdk_user): 3. Uncomment this when you need it. It is commented out so
- * that the compiler doesn't complain about unused functions.
- */
-#if 0
-static struct PP_Var AllocateVarFromCStr(const char* str) {
- if (var_interface != NULL)
- return var_interface->VarFromUtf8(module_id, str, strlen(str));
- return PP_MakeUndefined();
-}
-#endif
-
-/**
- * Called when the NaCl module is instantiated on the web page. The identifier
- * of the new instance will be passed in as the first argument (this value is
- * generated by the browser and is an opaque handle). This is called for each
- * instantiation of the NaCl module, which is each time the <embed> tag for
- * this module is encountered.
- *
- * If this function reports a failure (by returning @a PP_FALSE), the NaCl
- * module will be deleted and DidDestroy will be called.
- * @param[in] instance The identifier of the new instance representing this
- * NaCl module.
- * @param[in] argc The number of arguments contained in @a argn and @a argv.
- * @param[in] argn An array of argument names. These argument names are
- * supplied in the <embed> tag, for example:
- * <embed id="nacl_module" dimensions="2">
- * will produce two arguments, one named "id" and one named "dimensions".
- * @param[in] argv An array of argument values. These are the values of the
- * arguments listed in the <embed> tag. In the above example, there will
- * be two elements in this array, "nacl_module" and "2". The indices of
- * these values match the indices of the corresponding names in @a argn.
- * @return @a PP_TRUE on success.
- */
-static PP_Bool Instance_DidCreate(PP_Instance instance,
- uint32_t argc,
- const char* argn[],
- const char* argv[]) {
- return PP_TRUE;
-}
-
-/**
- * Called when the NaCl module is destroyed. This will always be called,
- * even if DidCreate returned failure. This routine should deallocate any data
- * associated with the instance.
- * @param[in] instance The identifier of the instance representing this NaCl
- * module.
- */
-static void Instance_DidDestroy(PP_Instance instance) {
-}
-
-/**
- * Called when the position, the size, or the clip rect of the element in the
- * browser that corresponds to this NaCl module has changed.
- * @param[in] instance The identifier of the instance representing this NaCl
- * module.
- * @param[in] position The location on the page of this NaCl module. This is
- * relative to the top left corner of the viewport, which changes as the
- * page is scrolled.
- * @param[in] clip The visible region of the NaCl module. This is relative to
- * the top left of the plugin's coordinate system (not the page). If the
- * plugin is invisible, @a clip will be (0, 0, 0, 0).
- */
-static void Instance_DidChangeView(PP_Instance instance,
- const struct PP_Rect* position,
- const struct PP_Rect* clip) {
-}
-
-/**
- * Notification that the given NaCl module has gained or lost focus.
- * Having focus means that keyboard events will be sent to the NaCl module
- * represented by @a instance. A NaCl module's default condition is that it
- * will not have focus.
- *
- * Note: clicks on NaCl modules will give focus only if you handle the
- * click event. You signal if you handled it by returning @a true from
- * HandleInputEvent. Otherwise the browser will bubble the event and give
- * focus to the element on the page that actually did end up consuming it.
- * If you're not getting focus, check to make sure you're returning true from
- * the mouse click in HandleInputEvent.
- * @param[in] instance The identifier of the instance representing this NaCl
- * module.
- * @param[in] has_focus Indicates whether this NaCl module gained or lost
- * event focus.
- */
-static void Instance_DidChangeFocus(PP_Instance instance,
- PP_Bool has_focus) {
-}
-
-/**
- * Handler that gets called after a full-frame module is instantiated based on
- * registered MIME types. This function is not called on NaCl modules. This
- * function is essentially a place-holder for the required function pointer in
- * the PPP_Instance structure.
- * @param[in] instance The identifier of the instance representing this NaCl
- * module.
- * @param[in] url_loader A PP_Resource an open PPB_URLLoader instance.
- * @return PP_FALSE.
- */
-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;
-}
-
-
-/**
- * Handler for messages coming in from the browser via postMessage. The
- * @a var_message can contain anything: a JSON string; a string that encodes
- * method names and arguments; etc. For example, you could use JSON.stringify
- * in the browser to create a message that contains a method name and some
- * parameters, something like this:
- * var json_message = JSON.stringify({ "myMethod" : "3.14159" });
- * nacl_module.postMessage(json_message);
- * On receipt of this message in @a var_message, you could parse the JSON to
- * retrieve the method name, match it to a function call, and then call it with
- * the parameter.
- * @param[in] instance The instance ID.
- * @param[in] message The contents, copied by value, of the message sent from
- * browser via postMessage.
- */
-void Messaging_HandleMessage(PP_Instance instance, struct PP_Var var_message) {
- /* TODO(sdk_user): 1. Make this function handle the incoming message. */
-}
-
-/**
- * Entry points for the module.
- * Initialize instance interface and scriptable object class.
- * @param[in] a_module_id Module ID
- * @param[in] get_browser_interface Pointer to PPB_GetInterface
- * @return PP_OK on success, any other value on failure.
- */
-PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
- PPB_GetInterface get_browser_interface) {
- module_id = a_module_id;
- var_interface = (struct PPB_Var*)(get_browser_interface(PPB_VAR_INTERFACE));
- messaging_interface =
- (struct PPB_Messaging*)(get_browser_interface(PPB_MESSAGING_INTERFACE));
- return PP_OK;
-}
-
-/**
- * Returns an interface pointer for the interface of the given name, or NULL
- * if the interface is not supported.
- * @param[in] interface_name name of the interface
- * @return pointer to the interface
- */
-PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
- if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
- static struct PPP_Instance instance_interface = {
- &Instance_DidCreate,
- &Instance_DidDestroy,
- &Instance_DidChangeView,
- &Instance_DidChangeFocus,
- &Instance_HandleDocumentLoad
- };
- return &instance_interface;
- } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
- static struct PPP_Messaging messaging_interface = {
- &Messaging_HandleMessage
- };
- return &messaging_interface;
- }
- return NULL;
-}
-
-/**
- * Called before the plugin module is unloaded.
- */
-PP_EXPORT void PPP_ShutdownModule() {
-}
diff --git a/native_client_sdk/src/project_templates/cc/build.scons b/native_client_sdk/src/project_templates/cc/build.scons
deleted file mode 100644
index 04d661b84c..0000000000
--- a/native_client_sdk/src/project_templates/cc/build.scons
+++ /dev/null
@@ -1,16 +0,0 @@
-#! -*- python -*-
-#
-# Copyright (c) 2011 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.
-
-import make_nacl_env
-import nacl_utils
-import os
-
-nacl_env = make_nacl_env.NaClEnvironment(
- use_c_plus_plus_libs=True, nacl_platform=os.getenv('NACL_TARGET_PLATFORM'))
-
-sources = ['<PROJECT_NAME>.cc']
-
-nacl_env.AllNaClModules(sources, '<PROJECT_NAME>')
diff --git a/native_client_sdk/src/project_templates/cc/project_file.cc b/native_client_sdk/src/project_templates/cc/project_file.cc
deleted file mode 100644
index c0123fe128..0000000000
--- a/native_client_sdk/src/project_templates/cc/project_file.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-/// @file <PROJECT_NAME>.cc
-/// This example demonstrates loading, running and scripting a very simple NaCl
-/// module. To load the NaCl module, the browser first looks for the
-/// CreateModule() factory method (at the end of this file). It calls
-/// CreateModule() once to load the module code from your .nexe. After the
-/// .nexe code is loaded, CreateModule() is not called again.
-///
-/// Once the .nexe code is loaded, the browser than calls the CreateInstance()
-/// method on the object returned by CreateModule(). It calls CreateInstance()
-/// each time it encounters an <embed> tag that references your NaCl module.
-///
-/// The browser can talk to your NaCl module via the postMessage() Javascript
-/// function. When you call postMessage() on your NaCl module from the browser,
-/// this becomes a call to the HandleMessage() method of your pp::Instance
-/// subclass. You can send messages back to the browser by calling the
-/// PostMessage() method on your pp::Instance. Note that these two methods
-/// (postMessage() in Javascript and PostMessage() in C++) are asynchronous.
-/// This means they return immediately - there is no waiting for the message
-/// to be handled. This has implications in your program design, particularly
-/// when mutating property values that are exposed to both the browser and the
-/// NaCl module.
-
-#include <cstdio>
-#include <string>
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/module.h"
-#include "ppapi/cpp/var.h"
-
-/// The Instance class. One of these exists for each instance of your NaCl
-/// module on the web page. The browser will ask the Module object to create
-/// a new Instance for each occurence of the <embed> tag that has these
-/// attributes:
-/// type="application/x-nacl"
-/// src="<PROJECT_NAME>.nmf"
-/// To communicate with the browser, you must override HandleMessage() for
-/// receiving messages from the borwser, and use PostMessage() to send messages
-/// back to the browser. Note that this interface is entirely asynchronous.
-class <ProjectName>Instance : public pp::Instance {
- public:
- /// The constructor creates the plugin-side instance.
- /// @param[in] instance the handle to the browser-side plugin instance.
- explicit <ProjectName>Instance(PP_Instance instance) : pp::Instance(instance)
- {}
- virtual ~<ProjectName>Instance() {}
-
- /// Handler for messages coming in from the browser via postMessage(). The
- /// @a var_message can contain anything: a JSON string; a string that encodes
- /// method names and arguments; etc. For example, you could use
- /// JSON.stringify in the browser to create a message that contains a method
- /// name and some parameters, something like this:
- /// var json_message = JSON.stringify({ "myMethod" : "3.14159" });
- /// nacl_module.postMessage(json_message);
- /// On receipt of this message in @a var_message, you could parse the JSON to
- /// retrieve the method name, match it to a function call, and then call it
- /// with the parameter.
- /// @param[in] var_message The message posted by the browser.
- virtual void HandleMessage(const pp::Var& var_message) {
- // TODO(sdk_user): 1. Make this function handle the incoming message.
- }
-};
-
-/// The Module class. The browser calls the CreateInstance() method to create
-/// an instance of your NaCl module on the web page. The browser creates a new
-/// instance for each <embed> tag with type="application/x-nacl".
-class <ProjectName>Module : public pp::Module {
- public:
- <ProjectName>Module() : pp::Module() {}
- virtual ~<ProjectName>Module() {}
-
- /// Create and return a <ProjectName>Instance object.
- /// @param[in] instance The browser-side instance.
- /// @return the plugin-side instance.
- virtual pp::Instance* CreateInstance(PP_Instance instance) {
- return new <ProjectName>Instance(instance);
- }
-};
-
-namespace pp {
-/// Factory function called by the browser when the module is first loaded.
-/// The browser keeps a singleton of this module. It calls the
-/// CreateInstance() method on the object you return to make instances. There
-/// is one instance per <embed> tag on the page. This is the main binding
-/// point for your NaCl module with the browser.
-Module* CreateModule() {
- return new <ProjectName>Module();
-}
-} // namespace pp
diff --git a/native_client_sdk/src/project_templates/html/project_file.html b/native_client_sdk/src/project_templates/html/project_file.html
deleted file mode 100644
index db3bc1a74a..0000000000
--- a/native_client_sdk/src/project_templates/html/project_file.html
+++ /dev/null
@@ -1,95 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title><ProjectName>!</title>
-
- <script type="text/javascript">
- <ProjectName>Module = null; // Global application object.
- statusText = 'NO-STATUS';
-
- // Indicate load success.
- function moduleDidLoad() {
- <ProjectName>Module = document.getElementById('<PROJECT_NAME>');
- updateStatus('SUCCESS');
- }
-
- // The 'message' event handler. This handler is fired when the NaCl module
- // posts a message to the browser by calling PPB_Messaging.PostMessage()
- // (in C) or pp::Instance.PostMessage() (in C++). This implementation
- // simply displays the content of the message in an alert panel.
- function handleMessage(message_event) {
- alert(message_event.data);
- }
-
- // If the page loads before the Native Client module loads, then set the
- // status message indicating that the module is still loading. Otherwise,
- // do not change the status message.
- function pageDidLoad() {
- if (<ProjectName>Module == null) {
- updateStatus('LOADING...');
- } else {
- // It's possible that the Native Client module onload event fired
- // before the page's onload event. In this case, the status message
- // will reflect 'SUCCESS', but won't be displayed. This call will
- // display the current message.
- updateStatus();
- }
- }
-
- // Set the global status message. If the element with id 'statusField'
- // exists, then set its HTML to the status message as well.
- // opt_message The message test. If this is null or undefined, then
- // attempt to set the element with id 'statusField' to the value of
- // |statusText|.
- function updateStatus(opt_message) {
- if (opt_message)
- statusText = opt_message;
- var statusField = document.getElementById('status_field');
- if (statusField) {
- statusField.innerHTML = statusText;
- }
- }
- </script>
-</head>
-<body onload="pageDidLoad()">
-
-<h1>Native Client Module <ProjectName></h1>
-<p>
- <!-- Load the published .nexe. This includes the 'nacl' attribute which
- shows how to load multi-architecture modules. Each entry in the "nexes"
- object in the .nmf manifest file is a key-value pair: the key is the
- instruction set architecture ('x86-32', 'x86-64', etc.); the value is a URL
- for the desired NaCl module.
- To load the debug versions of your .nexes, set the 'nacl' attribute to the
- _dbg.nmf version of the manifest file.
-
- Note: Since this NaCl module does not use any real-estate in the browser,
- its width and height are set to 0.
-
- Note: The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
- and a 'message' event listener attached. This wrapping method is used
- instead of attaching the event listeners directly to the <EMBED> element to
- ensure that the listeners are active before the NaCl module 'load' event
- fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or
- pp::Instance.PostMessage() (in C++) from within the initialization code in
- your NaCl module.
- -->
- <div id="listener">
- <script type="text/javascript">
- var listener = document.getElementById('listener');
- listener.addEventListener('load', moduleDidLoad, true);
- listener.addEventListener('message', handleMessage, true);
- </script>
-
- <embed name="nacl_module"
- id="<PROJECT_NAME>"
- width=0 height=0
- src="<PROJECT_NAME>.nmf"
- type="application/x-nacl" />
- </div>
-</p>
-
-<h2>Status</h2>
-<div id="status_field">NO-STATUS</div>
-</body>
-</html>
diff --git a/native_client_sdk/src/project_templates/init_project.py b/native_client_sdk/src/project_templates/init_project.py
deleted file mode 100755
index 0201fa7002..0000000000
--- a/native_client_sdk/src/project_templates/init_project.py
+++ /dev/null
@@ -1,505 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""A simple project generator for Native Client projects written in C or C++.
-
-This script accepts a few argument which it uses as a description of a new NaCl
-project. It sets up a project with a given name and a given primary language
-(default: C++, optionally, C) using the appropriate files from this area.
-This script does not handle setup for complex applications, just the basic
-necessities to get a functional native client application stub. When this
-script terminates a compileable project stub will exist with the specified
-name, at the specified location.
-
-GetCamelCaseName(): Converts an underscore name to a camel case name.
-GetCodeDirectory(): Decides what directory to pull source code from.
-GetCodeSoureFiles(): Decides what source files to pull into the stub.
-GetCommonSourceFiles(): Gives list of files needed by all project types.
-GetHTMLDirectory(): Decides what directory to pull HTML stub from.
-GetHTMLSourceFiles(): Gives HTML files to be included in project stub.
-GetTargetFileName(): Converts a source file name into a project file name.
-ParseArguments(): Parses the arguments provided by the user.
-ReplaceInFile(): Replaces a given string with another in a given file.
-ProjectInitializer: Maintains some state applicable to setting up a project.
-main(): Executes the script.
-"""
-
-__author__ = 'mlinck@google.com (Michael Linck)'
-
-import fileinput
-import optparse
-import os.path
-import shutil
-import sys
-import uuid
-
-# A list of all platforms that should have make.cmd.
-WINDOWS_BUILD_PLATFORMS = ['cygwin', 'win32']
-
-# Tags that will be replaced in our the new project's source files.
-PROJECT_NAME_TAG = '<PROJECT_NAME>'
-PROJECT_NAME_CAMEL_CASE_TAG = '<ProjectName>'
-SDK_ROOT_TAG = '<NACL_SDK_ROOT>'
-NACL_PLATFORM_TAG = '<NACL_PLATFORM>'
-VS_PROJECT_UUID_TAG = '<VS_PROJECT_UUID>'
-VS_SOURCE_UUID_TAG = '<VS_SOURCE_UUID>'
-VS_HEADER_UUID_TAG = '<VS_HEADER_UUID>'
-VS_RESOURCE_UUID_TAG = '<VS_RESOURCE_UUID>'
-
-# This string is the part of the file name that will be replaced.
-PROJECT_FILE_NAME = 'project_file'
-
-# Lists of source files that will be used for the new project.
-COMMON_PROJECT_FILES = ['scons']
-C_SOURCE_FILES = ['build.scons', '%s.c' % PROJECT_FILE_NAME]
-CC_SOURCE_FILES = ['build.scons', '%s.cc' % PROJECT_FILE_NAME]
-HTML_FILES = ['%s.html' % PROJECT_FILE_NAME]
-VS_FILES = ['%s.sln' % PROJECT_FILE_NAME, '%s.vcproj' % PROJECT_FILE_NAME]
-
-# Error needs to be a class, since we 'raise' it in several places.
-class Error(Exception):
- pass
-
-
-def GetCamelCaseName(lower_case_name):
- """Converts an underscore name to a camel case name.
-
- Args:
- lower_case_name: The name in underscore-delimited lower case format.
-
- Returns:
- The name in camel case format.
- """
- camel_case_name = ''
- name_parts = lower_case_name.split('_')
- for part in name_parts:
- if part:
- camel_case_name += part.capitalize()
- return camel_case_name
-
-
-def GetCodeDirectory(is_c_project, project_templates_dir):
- """Decides what directory to pull source code from.
-
- Args:
- is_c_project: A boolean indicating whether this project is in C or not.
- project_templates_dir: The path to the project_templates directory.
-
- Returns:
- The code directory for the given project type.
- """
- stub_directory = ''
- if is_c_project:
- stub_directory = os.path.join(project_templates_dir, 'c')
- else:
- stub_directory = os.path.join(project_templates_dir, 'cc')
- return stub_directory
-
-
-def GetCodeSourceFiles(is_c_project):
- """Decides what source files to pull into the stub.
-
- Args:
- is_c_project: A boolean indicating whether this project is in C or not.
-
- Returns:
- The files that are specific to the requested type of project and live in its
- directory.
- """
- project_files = []
- if is_c_project:
- project_files = C_SOURCE_FILES
- else:
- project_files = CC_SOURCE_FILES
- return project_files
-
-
-def GetCommonSourceFiles():
- """Gives list of files needed by all project types.
-
- Returns:
- The files C and C++ projects have in common. These are the files that live
- in the top level project_templates directory.
- """
- project_files = COMMON_PROJECT_FILES
- if sys.platform in WINDOWS_BUILD_PLATFORMS:
- project_files.extend(['scons.bat'])
- return project_files
-
-
-def GetVsDirectory(project_templates_dir):
- """Decides what directory to pull Visual Studio stub from.
-
- Args:
- project_templates_dir: The path to the project_templates directory.
-
- Returns:
- The directory where the HTML stub is to be found.
- """
- return os.path.join(project_templates_dir, 'vs')
-
-
-def GetVsProjectFiles():
- """Gives VisualStudio files to be included in project stub.
-
- Returns:
- The VisualStudio files needed for the project.
- """
- return VS_FILES
-
-
-def GetHTMLDirectory(project_templates_dir):
- """Decides what directory to pull HTML stub from.
-
- Args:
- project_templates_dir: The path to the project_templates directory.
-
- Returns:
- The directory where the HTML stub is to be found.
- """
- return os.path.join(project_templates_dir, 'html')
-
-
-def GetHTMLSourceFiles():
- """Gives HTML files to be included in project stub.
-
- Returns:
- The HTML files needed for the project.
- """
- return HTML_FILES
-
-
-def GetTargetFileName(source_file_name, project_name):
- """Converts a source file name into a project file name.
-
- Args:
- source_file_name: The name of a file that is to be included in the project
- stub, as it appears at the source location.
- project_name: The name of the project that is being generated.
-
- Returns:
- The target file name for a given source file. All project files are run
- through this filter and it modifies them as needed.
- """
- target_file_name = ''
- if source_file_name.startswith(PROJECT_FILE_NAME):
- target_file_name = source_file_name.replace(PROJECT_FILE_NAME,
- project_name)
- else:
- target_file_name = source_file_name
- return target_file_name
-
-
-def GetDefaultProjectDir():
- """Determines the default project directory.
-
- The default directory root for new projects is called 'nacl_projects' under
- the user's home directory. There are two ways to override this: you can set
- the NACL_PROJECT_ROOT environment variable, or use the --directory option.
-
- Returns:
- An os-specific path to the default project directory, which is called
- 'nacl_projects' under the user's home directory.
- """
- return os.getenv('NACL_PROJECT_ROOT',
- os.path.join(os.path.expanduser('~'), 'nacl_projects'))
-
-
-def ParseArguments(argv):
- """Parses the arguments provided by the user.
-
- Parses the command line options and makes sure the script errors when it is
- supposed to.
-
- Args:
- argv: The argument array.
-
- Returns:
- The options structure that represents the arguments after they have been
- parsed.
- """
- parser = optparse.OptionParser()
- parser.add_option(
- '-n', '--name', dest='project_name',
- default='',
- help=('Required: the name of the new project to be stubbed out.\n'
- 'Please use lower case names with underscore, i.e. hello_world.'))
- parser.add_option(
- '-d', '--directory', dest='project_directory',
- default=GetDefaultProjectDir(),
- help=('Optional: If set, the new project will be created under this '
- 'directory and the directory created if necessary.'))
- parser.add_option(
- '-c', action='store_true', dest='is_c_project',
- default=False,
- help=('Optional: If set, this will generate a C project. Default '
- 'is C++.'))
- parser.add_option(
- '-p', '--nacl-platform', dest='nacl_platform',
- default='pepper_17',
- help=('Optional: if set, the new project will target the given nacl\n'
- 'platform. Default is the most current platform. e.g. pepper_17'))
- parser.add_option(
- '--vsproj', action='store_true', dest='is_vs_project',
- default=False,
- help=('Optional: If set, generate Visual Studio project files.'))
- result = parser.parse_args(argv)
- options = result[0]
- args = result[1]
- #options, args) = parser.parse_args(argv)
- if args:
- parser.print_help()
- sys.exit(1)
- elif not options.project_name.islower():
- print('--name missing or in incorrect format. Please use -h for '
- 'instructions.')
- sys.exit(1)
- return options
-
-
-class ProjectInitializer(object):
- """Maintains the state of the project that is being created."""
-
- def __init__(self, is_c_project, is_vs_project, project_name,
- project_location, nacl_platform, project_templates_dir,
- nacl_sdk_root=None, os_resource=os):
- """Initializes all the fields that are known after parsing the parameters.
-
- Args:
- is_c_project: A boolean indicating whether this project is in C or not.
- is_vs_project: A boolean indicating whether this project has Visual
- Studio support.
- project_name: A string containing the name of the project to be created.
- project_location: A path indicating where the new project is to be placed.
- project_templates_dir: The path to the project_templates directory.
- os_resource: A resource to be used as os. Provided for unit testing.
- """
- self.__is_c_project = is_c_project
- self.__is_vs_project = is_vs_project
- self.__project_files = []
- self.__project_dir = None
- self.__project_name = project_name
- self.__project_location = project_location
- self.__nacl_platform = nacl_platform
- self.__project_templates_dir = project_templates_dir
- # System resources are properties so mocks can be inserted.
- self.__fileinput = fileinput
- self.__nacl_sdk_root = nacl_sdk_root
- self.__os = os_resource
- self.__shutil = shutil
- self.__sys = sys
- self.__CreateProjectDirectory()
-
- def CopyAndRenameFiles(self, source_dir, file_names):
- """Places files in the new project's directory and renames them as needed.
-
- Copies the given files from the given source directory into the new
- project's directory, renaming them as necessary. Each file that is created
- in the project directory is also added to self.__project_files.
-
- Args:
- source_dir: A path indicating where the files are to be copied from.
- file_names: The list of files that is to be copied out of source_dir.
- """
- for source_file_name in file_names:
- target_file_name = GetTargetFileName(source_file_name,
- self.__project_name)
- copy_source_file = self.os.path.join(source_dir, source_file_name)
- copy_target_file = self.os.path.join(self.__project_dir, target_file_name)
- self.shutil.copy(copy_source_file, copy_target_file)
- self.__project_files += [copy_target_file]
-
- def __CreateProjectDirectory(self):
- """Creates the project's directory and any parents as necessary."""
- self.__project_dir = self.os.path.join(self.__project_location,
- self.__project_name)
- if self.os.path.exists(self.__project_dir):
- raise Error("Error: directory '%s' already exists" % self.__project_dir)
- self.os.makedirs(self.__project_dir)
-
- def PrepareDirectoryContent(self):
- """Prepares the directory for the new project.
-
- This function's job is to know what directories need to be used and what
- files need to be copied and renamed. It uses several tiny helper functions
- to do this.
- There are three locations from which files are copied to create a project.
- That number may change in the future.
- """
- code_source_dir = GetCodeDirectory(self.__is_c_project,
- self.__project_templates_dir)
- code_source_files = GetCodeSourceFiles(self.__is_c_project)
- html_source_dir = GetHTMLDirectory(self.__project_templates_dir)
- html_source_files = GetHTMLSourceFiles()
- common_source_files = GetCommonSourceFiles()
- self.CopyAndRenameFiles(code_source_dir, code_source_files)
- self.CopyAndRenameFiles(html_source_dir, html_source_files)
- self.CopyAndRenameFiles(self.__project_templates_dir,
- common_source_files)
- if self.__is_vs_project:
- vs_source_dir = GetVsDirectory(self.__project_templates_dir)
- vs_files = GetVsProjectFiles()
- self.CopyAndRenameFiles(vs_source_dir, vs_files)
- print('init_project has copied the appropriate files to: %s' %
- self.__project_dir)
-
- def PrepareFileContent(self):
- """Changes contents of files in the new project as needed.
-
- Goes through each file in the project that is being created and replaces
- contents as necessary.
- """
- camel_case_name = GetCamelCaseName(self.__project_name)
- sdk_root_dir = self.__nacl_sdk_root
- if not sdk_root_dir:
- raise Error("Error: NACL_SDK_ROOT is not set")
- sdk_root_dir = self.os.path.abspath(sdk_root_dir)
- if self.__is_vs_project:
- project_uuid = str(uuid.uuid4()).upper()
- vs_source_uuid = str(uuid.uuid4()).upper()
- vs_header_uuid = str(uuid.uuid4()).upper()
- vs_resource_uuid = str(uuid.uuid4()).upper()
- for project_file in self.__project_files:
- self.ReplaceInFile(project_file, PROJECT_NAME_TAG, self.__project_name)
- self.ReplaceInFile(project_file,
- PROJECT_NAME_CAMEL_CASE_TAG,
- camel_case_name)
- self.ReplaceInFile(project_file, SDK_ROOT_TAG, sdk_root_dir)
- self.ReplaceInFile(project_file, NACL_PLATFORM_TAG, self.__nacl_platform)
- if self.__is_vs_project:
- self.ReplaceInFile(project_file, VS_PROJECT_UUID_TAG, project_uuid)
- self.ReplaceInFile(project_file, VS_SOURCE_UUID_TAG, vs_source_uuid)
- self.ReplaceInFile(project_file, VS_HEADER_UUID_TAG, vs_header_uuid)
- self.ReplaceInFile(project_file, VS_RESOURCE_UUID_TAG, vs_resource_uuid)
-
- def ReplaceInFile(self, file_path, old_text, new_text):
- """Replaces a given string with another in a given file.
-
- Args:
- file_path: The path to the file that is to be modified.
- old_text: The text that is to be removed.
- new_text: The text that is to be added in place of old_text.
- """
- for line in self.fileinput.input(file_path, inplace=1, mode='U'):
- self.sys.stdout.write(line.replace(old_text, new_text))
-
- # The following properties exist to make unit testing possible.
-
- def _GetFileinput(self):
- """Accessor for Fileinput property."""
- return self.__fileinput
-
- def __GetFileinput(self):
- """Indirect Accessor for _GetFileinput."""
- return self._GetFileinput()
-
- def _SetFileinput(self, fileinput_resource):
- """Accessor for Fileinput property."""
- self.__fileinput = fileinput_resource
-
- def __SetFileinput(self, fileinput_resource):
- """Indirect Accessor for _SetFileinput."""
- return self._SetFileinput(fileinput_resource)
-
- fileinput = property(
- __GetFileinput, __SetFileinput,
- doc="""Gets and sets the resource to use as fileinput.""")
-
- def _GetOS(self):
- """Accessor for os property."""
- return self.__os
-
- def __GetOS(self):
- """Indirect Accessor for _GetOS."""
- return self._GetOS()
-
- def _SetOS(self, os_resource):
- """Accessor for os property."""
- self.__os = os_resource
-
- def __SetOS(self, os_resource):
- """Indirect Accessor for _SetOS."""
- return self._SetOS(os_resource)
-
- os = property(__GetOS, __SetOS,
- doc="""Gets and sets the resource to use as os.""")
-
- def _GetShutil(self):
- """Accessor for shutil property."""
- return self.__shutil
-
- def __GetShutil(self):
- """Indirect Accessor for _GetShutil."""
- return self._GetShutil()
-
- def _SetShutil(self, shutil_resource):
- """Accessor for shutil property."""
- self.__shutil = shutil_resource
-
- def __SetShutil(self, shutil_resource):
- """Indirect Accessor for _SetShutil."""
- return self._SetShutil(shutil_resource)
-
- shutil = property(__GetShutil, __SetShutil,
- doc="""Gets and sets the resource to use as shutil.""")
-
- def _GetSys(self):
- """Accessor for sys property."""
- return self.__sys
-
- def __GetSys(self):
- """Indirect Accessor for _GetSys."""
- return self._GetSys()
-
- def _SetSys(self, sys_resource):
- """Accessor for sys property."""
- self.__sys = sys_resource
-
- def __SetSys(self, sys_resource):
- """Indirect Accessor for _SetSys."""
- return self._SetSys(sys_resource)
-
- sys = property(__GetSys, __SetSys,
- doc="""Gets and sets the resource to use as sys.""")
-
-
-def main(argv):
- """Prepares the new project.
-
- Args:
- argv: The arguments passed to the script by the shell.
- """
- print 'init_project parsing its arguments.'
- script_dir = os.path.abspath(os.path.dirname(__file__))
- options = ParseArguments(argv)
- print 'init_project is preparing your project.'
- # Check to see if the project is going into the SDK bundle. If so, issue a
- # warning.
- sdk_root_dir = os.getenv('NACL_SDK_ROOT',
- os.path.dirname(os.path.dirname(script_dir)))
- if sdk_root_dir:
- if os.path.normpath(options.project_directory).count(
- os.path.normpath(sdk_root_dir)) > 0:
- print('WARNING: It looks like you are creating projects in the NaCl SDK '
- 'directory %s.\nThese might be removed at the next update.' %
- sdk_root_dir)
- project_initializer = ProjectInitializer(options.is_c_project,
- options.is_vs_project,
- options.project_name,
- options.project_directory,
- options.nacl_platform,
- script_dir,
- nacl_sdk_root=sdk_root_dir)
- project_initializer.PrepareDirectoryContent()
- project_initializer.PrepareFileContent()
- return 0
-
-
-if __name__ == '__main__':
- try:
- sys.exit(main(sys.argv[1:]))
- except Exception as error:
- print error
- sys.exit(1)
diff --git a/native_client_sdk/src/project_templates/init_project_test.py b/native_client_sdk/src/project_templates/init_project_test.py
deleted file mode 100755
index ae1d0b291f..0000000000
--- a/native_client_sdk/src/project_templates/init_project_test.py
+++ /dev/null
@@ -1,263 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""Unit tests for init_project.py."""
-
-__author__ = 'mlinck@google.com (Michael Linck)'
-
-import fileinput
-import os
-import shutil
-import sys
-import unittest
-import mox
-import init_project
-
-
-def TestMock(file_path, open_func):
- temp_file = open_func(file_path)
- temp_file.close()
-
-
-class TestGlobalFunctions(unittest.TestCase):
- """Class for test cases to cover globally declared helper functions."""
-
- def testGetCamelCaseName(self):
- output = init_project.GetCamelCaseName('camel_case_name')
- self.assertEqual(output, 'CamelCaseName')
- output = init_project.GetCamelCaseName('print_42')
- self.assertEqual(output, 'Print42')
-
- def testGetCodeDirectory(self):
- output = init_project.GetCodeDirectory(True, '')
- self.assertEqual(output, 'c')
- output = init_project.GetCodeDirectory(False, '')
- self.assertEqual(output, 'cc')
- output = init_project.GetCodeDirectory(True, 'test')
- self.assertEqual(output, 'test/c')
- output = init_project.GetCodeDirectory(False, 'test')
- self.assertEqual(output, 'test/cc')
-
- def testGetCodeSourceFiles(self):
- output = init_project.GetCodeSourceFiles(False)
- self.assertEqual(output, init_project.CC_SOURCE_FILES)
- output = init_project.GetCodeSourceFiles(True)
- self.assertEqual(output, init_project.C_SOURCE_FILES)
-
- def testGetCommonSourceFiles(self):
- output = init_project.GetCommonSourceFiles()
- expected_output_linux = init_project.COMMON_PROJECT_FILES
- expected_output_windows = init_project.COMMON_PROJECT_FILES
- expected_output_windows.extend(['scons.bat'])
- linux_match = (output == expected_output_linux)
- windows_match = (output == expected_output_windows)
- passed = (linux_match | windows_match)
- self.assertTrue(passed)
-
- def testGetHTMLDirectory(self):
- output = init_project.GetHTMLDirectory('')
- self.assertEqual(output, 'html')
- output = init_project.GetHTMLDirectory('test')
- self.assertEqual(output, 'test/html')
-
- def testGetHTMLSourceFiles(self):
- output = init_project.GetHTMLSourceFiles()
- self.assertEqual(output, init_project.HTML_FILES)
-
- def testGetTargetFileName(self):
- output = init_project.GetTargetFileName('project_file.cc', 'bonkers')
- self.assertEqual(output, 'bonkers.cc')
- output = init_project.GetTargetFileName('constant.html', 'bonkers')
- self.assertEqual(output, 'constant.html')
-
- def testParseArguments(self):
- output = init_project.ParseArguments(['-n', 'test_name', '-d', 'test/dir'])
- self.assertEqual(output.is_c_project, False)
- self.assertEqual(output.project_name, 'test_name')
- self.assertEqual(output.project_directory, 'test/dir')
- output = init_project.ParseArguments(['-n', 'test_name_2', '-c'])
- self.assertEqual(output.is_c_project, True)
- self.assertEqual(output.project_name, 'test_name_2')
- self.assertEqual(output.project_directory,
- init_project.GetDefaultProjectDir())
-
-
-class TestProjectInitializer(unittest.TestCase):
- """Class for test cases to cover public interface of ProjectInitializer."""
-
- def __init__(self):
- unittest.TestCase.__init__(self)
- self.os_mock = None
- self.fileinput_mock = None
- self.sys_mock = None
- self.shutil_mock = None
-
- def setUp(self):
- self.script_dir = os.path.abspath(os.path.dirname(__file__))
- self.nacl_src_dir = os.getenv('NACL_SDK_ROOT', None)
- self.mock_factory = mox.Mox()
- # This mock is only valid for initialization and will be overwritten
- # after ward by self.os_mock.
- init_path_mock = self.mock_factory.CreateMock(os.path)
- init_path_mock.join('test/dir', 'test_project').AndReturn(
- 'test/dir/test_project')
- init_path_mock.exists('test/dir/test_project').AndReturn(False)
- init_os_mock = self.mock_factory.CreateMock(os)
- init_os_mock.path = init_path_mock
- init_os_mock.makedirs('test/dir/test_project')
- self.mock_factory.ReplayAll()
- self.test_subject = init_project.ProjectInitializer(
- # True => is C project, False => is vs project
- True, False, 'test_project', 'test/dir', 'pepper_14', self.script_dir,
- self.nacl_src_dir, os_resource=init_os_mock)
- self.mock_factory.VerifyAll()
- self.InitializeResourceMocks()
-
- def InitializeResourceMocks(self):
- """Can be called multiple times if multiple functions need to be tested."""
- self.fileinput_mock = self.mock_factory.CreateMock(fileinput)
- self.test_subject.fileinput = self.fileinput_mock
- self.os_mock = self.mock_factory.CreateMock(os)
- self.test_subject.os = self.os_mock
- self.shutil_mock = self.mock_factory.CreateMock(shutil)
- self.test_subject.shutil = self.shutil_mock
- self.sys_mock = self.mock_factory.CreateMock(sys)
- self.test_subject.sys = self.sys_mock
-
- def testCopyAndRenameFiles(self):
- self.shutil_mock.copy('source/dir/normal_name.txt',
- 'test/dir/test_project/normal_name.txt')
- self.shutil_mock.copy('source/dir/project_file.txt',
- 'test/dir/test_project/test_project.txt')
- self.os_mock.path = os.path
- self.mock_factory.ReplayAll()
- self.test_subject.CopyAndRenameFiles(
- 'source/dir', ['normal_name.txt', 'project_file.txt'])
- self.mock_factory.VerifyAll()
-
- def testPrepareDirectoryContent(self):
- self.shutil_mock.copy(
- '%s/c/build.scons' % self.script_dir,
- 'test/dir/test_project/build.scons')
- self.shutil_mock.copy(
- '%s/c/project_file.c' % self.script_dir,
- 'test/dir/test_project/test_project.c')
- self.shutil_mock.copy(
- '%s/html/project_file.html' % self.script_dir,
- 'test/dir/test_project/test_project.html')
- self.shutil_mock.copy(
- '%s/scons' % self.script_dir,
- 'test/dir/test_project/scons')
- self.shutil_mock.copy(
- '%s/scons.bat' % self.script_dir,
- 'test/dir/test_project/scons.bat')
- self.os_mock.path = os.path
- self.mock_factory.ReplayAll()
- self.test_subject.PrepareDirectoryContent()
- self.mock_factory.VerifyAll()
-
- def testPrepareFileContent(self):
- self.testCopyAndRenameFiles()
- # We need a new set of resource mocks since the old ones have already been
- # used.
- self.InitializeResourceMocks()
- path_mock = self.mock_factory.CreateMock(os.path)
- stdout_mock = self.mock_factory.CreateMock(sys.stdout)
- self.os_mock.path = path_mock
- path_mock.abspath(self.nacl_src_dir).AndReturn(self.nacl_src_dir)
- self.fileinput_mock.input(
- 'test/dir/test_project/normal_name.txt',
- inplace=1, mode='U').AndReturn(
- ['A line with <PROJECT_NAME>.',
- 'A line with <ProjectName>.',
- 'A line with <NACL_SDK_ROOT>.',
- 'A line with <NACL_PLATFORM>.'])
- stdout_mock.write('A line with test_project.')
- stdout_mock.write('A line with <ProjectName>.')
- stdout_mock.write('A line with <NACL_SDK_ROOT>.')
- stdout_mock.write('A line with <NACL_PLATFORM>.')
- self.fileinput_mock.input(
- 'test/dir/test_project/normal_name.txt',
- inplace=1, mode='U').AndReturn(
- ['A line with test_project.',
- 'A line with <ProjectName>.',
- 'A line with <NACL_SDK_ROOT>.',
- 'A line with <NACL_PLATFORM>.'])
- stdout_mock.write('A line with test_project.')
- stdout_mock.write('A line with TestProject.')
- stdout_mock.write('A line with <NACL_SDK_ROOT>.')
- stdout_mock.write('A line with <NACL_PLATFORM>.')
- self.fileinput_mock.input(
- 'test/dir/test_project/normal_name.txt',
- inplace=1, mode='U').AndReturn(
- ['A line with test_project.',
- 'A line with TestProject.',
- 'A line with <NACL_SDK_ROOT>.',
- 'A line with <NACL_PLATFORM>.'])
- stdout_mock.write('A line with test_project.')
- stdout_mock.write('A line with TestProject.')
- stdout_mock.write('A line with %s.' % self.nacl_src_dir)
- stdout_mock.write('A line with <NACL_PLATFORM>.')
- self.fileinput_mock.input(
- 'test/dir/test_project/normal_name.txt',
- inplace=1, mode='U').AndReturn(
- ['A line with test_project.',
- 'A line with TestProject.',
- 'A line with some/dir.',
- 'A line with <NACL_PLATFORM>.'])
- stdout_mock.write('A line with test_project.')
- stdout_mock.write('A line with TestProject.')
- stdout_mock.write('A line with some/dir.')
- stdout_mock.write('A line with pepper_14.')
- # One multi-line file with different replacements has already been mocked
- # so we make this next test simpler.
- self.fileinput_mock.input(
- 'test/dir/test_project/test_project.txt',
- inplace=1, mode='U').AndReturn(['A line with no replaceable text.'])
- stdout_mock.write('A line with no replaceable text.')
- self.fileinput_mock.input(
- 'test/dir/test_project/test_project.txt',
- inplace=1, mode='U').AndReturn(['A line with no replaceable text.'])
- stdout_mock.write('A line with no replaceable text.')
- self.fileinput_mock.input(
- 'test/dir/test_project/test_project.txt',
- inplace=1, mode='U').AndReturn(['A line with no replaceable text.'])
- stdout_mock.write('A line with no replaceable text.')
- self.fileinput_mock.input(
- 'test/dir/test_project/test_project.txt',
- inplace=1, mode='U').AndReturn(['A line with no replaceable text.'])
- stdout_mock.write('A line with no replaceable text.')
- self.sys_mock.stdout = stdout_mock
- self.mock_factory.ReplayAll()
- self.test_subject.PrepareFileContent()
- self.mock_factory.VerifyAll()
-
- def testReplaceInFile(self):
- self.fileinput_mock.input('test/path', inplace=1, mode='U').AndReturn(
- ['A sentence replace_me.'])
- stdout_mock = self.mock_factory.CreateMock(sys.stdout)
- stdout_mock.write('A sentence with_this.')
- self.sys_mock.stdout = stdout_mock
- self.mock_factory.ReplayAll()
- self.test_subject.ReplaceInFile('test/path', 'replace_me', 'with_this')
- self.mock_factory.VerifyAll()
-
-
-def RunTests():
- # It's possible to do this with one suite instead of two, but then it's
- # harder to read the test output.
- return_value = 1
- suite_one = unittest.TestLoader().loadTestsFromTestCase(TestGlobalFunctions)
- result_one = unittest.TextTestRunner(verbosity=2).run(suite_one)
- suite_two = unittest.TestLoader().loadTestsFromTestCase(
- TestProjectInitializer)
- result_two = unittest.TextTestRunner(verbosity=2).run(suite_two)
- if result_one.wasSuccessful() and result_two.wasSuccessful():
- return_value = 0
- return return_value
-
-
-if __name__ == '__main__':
- sys.exit(RunTests())
diff --git a/native_client_sdk/src/project_templates/scons b/native_client_sdk/src/project_templates/scons
deleted file mode 100755
index 17e9350017..0000000000
--- a/native_client_sdk/src/project_templates/scons
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2011 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.
-
-readonly SCRIPT_DIR="$(dirname "$0")"
-readonly SCRIPT_DIR_ABS="$(cd "${SCRIPT_DIR}" ; pwd -P)"
-readonly SRC_DIR="$(dirname $(dirname $(dirname ${SCRIPT_DIR_ABS})))"
-
-# NACL_SDK_ROOT must be set.
-if [ x"${NACL_SDK_ROOT}"x == "xx" ] ; then
- echo "Error: NACL_SDK_ROOT is not set."
- exit 1;
-fi
-
-# NACL_TARGET_PLATFORM is really the name of a folder with the base dir -
-# usually NACL_SDK_ROOT - within which the toolchain for the target platform
-# are found.
-# Replace the platform with the name of your target platform. For example, to
-# build applications that target the pepper_17 API, set
-# NACL_TARGET_PLATFORM="pepper_17"
-if [ x"${NACL_TARGET_PLATFORM}"x == "xx" ] ; then
- export NACL_TARGET_PLATFORM="pepper_17"
-fi
-
-readonly NACL_PLATFORM_DIR="${NACL_SDK_ROOT}/${NACL_TARGET_PLATFORM}"
-
-SCONS_DIR="${NACL_PLATFORM_DIR}/third_party/scons-2.0.1"
-
-if [ ! -f ${SCONS_DIR}/script/scons ]; then
- SCONS_DIR="${SRC_DIR}/third_party/scons-2.0.1"
-fi
-
-BASE_SCRIPT="${SCONS_DIR}/script/scons"
-
-export SCONS_LIB_DIR="${SCONS_DIR}/engine"
-export PYTHONPATH="${SCONS_LIB_DIR}"
-export PYTHONPATH="${PYTHONPATH}:${NACL_PLATFORM_DIR}/build_tools"
-
-# We have to do this because scons overrides PYTHONPATH and does not preserve
-# what is provided by the OS. The custom variable name won't be overwritten.
-export PYMOX="${NACL_PLATFORM_DIR}/third_party/pymox/src"
-
-"${BASE_SCRIPT}" --file=build.scons \
- --site-dir="${SCRIPT_DIR_ABS}/../build_tools/nacl_sdk_scons" \
- $*
diff --git a/native_client_sdk/src/project_templates/scons.bat b/native_client_sdk/src/project_templates/scons.bat
deleted file mode 100755
index d56f2456cc..0000000000
--- a/native_client_sdk/src/project_templates/scons.bat
+++ /dev/null
@@ -1,50 +0,0 @@
-@echo off
-
-:: Copyright (c) 2011 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.
-
-setlocal
-
-:: NACL_SDK_ROOT must be set.
-if not defined NACL_SDK_ROOT (
- echo Error: NACL_SDK_ROOT is not set.
- echo Please set NACL_SDK_ROOT to the full path of the Native Client SDK.
- echo For example:
- echo set NACL_SDK_ROOT=D:\nacl_sdk
- goto end
-)
-
-:: NACL_TARGET_PLATFORM is really the name of a folder with the base dir -
-:: usually NACL_SDK_ROOT - within which the toolchain for the target platform
-:: are found.
-:: Replace the platform with the name of your target platform. For example, to
-:: build applications that target the pepper_17 API, set
-:: NACL_TARGET_PLATFORM=pepper_17
-if not defined NACL_TARGET_PLATFORM (
- set NACL_TARGET_PLATFORM=pepper_17
-)
-
-set NACL_PLATFORM_DIR=%NACL_SDK_ROOT%\%NACL_TARGET_PLATFORM%
-
-set SCONS_DIR=%NACL_PLATFORM_DIR%\third_party\scons-2.0.1
-if exist %SCONS_DIR% goto gotscons
-set SCONS_DIR=%~dp0..\..\..\third_party\scons-2.0.1
-:gotscons
-
-set SCONS_LIB_DIR=%SCONS_DIR%\engine
-set PYTHONPATH=%SCONS_LIB_DIR%;%NACL_PLATFORM_DIR%\build_tools
-
-:: We have to do this because scons overrides PYTHONPATH and does not preserve
-:: what is provided by the OS. The custom variable name won't be overwritten.
-set PYMOX=%NACL_PLATFORM_DIR%\third_party\pymox\src
-
-set BASE_SCRIPT=%SCONS_DIR%\script\scons
-
-:: Run the included copy of scons.
-python -O -OO %BASE_SCRIPT% ^
---warn no-visual-c-missing ^
---file=build.scons ^
---site-dir="%~dp0..\build_tools\nacl_sdk_scons" %*
-
-:end
diff --git a/native_client_sdk/src/project_templates/test.scons b/native_client_sdk/src/project_templates/test.scons
deleted file mode 100644
index 56c3ac2731..0000000000
--- a/native_client_sdk/src/project_templates/test.scons
+++ /dev/null
@@ -1,26 +0,0 @@
-#! -*- python -*-
-#
-# Copyright (c) 2010 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.
-
-"""Build file for tests of init_project interface.
-
-Adapted from scons documentation: http://www.scons.org/wiki/UnitTests
-
-RunUnitTests(): Runs a comment and uses the return code to determine success.
-"""
-
-__author__ = 'mlinck@google.com (Michael Linck)'
-
-import os
-import sys
-
-Import('env')
-
-#TODO(mlinck) Enable this test again when it works on Windows
-cmd = env.CreatePythonUnitTest(filename='init_project_test.py',
- dependencies=['init_project.py'],
- disabled=env['IS_WINDOWS'])
-
-env.AddNodeToTestSuite(cmd, ['bot'], 'run_init_project_test', 'small')
diff --git a/native_client_sdk/src/project_templates/vs/project_file.sln b/native_client_sdk/src/project_templates/vs/project_file.sln
deleted file mode 100644
index 05f5169222..0000000000
--- a/native_client_sdk/src/project_templates/vs/project_file.sln
+++ /dev/null
@@ -1,20 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "<PROJECT_NAME>", "<PROJECT_NAME>.vcproj", "{<VS_PROJECT_UUID>}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Release|Win32 = Release|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {<VS_PROJECT_UUID>}.Debug|Win32.ActiveCfg = Debug|Win32
- {<VS_PROJECT_UUID>}.Debug|Win32.Build.0 = Debug|Win32
- {<VS_PROJECT_UUID>}.Release|Win32.ActiveCfg = Release|Win32
- {<VS_PROJECT_UUID>}.Release|Win32.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/native_client_sdk/src/project_templates/vs/project_file.vcproj b/native_client_sdk/src/project_templates/vs/project_file.vcproj
deleted file mode 100644
index d2b0f253e8..0000000000
--- a/native_client_sdk/src/project_templates/vs/project_file.vcproj
+++ /dev/null
@@ -1,184 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="<PROJECT_NAME>"
- ProjectGUID="{<VS_PROJECT_UUID>"
- RootNamespace="<PROJECT_NAME>"
- Keyword="MakeFileProj"
- TargetFrameworkVersion="196613"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="0"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons"
- ReBuildCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons -c &amp;&amp; $(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons"
- CleanCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons -c"
- Output="<PROJECT_NAME>_x86_64_dbg.nexe"
- PreprocessorDefinitions="WIN32;_DEBUG"
- IncludeSearchPath=""
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="0"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine=""
- ReBuildCommandLine=""
- CleanCommandLine=""
- Output="<PROJECT_NAME>.exe"
- PreprocessorDefinitions="WIN32;NDEBUG"
- IncludeSearchPath=""
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{<VS_SOURCE_UUID>}"
- >
- <File
- RelativePath=".\build.scons"
- >
- </File>
- <File
- RelativePath=".\<PROJECT_NAME>.cc"
- >
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{<VS_HEADER_UUID>}"
- >
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
- UniqueIdentifier="{<VS_RESOURCE_UUID>}"
- >
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="<PROJECT_NAME>"
- ProjectGUID="{<VS_PROJECT_UUID>"
- RootNamespace="<PROJECT_NAME>"
- Keyword="MakeFileProj"
- TargetFrameworkVersion="196613"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="0"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons"
- ReBuildCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons -c &amp;&amp; $(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons"
- CleanCommandLine="$(NACL_SDK_ROOT)\<NACL_PLATFORM>\examples\scons -c"
- Output="<PROJECT_NAME>_x86_64_dbg.nexe"
- PreprocessorDefinitions="WIN32;_DEBUG"
- IncludeSearchPath=""
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="0"
- >
- <Tool
- Name="VCNMakeTool"
- BuildCommandLine=""
- ReBuildCommandLine=""
- CleanCommandLine=""
- Output="<PROJECT_NAME>.exe"
- PreprocessorDefinitions="WIN32;NDEBUG"
- IncludeSearchPath=""
- ForcedIncludes=""
- AssemblySearchPath=""
- ForcedUsingAssemblies=""
- CompileAsManaged=""
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{<VS_SOURCE_UUID>}"
- >
- <File
- RelativePath=".\build.scons"
- >
- </File>
- <File
- RelativePath=".\<PROJECT_NAME>.cc"
- >
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{<VS_HEADER_UUID>}"
- >
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
- UniqueIdentifier="{<VS_RESOURCE_UUID>}"
- >
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/native_client_sdk/src/tools/common.mk b/native_client_sdk/src/tools/common.mk
index 058af1b383..ae8604d48c 100644
--- a/native_client_sdk/src/tools/common.mk
+++ b/native_client_sdk/src/tools/common.mk
@@ -28,6 +28,7 @@ TOP_MAKE := $(word 1,$(MAKEFILE_LIST))
# Figure out which OS we are running on.
#
GETOS = python $(NACL_SDK_ROOT)/tools/getos.py
+FIXDEPS = python $(NACL_SDK_ROOT)/tools/fix_deps.py
OSNAME := $(shell $(GETOS))
@@ -77,10 +78,23 @@ else # TOOLCHAIN=all
# Verify we selected a valid toolchain for this example
#
ifeq (,$(findstring $(TOOLCHAIN),$(VALID_TOOLCHAINS)))
+
+# Only fail to build if this is a top-level make. When building recursively, we
+# don't care if an example can't build with this toolchain.
+ifeq ($(MAKELEVEL),0)
$(warning Availbile choices are: $(VALID_TOOLCHAINS))
$(error Can not use TOOLCHAIN=$(TOOLCHAIN) on this example.)
+else
+
+# Dummy targets for recursive make with unsupported toolchain...
+.PHONY: all clean install
+all:
+clean:
+install:
+
endif
+else # TOOLCHAIN is valid...
#
# Build Configuration
@@ -234,7 +248,7 @@ clean:
# $3 = Extra Settings
#
define DEPEND_RULE
-ifndef $(IGNORE_DEPS)
+ifndef IGNORE_DEPS
.PHONY: rebuild_$(1)
rebuild_$(1) :| $(STAMPDIR)/dir.stamp
@@ -370,7 +384,7 @@ endif
#
# Assign a sensible default to CHROME_PATH.
#
-CHROME_PATH ?= $(shell python $(NACL_SDK_ROOT)/tools/getos.py --chrome 2> $(DEV_NULL))
+CHROME_PATH ?= $(shell $(GETOS) --chrome 2> $(DEV_NULL))
#
# Verify we can find the Chrome executable if we need to launch it.
@@ -423,7 +437,7 @@ run_package: check_for_chrome all
$(CHROME_PATH) --load-and-launch-app=$(CURDIR) $(CHROME_ARGS)
-SYSARCH = $(shell python $(NACL_SDK_ROOT)/tools/getos.py --nacl-arch)
+SYSARCH = $(shell $(GETOS) --nacl-arch)
GDB_ARGS += -D $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/$(SYSARCH)-nacl-gdb
GDB_ARGS += -D $(abspath $(OUTDIR))/$(TARGET)_$(SYSARCH).nexe
@@ -443,4 +457,6 @@ DEBUG: debug
LAUNCH: run
RUN: run
+endif # TOOLCHAIN is valid...
+
endif # TOOLCHAIN=all
diff --git a/native_client_sdk/src/tools/create_html.py b/native_client_sdk/src/tools/create_html.py
index c0d1eb43ce..8634d4a4a2 100755
--- a/native_client_sdk/src/tools/create_html.py
+++ b/native_client_sdk/src/tools/create_html.py
@@ -136,6 +136,8 @@ def CreateHTML(filenames, options):
cmd = [create_nmf, '-s', staging, '-o', nmf] + filenames
if options.verbose:
cmd.append('-v')
+ if options.debug_libs:
+ cmd.append('--debug-libs')
Log(cmd)
try:
subprocess.check_call(cmd)
@@ -158,6 +160,8 @@ def main(argv):
parser = optparse.OptionParser(usage, description=description, epilog=epilog)
parser.add_option('-v', '--verbose', action='store_true',
help='Verbose output')
+ parser.add_option('-d', '--debug-libs', action='store_true',
+ help='When calling create_nmf request debug libaries')
parser.add_option('-o', '--output', dest='output',
help='Name of html file to write (default is '
'input name with .html extension)',
diff --git a/native_client_sdk/src/tools/fix_deps.py b/native_client_sdk/src/tools/fix_deps.py
new file mode 100755
index 0000000000..a10feacc11
--- /dev/null
+++ b/native_client_sdk/src/tools/fix_deps.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+# 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.
+
+"""Fixup GCC-generated dependency files.
+
+Modify GCC generated dependency files in-place so they are more suitable
+for including in a GNU Makefile. Without the fixups, deleting or renaming
+headers can cause the build to be broken. See:
+http://mad-scientist.net/make/autodep.html for more details of the problem.
+"""
+
+import os
+import optparse
+import sys
+
+TAG_LINE = '# Updated by fix_deps.py\n'
+
+
+class Error(Exception):
+ pass
+
+
+def ParseLine(line, new_target):
+ """Parse one line of a GCC-generated deps file.
+
+ Each line contains an optional target and then a list
+ of space seperated dependencies. Spaces within filenames
+ are escaped with a backslash.
+ """
+ filenames = []
+
+ if new_target and ':' in line:
+ line = line.split(':', 1)[1]
+
+ line = line.strip()
+ line = line.rstrip('\\')
+
+ while True:
+ # Find the next non-escaped space
+ line = line.strip()
+ pos = line.find(' ')
+ while pos > 0 and line[pos-1] == '\\':
+ pos = line.find(' ', pos+1)
+
+ if pos == -1:
+ filenames.append(line)
+ break
+ filenames.append(line[:pos])
+ line = line[pos+1:]
+
+ return filenames
+
+
+def FixupDepFile(filename):
+ if not os.path.exists(filename):
+ raise Error('File not found: %s' % filename)
+
+ outlines = [TAG_LINE]
+ deps = []
+ new_target = True
+ with open(filename) as infile:
+ for line in infile:
+ if line == TAG_LINE:
+ raise Error('Already processed: %s' % filename)
+ outlines.append(line)
+ deps += ParseLine(line, new_target)
+ new_target = line.endswith('\\')
+
+ # For every depenency found output a dummy target with no rules
+ for dep in deps:
+ outlines.append('%s:\n' % dep)
+
+ with open(filename, 'w') as outfile:
+ for line in outlines:
+ outfile.write(line)
+
+
+def main(argv):
+ usage = "usage: %prog [options] <dep_file ...>"
+ parser = optparse.OptionParser(usage=usage, description=__doc__)
+ args = parser.parse_args(argv)[1]
+ if not args:
+ raise parser.error('expected one or more files as arguments')
+ for arg in args:
+ FixupDepFile(arg)
+
+
+if __name__ == '__main__':
+ try:
+ sys.exit(main(sys.argv[1:]))
+ except Error as e:
+ sys.stderr.write('%s: %s\n' % (os.path.basename(__file__), e))
+ sys.exit(1)
diff --git a/native_client_sdk/src/tools/getos.py b/native_client_sdk/src/tools/getos.py
index bd312b4b90..70971a67a8 100755
--- a/native_client_sdk/src/tools/getos.py
+++ b/native_client_sdk/src/tools/getos.py
@@ -69,7 +69,7 @@ def GetSDKVersion():
name, value = line.split(':', 1)
if name == "Version":
version = value.strip()
- if name == "Revision":
+ if name == "Chrome Revision":
revision = value.strip()
if revision == None or version == None:
diff --git a/native_client_sdk/src/tools/host_gcc.mk b/native_client_sdk/src/tools/host_gcc.mk
index 61b4a7e322..601ec814ca 100644
--- a/native_client_sdk/src/tools/host_gcc.mk
+++ b/native_client_sdk/src/tools/host_gcc.mk
@@ -14,8 +14,8 @@
# We use the C++ compiler for everything and then use the -Wl,-as-needed flag
# in the linker to drop libc++ unless it's actually needed.
#
-HOST_CC ?= gcc
-HOST_CXX ?= g++
+HOST_CC ?= $(NACL_COMPILER_PREFIX) gcc
+HOST_CXX ?= $(NACL_COMPILER_PREFIX) g++
HOST_LINK ?= g++
HOST_LIB ?= ar
HOST_STRIP ?= strip
@@ -41,15 +41,19 @@ define C_COMPILER_RULE
-include $(call SRC_TO_DEP,$(1))
$(call SRC_TO_OBJ,$(1)): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CC ,$$@,$(HOST_CC) -o $$@ -c $$< -fPIC $(POSIX_FLAGS) $(2) $(LINUX_FLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1))
endef
define CXX_COMPILER_RULE
-include $(call SRC_TO_DEP,$(1))
$(call SRC_TO_OBJ,$(1)): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CXX ,$$@,$(HOST_CXX) -o $$@ -c $$< -fPIC $(POSIX_FLAGS) $(2) $(LINUX_FLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1))
endef
-
+#
+# Compile Macro
+#
# $1 = Source Name
# $2 = POSIX Compile Flags
# $3 = VC Flags (unused)
diff --git a/native_client_sdk/src/tools/nacl_gcc.mk b/native_client_sdk/src/tools/nacl_gcc.mk
index 383f0f45c3..86c867913d 100644
--- a/native_client_sdk/src/tools/nacl_gcc.mk
+++ b/native_client_sdk/src/tools/nacl_gcc.mk
@@ -22,27 +22,29 @@ LD_ARM := -L$(NACL_SDK_ROOT)/lib/$(TOOLCHAIN)_arm/$(CONFIG)
# We always link with the C++ compiler but include -Wl,-as-needed flag
# in LD_FLAGS so the linker should drop libc++ unless it's actually needed.
#
-X86_32_CC ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/i686-nacl-gcc
-X86_32_CXX ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/i686-nacl-g++
-X86_32_LINK ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/i686-nacl-g++
-X86_32_LIB ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/i686-nacl-ar
-X86_32_STRIP ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/i686-nacl-strip
-X86_32_NM ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/i686-nacl-nm
-
-X86_64_CC ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/x86_64-nacl-gcc
-X86_64_CXX ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/x86_64-nacl-g++
-X86_64_LINK ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/x86_64-nacl-g++
-X86_64_LIB ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/x86_64-nacl-ar
-X86_64_STRIP ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/x86_64-nacl-strip
-X86_64_NM ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin/x86_64-nacl-nm
-
-ARM_CC ?= $(TC_PATH)/$(OSNAME)_arm_$(TOOLCHAIN)/bin/arm-nacl-gcc
-ARM_CXX ?= $(TC_PATH)/$(OSNAME)_arm_$(TOOLCHAIN)/bin/arm-nacl-g++
-ARM_LINK ?= $(TC_PATH)/$(OSNAME)_arm_$(TOOLCHAIN)/bin/arm-nacl-g++
-ARM_LIB ?= $(TC_PATH)/$(OSNAME)_arm_$(TOOLCHAIN)/bin/arm-nacl-ar
-ARM_STRIP ?= $(TC_PATH)/$(OSNAME)_arm_$(TOOLCHAIN)/bin/arm-nacl-strip
-ARM_NM ?= $(TC_PATH)/$(OSNAME)_arm_$(TOOLCHAIN)/bin/arm-nacl-nm
-
+X86_TC_BIN ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/bin
+ARM_TC_BIN ?= $(TC_PATH)/$(OSNAME)_arm_$(TOOLCHAIN)/bin
+
+X86_32_CC ?= $(NACL_COMPILER_PREFIX) $(X86_TC_BIN)/i686-nacl-gcc
+X86_32_CXX ?= $(NACL_COMPILER_PREFIX) $(X86_TC_BIN)/i686-nacl-g++
+X86_32_LINK ?= $(X86_TC_BIN)/i686-nacl-g++
+X86_32_LIB ?= $(X86_TC_BIN)/i686-nacl-ar
+X86_32_STRIP ?= $(X86_TC_BIN)/i686-nacl-strip
+X86_32_NM ?= $(X86_TC_BIN)/i686-nacl-nm
+
+X86_64_CC ?= $(NACL_COMPILER_PREFIX) $(X86_TC_BIN)/x86_64-nacl-gcc
+X86_64_CXX ?= $(NACL_COMPILER_PREFIX) $(X86_TC_BIN)/x86_64-nacl-g++
+X86_64_LINK ?= $(X86_TC_BIN)/x86_64-nacl-g++
+X86_64_LIB ?= $(X86_TC_BIN)/x86_64-nacl-ar
+X86_64_STRIP ?= $(X86_TC_BIN)/x86_64-nacl-strip
+X86_64_NM ?= $(X86_TC_BIN)/x86_64-nacl-nm
+
+ARM_CC ?= $(NACL_COMPILER_PREFIX) $(ARM_TC_BIN)/arm-nacl-gcc
+ARM_CXX ?= $(NACL_COMPILER_PREFIX) $(ARM_TC_BIN)/arm-nacl-g++
+ARM_LINK ?= $(ARM_TC_BIN)/arm-nacl-g++
+ARM_LIB ?= $(ARM_TC_BIN)/arm-nacl-ar
+ARM_STRIP ?= $(ARM_TC_BIN)/arm-nacl-strip
+ARM_NM ?= $(ARM_TC_BIN)/arm-nacl-nm
# Architecture-specific flags
X86_32_CFLAGS ?=
@@ -53,6 +55,9 @@ X86_32_CXXFLAGS ?=
X86_64_CXXFLAGS ?=
ARM_CXXFLAGS ?=
+X86_32_LDFLAGS ?= -Wl,-Map,$(OUTDIR)/$(TARGET)_x86_32.map
+X86_64_LDFLAGS ?= -Wl,-Map,$(OUTDIR)/$(TARGET)_x86_64.map
+ARM_LDFLAGS ?= -Wl,-Map,$(OUTDIR)/$(TARGET)_arm.map
#
# Compile Macro
@@ -64,52 +69,64 @@ define C_COMPILER_RULE
-include $(call SRC_TO_DEP,$(1),_x86_32)
$(call SRC_TO_OBJ,$(1),_x86_32): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CC ,$$@,$(X86_32_CC) -o $$@ -c $$< $(POSIX_FLAGS) $(2) $(NACL_CFLAGS) $(X86_32_CFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_x86_32)
-include $(call SRC_TO_DEP,$(1),_x86_64)
$(call SRC_TO_OBJ,$(1),_x86_64): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CC ,$$@,$(X86_64_CC) -o $$@ -c $$< $(POSIX_FLAGS) $(2) $(NACL_CFLAGS) $(X86_64_CFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_x86_64)
-include $(call SRC_TO_DEP,$(1),_arm)
$(call SRC_TO_OBJ,$(1),_arm): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CC ,$$@,$(ARM_CC) -o $$@ -c $$< $(POSIX_FLAGS) $(2) $(NACL_CFLAGS) $(ARM_CFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_arm)
-include $(call SRC_TO_DEP,$(1),_x86_32_pic)
$(call SRC_TO_OBJ,$(1),_x86_32_pic): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CC ,$$@,$(X86_32_CC) -o $$@ -c $$< -fPIC $(POSIX_FLAGS) $(2) $(NACL_CFLAGS) $(X86_32_CFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_x86_32_pic)
-include $(call SRC_TO_DEP,$(1),_x86_64_pic)
$(call SRC_TO_OBJ,$(1),_x86_64_pic): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CC ,$$@,$(X86_64_CC) -o $$@ -c $$< -fPIC $(POSIX_FLAGS) $(2) $(NACL_CFLAGS) $(X86_64_CFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_x86_64_pic)
-include $(call SRC_TO_DEP,$(1),_arm_pic)
$(call SRC_TO_OBJ,$(1),_arm_pic): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CC ,$$@,$(ARM_CC) -o $$@ -c $$< -fPIC $(POSIX_FLAGS) $(2) $(NACL_CFLAGS) $(ARM_CFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_arm_pic)
endef
define CXX_COMPILER_RULE
-include $(call SRC_TO_DEP,$(1),_x86_32)
$(call SRC_TO_OBJ,$(1),_x86_32): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CXX ,$$@,$(X86_32_CXX) -o $$@ -c $$< $(POSIX_FLAGS) $(2) $(NACL_CXXFLAGS) $(X86_32_CXXFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_x86_32)
-include $(call SRC_TO_DEP,$(1),_x86_64)
$(call SRC_TO_OBJ,$(1),_x86_64): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CXX ,$$@,$(X86_64_CXX) -o $$@ -c $$< $(POSIX_FLAGS) $(2) $(NACL_CXXFLAGS) $(X86_64_CXXFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_x86_64)
-include $(call SRC_TO_DEP,$(1),_arm)
$(call SRC_TO_OBJ,$(1),_arm): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CXX ,$$@,$(ARM_CXX) -o $$@ -c $$< $(POSIX_FLAGS) $(2) $(NACL_CXXFLAGS) $(ARM_CXXFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_arm)
-include $(call SRC_TO_DEP,$(1),_x86_32_pic)
$(call SRC_TO_OBJ,$(1),_x86_32_pic): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CXX ,$$@,$(X86_32_CXX) -o $$@ -c $$< -fPIC $(POSIX_FLAGS) $(2) $(NACL_CXXFLAGS) $(X86_32_CXXFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_x86_32_pic)
-include $(call SRC_TO_DEP,$(1),_x86_64_pic)
$(call SRC_TO_OBJ,$(1),_x86_64_pic): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CXX ,$$@,$(X86_64_CXX) -o $$@ -c $$< -fPIC $(POSIX_FLAGS) $(2) $(NACL_CXXFLAGS) $(X86_64_CXXFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_x86_64_pic)
-include $(call SRC_TO_DEP,$(1),_arm_pic)
$(call SRC_TO_OBJ,$(1),_arm_pic): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CXX ,$$@,$(ARM_CXX) -o $$@ -c $$< -fPIC $(POSIX_FLAGS) $(2) $(NACL_CXXFLAGS) $(ARM_CXXFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_arm_pic)
endef
@@ -249,19 +266,19 @@ define LINKER_RULE
ifneq (,$(findstring x86_32,$(ARCHES)))
all: $(OUTDIR)/$(1)_x86_32.nexe
$(OUTDIR)/$(1)_x86_32.nexe: $(foreach src,$(2),$(call SRC_TO_OBJ,$(src),_x86_32)) $(foreach dep,$(4),$(STAMPDIR)/$(dep).stamp)
- $(call LOG,LINK,$$@,$(X86_32_LINK) -o $$@ $$(filter %.o,$$^) $(NACL_LDFLAGS) $(foreach path,$(6),-L$(path)/$(TOOLCHAIN)_x86_32/$(CONFIG)) $(foreach lib,$(3),-l$(lib)) $(5))
+ $(call LOG,LINK,$$@,$(X86_32_LINK) -o $$@ $$(filter %.o,$$^) $(NACL_LDFLAGS) $(X86_32_LDFLAGS) $(foreach path,$(6),-L$(path)/$(TOOLCHAIN)_x86_32/$(CONFIG)) $(foreach lib,$(3),-l$(lib)) $(5))
endif
ifneq (,$(findstring x86_64,$(ARCHES)))
all: $(OUTDIR)/$(1)_x86_64.nexe
$(OUTDIR)/$(1)_x86_64.nexe: $(foreach src,$(2),$(call SRC_TO_OBJ,$(src),_x86_64)) $(foreach dep,$(4),$(STAMPDIR)/$(dep).stamp)
- $(call LOG,LINK,$$@,$(X86_64_LINK) -o $$@ $$(filter %.o,$$^) $(NACL_LDFLAGS) $(foreach path,$(6),-L$(path)/$(TOOLCHAIN)_x86_64/$(CONFIG)) $(foreach lib,$(3),-l$(lib)) $(5))
+ $(call LOG,LINK,$$@,$(X86_64_LINK) -o $$@ $$(filter %.o,$$^) $(NACL_LDFLAGS) $(X86_64_LDFLAGS) $(foreach path,$(6),-L$(path)/$(TOOLCHAIN)_x86_64/$(CONFIG)) $(foreach lib,$(3),-l$(lib)) $(5))
endif
ifneq (,$(findstring arm,$(ARCHES)))
all: $(OUTDIR)/$(1)_arm.nexe
$(OUTDIR)/$(1)_arm.nexe: $(foreach src,$(2),$(call SRC_TO_OBJ,$(src),_arm)) $(foreach dep,$(4),$(STAMPDIR)/$(dep).stamp)
- $(call LOG,LINK,$$@,$(ARM_LINK) -o $$@ $$(filter %.o,$$^) $(NACL_LDFLAGS) $(foreach path,$(6),-L$(path)/$(TOOLCHAIN)_arm/$(CONFIG)) $(foreach lib,$(3),-l$(lib)) $(5))
+ $(call LOG,LINK,$$@,$(ARM_LINK) -o $$@ $$(filter %.o,$$^) $(NACL_LDFLAGS) $(ARM_LDFLAGS) $(foreach path,$(6),-L$(path)/$(TOOLCHAIN)_arm/$(CONFIG)) $(foreach lib,$(3),-l$(lib)) $(5))
endif
endef
@@ -368,12 +385,14 @@ ARCH_SUFFIXES := $(foreach arch,$(ARCHES),_$(arch).nexe)
NMF := python $(NACL_SDK_ROOT)/tools/create_nmf.py
ifeq ($(CONFIG),Debug)
NMF_FLAGS += --debug-libs
+HTML_FLAGS += --debug-libs
endif
+EXECUTABLES=$(foreach arch,$(ARCH_SUFFIXES),$(OUTDIR)/$(1)$(arch)) $(GLIBC_SO_LIST)
define NMF_RULE
all: $(OUTDIR)/$(1).nmf
-$(OUTDIR)/$(1).nmf: $(foreach arch,$(ARCH_SUFFIXES),$(OUTDIR)/$(1)$(arch)) $(GLIBC_SO_LIST)
+$(OUTDIR)/$(1).nmf: $(EXECUTABLES)
$(call LOG,CREATE_NMF,$$@,$(NMF) $(NMF_FLAGS) -o $$@ $$^ $(GLIBC_PATHS) -s $(OUTDIR) $(2) $(GLIBC_REMAP))
endef
@@ -384,6 +403,6 @@ CREATE_HTML := python $(NACL_SDK_ROOT)/tools/create_html.py
define HTML_RULE
all: $(OUTDIR)/$(1).html
-$(OUTDIR)/$(1).html: $(foreach arch,$(ARCH_SUFFIXES),$(OUTDIR)/$(1)$(arch)) $(GLIBC_SO_LIST)
- $(call LOG,CREATE_HTML,$$@,$(CREATE_HTML) -o $$@ $$^)
+$(OUTDIR)/$(1).html: $(EXECUTABLES)
+ $(call LOG,CREATE_HTML,$$@,$(CREATE_HTML) $(HTML_FLAGS) -o $$@ $$^)
endef
diff --git a/native_client_sdk/src/tools/nacl_llvm.mk b/native_client_sdk/src/tools/nacl_llvm.mk
index fe9762bf26..f6301e5e5d 100644
--- a/native_client_sdk/src/tools/nacl_llvm.mk
+++ b/native_client_sdk/src/tools/nacl_llvm.mk
@@ -7,15 +7,16 @@
# http://www.gnu.org/software/make/manual/make.html
#
-
#
# Paths to Tools
#
-PNACL_CC ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/newlib/bin/pnacl-clang -c
-PNACL_CXX ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/newlib/bin/pnacl-clang++ -c
-PNACL_LINK ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/newlib/bin/pnacl-clang++
-PNACL_LIB ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/newlib/bin/pnacl-ar
-PNACL_STRIP ?= $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/newlib/bin/pnacl-finalize
+PNACL_BIN = $(TC_PATH)/$(OSNAME)_x86_$(TOOLCHAIN)/newlib/bin
+PNACL_CC ?= $(PNACL_BIN)/pnacl-clang -c
+PNACL_CXX ?= $(PNACL_BIN)/pnacl-clang++ -c
+PNACL_LINK ?= $(PNACL_BIN)/pnacl-clang++
+PNACL_LIB ?= $(PNACL_BIN)/pnacl-ar
+PNACL_STRIP ?= $(PNACL_BIN)/pnacl-strip
+PNACL_FINALIZE ?= $(PNACL_BIN)/pnacl-finalize
#
# Compile Macro
@@ -28,12 +29,14 @@ define C_COMPILER_RULE
-include $(call SRC_TO_DEP,$(1),_pnacl)
$(call SRC_TO_OBJ,$(1),_pnacl): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CC ,$$@,$(PNACL_CC) -o $$@ -c $$< $(POSIX_FLAGS) $(2) $(NACL_CFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_pnacl)
endef
define CXX_COMPILER_RULE
--include $(call SRC_TO_DEP,$(1))
+-include $(call SRC_TO_DEP,$(1),_pnacl)
$(call SRC_TO_OBJ,$(1),_pnacl): $(1) $(TOP_MAKE) | $(dir $(call SRC_TO_OBJ,$(1)))dir.stamp
$(call LOG,CXX ,$$@,$(PNACL_CXX) -o $$@ -c $$< $(POSIX_FLAGS) $(2) $(NACL_CFLAGS))
+ @$(FIXDEPS) $(call SRC_TO_DEP,$(1),_pnacl)
endef
@@ -91,9 +94,10 @@ endef
# $6 = Other Linker Args
#
define LINKER_RULE
-all: $(1)
-$(1): $(2) $(foreach dep,$(4),$(STAMPDIR)/$(dep).stamp)
- $(call LOG,LINK,$$@,$(PNACL_LINK) -o $(1) $(2) $(foreach path,$(5),-L$(path)/pnacl/$(CONFIG)) $(foreach lib,$(3),-l$(lib)) $(6))
+all: $(1).pexe
+$(1).pexe: $(2) $(foreach dep,$(4),$(STAMPDIR)/$(dep).stamp)
+ $(call LOG,LINK,$(1).bc,$(PNACL_LINK) -o $(1).bc $(2) $(foreach path,$(5),-L$(path)/pnacl/$(CONFIG)) $(foreach lib,$(3),-l$(lib)) $(6))
+ $(call LOG,FINALIZE,$(1).pexe,$(PNACL_FINALIZE) -o $(1).pexe $(1).bc)
endef
@@ -108,20 +112,25 @@ endef
# $6 = VC Linker Switches
#
define LINK_RULE
-$(call LINKER_RULE,$(OUTDIR)/$(1).pexe,$(foreach src,$(2),$(call SRC_TO_OBJ,$(src),_pnacl)),$(filter-out pthread,$(3)),$(4),$(LIB_PATHS),$(5))
+$(call LINKER_RULE,$(OUTDIR)/$(1),$(foreach src,$(2),$(call SRC_TO_OBJ,$(src),_pnacl)),$(filter-out pthread,$(3)),$(4),$(LIB_PATHS),$(5))
endef
#
# Strip Macro
#
+# NOTE: pnacl-strip does not currently support stripping finalized pexes (in a
+# sense, they are already stripped). So we just copy the file instead.
+#
+# See https://code.google.com/p/nativeclient/issues/detail?id=3534
+#
# $1 = Target Name
# $2 = Input Name
#
define STRIP_RULE
all: $(OUTDIR)/$(1).pexe
$(OUTDIR)/$(1).pexe: $(OUTDIR)/$(2).pexe
- $(call LOG,STRIP,$$@,$(PNACL_STRIP) -o $$@ $$^)
+ $(CP) $$^ $$@
endef
diff --git a/native_client_sdk/src/tools/tests/fix_deps_test.py b/native_client_sdk/src/tools/tests/fix_deps_test.py
new file mode 100755
index 0000000000..d02f8ac12e
--- /dev/null
+++ b/native_client_sdk/src/tools/tests/fix_deps_test.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# 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.
+import os
+import sys
+import tempfile
+import unittest
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+PARENT_DIR = os.path.dirname(SCRIPT_DIR)
+DATA_DIR = os.path.join(SCRIPT_DIR, 'data')
+CHROME_SRC = os.path.dirname(os.path.dirname(os.path.dirname(PARENT_DIR)))
+MOCK_DIR = os.path.join(CHROME_SRC, "third_party", "pymock")
+
+# For the mock library
+sys.path.append(MOCK_DIR)
+sys.path.append(PARENT_DIR)
+
+import fix_deps
+import mock
+
+
+class TestFixDeps(unittest.TestCase):
+ def setUp(self):
+ self.tempfile = None
+
+ def tearDown(self):
+ if self.tempfile:
+ os.remove(self.tempfile)
+
+ def testRequiresFile(self):
+ with mock.patch('sys.stderr'):
+ self.assertRaises(SystemExit, fix_deps.main, [])
+
+ def testInvalidOption(self):
+ with mock.patch('sys.stderr'):
+ self.assertRaises(SystemExit, fix_deps.main, ['--foo', 'bar'])
+
+ def testMissingFile(self):
+ with mock.patch('sys.stderr'):
+ self.assertRaises(fix_deps.Error, fix_deps.main, ['nonexistent.file'])
+
+ def testAddsDeps(self):
+ self.tempfile = tempfile.mktemp("_sdktest")
+ with open(self.tempfile, 'w') as out:
+ out.write('foo.o: foo.c foo.h bar.h\n')
+ fix_deps.FixupDepFile(self.tempfile)
+ with open(self.tempfile) as infile:
+ contents = infile.read()
+ lines = contents.splitlines()
+ self.assertEqual(len(lines), 5)
+ self.assertTrue('foo.c:' in lines)
+ self.assertTrue('foo.h:' in lines)
+ self.assertTrue('bar.h:' in lines)
+
+ def testSpacesInFilenames(self):
+ self.tempfile = tempfile.mktemp("_sdktest")
+ with open(self.tempfile, 'w') as out:
+ out.write('foo.o: foo\\ bar.h\n')
+ fix_deps.FixupDepFile(self.tempfile)
+ with open(self.tempfile) as infile:
+ contents = infile.read()
+ lines = contents.splitlines()
+ self.assertEqual(len(lines), 3)
+ self.assertEqual(lines[2], 'foo\\ bar.h:')
+
+ def testColonInFilename(self):
+ self.tempfile = tempfile.mktemp("_sdktest")
+ with open(self.tempfile, 'w') as out:
+ out.write('foo.o: c:foo.c\\\n c:bar.h\n')
+ fix_deps.FixupDepFile(self.tempfile)
+ with open(self.tempfile) as infile:
+ contents = infile.read()
+ lines = contents.splitlines()
+ self.assertEqual(len(lines), 5)
+ self.assertEqual(lines[3], 'c:foo.c:')
+ self.assertEqual(lines[4], 'c:bar.h:')
+
+ def testDoubleInvoke(self):
+ self.tempfile = tempfile.mktemp("_sdktest")
+ with open(self.tempfile, 'w') as out:
+ out.write('foo.o: foo\\ bar.h\n')
+ fix_deps.FixupDepFile(self.tempfile)
+ self.assertRaises(fix_deps.Error, fix_deps.FixupDepFile, self.tempfile)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/native_client_sdk/src/tools/tests/getos_test.py b/native_client_sdk/src/tools/tests/getos_test.py
index 3a6ad60c1e..99ffb95079 100755
--- a/native_client_sdk/src/tools/tests/getos_test.py
+++ b/native_client_sdk/src/tools/tests/getos_test.py
@@ -145,7 +145,7 @@ class TestGetosWithTempdir(TestCaseExtended):
expected_version = (16, 196)
with open(os.path.join(self.tempdir, 'README'), 'w') as out:
out.write('Version: %s\n' % expected_version[0])
- out.write('Revision: %s\n' % expected_version[1])
+ out.write('Chrome Revision: %s\n' % expected_version[1])
version = getos.GetSDKVersion()
self.assertEqual(version, expected_version)