summaryrefslogtreecommitdiff
path: root/native_client_sdk
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-06-11 10:57:03 +0100
committerTorne (Richard Coles) <torne@google.com>2013-06-11 10:57:03 +0100
commit868fa2fe829687343ffae624259930155e16dbd8 (patch)
tree54d316199dd9739c57c3aacd131853bbd6554a94 /native_client_sdk
parentbb1bdbd796f966b5bf11f40ecbea12621c7bfac9 (diff)
downloadchromium_org-868fa2fe829687343ffae624259930155e16dbd8.tar.gz
Merge from Chromium at DEPS revision r205460
This commit was generated by merge_to_master.py. Change-Id: I4a744a5e426bd3bb378d887cfa56fe054742a540
Diffstat (limited to 'native_client_sdk')
-rwxr-xr-xnative_client_sdk/src/build_tools/build_sdk.py104
-rw-r--r--native_client_sdk/src/build_tools/buildbot_common.py35
-rwxr-xr-xnative_client_sdk/src/build_tools/buildbot_run.py25
-rw-r--r--native_client_sdk/src/build_tools/generate_make.py3
-rw-r--r--native_client_sdk/src/build_tools/sdk_files.list144
-rw-r--r--native_client_sdk/src/build_tools/sdk_tools/command/info.py12
-rwxr-xr-xnative_client_sdk/src/build_tools/tests/sdktools_commands_test.py12
-rwxr-xr-xnative_client_sdk/src/build_tools/verify_filelist.py2
-rw-r--r--native_client_sdk/src/examples/api/file_io/example.js12
-rw-r--r--native_client_sdk/src/examples/api/file_io/file_io.cc38
-rw-r--r--native_client_sdk/src/examples/api/file_io/index.html4
-rw-r--r--native_client_sdk/src/examples/demo/life/example.dsc18
-rw-r--r--native_client_sdk/src/examples/demo/life/index.html (renamed from native_client_sdk/src/examples/hello_world_instance3d/index.html)9
-rw-r--r--native_client_sdk/src/examples/demo/life/life.c305
-rw-r--r--native_client_sdk/src/examples/demo/voronoi/example.dsc21
-rw-r--r--native_client_sdk/src/examples/demo/voronoi/example.js59
-rw-r--r--native_client_sdk/src/examples/demo/voronoi/index.html61
-rw-r--r--native_client_sdk/src/examples/demo/voronoi/voronoi.cc582
-rw-r--r--native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/example.dsc18
-rw-r--r--native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/hello_world.c50
-rw-r--r--native_client_sdk/src/examples/getting_started/simple_hello_world/example.dsc19
-rw-r--r--native_client_sdk/src/examples/getting_started/simple_hello_world/example.js (renamed from native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/example.js)0
-rw-r--r--native_client_sdk/src/examples/getting_started/simple_hello_world/hello_world.c24
-rw-r--r--native_client_sdk/src/examples/getting_started/simple_hello_world/index.html (renamed from native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/index.html)0
-rw-r--r--native_client_sdk/src/examples/hello_world_instance3d/example.dsc27
-rw-r--r--native_client_sdk/src/examples/hello_world_instance3d/fragment_shader_es2.frag8
-rw-r--r--native_client_sdk/src/examples/hello_world_instance3d/hello.rawbin49152 -> 0 bytes
-rw-r--r--native_client_sdk/src/examples/hello_world_instance3d/hello_world.cc325
-rw-r--r--native_client_sdk/src/examples/hello_world_instance3d/matrix.cc140
-rw-r--r--native_client_sdk/src/examples/hello_world_instance3d/matrix.h43
-rw-r--r--native_client_sdk/src/examples/hello_world_instance3d/vertex_shader_es2.vert12
-rw-r--r--native_client_sdk/src/examples/tutorial/dlopen/dlopen.cc14
-rw-r--r--native_client_sdk/src/libraries/error_handling/error_handling.h5
-rw-r--r--native_client_sdk/src/libraries/nacl_io/error.h17
-rw-r--r--native_client_sdk/src/libraries/nacl_io/inode_pool.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_handle.cc63
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_handle.h13
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.cc57
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.h15
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc415
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.h5
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_real.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/library.dsc14
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount.cc32
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount.h57
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.cc354
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.h23
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc138
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_html5fs.h18
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_http.cc771
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_http.h20
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_mem.cc256
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_mem.h18
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.cc135
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.h56
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc109
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_dir.h17
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc241
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h31
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_http.cc523
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_http.h70
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc74
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_mem.h9
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc165
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.h14
-rw-r--r--native_client_sdk/src/libraries/nacl_io/nacl_io.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/nacl_mounts.vcproj2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/osdirent.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/path.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper_interface.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/example.dsc1
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc71
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc86
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc4
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc157
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc98
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc117
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_test.cc123
-rw-r--r--native_client_sdk/src/libraries/ppapi_cpp/library.dsc1
-rw-r--r--native_client_sdk/src/libraries/ppapi_cpp_private/library.dsc1
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/library.dsc31
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_event.h81
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_instance.cc375
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_instance.h106
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_instance2d.cc87
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_instance2d.h36
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.cc144
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.h40
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_main.cc71
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_main.h62
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_queue.cc97
-rw-r--r--native_client_sdk/src/libraries/ppapi_main/ppapi_queue.h84
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/library.dsc28
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps.cc51
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps.h113
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_event.cc45
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_event.h95
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc357
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_instance.h121
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_main.cc17
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_main.h38
-rw-r--r--native_client_sdk/src/libraries/sdk_util/auto_lock.h (renamed from native_client_sdk/src/libraries/utils/auto_lock.h)7
-rw-r--r--native_client_sdk/src/libraries/sdk_util/library.dsc29
-rw-r--r--native_client_sdk/src/libraries/sdk_util/macros.h (renamed from native_client_sdk/src/libraries/utils/macros.h)7
-rw-r--r--native_client_sdk/src/libraries/sdk_util/ref_object.h (renamed from native_client_sdk/src/libraries/utils/ref_object.h)7
-rw-r--r--native_client_sdk/src/libraries/sdk_util/thread_pool.cc144
-rw-r--r--native_client_sdk/src/libraries/sdk_util/thread_pool.h45
-rw-r--r--native_client_sdk/src/libraries/sdk_util/thread_safe_queue.h63
-rwxr-xr-xnative_client_sdk/src/tools/create_nmf.py18
-rw-r--r--native_client_sdk/src/tools/host_vc.mk8
-rw-r--r--native_client_sdk/src/tools/nacl_gcc.mk13
114 files changed, 5080 insertions, 3882 deletions
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py
index 5b793536a7..9839dff510 100755
--- a/native_client_sdk/src/build_tools/build_sdk.py
+++ b/native_client_sdk/src/build_tools/build_sdk.py
@@ -54,7 +54,9 @@ import oshelpers
CYGTAR = os.path.join(NACL_DIR, 'build', 'cygtar.py')
NACLPORTS_URL = 'https://naclports.googlecode.com/svn/trunk/src'
-NACLPORTS_REV = 757
+NACLPORTS_REV = 774
+
+GYPBUILD_DIR = 'gypbuild'
options = None
@@ -434,21 +436,30 @@ TOOLCHAIN_LIBS = {
def GypNinjaInstall(pepperdir, platform, toolchains):
- build_dir = 'gypbuild'
+ build_dir = GYPBUILD_DIR
ninja_out_dir = os.path.join(OUT_DIR, build_dir, 'Release')
tools_files = [
- ['dump_syms', 'dump_syms'],
['sel_ldr', 'sel_ldr_x86_32'],
- ['ncval_x86_32', 'ncval_x86_32'],
- ['ncval_arm', 'ncval_arm'],
+ ['ncval_new', 'ncval'],
['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)
+
+ # 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'])
if platform != 'mac':
# Mac doesn't build 64-bit binaries.
tools_files.append(['sel_ldr64', 'sel_ldr_x86_64'])
- tools_files.append(['ncval_x86_64', 'ncval_x86_64'])
if platform == 'linux':
tools_files.append(['nacl_helper_bootstrap',
@@ -473,10 +484,10 @@ def GypNinjaInstall(pepperdir, platform, toolchains):
tc_dir = 'tc_' + tc
lib_dir = 'lib' + archname
if archname == 'arm':
- build_dir = 'gypbuild-arm'
+ build_dir = GYPBUILD_DIR + '-arm'
tcdir = '%s_arm_%s' % (platform, tc)
else:
- build_dir = 'gypbuild'
+ build_dir = GYPBUILD_DIR
tcdir = '%s_x86_%s' % (platform, tc)
ninja_out_dir = os.path.join(OUT_DIR, build_dir, 'Release')
@@ -502,22 +513,18 @@ def GypNinjaBuild_NaCl(platform, rel_out_dir):
out_dir_arm = MakeNinjaRelPath(rel_out_dir + '-arm')
GypNinjaBuild('ia32', gyp_py, nacl_core_sdk_gyp, 'nacl_core_sdk', out_dir)
GypNinjaBuild('arm', gyp_py, nacl_core_sdk_gyp, 'nacl_core_sdk', out_dir_arm)
- GypNinjaBuild('ia32', gyp_py, all_gyp, 'ncval_x86_32', out_dir)
- GypNinjaBuild(None, gyp_py, all_gyp, 'ncval_arm', out_dir)
+ GypNinjaBuild('ia32', gyp_py, all_gyp, 'ncval_new', out_dir)
if platform == 'win':
NinjaBuild('sel_ldr64', out_dir)
- NinjaBuild('ncval_x86_64', out_dir)
elif platform == 'linux':
out_dir_64 = MakeNinjaRelPath(rel_out_dir + '-64')
GypNinjaBuild('x64', gyp_py, nacl_core_sdk_gyp, 'sel_ldr', out_dir_64)
- GypNinjaBuild('x64', gyp_py, all_gyp, 'ncval_x86_64', out_dir_64)
- # We only need sel_ldr and ncval_x86_64 from the 64-bit out directory.
+ # We only need sel_ldr from the 64-bit out directory.
# sel_ldr needs to be renamed, so we'll call it sel_ldr64.
files_to_copy = [
('sel_ldr', 'sel_ldr64'),
- ('ncval_x86_64', 'ncval_x86_64'),
('nacl_helper_bootstrap', 'nacl_helper_bootstrap64'),
]
@@ -528,10 +535,16 @@ def GypNinjaBuild_NaCl(platform, rel_out_dir):
def GypNinjaBuild_Breakpad(platform, rel_out_dir):
+ # TODO(binji): dump_syms doesn't currently build on Windows. See
+ # http://crbug.com/245456
+ if platform == 'win':
+ return
+
gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium')
out_dir = MakeNinjaRelPath(rel_out_dir)
gyp_file = os.path.join(SRC_DIR, 'breakpad', 'breakpad.gyp')
- GypNinjaBuild('ia32', gyp_py, gyp_file, 'dump_syms', out_dir)
+ build_list = ['dump_syms', 'minidump_dump', 'minidump_stackwalk']
+ GypNinjaBuild('ia32', gyp_py, gyp_file, build_list, out_dir)
def GypNinjaBuild_PPAPI(arch, rel_out_dir):
@@ -554,6 +567,16 @@ def GypNinjaBuild_Pnacl(rel_out_dir, target_arch):
targets = ['pnacl_irt_shim']
GypNinjaBuild(target_arch, gyp_py, gyp_file, targets, out_dir, False)
+ gyp_py = os.path.join(NACL_DIR, 'build', 'gyp_nacl')
+ gyp_file = os.path.join(NACL_DIR, 'src', 'untrusted', 'minidump_generator',
+ 'minidump_generator.gyp')
+ targets = ['minidump_generator_lib']
+ GypNinjaBuild(target_arch, gyp_py, gyp_file, targets, out_dir, False)
+
+ gyp_file = os.path.join(NACL_DIR, 'src', 'untrusted', 'nacl', 'nacl.gyp')
+ targets = ['nacl_exception_lib']
+ GypNinjaBuild(target_arch, gyp_py, gyp_file, targets, out_dir, False)
+
def GypNinjaBuild(arch, gyp_py_script, gyp_file, targets,
out_dir, force_arm_gcc=True):
@@ -593,8 +616,8 @@ def NinjaBuild(targets, out_dir):
def BuildStepBuildToolchains(pepperdir, platform, toolchains):
buildbot_common.BuildStep('SDK Items')
- GypNinjaBuild_NaCl(platform, 'gypbuild')
- GypNinjaBuild_Breakpad(platform, 'gypbuild')
+ GypNinjaBuild_NaCl(platform, GYPBUILD_DIR)
+ GypNinjaBuild_Breakpad(platform, GYPBUILD_DIR)
tcname = platform + '_x86'
newlibdir = os.path.join(pepperdir, 'toolchain', tcname + '_newlib')
@@ -602,10 +625,10 @@ def BuildStepBuildToolchains(pepperdir, platform, toolchains):
pnacldir = os.path.join(pepperdir, 'toolchain', tcname + '_pnacl')
if set(toolchains) & set(['glibc', 'newlib']):
- GypNinjaBuild_PPAPI('ia32', 'gypbuild')
+ GypNinjaBuild_PPAPI('ia32', GYPBUILD_DIR)
if 'arm' in toolchains:
- GypNinjaBuild_PPAPI('arm', 'gypbuild-arm')
+ GypNinjaBuild_PPAPI('arm', GYPBUILD_DIR + '-arm')
GypNinjaInstall(pepperdir, platform, toolchains)
@@ -624,6 +647,8 @@ def BuildStepBuildToolchains(pepperdir, platform, toolchains):
'arm')
if 'pnacl' in toolchains:
+ # shell=True is needed on windows to enable searching of the PATH:
+ # http://bugs.python.org/issue8557
shell = platform == 'win'
buildbot_common.Run(
GetSconsArgs(pnacldir, pepperdir, 'x86', '32'),
@@ -632,7 +657,7 @@ def BuildStepBuildToolchains(pepperdir, platform, toolchains):
for arch in ('ia32', 'arm'):
# Fill in the latest native pnacl shim library from the chrome build.
- build_dir = 'gypbuild-pnacl-' + arch
+ build_dir = GYPBUILD_DIR + '-pnacl-' + arch
GypNinjaBuild_Pnacl(build_dir, arch)
pnacl_libdir_map = {'ia32': 'x86-64', 'arm': 'arm'}
release_build_dir = os.path.join(OUT_DIR, build_dir, 'Release',
@@ -643,6 +668,16 @@ def BuildStepBuildToolchains(pepperdir, platform, toolchains):
os.path.join(release_build_dir, 'libpnacl_irt_shim.a'),
GetPNaClNativeLib(pnacldir, pnacl_libdir_map[arch]))
+ release_build_dir = os.path.join(OUT_DIR, build_dir, 'Release',
+ 'gen', 'tc_pnacl_newlib', 'lib')
+ buildbot_common.CopyFile(
+ os.path.join(release_build_dir, 'libminidump_generator.a'),
+ GetPNaClNativeLib(pnacldir, pnacl_libdir_map[arch]))
+
+ buildbot_common.CopyFile(
+ os.path.join(release_build_dir, 'libnacl_exception.a'),
+ GetPNaClNativeLib(pnacldir, pnacl_libdir_map[arch]))
+
InstallNaClHeaders(GetToolchainNaClInclude('pnacl', pnacldir, 'x86'),
'newlib')
@@ -741,9 +776,30 @@ def GenerateNotice(fileroot, output_filename='NOTICE', extra_files=None):
def BuildStepVerifyFilelist(pepperdir, platform):
buildbot_common.BuildStep('Verify SDK Files')
- verify_filelist.Verify(platform, os.path.join(SCRIPT_DIR, 'sdk_files.list'),
- pepperdir)
- print 'OK'
+ file_list_path = os.path.join(SCRIPT_DIR, 'sdk_files.list')
+ try:
+ verify_filelist.Verify(platform, file_list_path, pepperdir)
+ print 'OK'
+ except verify_filelist.ParseException, e:
+ buildbot_common.ErrorExit('Parsing sdk_files.list failed:\n\n%s' % e)
+ except verify_filelist.VerifyException, e:
+ file_list_rel = os.path.relpath(file_list_path)
+ verify_filelist_py = os.path.splitext(verify_filelist.__file__)[0] + '.py'
+ verify_filelist_py = os.path.relpath(verify_filelist_py)
+ pepperdir_rel = os.path.relpath(pepperdir)
+
+ msg = """\
+SDK verification failed:
+
+%s
+Add/remove files from %s to fix.
+
+Run:
+ ./%s %s %s
+to test.""" % (e, file_list_rel, verify_filelist_py, file_list_rel,
+ pepperdir_rel)
+ buildbot_common.ErrorExit(msg)
+
def BuildStepTarBundle(pepper_ver, tarfile):
@@ -959,7 +1015,7 @@ def main(args):
# Archive on non-trybots.
if options.archive:
BuildStepArchiveBundle('build', pepper_ver, clnumber, tarfile)
- if platform == 'linux':
+ if options.build_ports and platform == 'linux':
BuildStepArchiveBundle('naclports', pepper_ver, clnumber, ports_tarfile)
BuildStepArchiveSDKTools()
diff --git a/native_client_sdk/src/build_tools/buildbot_common.py b/native_client_sdk/src/build_tools/buildbot_common.py
index 4de37f8d83..157cd0b856 100644
--- a/native_client_sdk/src/build_tools/buildbot_common.py
+++ b/native_client_sdk/src/build_tools/buildbot_common.py
@@ -14,6 +14,7 @@ from build_paths import SDK_SRC_DIR, NACL_DIR
sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
import oshelpers
+import getos
def IsSDKBuilder():
"""Returns True if this script is running on an SDK builder.
@@ -39,7 +40,7 @@ def IsSDKTrybot():
def ErrorExit(msg):
"""Write and error to stderr, then exit with 1 signaling failure."""
- sys.stderr.write(msg + '\n')
+ sys.stderr.write(str(msg) + '\n')
sys.exit(1)
@@ -101,16 +102,19 @@ def Run(args, cwd=None, env=None, shell=False):
so this should be avoided when not using platform dependent shell scripts."""
# We need to modify the environment to build host on Windows.
- if not env:
- if sys.platform.startswith('cygwin') or sys.platform.startswith('win'):
- env = GetWindowsEnvironment()
- else:
- env = os.environ
+ if not env and getos.GetPlatform() == 'win':
+ env = GetWindowsEnvironment()
print 'Running: ' + ' '.join(args)
sys.stdout.flush()
sys.stderr.flush()
- subprocess.check_call(args, cwd=cwd, env=env, shell=shell)
+ try:
+ subprocess.check_call(args, cwd=cwd, env=env, shell=shell)
+ except subprocess.CalledProcessError as e:
+ sys.stdout.flush()
+ sys.stderr.flush()
+ ErrorExit('buildbot_common: %s' % e)
+
sys.stdout.flush()
sys.stderr.flush()
@@ -159,12 +163,17 @@ def RemoveFile(dst):
BOT_GSUTIL = '/b/build/scripts/slave/gsutil'
+# On Windows, the current working directory may be on a different drive than
+# gsutil.
+WIN_BOT_GSUTIL = 'E:' + BOT_GSUTIL
LOCAL_GSUTIL = 'gsutil'
def GetGsutil():
if os.environ.get('BUILDBOT_BUILDERNAME') \
and not os.environ.get('BUILDBOT_FAKE'):
+ if getos.GetPlatform() == 'win':
+ return WIN_BOT_GSUTIL
return BOT_GSUTIL
else:
return LOCAL_GSUTIL
@@ -174,10 +183,14 @@ def Archive(filename, bucket_path, cwd=None, step_link=True):
"""Upload the given filename to Google Store."""
full_dst = 'gs://%s/%s' % (bucket_path, filename)
- subprocess.check_call(
- '%s cp -a public-read %s %s' % (GetGsutil(), filename, full_dst),
- shell=True,
- cwd=cwd)
+ # Since GetGsutil() might just return 'gsutil' and expect it to be looked
+ # up in the PATH, we must pass shell=True on windows.
+ # Without shell=True the windows implementation of subprocess.call will not
+ # search the PATH for the executable: http://bugs.python.org/issue8557
+ shell = getos.GetPlatform() == 'win'
+
+ cmd = [GetGsutil(), 'cp', '-a', 'public-read', filename, full_dst]
+ Run(cmd, shell=shell, cwd=cwd)
url = 'https://commondatastorage.googleapis.com/'\
'%s/%s' % (bucket_path, filename)
if step_link:
diff --git a/native_client_sdk/src/build_tools/buildbot_run.py b/native_client_sdk/src/build_tools/buildbot_run.py
index f5e4ba585d..c74308e724 100755
--- a/native_client_sdk/src/build_tools/buildbot_run.py
+++ b/native_client_sdk/src/build_tools/buildbot_run.py
@@ -14,9 +14,12 @@ run.
import buildbot_common
import os
+import subprocess
import sys
+
from buildbot_common import Run
-from build_paths import SDK_SRC_DIR, SCRIPT_DIR
+from build_paths import SRC_DIR, SDK_SRC_DIR, SCRIPT_DIR
+import getos
def StepRunUnittests():
@@ -33,7 +36,25 @@ def StepRunUnittests():
def StepBuildSDK(args):
- Run([sys.executable, 'build_sdk.py'] + args, cwd=SCRIPT_DIR)
+ is_win = getos.GetPlatform() == 'win'
+
+ # Windows has a path length limit of 255 characters, after joining cwd with a
+ # relative path. Use subst before building to keep the path lengths short.
+ if is_win:
+ subst_drive = 'S:'
+ root_dir = os.path.dirname(SRC_DIR)
+ new_root_dir = subst_drive + '\\'
+ subprocess.check_call(['subst', subst_drive, root_dir])
+ new_script_dir = os.path.join(new_root_dir,
+ os.path.relpath(SCRIPT_DIR, root_dir))
+ else:
+ new_script_dir = SCRIPT_DIR
+
+ try:
+ Run([sys.executable, 'build_sdk.py'] + args, cwd=new_script_dir)
+ finally:
+ if is_win:
+ subprocess.check_call(['subst', '/D', subst_drive])
def StepTestSDK():
diff --git a/native_client_sdk/src/build_tools/generate_make.py b/native_client_sdk/src/build_tools/generate_make.py
index 2c87f7c306..faad723a43 100644
--- a/native_client_sdk/src/build_tools/generate_make.py
+++ b/native_client_sdk/src/build_tools/generate_make.py
@@ -160,6 +160,9 @@ def FindAndCopyFiles(src_files, root, search_dirs, dst_dir):
Trace('Skipping "%s", destination "%s" is newer.' % (
src_file, dst_file))
continue
+ dst_path = os.path.dirname(dst_file)
+ if not os.path.exists(dst_path):
+ buildbot_common.MakeDir(dst_path)
buildbot_common.CopyFile(src_file, dst_file)
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index b1144262b9..67eafd07e2 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -114,6 +114,14 @@ examples/demo/drive/Makefile
examples/demo/drive/manifest.json
[win]examples/demo/make.bat
examples/demo/Makefile
+[win]examples/demo/life/make.bat
+examples/demo/life/Makefile
+examples/demo/life/background.js
+examples/demo/life/common.js
+examples/demo/life/icon128.png
+examples/demo/life/index.html
+examples/demo/life/life.c
+examples/demo/life/manifest.json
examples/demo/nacl_io/background.js
examples/demo/nacl_io/common.js
examples/demo/nacl_io/example.js
@@ -137,25 +145,34 @@ examples/demo/pi_generator/index.html
examples/demo/pi_generator/Makefile
examples/demo/pi_generator/manifest.json
examples/demo/pi_generator/pi_generator.cc
+examples/demo/voronoi/background.js
+examples/demo/voronoi/common.js
+examples/demo/voronoi/example.js
+examples/demo/voronoi/icon128.png
+examples/demo/voronoi/index.html
+examples/demo/voronoi/Makefile
+[win]examples/demo/voronoi/make.bat
+examples/demo/voronoi/manifest.json
+examples/demo/voronoi/voronoi.cc
examples/favicon.ico
+[win]examples/getting_started/hello_world/make.bat
+examples/getting_started/hello_world/Makefile
+examples/getting_started/hello_world/manifest.json
examples/getting_started/hello_world/background.js
examples/getting_started/hello_world/common.js
examples/getting_started/hello_world/example.js
examples/getting_started/hello_world/hello_world.c
examples/getting_started/hello_world/icon128.png
examples/getting_started/hello_world/index.html
-[win]examples/getting_started/hello_world/make.bat
-examples/getting_started/hello_world/Makefile
-examples/getting_started/hello_world/manifest.json
-examples/getting_started/hello_world_ppapi_main/background.js
-examples/getting_started/hello_world_ppapi_main/common.js
-examples/getting_started/hello_world_ppapi_main/example.js
-examples/getting_started/hello_world_ppapi_main/hello_world.c
-examples/getting_started/hello_world_ppapi_main/icon128.png
-examples/getting_started/hello_world_ppapi_main/index.html
-[win]examples/getting_started/hello_world_ppapi_main/make.bat
-examples/getting_started/hello_world_ppapi_main/Makefile
-examples/getting_started/hello_world_ppapi_main/manifest.json
+[win]examples/getting_started/simple_hello_world/make.bat
+examples/getting_started/simple_hello_world/Makefile
+examples/getting_started/simple_hello_world/manifest.json
+examples/getting_started/simple_hello_world/background.js
+examples/getting_started/simple_hello_world/common.js
+examples/getting_started/simple_hello_world/example.js
+examples/getting_started/simple_hello_world/hello_world.c
+examples/getting_started/simple_hello_world/icon128.png
+examples/getting_started/simple_hello_world/index.html
[win]examples/getting_started/make.bat
examples/getting_started/Makefile
examples/httpd.cmd
@@ -215,6 +232,7 @@ include/json/reader.h
include/json/value.h
include/json/writer.h
include/KHR/khrplatform.h
+include/nacl_io/error.h
include/nacl_io/inode_pool.h
include/nacl_io/kernel_handle.h
include/nacl_io/kernel_intercept.h
@@ -230,6 +248,7 @@ include/nacl_io/mount_mem.h
include/nacl_io/mount_node_dir.h
include/nacl_io/mount_node.h
include/nacl_io/mount_node_html5fs.h
+include/nacl_io/mount_node_http.h
include/nacl_io/mount_node_mem.h
include/nacl_io/mount_passthrough.h
include/nacl_io/nacl_io.h
@@ -259,6 +278,7 @@ include/ppapi/c/dev/ppb_graphics_2d_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
@@ -359,6 +379,7 @@ include/ppapi/cpp/dev/font_dev.h
include/ppapi/cpp/dev/graphics_2d_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
@@ -443,12 +464,10 @@ include/ppapi/cpp/view.h
include/ppapi/cpp/websocket.h
include/ppapi/gles2/gl2ext_ppapi.h
include/ppapi/lib/gl/gles2/gl2ext_ppapi.h
-include/ppapi_main/ppapi_event.h
-include/ppapi_main/ppapi_instance2d.h
-include/ppapi_main/ppapi_instance3d.h
-include/ppapi_main/ppapi_instance.h
-include/ppapi_main/ppapi_main.h
-include/ppapi_main/ppapi_queue.h
+include/ppapi_simple/ps.h
+include/ppapi_simple/ps_event.h
+include/ppapi_simple/ps_instance.h
+include/ppapi_simple/ps_main.h
include/ppapi/utility/completion_callback_factory.h
include/ppapi/utility/completion_callback_factory_thread_traits.h
include/ppapi/utility/graphics/paint_aggregator.h
@@ -463,9 +482,11 @@ include/ppapi/utility/websocket/websocket_api.h
[win]include/win/pthread.h
[win]include/win/sched.h
[win]include/win/semaphore.h
-include/utils/auto_lock.h
-include/utils/macros.h
-include/utils/ref_object.h
+include/sdk_util/auto_lock.h
+include/sdk_util/macros.h
+include/sdk_util/ref_object.h
+include/sdk_util/thread_safe_queue.h
+include/sdk_util/thread_pool.h
lib/glibc_x86_32/Debug/libjsoncpp.a
lib/glibc_x86_32/Debug/libjsoncpp.so
lib/glibc_x86_32/Debug/libnacl_io.a
@@ -476,7 +497,10 @@ lib/glibc_x86_32/Debug/libppapi_cpp_private.a
lib/glibc_x86_32/Debug/libppapi_cpp_private.so
lib/glibc_x86_32/Debug/libppapi_gles2.a
lib/glibc_x86_32/Debug/libppapi_gles2.so
-lib/glibc_x86_32/Debug/libppapi_main.a
+lib/glibc_x86_32/Debug/libppapi_simple.a
+lib/glibc_x86_32/Debug/libppapi_simple.so
+lib/glibc_x86_32/Debug/libsdk_util.a
+lib/glibc_x86_32/Debug/libsdk_util.so
lib/glibc_x86_32/Release/libjsoncpp.a
lib/glibc_x86_32/Release/libjsoncpp.so
lib/glibc_x86_32/Release/libnacl_io.a
@@ -487,7 +511,10 @@ lib/glibc_x86_32/Release/libppapi_cpp_private.a
lib/glibc_x86_32/Release/libppapi_cpp_private.so
lib/glibc_x86_32/Release/libppapi_gles2.a
lib/glibc_x86_32/Release/libppapi_gles2.so
-lib/glibc_x86_32/Release/libppapi_main.a
+lib/glibc_x86_32/Release/libppapi_simple.a
+lib/glibc_x86_32/Release/libppapi_simple.so
+lib/glibc_x86_32/Release/libsdk_util.a
+lib/glibc_x86_32/Release/libsdk_util.so
lib/glibc_x86_64/Debug/libjsoncpp.a
lib/glibc_x86_64/Debug/libjsoncpp.so
lib/glibc_x86_64/Debug/libnacl_io.a
@@ -498,7 +525,10 @@ lib/glibc_x86_64/Debug/libppapi_cpp_private.a
lib/glibc_x86_64/Debug/libppapi_cpp_private.so
lib/glibc_x86_64/Debug/libppapi_gles2.a
lib/glibc_x86_64/Debug/libppapi_gles2.so
-lib/glibc_x86_64/Debug/libppapi_main.a
+lib/glibc_x86_64/Debug/libppapi_simple.a
+lib/glibc_x86_64/Debug/libppapi_simple.so
+lib/glibc_x86_64/Debug/libsdk_util.a
+lib/glibc_x86_64/Debug/libsdk_util.so
lib/glibc_x86_64/Release/libjsoncpp.a
lib/glibc_x86_64/Release/libjsoncpp.so
lib/glibc_x86_64/Release/libnacl_io.a
@@ -509,7 +539,10 @@ lib/glibc_x86_64/Release/libppapi_cpp_private.a
lib/glibc_x86_64/Release/libppapi_cpp_private.so
lib/glibc_x86_64/Release/libppapi_gles2.a
lib/glibc_x86_64/Release/libppapi_gles2.so
-lib/glibc_x86_64/Release/libppapi_main.a
+lib/glibc_x86_64/Release/libppapi_simple.a
+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]lib/${PLATFORM}_host/Debug/libppapi_cpp.a
@@ -534,60 +567,70 @@ lib/glibc_x86_64/Release/libppapi_main.a
[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/pthread.lib
+[win]lib/${PLATFORM}_x86_32_host/Debug/sdk_util.lib
+[win]lib/${PLATFORM}_x86_32_host/Release/sdk_util.lib
lib/newlib_arm/Debug/liberror_handling.a
lib/newlib_arm/Debug/libjsoncpp.a
lib/newlib_arm/Debug/libnacl_io.a
lib/newlib_arm/Debug/libppapi_cpp.a
lib/newlib_arm/Debug/libppapi_cpp_private.a
lib/newlib_arm/Debug/libppapi_gles2.a
-lib/newlib_arm/Debug/libppapi_main.a
+lib/newlib_arm/Debug/libppapi_simple.a
+lib/newlib_arm/Debug/libsdk_util.a
lib/newlib_arm/Release/liberror_handling.a
lib/newlib_arm/Release/libjsoncpp.a
lib/newlib_arm/Release/libnacl_io.a
lib/newlib_arm/Release/libppapi_cpp.a
lib/newlib_arm/Release/libppapi_cpp_private.a
lib/newlib_arm/Release/libppapi_gles2.a
-lib/newlib_arm/Release/libppapi_main.a
+lib/newlib_arm/Release/libppapi_simple.a
+lib/newlib_arm/Release/libsdk_util.a
lib/newlib_x86_32/Debug/liberror_handling.a
lib/newlib_x86_32/Debug/libjsoncpp.a
lib/newlib_x86_32/Debug/libnacl_io.a
lib/newlib_x86_32/Debug/libppapi_cpp.a
lib/newlib_x86_32/Debug/libppapi_cpp_private.a
lib/newlib_x86_32/Debug/libppapi_gles2.a
-lib/newlib_x86_32/Debug/libppapi_main.a
+lib/newlib_x86_32/Debug/libppapi_simple.a
+lib/newlib_x86_32/Debug/libsdk_util.a
lib/newlib_x86_32/Release/liberror_handling.a
lib/newlib_x86_32/Release/libjsoncpp.a
lib/newlib_x86_32/Release/libnacl_io.a
lib/newlib_x86_32/Release/libppapi_cpp.a
lib/newlib_x86_32/Release/libppapi_cpp_private.a
lib/newlib_x86_32/Release/libppapi_gles2.a
-lib/newlib_x86_32/Release/libppapi_main.a
+lib/newlib_x86_32/Release/libppapi_simple.a
+lib/newlib_x86_32/Release/libsdk_util.a
lib/newlib_x86_64/Debug/liberror_handling.a
lib/newlib_x86_64/Debug/libjsoncpp.a
lib/newlib_x86_64/Debug/libnacl_io.a
lib/newlib_x86_64/Debug/libppapi_cpp.a
lib/newlib_x86_64/Debug/libppapi_cpp_private.a
lib/newlib_x86_64/Debug/libppapi_gles2.a
-lib/newlib_x86_64/Debug/libppapi_main.a
+lib/newlib_x86_64/Debug/libppapi_simple.a
+lib/newlib_x86_64/Debug/libsdk_util.a
lib/newlib_x86_64/Release/liberror_handling.a
lib/newlib_x86_64/Release/libjsoncpp.a
lib/newlib_x86_64/Release/libnacl_io.a
lib/newlib_x86_64/Release/libppapi_cpp.a
lib/newlib_x86_64/Release/libppapi_cpp_private.a
lib/newlib_x86_64/Release/libppapi_gles2.a
-lib/newlib_x86_64/Release/libppapi_main.a
+lib/newlib_x86_64/Release/libppapi_simple.a
+lib/newlib_x86_64/Release/libsdk_util.a
lib/pnacl/Debug/libjsoncpp.a
lib/pnacl/Debug/libnacl_io.a
lib/pnacl/Debug/libppapi_cpp.a
lib/pnacl/Debug/libppapi_cpp_private.a
lib/pnacl/Debug/libppapi_gles2.a
-lib/pnacl/Debug/libppapi_main.a
+lib/pnacl/Debug/libppapi_simple.a
+lib/pnacl/Debug/libsdk_util.a
lib/pnacl/Release/libjsoncpp.a
lib/pnacl/Release/libnacl_io.a
lib/pnacl/Release/libppapi_cpp.a
lib/pnacl/Release/libppapi_cpp_private.a
lib/pnacl/Release/libppapi_gles2.a
-lib/pnacl/Release/libppapi_main.a
+lib/pnacl/Release/libppapi_simple.a
+lib/pnacl/Release/libsdk_util.a
LICENSE
NOTICE
README
@@ -626,6 +669,7 @@ src/nacl_io/mount_mem.cc
src/nacl_io/mount_node.cc
src/nacl_io/mount_node_dir.cc
src/nacl_io/mount_node_html5fs.cc
+src/nacl_io/mount_node_http.cc
src/nacl_io/mount_node_mem.cc
src/nacl_io/mount_passthrough.cc
src/nacl_io/nacl_io.cc
@@ -636,6 +680,7 @@ src/ppapi_cpp/array_output.cc
src/ppapi_cpp/audio.cc
src/ppapi_cpp/audio_config.cc
src/ppapi_cpp/core.cc
+src/ppapi_cpp/directory_entry.cc
src/ppapi_cpp/file_io.cc
src/ppapi_cpp/file_ref.cc
src/ppapi_cpp/file_system.cc
@@ -672,17 +717,17 @@ src/ppapi_gles2/gl2ext_ppapi.c
src/ppapi_gles2/gles2.c
[win]src/ppapi_gles2/make.bat
src/ppapi_gles2/Makefile
-[win]src/ppapi_main/make.bat
-src/ppapi_main/Makefile
-src/ppapi_main/ppapi_instance2d.cc
-src/ppapi_main/ppapi_instance3d.cc
-src/ppapi_main/ppapi_instance.cc
-src/ppapi_main/ppapi_main.cc
-src/ppapi_main/ppapi_queue.cc
+[win]src/ppapi_simple/make.bat
+src/ppapi_simple/Makefile
+src/ppapi_simple/ps.cc
+src/ppapi_simple/ps_event.cc
+src/ppapi_simple/ps_instance.cc
+src/ppapi_simple/ps_main.cc
src/ppapi_cpp_private/Makefile
[win]src/ppapi_cpp_private/make.bat
src/ppapi_cpp_private/file_io_private.cc
src/ppapi_cpp_private/net_address_private.cc
+src/ppapi_cpp_private/pass_file_handle.cc
src/ppapi_cpp_private/tcp_socket_private.cc
src/ppapi_cpp_private/udp_socket_private.cc
src/ppapi_cpp_private/ext_crx_file_system_private.cc
@@ -836,6 +881,9 @@ src/ppapi_cpp_private/x509_certificate_private.cc
[win]src/ppapi/make.bat
[win,linux]src/ppapi/Makefile
[win,linux]src/ppapi/ppapi_externs.c
+src/sdk_util/Makefile
+[win]src/sdk_util/make.bat
+src/sdk_util/thread_pool.cc
toolchain/${PLATFORM}_arm_newlib/arm-nacl/include/irt.h
toolchain/${PLATFORM}_arm_newlib/arm-nacl/include/irt_ppapi.h
toolchain/${PLATFORM}_arm_newlib/arm-nacl/include/nacl/dynamic_annotations.h
@@ -944,7 +992,8 @@ tools/compiler-wrapper.py
tools/create_nmf.py
tools/decode_dump.py
[linux,mac]tools/dump_syms
-[win]tools/dump_syms.exe
+[linux,mac]tools/minidump_stackwalk
+[linux,mac]tools/minidump_dump
tools/genhttpfs.py
tools/getos.py
tools/host_gcc.mk
@@ -957,17 +1006,10 @@ tools/nacl_gcc.mk
[linux]tools/nacl_helper_bootstrap_x86_32
[linux]tools/nacl_helper_bootstrap_x86_64
tools/nacl_llvm.mk
-[linux,mac]tools/ncval_arm
-[win]tools/ncval_arm.exe
-[linux,mac]tools/ncval_x86_32
-[linux]tools/ncval_x86_64
-[win]tools/ncval_x86_32.exe
-[win]tools/ncval_x86_64.exe
+tools/ncval${EXE_EXT}
tools/oshelpers.py
tools/oshelpers.pyc
tools/quote.py
tools/run.py
-[linux,mac]tools/sel_ldr_x86_32
-[linux]tools/sel_ldr_x86_64
-[win]tools/sel_ldr_x86_32.exe
-[win]tools/sel_ldr_x86_64.exe
+tools/sel_ldr_x86_32${EXE_EXT}
+[linux,win]tools/sel_ldr_x86_64${EXE_EXT}
diff --git a/native_client_sdk/src/build_tools/sdk_tools/command/info.py b/native_client_sdk/src/build_tools/sdk_tools/command/info.py
index c412ddd281..6bf310fc6a 100644
--- a/native_client_sdk/src/build_tools/sdk_tools/command/info.py
+++ b/native_client_sdk/src/build_tools/sdk_tools/command/info.py
@@ -23,13 +23,11 @@ def Info(manifest, bundle_names):
for key in sorted(bundle.iterkeys()):
value = bundle[key]
if key == manifest_util.ARCHIVES_KEY:
- archive = bundle.GetHostOSArchive()
- print ' Archive:'
- if archive:
- for archive_key in sorted(archive.iterkeys()):
- print ' %s: %s' % (archive_key, archive[archive_key])
- else:
- print ' No archives for this host.'
+ for archive in bundle.GetArchives():
+ print ' Archive:'
+ if archive:
+ for archive_key in sorted(archive.iterkeys()):
+ print ' %s: %s' % (archive_key, archive[archive_key])
elif key not in (manifest_util.ARCHIVES_KEY, manifest_util.NAME_KEY):
print ' %s: %s' % (key, value)
print
diff --git a/native_client_sdk/src/build_tools/tests/sdktools_commands_test.py b/native_client_sdk/src/build_tools/tests/sdktools_commands_test.py
index 2fae323c97..8abef29bfe 100755
--- a/native_client_sdk/src/build_tools/tests/sdktools_commands_test.py
+++ b/native_client_sdk/src/build_tools/tests/sdktools_commands_test.py
@@ -99,6 +99,18 @@ class TestCommands(SdkToolsTestCase):
self.assertTrue('pepper_24' in output)
self.assertFalse(re.search(r'[uU]nknown', output))
+ def testInfoMultipleArchives(self):
+ """The info command should display multiple archives."""
+ bundle = self._AddDummyBundle(self.manifest, 'pepper_26')
+ archive2 = self._MakeDummyArchive('pepper_26', tarname='pepper_26_more',
+ filename='dummy2.txt')
+ archive2.host_os = 'all'
+ bundle.AddArchive(archive2)
+ self._WriteManifest()
+ output = self._Run(['info', 'pepper_26'])
+ self.assertTrue('pepper_26' in output)
+ self.assertTrue('pepper_26_more' in output)
+
def testListBasic(self):
"""The list command should display basic information about remote
bundles."""
diff --git a/native_client_sdk/src/build_tools/verify_filelist.py b/native_client_sdk/src/build_tools/verify_filelist.py
index 7b75e91488..b97e4205ec 100755
--- a/native_client_sdk/src/build_tools/verify_filelist.py
+++ b/native_client_sdk/src/build_tools/verify_filelist.py
@@ -37,6 +37,7 @@ class Rules(object):
self.exact_filenames = set()
self.filename = filename
self.platform = platform
+ self.exe_ext = '.exe' if platform == 'win' else ''
if platform not in VALID_PLATFORMS:
raise ParseException(self.filename, 1, 'Unknown platform %s' % platform)
@@ -67,6 +68,7 @@ class Rules(object):
pattern = match.group(2)
pattern = pattern.replace('${PLATFORM}', self.platform)
+ pattern = pattern.replace('${EXE_EXT}', self.exe_ext)
if '*' in pattern:
# glob pattern
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 e73f4b9462..1183c9cd43 100644
--- a/native_client_sdk/src/examples/api/file_io/example.js
+++ b/native_client_sdk/src/examples/api/file_io/example.js
@@ -19,6 +19,7 @@ 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);
}
function loadFile() {
@@ -55,6 +56,17 @@ function deleteFile() {
}
}
+function listDir() {
+ if (common.naclModule) {
+ var dirName = document.getElementById('dirName').value;
+
+ // Package a message using a simple protocol containing:
+ // instruction file_name_length file_name
+ var msg = "ls " + dirName.length + " " + dirName;
+ common.naclModule.postMessage(msg);
+ }
+}
+
// Called by the common.js module.
function handleMessage(message_event) {
var messageParts = message_event.data.split("|", 3);
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 9de72f8f6a..d8e27afd0f 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
@@ -11,6 +11,7 @@
#include "ppapi/c/pp_stdint.h"
#include "ppapi/c/ppb_file_io.h"
+#include "ppapi/cpp/directory_entry.h"
#include "ppapi/cpp/file_io.h"
#include "ppapi/cpp/file_ref.h"
#include "ppapi/cpp/file_system.h"
@@ -39,6 +40,7 @@ namespace {
const char* const kLoadPrefix = "ld";
const char* const kSavePrefix = "sv";
const char* const kDeletePrefix = "de";
+const char* const kListPrefix = "ls";
}
/// The Instance class. One of these exists for each instance of your NaCl
@@ -133,6 +135,13 @@ class FileIoInstance : public pp::Instance {
callback_factory_.NewCallback(&FileIoInstance::Delete, file_name));
return;
}
+
+ if (instruction.compare(kListPrefix) == 0) {
+ const std::string& dir_name = file_name;
+ file_thread_.message_loop().PostWork(
+ callback_factory_.NewCallback(&FileIoInstance::List, dir_name));
+ return;
+ }
}
void OpenFileSystem(int32_t /* result */) {
@@ -267,6 +276,35 @@ class FileIoInstance : public pp::Instance {
ShowStatusMessage("File deleted");
}
+ void List(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());
+
+ // Pass ref along to keep it alive.
+ ref.ReadDirectoryEntries(callback_factory_.NewCallbackWithOutput(
+ &FileIoInstance::ListCallback, ref));
+ }
+
+ void ListCallback(int32_t result,
+ const std::vector<pp::DirectoryEntry>& entries,
+ pp::FileRef /* unused_ref */) {
+ if (result != PP_OK) {
+ ShowErrorMessage("List failed", result);
+ return;
+ }
+
+ std::string buffer = "File 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();
+ }
+ ShowStatusMessage(buffer);
+ }
+
/// Encapsulates our simple javascript communication protocol
void ShowErrorMessage(const std::string& message, int32_t result) {
std::stringstream ss;
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 7625bd69c0..7c62ebdd9c 100644
--- a/native_client_sdk/src/examples/api/file_io/index.html
+++ b/native_client_sdk/src/examples/api/file_io/index.html
@@ -29,6 +29,10 @@
<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>
+
<!-- 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/life/example.dsc b/native_client_sdk/src/examples/demo/life/example.dsc
new file mode 100644
index 0000000000..215cfa8e8b
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/life/example.dsc
@@ -0,0 +1,18 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
+ 'TARGETS': [
+ {
+ 'NAME' : 'life',
+ 'TYPE' : 'main',
+ 'SOURCES' : [
+ 'life.c',
+ ],
+ 'DEPS': ['ppapi_simple', 'nacl_io'],
+ 'LIBS': ['ppapi_cpp', 'ppapi', 'pthread']
+ }
+ ],
+ 'DEST': 'examples/demo',
+ 'NAME': 'life',
+ 'TITLE': "Conway's Life",
+ 'GROUP': 'Demo'
+}
diff --git a/native_client_sdk/src/examples/hello_world_instance3d/index.html b/native_client_sdk/src/examples/demo/life/index.html
index fa132dc7fd..626f532b5b 100644
--- a/native_client_sdk/src/examples/hello_world_instance3d/index.html
+++ b/native_client_sdk/src/examples/demo/life/index.html
@@ -11,17 +11,10 @@ found in the LICENSE file.
<title>{{title}}</title>
<script type="text/javascript" src="common.js"></script>
</head>
-<body data-width="640" data-height="480" {{attrs}}>
+<body data-width="640" data-height="640" {{attrs}}>
<h1>{{title}}</h1>
<h2>Status: <code id="statusField">NO-STATUS</code></h2>
<p>
- The Hello World instance3d example is similar to the Hello World GLES 2.0
- example, but uses the ppapi_main and nacl_io libraries to simplify the code:
- <ul>
- <li>URL loading is handled by a synchronous read from an HTTP mount.</li>
- <li>Instance creation is hidden; instead the functions ppapi_main and
- PPAPIRender are used.</li>
- </ul>
</p>
<!-- The NaCl plugin will be embedded inside the element with id "listener".
See common.js.-->
diff --git a/native_client_sdk/src/examples/demo/life/life.c b/native_client_sdk/src/examples/demo/life/life.c
new file mode 100644
index 0000000000..389d10e1fb
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/life/life.c
@@ -0,0 +1,305 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_fullscreen.h"
+#include "ppapi/c/ppb_graphics_2d.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/c/ppb_input_event.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_view.h"
+
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_main.h"
+
+PPB_Core* g_pCore;
+PPB_Fullscreen* g_pFullscreen;
+PPB_Graphics2D* g_pGraphics2D;
+PPB_ImageData* g_pImageData;
+PPB_Instance* g_pInstance;
+PPB_View* g_pView;
+PPB_InputEvent* g_pInputEvent;
+PPB_KeyboardInputEvent* g_pKeyboardInput;
+PPB_MouseInputEvent* g_pMouseInput;
+PPB_TouchInputEvent* g_pTouchInput;
+
+struct {
+ PP_Resource ctx;
+ struct PP_Size size;
+ int bound;
+ uint8_t* cell_in;
+ uint8_t* cell_out;
+} g_Context;
+
+
+const unsigned int kInitialRandSeed = 0xC0DE533D;
+
+#define MakeRGBA(r, g, b, a) \
+ (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+
+
+/*
+ * Given a count of cells in a 3x3 grid where cells are worth 1 except for
+ * the center which is worth 9, this is a color representation of how
+ * "alive" that cell is making for a more interesting representation than
+ * a binary alive or dead.
+ */
+const uint32_t kNeighborColors[] = {
+ MakeRGBA(0x00, 0x00, 0x00, 0xff),
+ MakeRGBA(0x00, 0x40, 0x00, 0xff),
+ MakeRGBA(0x00, 0x60, 0x00, 0xff),
+ MakeRGBA(0x00, 0x80, 0x00, 0xff),
+ MakeRGBA(0x00, 0xA0, 0x00, 0xff),
+ MakeRGBA(0x00, 0xC0, 0x00, 0xff),
+ MakeRGBA(0x00, 0xE0, 0x00, 0xff),
+ MakeRGBA(0x00, 0x00, 0x00, 0xff),
+ MakeRGBA(0x00, 0x40, 0x00, 0xff),
+ MakeRGBA(0x00, 0x60, 0x00, 0xff),
+ MakeRGBA(0x00, 0x80, 0x00, 0xff),
+ MakeRGBA(0x00, 0xA0, 0x00, 0xff),
+ MakeRGBA(0x00, 0xC0, 0x00, 0xff),
+ MakeRGBA(0x00, 0xE0, 0x00, 0xff),
+ MakeRGBA(0x00, 0xFF, 0x00, 0xff),
+ MakeRGBA(0x00, 0xFF, 0x00, 0xff),
+ MakeRGBA(0x00, 0xFF, 0x00, 0xff),
+ MakeRGBA(0x00, 0xFF, 0x00, 0xff),
+};
+
+/*
+ * These represent the new health value of a cell based on its neighboring
+ * values. The health is binary: either alive or dead.
+ */
+const uint8_t kIsAlive[] = {
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, /* Values if the center cell is dead. */
+ 0, 0, 1, 1, 0, 0, 0, 0, 0 /* Values if the center cell is alive. */
+};
+
+void UpdateContext(uint32_t width, uint32_t height) {
+ if (width != g_Context.size.width || height != g_Context.size.height) {
+ size_t size = width * height;
+ size_t index;
+
+ free(g_Context.cell_in);
+ free(g_Context.cell_out);
+
+ /* Create a new context */
+ g_Context.cell_in = (uint8_t*) malloc(size);
+ g_Context.cell_out = (uint8_t*) malloc(size);
+
+ memset(g_Context.cell_out, 0, size);
+ for (index = 0; index < size; index++) {
+ g_Context.cell_in[index] = rand() & 1;
+ }
+ }
+
+ /* Recreate the graphics context on a view change */
+ g_pCore->ReleaseResource(g_Context.ctx);
+ g_Context.size.width = width;
+ g_Context.size.height = height;
+ g_Context.ctx =
+ g_pGraphics2D->Create(PSGetInstanceId(), &g_Context.size, PP_TRUE);
+ g_Context.bound =
+ g_pInstance->BindGraphics(PSGetInstanceId(), g_Context.ctx);
+}
+
+void DrawCell(int32_t x, int32_t y) {
+ int32_t width = g_Context.size.width;
+ int32_t height = g_Context.size.height;
+
+ if (!g_Context.cell_in) return;
+
+ if (x > 0 && x < width - 1 && y > 0 && y < height - 1) {
+ g_Context.cell_in[x - 1 + y * width] = 1;
+ g_Context.cell_in[x + 1 + y * width] = 1;
+ g_Context.cell_in[x + (y - 1) * width] = 1;
+ g_Context.cell_in[x + (y + 1) * width] = 1;
+ }
+}
+
+
+void ProcessEvent(PSEvent* event) {
+ switch(event->type) {
+ /* If the view updates, build a new Graphics 2D Context */
+ case PSE_INSTANCE_DIDCHANGEVIEW: {
+ struct PP_Rect rect;
+
+ g_pView->GetRect(event->as_resource, &rect);
+ UpdateContext(rect.size.width, rect.size.height);
+ break;
+ }
+
+ case PSE_INSTANCE_HANDLEINPUT: {
+ PP_InputEvent_Type type = g_pInputEvent->GetType(event->as_resource);
+ PP_InputEvent_Modifier modifiers =
+ g_pInputEvent->GetModifiers(event->as_resource);
+
+ switch(type) {
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
+ struct PP_Point location =
+ g_pMouseInput->GetPosition(event->as_resource);
+ DrawCell(location.x, location.y);
+ break;
+ }
+
+ case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
+ struct PP_Point location =
+ g_pMouseInput->GetPosition(event->as_resource);
+
+ /* If the button is down, draw */
+ if (modifiers & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
+ DrawCell(location.x, location.y);
+ }
+ break;
+ }
+
+ case PP_INPUTEVENT_TYPE_KEYDOWN: {
+ PP_Bool fullscreen = g_pFullscreen->IsFullscreen(PSGetInstanceId());
+ g_pFullscreen->SetFullscreen(PSGetInstanceId(),
+ fullscreen ? PP_FALSE : PP_TRUE);
+ break;
+ }
+ default:
+ break;
+ }
+ /* case PSE_INSTANCE_HANDLEINPUT */
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+
+void Stir(uint32_t width, uint32_t height) {
+ int i;
+ if (g_Context.cell_in == NULL || g_Context.cell_out == NULL)
+ return;
+
+ for (i = 0; i < width; ++i) {
+ g_Context.cell_in[i] = rand() & 1;
+ g_Context.cell_in[i + (height - 1) * width] = rand() & 1;
+ }
+ for (i = 0; i < height; ++i) {
+ g_Context.cell_in[i * width] = rand() & 1;
+ g_Context.cell_in[i * width + (width - 1)] = rand() & 1;
+ }
+}
+
+void Render() {
+ struct PP_Size* psize = &g_Context.size;
+ PP_ImageDataFormat format = g_pImageData->GetNativeImageDataFormat();
+
+ /*
+ * Create a buffer to draw into. Since we are waiting until the next flush
+ * chrome has an opportunity to cache this buffer see ppb_graphics_2d.h.
+ */
+ PP_Resource image =
+ g_pImageData->Create(PSGetInstanceId(), format, psize, PP_FALSE);
+ uint8_t* pixels = g_pImageData->Map(image);
+
+ struct PP_ImageDataDesc desc;
+ uint8_t* cell_temp;
+ uint32_t x, y;
+
+ /* If we somehow have not allocated these pointers yet, skip this frame. */
+ if (!g_Context.cell_in || !g_Context.cell_out) return;
+
+ /* Get the stride. */
+ g_pImageData->Describe(image, &desc);
+
+ /* Stir up the edges to prevent the simulation from reaching steady state. */
+ Stir(desc.size.width, desc.size.height);
+
+ /* Do neighbor summation; apply rules, output pixel color. */
+ for (y = 1; y < desc.size.height - 1; ++y) {
+ uint8_t *src0 = (g_Context.cell_in + (y - 1) * desc.size.width) + 1;
+ uint8_t *src1 = src0 + desc.size.width;
+ uint8_t *src2 = src1 + desc.size.width;
+ int count;
+ uint32_t color;
+ uint8_t *dst = (g_Context.cell_out + y * desc.size.width) + 1;
+ uint32_t *pixel_line = (uint32_t*) (pixels + y * desc.stride);
+
+ for (x = 1; x < (desc.size.width - 1); ++x) {
+ /* Build sum, weight center by 9x. */
+ count = src0[-1] + src0[0] + src0[1] +
+ src1[-1] + src1[0] * 9 + src1[1] +
+ src2[-1] + src2[0] + src2[1];
+ color = kNeighborColors[count];
+
+ *pixel_line++ = color;
+ *dst++ = kIsAlive[count];
+ ++src0;
+ ++src1;
+ ++src2;
+ }
+ }
+
+ cell_temp = g_Context.cell_in;
+ g_Context.cell_in = g_Context.cell_out;
+ g_Context.cell_out = cell_temp;
+
+ /* Unmap the range, we no longer need it. */
+ g_pImageData->Unmap(image);
+
+ /* Replace the contexts, and block until it's on the screen. */
+ g_pGraphics2D->ReplaceContents(g_Context.ctx, image);
+ g_pGraphics2D->Flush(g_Context.ctx, PP_BlockUntilComplete());
+
+ /* Release the image data, we no longer need it. */
+ g_pCore->ReleaseResource(image);
+}
+
+/*
+ * Starting point for the module. We do not use main since it would
+ * collide with main in libppapi_cpp.
+ */
+int example_main(int argc, const char *argv[]) {
+ fprintf(stdout,"Started main.\n");
+ g_pCore = (PPB_Core*)PSGetInterface(PPB_CORE_INTERFACE);
+ g_pFullscreen = (PPB_Fullscreen*)PSGetInterface(PPB_FULLSCREEN_INTERFACE);
+ g_pGraphics2D = (PPB_Graphics2D*)PSGetInterface(PPB_GRAPHICS_2D_INTERFACE);
+ g_pInstance = (PPB_Instance*)PSGetInterface(PPB_INSTANCE_INTERFACE);
+ g_pImageData = (PPB_ImageData*)PSGetInterface(PPB_IMAGEDATA_INTERFACE);
+ g_pView = (PPB_View*)PSGetInterface(PPB_VIEW_INTERFACE);
+
+ g_pInputEvent =
+ (PPB_InputEvent*) PSGetInterface(PPB_INPUT_EVENT_INTERFACE);
+ g_pKeyboardInput = (PPB_KeyboardInputEvent*)
+ PSGetInterface(PPB_KEYBOARD_INPUT_EVENT_INTERFACE);
+ g_pMouseInput =
+ (PPB_MouseInputEvent*) PSGetInterface(PPB_MOUSE_INPUT_EVENT_INTERFACE);
+ g_pTouchInput =
+ (PPB_TouchInputEvent*) PSGetInterface(PPB_TOUCH_INPUT_EVENT_INTERFACE);
+
+ PSEventSetFilter(PSE_ALL);
+ while (1) {
+ /* Process all waiting events without blocking */
+ PSEvent* event;
+ while ((event = PSEventTryAcquire()) != NULL) {
+ ProcessEvent(event);
+ PSEventRelease(event);
+ }
+
+ /* Render a frame, blocking until complete. */
+ if (g_Context.bound) {
+ Render();
+ }
+ }
+ 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.dsc b/native_client_sdk/src/examples/demo/voronoi/example.dsc
new file mode 100644
index 0000000000..d9fabcebc9
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/voronoi/example.dsc
@@ -0,0 +1,21 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
+ 'TARGETS': [
+ {
+ 'NAME' : 'voronoi',
+ 'TYPE' : 'main',
+ 'SOURCES' : [
+ 'voronoi.cc'
+ ],
+
+ 'LIBS': ['sdk_util', 'ppapi_cpp', 'ppapi', 'pthread']
+ }
+ ],
+ 'DATA': [
+ 'example.js',
+ ],
+ 'DEST': 'examples/demo',
+ 'NAME': 'voronoi',
+ 'TITLE': 'Multi-Threaded Voronoi Demo',
+ 'GROUP': 'Demo'
+}
diff --git a/native_client_sdk/src/examples/demo/voronoi/example.js b/native_client_sdk/src/examples/demo/voronoi/example.js
new file mode 100644
index 0000000000..aa02f38049
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/voronoi/example.js
@@ -0,0 +1,59 @@
+// 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('threads: ' + 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('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');
+ });
+ 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');
+ });
+ 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('pointRange').addEventListener('change',
+ function() {
+ var value = document.getElementById('pointRange').value;
+ common.naclModule.postMessage('points: ' + value);
+ document.getElementById('pointCount').textContent = value + ' points';
+ });
+}
+
+// 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')
+}
+
diff --git a/native_client_sdk/src/examples/demo/voronoi/index.html b/native_client_sdk/src/examples/demo/voronoi/index.html
new file mode 100644
index 0000000000..7cbbd19deb
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/voronoi/index.html
@@ -0,0 +1,61 @@
+<!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">
+ <title>{{title}}</title>
+ <script type="text/javascript" src="common.js"></script>
+ <script type="text/javascript" src="example.js"></script>
+</head>
+<body {{attrs}} data-width="512" data-height="512">
+ <h1>{{title}}</h1>
+ <h2>Status: <code id="statusField">NO-STATUS</code></h2>
+ <div>
+ This demo renders the Voronoi diagram for a moving set of points using a
+ brute force technique.
+ <br>
+ Number of points:
+ <input type="range" id="pointRange"
+ min="1" max="1024" step="1" value="256" />
+ <label id="pointCount" >256 points</label>
+ <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="checkbox" id="drawPoints" checked="checked">
+ <label for="draw_points">Draw Points</label>
+ <input type="checkbox" id="drawInteriors" checked="checked">
+ <label for="draw_interiors">Draw Interiors</label>
+ <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/voronoi/voronoi.cc b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
new file mode 100644
index 0000000000..d4e1025181
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
@@ -0,0 +1,582 @@
+// 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/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 <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/thread_pool.h"
+
+// Global properties used to setup Voronoi demo.
+namespace {
+const int kMinRectSize = 4;
+const int kStartRecurseSize = 32; // must be power-of-two
+const float kHugeZ = 1.0e38f;
+const float kPI = M_PI;
+const float kTwoPI = kPI * 2.0f;
+const int kFramesToBenchmark = 100;
+const unsigned int kRandomStartSeed = 0xC0DE533D;
+const int kMaxPointCount = 1024;
+const int kStartPointCount = 256;
+
+unsigned int g_rand_state = kRandomStartSeed;
+
+// random number helper
+inline unsigned char rand255() {
+ return static_cast<unsigned char>(rand_r(&g_rand_state) & 255);
+}
+
+// random number helper
+inline float frand() {
+ return (static_cast<float>(rand_r(&g_rand_state)) /
+ static_cast<float>(RAND_MAX));
+}
+
+// reset random seed
+inline void rand_reset(unsigned int seed) {
+ g_rand_state = seed;
+}
+
+// returns true if input is power of two.
+inline bool is_pow2(int x) {
+ return (x & (x - 1)) == 0;
+}
+
+inline double getseconds() {
+ const double usec_to_sec = 0.000001;
+ timeval tv;
+ if (0 == gettimeofday(&tv, NULL))
+ return tv.tv_sec + tv.tv_usec * usec_to_sec;
+ return 0.0;
+}
+
+inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+ return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
+}
+} // namespace
+
+// Vec2, simple 2D vector
+struct Vec2 {
+ float x, y;
+ Vec2() {}
+ Vec2(float px, float py) {
+ x = px;
+ y = py;
+ }
+ void Set(float px, float py) {
+ x = px;
+ y = py;
+ }
+};
+
+// The main object that runs Voronoi simulation.
+class Voronoi : public pp::Instance {
+ public:
+ explicit Voronoi(PP_Instance instance);
+ virtual ~Voronoi();
+
+ virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
+ return true;
+ }
+
+ virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip);
+
+ // Catch events.
+ virtual bool HandleInputEvent(const pp::InputEvent& event);
+
+ // Catch messages posted from Javascript.
+ virtual void HandleMessage(const pp::Var& message);
+
+ private:
+ // Methods prefixed with 'w' are run on worker threads.
+ int wCell(float x, float y);
+ inline void wFillSpan(uint32_t *pixels, uint32_t color, int width);
+ void wRenderTile(int x, int y, int w, int h);
+ void wProcessTile(int x, int y, int w, int h);
+ void wSubdivide(int x, int y, int w, int h);
+ void wMakeRect(int region, int *x, int *y, int *w, int *h);
+ bool wTestRect(int *m, int x, int y, int w, int h);
+ void wFillRect(int x, int y, int w, int h, uint32_t color);
+ 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 Reset();
+ void UpdateSim();
+ void RenderDot(float x, float y, uint32_t color1, uint32_t color2);
+ void SuperimposePositions();
+ 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();
+
+ // Create and initialize the 2D context used for drawing.
+ void CreateContext(const pp::Size& size);
+ // Destroy the 2D drawing context.
+ void DestroyContext();
+ // Push the pixels to the browser, then attempt to flush the 2D context.
+ void FlushPixelBuffer();
+ static void FlushCallback(void* data, int32_t result);
+
+
+ pp::Graphics2D* graphics_2d_context_;
+ pp::ImageData* image_data_;
+ Vec2 positions_[kMaxPointCount];
+ Vec2 screen_positions_[kMaxPointCount];
+ Vec2 velocities_[kMaxPointCount];
+ uint32_t colors_[kMaxPointCount];
+ float ang_;
+ int point_count_;
+ int num_threads_;
+ const int num_regions_;
+ bool draw_points_;
+ bool draw_interiors_;
+ ThreadPool* workers_;
+ int width_;
+ int height_;
+ uint32_t stride_in_pixels_;
+ uint32_t* pixel_buffer_;
+ int benchmark_frame_counter_;
+ bool benchmarking_;
+ double benchmark_start_time_;
+ double benchmark_end_time_;
+};
+
+
+
+void Voronoi::Reset() {
+ rand_reset(kRandomStartSeed);
+ ang_ = 0.0f;
+ for (int i = 0; i < kMaxPointCount; i++) {
+ // random initial start position
+ const float x = frand();
+ const float y = frand();
+ positions_[i].Set(x, y);
+ // random directional velocity ( -1..1, -1..1 )
+ const float speed = 0.0005f;
+ const float u = (frand() * 2.0f - 1.0f) * speed;
+ const float v = (frand() * 2.0f - 1.0f) * speed;
+ velocities_[i].Set(u, v);
+ // 'unique' color (well... unique enough for our purposes)
+ colors_[i] = MakeRGBA(rand255(), rand255(), rand255(), 255);
+ }
+}
+
+Voronoi::Voronoi(PP_Instance instance) : pp::Instance(instance),
+ graphics_2d_context_(NULL),
+ image_data_(NULL),
+ num_regions_(256) {
+ draw_points_ = true;
+ draw_interiors_ = true;
+ width_ = 0;
+ height_ = 0;
+ stride_in_pixels_ = 0;
+ pixel_buffer_ = NULL;
+ benchmark_frame_counter_ = 0;
+ benchmarking_ = false;
+
+ point_count_ = kStartPointCount;
+ Reset();
+
+ // By default, render from the dispatch thread.
+ num_threads_ = 0;
+ workers_ = new ThreadPool(num_threads_);
+
+ // Request PPAPI input events for mouse & keyboard.
+ RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
+ RequestInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
+}
+
+Voronoi::~Voronoi() {
+ delete workers_;
+ DestroyContext();
+}
+
+// This is the core of the Voronoi calculation. At a given point on the
+// screen, iterate through all voronoi positions and render them as 3D cones.
+// We're looking for the voronoi cell that generates the closest z value.
+// (not really cones - since it is all relative, we avoid doing the
+// expensive sqrt and test against z*z instead)
+// If multithreading, this function is only called by the worker threads.
+int Voronoi::wCell(float x, float y) {
+ int closest_cell = 0;
+ float zz = kHugeZ;
+ Vec2* pos = screen_positions_;
+ for (int i = 0; i < point_count_; ++i) {
+ // measured 5.18 cycles per iteration on a core2
+ float dx = x - pos[i].x;
+ float dy = y - pos[i].y;
+ float dd = (dx * dx + dy * dy);
+ if (dd < zz) {
+ zz = dd;
+ closest_cell = i;
+ }
+ }
+ return closest_cell;
+}
+
+// Given a region r, derive a non-overlapping rectangle for a thread to
+// work on.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wMakeRect(int r, int* x, int* y, int* w, int* h) {
+ const int parts = 16;
+ assert(parts * parts == num_regions_);
+ *w = width_ / parts;
+ *h = height_ / parts;
+ *x = *w * (r % parts);
+ *y = *h * ((r / parts) % parts);
+}
+
+// Test 4 corners of a rectangle to see if they all belong to the same
+// voronoi cell. Each test is expensive so bail asap. Returns true
+// if all 4 corners match.
+// If multithreading, this function is only called by the worker threads.
+bool Voronoi::wTestRect(int* m, int x, int y, int w, int h) {
+ // each test is expensive, so exit ASAP
+ const int m0 = wCell(x, y);
+ const int m1 = wCell(x + w - 1, y);
+ if (m0 != m1) return false;
+ const int m2 = wCell(x, y + h - 1);
+ if (m0 != m2) return false;
+ const int m3 = wCell(x + w - 1, y + h - 1);
+ if (m0 != m3) return false;
+ // all 4 corners belong to the same cell
+ *m = m0;
+ return true;
+}
+
+// Quickly fill a span of pixels with a solid color. Assumes
+// span width is divisible by 4.
+// If multithreading, this function is only called by the worker threads.
+inline void Voronoi::wFillSpan(uint32_t* pixels, uint32_t color, int width) {
+ if (!draw_interiors_) {
+ const uint32_t gray = MakeRGBA(128, 128, 128, 255);
+ color = gray;
+ }
+ for (int i = 0; i < width; i += 4) {
+ *pixels++ = color;
+ *pixels++ = color;
+ *pixels++ = color;
+ *pixels++ = color;
+ }
+}
+
+// Quickly fill a rectangle with a solid color. Assumes
+// the width w parameter is evenly divisible by 4.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) {
+ const uint32_t pitch = width_;
+ uint32_t* pixels = pixel_buffer_ + y * pitch + x;
+ for (int j = 0; j < h; j++) {
+ wFillSpan(pixels, color, w);
+ pixels += pitch;
+ }
+}
+
+// When recursive subdivision reaches a certain minimum without finding a
+// rectangle that has four matching corners belonging to the same voronoi
+// cell, this function will break the retangular 'tile' into smaller scanlines
+// and look for opportunities to quick fill at the scanline level. If the
+// scanline can't be quick filled, it will slow down even further and compute
+// voronoi membership per pixel.
+void Voronoi::wRenderTile(int x, int y, int w, int h) {
+ // rip through a tile
+ uint32_t* pixels = pixel_buffer_ + y * stride_in_pixels_ + x;
+ for (int j = 0; j < h; j++) {
+ // get start and end cell values
+ int ms = wCell(x + 0, y + j);
+ int me = wCell(x + w - 1, y + j);
+ // if the end points are the same, quick fill the span
+ if (ms == me) {
+ wFillSpan(pixels, colors_[ms], w);
+ } else {
+ // else compute each pixel in the span... this is the slow part!
+ uint32_t* p = pixels;
+ *p++ = colors_[ms];
+ for (int i = 1; i < (w - 1); i++) {
+ int m = wCell(x + i, y + j);
+ *p++ = colors_[m];
+ }
+ *p++ = colors_[me];
+ }
+ pixels += stride_in_pixels_;
+ }
+}
+
+// Take a rectangular region and do one of -
+// If all four corners below to the same voronoi cell, stop recursion and
+// quick fill the rectangle.
+// If the minimum rectangle size has been reached, break out of recursion
+// and process the rectangle. This small rectangle is called a tile.
+// Otherwise, keep recursively subdividing the rectangle into 4 equally
+// sized smaller rectangles.
+// Note: at the moment, these will always be squares, not rectangles.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wSubdivide(int x, int y, int w, int h) {
+ int m;
+ // if all 4 corners are equal, quick fill interior
+ if (wTestRect(&m, x, y, w, h)) {
+ wFillRect(x, y, w, h, colors_[m]);
+ } else {
+ // did we reach the minimum rectangle size?
+ if ((w <= kMinRectSize) || (h <= kMinRectSize)) {
+ wRenderTile(x, y, w, h);
+ } else {
+ // else recurse into smaller rectangles
+ const int half_w = w / 2;
+ const int half_h = h / 2;
+ wSubdivide(x, y, half_w, half_h);
+ wSubdivide(x + half_w, y, half_w, half_h);
+ wSubdivide(x, y + half_h, half_w, half_h);
+ wSubdivide(x + half_w, y + half_h, half_w, half_h);
+ }
+ }
+}
+
+// This function cuts up the rectangle into power of 2 sized squares. It
+// assumes the input rectangle w & h are evenly divisible by
+// kStartRecurseSize.
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::wRenderRect(int x, int y, int w, int h) {
+ for (int iy = y; iy < (y + h); iy += kStartRecurseSize) {
+ for (int ix = x; ix < (x + w); ix += kStartRecurseSize) {
+ wSubdivide(ix, iy, kStartRecurseSize, kStartRecurseSize);
+ }
+ }
+}
+
+// If multithreading, this function is only called by the worker threads.
+void Voronoi::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 Voronoi::wRenderRegionEntry(int region, void* thiz) {
+ static_cast<Voronoi*>(thiz)->wRenderRegion(region);
+}
+
+// Function Voronoi::UpdateSim()
+// Run a simple sim to move the voronoi positions. This update loop
+// is run once per frame. Called from the main thread only, and only
+// when the worker threads are idle.
+void Voronoi::UpdateSim() {
+ ang_ += 0.002f;
+ if (ang_ > kTwoPI) {
+ ang_ = ang_ - kTwoPI;
+ }
+ float z = cosf(ang_) * 3.0f;
+ // push the points around on the screen for animation
+ for (int j = 0; j < kMaxPointCount; j++) {
+ positions_[j].x += (velocities_[j].x) * z;
+ positions_[j].y += (velocities_[j].y) * z;
+ screen_positions_[j].x = positions_[j].x * width_;
+ screen_positions_[j].y = positions_[j].y * height_;
+ }
+}
+
+// Renders a small diamond shaped dot at x, y clipped against the window
+void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) {
+ const int ix = static_cast<int>(x);
+ const int iy = static_cast<int>(y);
+ // clip it against window
+ if (ix < 1) return;
+ if (ix >= (width_ - 1)) return;
+ if (iy < 1) return;
+ if (iy >= (height_ - 1)) return;
+ uint32_t* pixel = pixel_buffer_ + iy * stride_in_pixels_ + ix;
+ // render dot as a small diamond
+ *pixel = color1;
+ *(pixel - 1) = color2;
+ *(pixel + 1) = color2;
+ *(pixel - stride_in_pixels_) = color2;
+ *(pixel + stride_in_pixels_) = color2;
+}
+
+// Superimposes dots on the positions.
+void Voronoi::SuperimposePositions() {
+ const uint32_t white = MakeRGBA(255, 255, 255, 255);
+ const uint32_t gray = MakeRGBA(192, 192, 192, 255);
+ for (int i = 0; i < point_count_; i++) {
+ RenderDot(
+ screen_positions_[i].x, screen_positions_[i].y, white, gray);
+ }
+}
+
+// Renders the Voronoi diagram, dispatching the work to multiple threads.
+// Note: This Dispatch() is from the main PPAPI thread, so care must be taken
+// not to attempt PPAPI calls from the worker threads, since Dispatch() will
+// block here until all work is complete. The worker threads are compute only
+// and do not make any PPAPI calls.
+void Voronoi::Render() {
+ workers_->Dispatch(num_regions_, wRenderRegionEntry, this);
+ if (draw_points_)
+ SuperimposePositions();
+}
+
+void Voronoi::DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
+ if (position.size().width() == width_ &&
+ position.size().height() == height_)
+ return; // Size didn't change, no need to update anything.
+
+ // Create a new device context with the new size.
+ DestroyContext();
+ CreateContext(position.size());
+ Update();
+}
+
+void Voronoi::StartBenchmark() {
+ Reset();
+ printf("Benchmark started...\n");
+ benchmark_frame_counter_ = kFramesToBenchmark;
+ benchmarking_ = true;
+ benchmark_start_time_ = getseconds();
+}
+
+void Voronoi::EndBenchmark() {
+ benchmark_end_time_ = getseconds();
+ printf("Benchmark ended... time: %2.5f\n",
+ benchmark_end_time_ - benchmark_start_time_);
+ benchmarking_ = false;
+ benchmark_frame_counter_ = 0;
+ pp::Var result(benchmark_end_time_ - benchmark_start_time_);
+ PostMessage(result);
+}
+
+// Handle input events from the user.
+bool Voronoi::HandleInputEvent(const pp::InputEvent& event) {
+ switch (event.GetType()) {
+ case PP_INPUTEVENT_TYPE_KEYDOWN: {
+ pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event);
+ uint32_t key_code = key.GetKeyCode();
+ if (key_code == 84) // 't' key
+ if (!benchmarking_)
+ StartBenchmark();
+ break;
+ }
+ default:
+ return false;
+ }
+ return true;
+}
+
+// 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_)
+ 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(), " "));
+ 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(), " "));
+ delete workers_;
+ workers_ = new ThreadPool(thread_count);
+ }
+ }
+}
+
+void Voronoi::FlushCallback(void* thiz, int32_t result) {
+ static_cast<Voronoi*>(thiz)->Update();
+}
+
+// Update the 2d region and flush to make it visible on the page.
+void Voronoi::FlushPixelBuffer() {
+ graphics_2d_context_->PaintImageData(*image_data_, pp::Point(0, 0));
+ graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
+}
+
+void Voronoi::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 Voronoi::CreateContext(const pp::Size& size) {
+ graphics_2d_context_ = new pp::Graphics2D(this, size, false);
+ if (!BindGraphics(*graphics_2d_context_))
+ printf("Couldn't bind the device context\n");
+ image_data_ = new pp::ImageData(this,
+ PP_IMAGEDATAFORMAT_BGRA_PREMUL,
+ size,
+ false);
+ width_ = image_data_->size().width();
+ height_ = image_data_->size().height();
+ // This demo requires power of two width & height buffers.
+ assert(is_pow2(width_) && is_pow2(height_));
+ stride_in_pixels_ = static_cast<uint32_t>(image_data_->stride() / 4);
+ pixel_buffer_ = static_cast<uint32_t*>(image_data_->data());
+}
+
+void Voronoi::DestroyContext() {
+ delete graphics_2d_context_;
+ delete image_data_;
+ graphics_2d_context_ = NULL;
+ image_data_ = NULL;
+ width_ = 0;
+ height_ = 0;
+ stride_in_pixels_ = 0;
+ pixel_buffer_ = NULL;
+}
+
+class VoronoiModule : public pp::Module {
+ public:
+ VoronoiModule() : pp::Module() {}
+ virtual ~VoronoiModule() {}
+
+ // Create and return a Voronoi instance.
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new Voronoi(instance);
+ }
+};
+
+namespace pp {
+Module* CreateModule() {
+ return new VoronoiModule();
+}
+} // namespace pp
+
diff --git a/native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/example.dsc b/native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/example.dsc
deleted file mode 100644
index 19a2b4173a..0000000000
--- a/native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/example.dsc
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- 'TOOLS': ['newlib', 'glibc', 'pnacl'],
- 'TARGETS': [
- {
- 'NAME': 'hello_world_stdio',
- 'TYPE': 'main',
- 'SOURCES': ['hello_world.c'],
- 'LIBS': ['ppapi_main', 'nacl_io', 'ppapi_cpp', 'ppapi', 'pthread']
- }
- ],
- 'DATA': [
- 'example.js',
- ],
- 'DEST': 'examples/getting_started',
- 'NAME': 'hello_world_ppapi_main',
- 'TITLE': 'Hello World (libppapi_main)',
- 'GROUP': 'Getting Started'
-}
diff --git a/native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/hello_world.c b/native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/hello_world.c
deleted file mode 100644
index 1d3d6f10ff..0000000000
--- a/native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/hello_world.c
+++ /dev/null
@@ -1,50 +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 <stdio.h>
-#include <string.h>
-
-#include "ppapi/c/ppb_var.h"
-#include "ppapi/c/ppb_messaging.h"
-#include "ppapi/c/ppb_console.h"
-
-#include "ppapi_main/ppapi_main.h"
-
-// The default arguments to PPAPI_MAIN maps:
-// STDIN -> /dev/stdin
-// STDOUT -> /dev/stdout
-// STDERR -> /dev/console3
-// We use our own args here so that stdout sends messages to JavaScript via
-// PostMessage (/dev/tty).
-PPAPI_MAIN_WITH_ARGS("pm_stdout", "/dev/tty", NULL, NULL)
-
-//
-// The "main" entry point called by PPAPIInstance once initialization
-// takes place. This is called off the main thread, which is hidden
-// from the developer, making it safe to use blocking calls.
-// The arguments are provided as:
-// argv[0] = "NEXE"
-// argv[1] = "--<KEY>"
-// argv[2] = "<VALUE>"
-// Where the embed tag for this module uses KEY=VALUE
-//
-int ppapi_main(int argc, const char* argv[]) {
- int index = 1;
-
- // Use PostMessage to send "Hello World" to JavaScript.
- printf("Hello World STDOUT.\n");
-
- // Use PPAPI Console interface to send "Hello World" to the
- // JavaScript Console.
- fprintf(stderr, "Hello World STDERR.\n");
-
- // Print the arguments we received from the web page
- printf("NAME: %s\n", argv[0]);
- while (index + 2 < argc) {
- printf(" ARGS: %s=%s\n", argv[index + 0], argv[index + 1]);
- index += 2;
- }
- return 0;
-}
diff --git a/native_client_sdk/src/examples/getting_started/simple_hello_world/example.dsc b/native_client_sdk/src/examples/getting_started/simple_hello_world/example.dsc
new file mode 100644
index 0000000000..de8c6a35f7
--- /dev/null
+++ b/native_client_sdk/src/examples/getting_started/simple_hello_world/example.dsc
@@ -0,0 +1,19 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
+ 'TARGETS': [
+ {
+ 'NAME' : 'simple_hello_world',
+ 'TYPE' : 'main',
+ 'SOURCES' : ['hello_world.c'],
+ 'LIBS': ['ppapi_simple', 'nacl_io', 'ppapi_cpp', 'ppapi', 'pthread']
+ }
+ ],
+ 'DATA': [
+ 'example.js',
+ ],
+ 'DEST': 'examples/getting_started',
+ 'NAME': 'simple_hello_world',
+ 'TITLE': 'Hello World (ppapi_simple)',
+ 'GROUP': 'Getting Started'
+}
+
diff --git a/native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/example.js b/native_client_sdk/src/examples/getting_started/simple_hello_world/example.js
index 7f269215fe..7f269215fe 100644
--- a/native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/example.js
+++ b/native_client_sdk/src/examples/getting_started/simple_hello_world/example.js
diff --git a/native_client_sdk/src/examples/getting_started/simple_hello_world/hello_world.c b/native_client_sdk/src/examples/getting_started/simple_hello_world/hello_world.c
new file mode 100644
index 0000000000..082c62d4ea
--- /dev/null
+++ b/native_client_sdk/src/examples/getting_started/simple_hello_world/hello_world.c
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "ppapi_simple/ps_main.h"
+
+int example_main(int argc, const char* argv[]) {
+ /* Use ppb_messaging to send "Hello World" to JavaScript. */
+ printf("Hello World STDOUT.\n");
+
+ /* Use ppb_console send "Hello World" to the JavaScript Console. */
+ fprintf(stderr, "Hello World STDERR.\n");
+ 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/getting_started/hello_world_ppapi_main/index.html b/native_client_sdk/src/examples/getting_started/simple_hello_world/index.html
index c6a4aa1ef4..c6a4aa1ef4 100644
--- a/native_client_sdk/src/examples/getting_started/hello_world_ppapi_main/index.html
+++ b/native_client_sdk/src/examples/getting_started/simple_hello_world/index.html
diff --git a/native_client_sdk/src/examples/hello_world_instance3d/example.dsc b/native_client_sdk/src/examples/hello_world_instance3d/example.dsc
deleted file mode 100644
index 8dda62375e..0000000000
--- a/native_client_sdk/src/examples/hello_world_instance3d/example.dsc
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- 'DISABLE': True,
- 'TOOLS': ['newlib', 'glibc', 'pnacl'],
- 'TARGETS': [
- {
- 'NAME' : 'hello_world_instance3d',
- 'TYPE' : 'main',
- 'SOURCES' : ['hello_world.cc', 'matrix.cc', 'matrix.h'],
- 'CXXFLAGS': [
- '-I../../src',
- '-I../../src/ppapi/lib/gl'
- ],
- 'DEPS': ['ppapi_main', 'nacl_io'],
- 'LIBS': ['ppapi_gles2', 'ppapi_cpp', 'ppapi',
- 'pthread']
- }
- ],
- 'DATA': [
- 'fragment_shader_es2.frag',
- 'hello.raw',
- 'vertex_shader_es2.vert'
- ],
- 'DEST': 'examples',
- 'NAME': 'hello_world_instance3d',
- 'TITLE': 'Hello World GLES 2.0 using ppapi_instance3d',
- 'GROUP': 'API'
-}
diff --git a/native_client_sdk/src/examples/hello_world_instance3d/fragment_shader_es2.frag b/native_client_sdk/src/examples/hello_world_instance3d/fragment_shader_es2.frag
deleted file mode 100644
index 247c559f8c..0000000000
--- a/native_client_sdk/src/examples/hello_world_instance3d/fragment_shader_es2.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-precision mediump float;
-varying vec3 v_color;
-varying vec2 v_texCoord;
-uniform sampler2D s_texture;
-void main()
-{
- gl_FragColor = texture2D( s_texture, vec2(v_texCoord.x,1.0 - v_texCoord.y) ) + vec4(v_color.x,v_color.y,v_color.z,1);
-} \ No newline at end of file
diff --git a/native_client_sdk/src/examples/hello_world_instance3d/hello.raw b/native_client_sdk/src/examples/hello_world_instance3d/hello.raw
deleted file mode 100644
index 3320575072..0000000000
--- a/native_client_sdk/src/examples/hello_world_instance3d/hello.raw
+++ /dev/null
Binary files differ
diff --git a/native_client_sdk/src/examples/hello_world_instance3d/hello_world.cc b/native_client_sdk/src/examples/hello_world_instance3d/hello_world.cc
deleted file mode 100644
index 26515b7249..0000000000
--- a/native_client_sdk/src/examples/hello_world_instance3d/hello_world.cc
+++ /dev/null
@@ -1,325 +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.
- */
-
-/** @file hello_world_gles.cc
- * This example demonstrates loading and running a simple 3D openGL ES 2.0
- * application.
- */
-
-//---------------------------------------------------------------------------
-// The spinning Cube
-//---------------------------------------------------------------------------
-
-#define _USE_MATH_DEFINES 1
-#include <fcntl.h>
-#include <limits.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "nacl_io/nacl_io.h"
-
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_stdint.h"
-#include "ppapi/c/pp_var.h"
-#include "ppapi/c/ppb.h"
-#include "ppapi/c/ppb_opengles2.h"
-#include "ppapi/c/ppb_var.h"
-#include "ppapi/c/ppp.h"
-#include "ppapi/c/ppp_graphics_3d.h"
-#include "ppapi/c/ppp_instance.h"
-
-#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
-
-#include "ppapi_main/ppapi_event.h"
-#include "ppapi_main/ppapi_instance3d.h"
-#include "ppapi_main/ppapi_main.h"
-
-#include <GLES2/gl2.h>
-#include "matrix.h"
-
-GLuint g_positionLoc;
-GLuint g_texCoordLoc;
-GLuint g_colorLoc;
-GLuint g_MVPLoc;
-GLuint g_vboID;
-GLuint g_ibID;
-GLubyte g_Indices[36];
-
-GLuint g_programObj;
-GLuint g_vertexShader;
-GLuint g_fragmentShader;
-
-GLuint g_textureLoc = 0;
-GLuint g_textureID = 0;
-
-float g_fSpinX = 0.0f;
-float g_fSpinY = 0.0f;
-
-//----------------------------------------------------------------------------
-// Rendering Assets
-//----------------------------------------------------------------------------
-struct Vertex {
- float tu, tv;
- float color[3];
- float loc[3];
-};
-
-Vertex* g_quadVertices = NULL;
-const char* g_TextureData = NULL;
-const char* g_VShaderData = NULL;
-const char* g_FShaderData = NULL;
-
-bool g_Loaded = false;
-bool g_Ready = false;
-
-float g_xSpin = 2.0f;
-float g_ySpin = 0.5f;
-
-GLuint compileShader(GLenum type, const char* data) {
- const char* shaderStrings[1];
- shaderStrings[0] = data;
-
- GLuint shader = glCreateShader(type);
- glShaderSource(shader, 1, shaderStrings, NULL);
- glCompileShader(shader);
- return shader;
-}
-
-void InitProgram(void) {
- g_vertexShader = compileShader(GL_VERTEX_SHADER, g_VShaderData);
- g_fragmentShader = compileShader(GL_FRAGMENT_SHADER, g_FShaderData);
-
- g_programObj = glCreateProgram();
- glAttachShader(g_programObj, g_vertexShader);
- glAttachShader(g_programObj, g_fragmentShader);
- glLinkProgram(g_programObj);
-
- glGenBuffers(1, &g_vboID);
- glBindBuffer(GL_ARRAY_BUFFER, g_vboID);
- glBufferData(GL_ARRAY_BUFFER,
- 24 * sizeof(Vertex),
- (void*)&g_quadVertices[0],
- GL_STATIC_DRAW);
-
- glGenBuffers(1, &g_ibID);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ibID);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER,
- 36 * sizeof(char),
- (void*)&g_Indices[0],
- GL_STATIC_DRAW);
-
- //
- // Create a texture to test out our fragment shader...
- //
- glGenTextures(1, &g_textureID);
- glBindTexture(GL_TEXTURE_2D, g_textureID);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, GL_UNSIGNED_BYTE,
- g_TextureData);
-
- //
- // Locate some parameters by name so we can set them later...
- //
- g_textureLoc = glGetUniformLocation(g_programObj, "arrowTexture");
- g_positionLoc = glGetAttribLocation(g_programObj, "a_position");
- g_texCoordLoc = glGetAttribLocation(g_programObj, "a_texCoord");
- g_colorLoc = glGetAttribLocation(g_programObj, "a_color");
- g_MVPLoc = glGetUniformLocation(g_programObj, "a_MVP");
- printf("Program initialized.\n");
-}
-
-void BuildQuad(Vertex* verts, int axis[3], float depth, float color[3]) {
- static float X[4] = { -1.0f, 1.0f, 1.0f, -1.0f };
- static float Y[4] = { -1.0f, -1.0f, 1.0f, 1.0f };
-
- for (int i = 0; i < 4; i++) {
- verts[i].tu = (1.0 - X[i]) / 2.0f;
- verts[i].tv = (Y[i] + 1.0f) / -2.0f * depth;
- verts[i].loc[axis[0]] = X[i] * depth;
- verts[i].loc[axis[1]] = Y[i] * depth;
- verts[i].loc[axis[2]] = depth;
- for (int j = 0; j < 3; j++)
- verts[i].color[j] = color[j] * (Y[i] + 1.0f) / 2.0f;
- }
-}
-
-Vertex* BuildCube() {
- Vertex* verts = new Vertex[24];
- for (int i = 0; i < 3; i++) {
- int Faxis[3];
- int Baxis[3];
- float Fcolor[3];
- float Bcolor[3];
- for (int j = 0; j < 3; j++) {
- Faxis[j] = (j + i) % 3;
- Baxis[j] = (j + i) % 3;
- }
- memset(Fcolor, 0, sizeof(float) * 3);
- memset(Bcolor, 0, sizeof(float) * 3);
- Fcolor[i] = 0.5f;
- Bcolor[i] = 1.0f;
- BuildQuad(&verts[0 + i * 4], Faxis, 1.0f, Fcolor);
- BuildQuad(&verts[12 + i * 4], Baxis, -1.0f, Bcolor);
- }
-
- for (int i = 0; i < 6; i++) {
- g_Indices[i * 6 + 0] = 2 + i * 4;
- g_Indices[i * 6 + 1] = 1 + i * 4;
- g_Indices[i * 6 + 2] = 0 + i * 4;
- g_Indices[i * 6 + 3] = 3 + i * 4;
- g_Indices[i * 6 + 4] = 2 + i * 4;
- g_Indices[i * 6 + 5] = 0 + i * 4;
- }
- return verts;
-}
-
-static float clamp(float val, float min, float max) {
- if (val < min)
- return min;
- if (val > max)
- return max;
- return val;
-}
-
-void ProcessEvent(PPAPIEvent* event) {
- if (event->event_type == PP_INPUTEVENT_TYPE_MOUSEMOVE) {
- PPAPIMouseEvent* mouse = (PPAPIMouseEvent*)event;
- g_ySpin = clamp((float) mouse->delta.x / 2, -4.0, 4.0);
- g_xSpin = clamp((float) mouse->delta.y / 2, -4.0, 4.0);
- }
- if (event->event_type == PP_INPUTEVENT_TYPE_KEYUP) {
- PPAPIKeyEvent* key = (PPAPIKeyEvent*)event;
- if (key->key_code == 13) {
- PPAPIInstance3D::GetInstance3D()->ToggleFullscreen();
- }
- }
-}
-
-void PPAPIRender(PP_Resource ctx, uint32_t width, uint32_t height) {
- if (!g_Ready) {
- if (g_Loaded) {
- InitProgram();
- g_Ready = true;
- } else {
- return;
- }
- }
-
- PPAPIEvent* event;
- while (PPAPIEvent* event = PPAPI_AcquireEvent()) {
- ProcessEvent(event);
- PPAPI_ReleaseEvent(event);
- }
-
- static float xRot = 0.0;
- static float yRot = 0.0;
-
- xRot -= g_xSpin;
- yRot -= g_ySpin;
-
- if (xRot >= 360.0f)
- xRot = 0.0;
- if (xRot <= -360.0f)
- xRot = 0.0;
-
- if (yRot >= 360.0f)
- yRot = 0.0;
- if (yRot <= -360.0f)
- yRot = 0.0;
-
- glClearColor(0.5, 0.5, 0.5, 1);
- glClearDepthf(1.0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glEnable(GL_DEPTH_TEST);
-
- //set what program to use
- glUseProgram(g_programObj);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, g_textureID);
- glUniform1i(g_textureLoc, 0);
-
- //create our perspective matrix
- float mpv[16];
- float trs[16];
- float rot[16];
-
- identity_matrix(mpv);
- glhPerspectivef2(&mpv[0], 45.0f, (float)(width) / (float) height, 1, 10);
-
- translate_matrix(0, 0, -4.0, trs);
- rotate_matrix(xRot, yRot, 0.0f, rot);
- multiply_matrix(trs, rot, trs);
- multiply_matrix(mpv, trs, mpv);
- glUniformMatrix4fv(g_MVPLoc, 1, GL_FALSE, (GLfloat*)mpv);
-
- //define the attributes of the vertex
- glBindBuffer(GL_ARRAY_BUFFER, g_vboID);
- glVertexAttribPointer(g_positionLoc,
- 3,
- GL_FLOAT,
- GL_FALSE,
- sizeof(Vertex),
- (void*)offsetof(Vertex, loc));
- glEnableVertexAttribArray(g_positionLoc);
- glVertexAttribPointer(g_texCoordLoc,
- 2,
- GL_FLOAT,
- GL_FALSE,
- sizeof(Vertex),
- (void*)offsetof(Vertex, tu));
- glEnableVertexAttribArray(g_texCoordLoc);
- glVertexAttribPointer(g_colorLoc,
- 3,
- GL_FLOAT,
- GL_FALSE,
- sizeof(Vertex),
- (void*)offsetof(Vertex, color));
- glEnableVertexAttribArray(g_colorLoc);
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ibID);
- glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, 0);
-}
-
-const char* LoadData(const char* url) {
- char* buf;
- struct stat stat_buf;
-
- int fp = open(url, O_RDONLY);
- fstat(fp, &stat_buf);
-
- int len = static_cast<int>(stat_buf.st_size);
- buf = new char[len + 1];
- int read_size = read(fp, buf, len);
- buf[len] = 0;
- return buf;
-}
-
-PPAPI_MAIN_USE(PPAPI_CreateInstance3D, PPAPI_MAIN_DEFAULT_ARGS)
-int ppapi_main(int argc, const char* argv[]) {
- printf("Started main.\n");
-
- // Mount URL loads to /http
- mount("", "/http", "httpfs", 0, "");
-
- g_TextureData = LoadData("/http/hello.raw");
- g_VShaderData = LoadData("/http/vertex_shader_es2.vert");
- g_FShaderData = LoadData("/http/fragment_shader_es2.frag");
- g_quadVertices = BuildCube();
-
- fprintf(stderr, "Loaded\n");
- g_Loaded = true;
- return 0;
-}
diff --git a/native_client_sdk/src/examples/hello_world_instance3d/matrix.cc b/native_client_sdk/src/examples/hello_world_instance3d/matrix.cc
deleted file mode 100644
index b87d496cb1..0000000000
--- a/native_client_sdk/src/examples/hello_world_instance3d/matrix.cc
+++ /dev/null
@@ -1,140 +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.
- */
-
-/** @file matrix.cc
- * Implements simple matrix manipulation functions.
- */
-
-//-----------------------------------------------------------------------------
-#include <stdlib.h>
-#include <string.h>
-#include "matrix.h"
-#define deg_to_rad(x) (x * (M_PI / 180.0f))
-
-void glhFrustumf2(Matrix_t mat,
- GLfloat left,
- GLfloat right,
- GLfloat bottom,
- GLfloat top,
- GLfloat znear,
- GLfloat zfar) {
- float temp, temp2, temp3, temp4;
- temp = 2.0f * znear;
- temp2 = right - left;
- temp3 = top - bottom;
- temp4 = zfar - znear;
- mat[0] = temp / temp2;
- mat[1] = 0.0f;
- mat[2] = 0.0f;
- mat[3] = 0.0f;
- mat[4] = 0.0f;
- mat[5] = temp / temp3;
- mat[6] = 0.0f;
- mat[7] = 0.0f;
- mat[8] = (right + left) / temp2;
- mat[9] = (top + bottom) / temp3;
- mat[10] = (-zfar - znear) / temp4;
- mat[11] = -1.0f;
- mat[12] = 0.0f;
- mat[13] = 0.0f;
- mat[14] = (-temp * zfar) / temp4;
- mat[15] = 0.0f;
-}
-
-void glhPerspectivef2(Matrix_t mat,
- GLfloat fovyInDegrees,
- GLfloat aspectRatio,
- GLfloat znear,
- GLfloat zfar) {
- float ymax, xmax;
- ymax = znear * tanf(fovyInDegrees * 3.14f / 360.0f);
- xmax = ymax * aspectRatio;
- glhFrustumf2(mat, -xmax, xmax, -ymax, ymax, znear, zfar);
-}
-
-void identity_matrix(Matrix_t mat) {
- memset(mat, 0, sizeof(Matrix_t));
- mat[0] = 1.0;
- mat[5] = 1.0;
- mat[10] = 1.0;
- mat[15] = 1.0;
-}
-
-void multiply_matrix(const Matrix_t a, const Matrix_t b, Matrix_t mat) {
- // Generate to a temporary first in case the output matrix and input
- // matrix are the same.
- Matrix_t out;
-
- out[0] = a[0] * b[0] + a[4] * b[1] + a[8] * b[2] + a[12] * b[3];
- out[1] = a[1] * b[0] + a[5] * b[1] + a[9] * b[2] + a[13] * b[3];
- out[2] = a[2] * b[0] + a[6] * b[1] + a[10] * b[2] + a[14] * b[3];
- out[3] = a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + a[15] * b[3];
-
- out[4] = a[0] * b[4] + a[4] * b[5] + a[8] * b[6] + a[12] * b[7];
- out[5] = a[1] * b[4] + a[5] * b[5] + a[9] * b[6] + a[13] * b[7];
- out[6] = a[2] * b[4] + a[6] * b[5] + a[10] * b[6] + a[14] * b[7];
- out[7] = a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + a[15] * b[7];
-
- out[8] = a[0] * b[8] + a[4] * b[9] + a[8] * b[10] + a[12] * b[11];
- out[9] = a[1] * b[8] + a[5] * b[9] + a[9] * b[10] + a[13] * b[11];
- out[10] = a[2] * b[8] + a[6] * b[9] + a[10] * b[10] + a[14] * b[11];
- out[11] = a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + a[15] * b[11];
-
- out[12] = a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12] * b[15];
- out[13] = a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13] * b[15];
- out[14] = a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15];
- out[15] = a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15];
-
- memcpy(mat, out, sizeof(Matrix_t));
-}
-
-void rotate_x_matrix(GLfloat x_rad, Matrix_t mat) {
- identity_matrix(mat);
- mat[5] = cosf(x_rad);
- mat[6] = -sinf(x_rad);
- mat[9] = -mat[6];
- mat[10] = mat[5];
-}
-
-void rotate_y_matrix(GLfloat y_rad, Matrix_t mat) {
- identity_matrix(mat);
- mat[0] = cosf(y_rad);
- mat[2] = sinf(y_rad);
- mat[8] = -mat[2];
- mat[10] = mat[0];
-}
-
-void rotate_z_matrix(GLfloat z_rad, Matrix_t mat) {
- identity_matrix(mat);
- mat[0] = cosf(z_rad);
- mat[1] = sinf(z_rad);
- mat[4] = -mat[1];
- mat[5] = mat[0];
-}
-
-void rotate_matrix(GLfloat x_deg, GLfloat y_deg, GLfloat z_deg, Matrix_t mat) {
- GLfloat x_rad = (GLfloat) deg_to_rad(x_deg);
- GLfloat y_rad = (GLfloat) deg_to_rad(y_deg);
- GLfloat z_rad = (GLfloat) deg_to_rad(z_deg);
-
- Matrix_t x_matrix;
- Matrix_t y_matrix;
- Matrix_t z_matrix;
-
- rotate_x_matrix(x_rad, x_matrix);
- rotate_y_matrix(y_rad, y_matrix);
- rotate_z_matrix(z_rad, z_matrix);
-
- Matrix_t xy_matrix;
- multiply_matrix(y_matrix, x_matrix, xy_matrix);
- multiply_matrix(z_matrix, xy_matrix, mat);
-}
-
-void translate_matrix(GLfloat x, GLfloat y, GLfloat z, Matrix_t mat) {
- identity_matrix(mat);
- mat[12] += x;
- mat[13] += y;
- mat[14] += z;
-}
diff --git a/native_client_sdk/src/examples/hello_world_instance3d/matrix.h b/native_client_sdk/src/examples/hello_world_instance3d/matrix.h
deleted file mode 100644
index ed094eda09..0000000000
--- a/native_client_sdk/src/examples/hello_world_instance3d/matrix.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef EXAMPLES_HELLO_WORLD_GLES_MATRIX_H
-#define EXAMPLES_HELLO_WORLD_GLES_MATRIX_H
-
-/* 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.
- */
-
-/** @file matrix.cc
- * Implements simple matrix manipulation functions.
- */
-
-//-----------------------------------------------------------------------------
-#define _USE_MATH_DEFINES 1
-#include <limits.h>
-#include <math.h>
-#include <GLES2/gl2.h>
-
-typedef GLfloat Matrix_t[16];
-
-/// Since GLES2 doesn't have all the nifty matrix transform functions that GL
-/// has, we emulate some of them here for the sake of sanity from:
-/// http://www.opengl.org/wiki/GluPerspective_code
-void glhFrustumf2(Matrix_t mat,
- GLfloat left,
- GLfloat right,
- GLfloat bottom,
- GLfloat top,
- GLfloat znear,
- GLfloat zfar);
-
-void glhPerspectivef2(Matrix_t mat,
- GLfloat fovyInDegrees,
- GLfloat aspectRatio,
- GLfloat znear,
- GLfloat zfar);
-
-void identity_matrix(Matrix_t mat);
-void multiply_matrix(const Matrix_t a, const Matrix_t b, Matrix_t mat);
-void rotate_matrix(GLfloat x_deg, GLfloat y_deg, GLfloat z_deg, Matrix_t mat);
-void translate_matrix(GLfloat x, GLfloat y, GLfloat z, Matrix_t mat);
-
-#endif // EXAMPLES_HELLO_WORLD_GLES_MATRIX_H
diff --git a/native_client_sdk/src/examples/hello_world_instance3d/vertex_shader_es2.vert b/native_client_sdk/src/examples/hello_world_instance3d/vertex_shader_es2.vert
deleted file mode 100644
index da616cb92a..0000000000
--- a/native_client_sdk/src/examples/hello_world_instance3d/vertex_shader_es2.vert
+++ /dev/null
@@ -1,12 +0,0 @@
-uniform mat4 a_MVP;
-attribute vec2 a_texCoord;
-attribute vec3 a_color;
-attribute vec4 a_position;
-varying vec3 v_color;
-varying vec2 v_texCoord;
-void main()
-{
- gl_Position = a_MVP * a_position;
- v_color = a_color;
- v_texCoord = a_texCoord;
-} \ No newline at end of file
diff --git a/native_client_sdk/src/examples/tutorial/dlopen/dlopen.cc b/native_client_sdk/src/examples/tutorial/dlopen/dlopen.cc
index 7d13a1028e..9291464165 100644
--- a/native_client_sdk/src/examples/tutorial/dlopen/dlopen.cc
+++ b/native_client_sdk/src/examples/tutorial/dlopen/dlopen.cc
@@ -23,9 +23,15 @@
#define CONFIG_NAME "Release"
#endif
-#define XSTRINGIFY(x) STRINGIFY(x)
-#define STRINGIFY(x) #x
-#define NACL_ARCH_STRING XSTRINGIFY(NACL_ARCH)
+#if defined __arm__
+#define NACL_ARCH "arm"
+#elif defined __i686__
+#define NACL_ARCH "x86_32"
+#elif defined __x86_64__
+#define NACL_ARCH "x86_64"
+#else
+#error "Unknown arch"
+#endif
class DlOpenInstance : public pp::Instance {
public:
@@ -66,7 +72,7 @@ class DlOpenInstance : public pp::Instance {
// dlclose, which would close the shared object and unload it from memory.
void LoadLibrary() {
const char reverse_so_path[] =
- "/http/glibc/" CONFIG_NAME "/libreverse_" NACL_ARCH_STRING ".so";
+ "/http/glibc/" CONFIG_NAME "/libreverse_" NACL_ARCH ".so";
const int32_t IMMEDIATELY = 0;
eightball_so_ = dlopen("libeightball.so", RTLD_LAZY);
reverse_so_ = dlopen(reverse_so_path, RTLD_LAZY);
diff --git a/native_client_sdk/src/libraries/error_handling/error_handling.h b/native_client_sdk/src/libraries/error_handling/error_handling.h
index 29b4aca96d..add76ceb41 100644
--- a/native_client_sdk/src/libraries/error_handling/error_handling.h
+++ b/native_client_sdk/src/libraries/error_handling/error_handling.h
@@ -8,7 +8,7 @@
#define ERROR_HANDLING_ERROR_HANDLING_H_
#include "error_handling/string_stream.h"
-#include "utils/macros.h"
+#include "sdk_util/macros.h"
EXTERN_C_BEGIN
@@ -82,4 +82,5 @@ int EHUnwindFrame(EHFrame* frame);
EXTERN_C_END
-#endif // ERROR_HANDLING_ERROR_HANDLING_H_ \ No newline at end of file
+#endif // ERROR_HANDLING_ERROR_HANDLING_H_
+
diff --git a/native_client_sdk/src/libraries/nacl_io/error.h b/native_client_sdk/src/libraries/nacl_io/error.h
new file mode 100644
index 0000000000..8f7510e46e
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/error.h
@@ -0,0 +1,17 @@
+/* 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_ERROR_H_
+#define LIBRARIES_NACL_IO_ERROR_H_
+
+struct Error {
+ // TODO(binji): Add debugging constructor w/ __FILE__, __LINE__.
+ // crbug.com/247816
+ Error(int error) : error(error) {}
+ operator int() const { return error; }
+
+ int error;
+};
+
+#endif // LIBRARIES_NACL_IO_ERROR_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/inode_pool.h b/native_client_sdk/src/libraries/nacl_io/inode_pool.h
index 5624b1d17a..4c3f44b36e 100644
--- a/native_client_sdk/src/libraries/nacl_io/inode_pool.h
+++ b/native_client_sdk/src/libraries/nacl_io/inode_pool.h
@@ -11,7 +11,7 @@
#include "nacl_io/osstat.h"
#include "pthread.h"
-#include "utils/auto_lock.h"
+#include "sdk_util/auto_lock.h"
class INodePool {
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 dcf42fb8c6..a943894595 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
@@ -17,40 +17,57 @@
#include "nacl_io/mount_node.h"
// It is only legal to construct a handle while the kernel lock is held.
-KernelHandle::KernelHandle(Mount* mnt, MountNode* node, int mode)
- : mount_(mnt),
- node_(node),
- mode_(mode),
- offs_(0) {
- if (mode & O_APPEND) offs_ = node->GetSize();
+KernelHandle::KernelHandle(Mount* mnt, MountNode* node)
+ : mount_(mnt), node_(node), offs_(0) {}
+
+Error KernelHandle::Init(int open_mode) {
+ if (open_mode & O_APPEND) {
+ size_t node_size;
+ Error error = node_->GetSize(&offs_);
+ if (error)
+ return error;
+ }
+
+ return 0;
}
-off_t KernelHandle::Seek(off_t offset, int whence) {
+Error KernelHandle::Seek(off_t offset, int whence, off_t* out_offset) {
+ // By default, don't move the offset.
+ *out_offset = offset;
+
size_t base;
- size_t node_size = node_->GetSize();
+ size_t node_size;
+ Error error = node_->GetSize(&node_size);
+ if (error)
+ return error;
switch (whence) {
- default: return -1;
- case SEEK_SET: base = 0; break;
- case SEEK_CUR: base = offs_; break;
- case SEEK_END: base = node_size; break;
+ default:
+ return -1;
+ case SEEK_SET:
+ base = 0;
+ break;
+ case SEEK_CUR:
+ base = offs_;
+ break;
+ case SEEK_END:
+ base = node_size;
+ break;
}
- if (base + offset < 0) {
- errno = EINVAL;
- return -1;
- }
+ if (base + offset < 0)
+ return EINVAL;
- offs_ = base + offset;
+ off_t new_offset = base + offset;
// Seeking past the end of the file will zero out the space between the old
// end and the new end.
- if (offs_ > node_size) {
- if (node_->FTruncate(offs_) < 0) {
- errno = EINVAL;
- return -1;
- }
+ if (new_offset > node_size) {
+ error = node_->FTruncate(new_offset);
+ if (error)
+ return EINVAL;
}
- return offs_;
+ *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 a047125085..ab7b7cd699 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
@@ -7,9 +7,10 @@
#include <pthread.h>
+#include "nacl_io/error.h"
#include "nacl_io/ostypes.h"
-#include "utils/macros.h"
-#include "utils/ref_object.h"
+#include "sdk_util/macros.h"
+#include "sdk_util/ref_object.h"
class Mount;
class MountNode;
@@ -19,13 +20,15 @@ class MountNode;
// KernelHandle can only be referenced when the KernelProxy lock is held.
class KernelHandle : public RefObject {
public:
- KernelHandle(Mount* mnt, MountNode* node, int oflags);
+ // Assumes |mnt| and |node| are non-NULL.
+ KernelHandle(Mount* mnt, MountNode* node);
- off_t Seek(off_t offset, int whence);
+ 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_;
- int mode_;
size_t offs_;
private:
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 b1bcf90d7c..c4b658dfd4 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
@@ -8,7 +8,7 @@
#include <ppapi/c/ppb.h>
#include <ppapi/c/pp_instance.h>
#include "nacl_io/ostypes.h"
-#include "utils/macros.h"
+#include "sdk_util/macros.h"
EXTERN_C_BEGIN
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 5c265309cc..6be3c9779b 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,7 @@
#include "nacl_io/kernel_handle.h"
#include "nacl_io/mount.h"
#include "nacl_io/mount_node.h"
-#include "utils/auto_lock.h"
+#include "sdk_util/auto_lock.h"
KernelObject::KernelObject() {
pthread_mutex_init(&kernel_lock_, NULL);
@@ -31,8 +31,12 @@ KernelObject::~KernelObject() {
// Uses longest prefix to find the mount for the give path, then
// acquires the mount and returns it with a relative path.
-Mount* KernelObject::AcquireMountAndPath(const std::string& relpath,
- Path* out_path) {
+Error KernelObject::AcquireMountAndPath(const std::string& relpath,
+ Mount** out_mount,
+ Path* out_path) {
+ *out_mount = NULL;
+ *out_path = Path();
+
Path abs_path;
{
AutoLock lock(&process_lock_);
@@ -42,7 +46,6 @@ Mount* KernelObject::AcquireMountAndPath(const std::string& relpath,
AutoLock lock(&kernel_lock_);
Mount* mount = NULL;
-
// Find longest prefix
size_t max = abs_path.Size();
for (size_t len = 0; len < abs_path.Size(); len++) {
@@ -55,14 +58,13 @@ Mount* KernelObject::AcquireMountAndPath(const std::string& relpath,
}
}
- if (NULL == mount) {
- errno = ENOTDIR;
- return NULL;
- }
+ if (NULL == mount)
+ return ENOTDIR;
// Acquire the mount while we hold the proxy lock
mount->Acquire();
- return mount;
+ *out_mount = mount;
+ return 0;
}
void KernelObject::ReleaseMount(Mount* mnt) {
@@ -70,43 +72,38 @@ void KernelObject::ReleaseMount(Mount* mnt) {
mnt->Release();
}
-KernelHandle* KernelObject::AcquireHandle(int fd) {
+Error KernelObject::AcquireHandle(int fd, KernelHandle** out_handle) {
+ *out_handle = NULL;
+
AutoLock lock(&process_lock_);
- if (fd < 0 || fd >= static_cast<int>(handle_map_.size())) {
- errno = EBADF;
- return NULL;
- }
+ if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
+ return EBADF;
KernelHandle* handle = handle_map_[fd];
- if (NULL == handle) {
- errno = EBADF;
- return NULL;
- }
+ if (NULL == handle)
+ return EBADF;
// Ref count while holding parent mutex
handle->Acquire();
lock.Unlock();
- if (handle->node_) handle->mount_->AcquireNode(handle->node_);
+ if (handle->node_)
+ handle->mount_->AcquireNode(handle->node_);
- return handle;
+ *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_);
+ if (handle->node_)
+ handle->mount_->ReleaseNode(handle->node_);
AutoLock lock(&process_lock_);
handle->Release();
}
-// Helper function to properly sort FD order in the heap, forcing
-// lower numbered FD to be available first.
-static bool FdOrder(int i, int j) {
- return i > j;
-}
-
int KernelObject::AllocateFD(KernelHandle* handle) {
AutoLock lock(&process_lock_);
int id;
@@ -119,7 +116,8 @@ int KernelObject::AllocateFD(KernelHandle* handle) {
// If we can recycle and FD, use that first
if (free_fds_.size()) {
id = free_fds_.front();
- std::pop_heap(free_fds_.begin(), free_fds_.end(), FdOrder);
+ // Force lower numbered FD to be available first.
+ std::pop_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
free_fds_.pop_back();
handle_map_[id] = handle;
} else {
@@ -166,7 +164,8 @@ void KernelObject::FreeFD(int fd) {
handle_map_[fd] = NULL;
free_fds_.push_back(fd);
- std::push_heap(free_fds_.begin(), free_fds_.end(), FdOrder);
+ // Force lower numbered FD to be available first.
+ std::push_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
}
Path KernelObject::GetAbsPathLocked(const std::string& 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 97b197f805..eb4c8ac041 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
+#include "nacl_io/error.h"
#include "nacl_io/path.h"
class KernelHandle;
@@ -28,17 +29,25 @@ class KernelObject {
KernelObject();
virtual ~KernelObject();
- // Find the mount for the given path, and acquires it
- Mount* AcquireMountAndPath(const std::string& relpath, Path *pobj);
+ // 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,
+ Path* out_path);
+ // Assumes |mnt| is non-NULL.
void ReleaseMount(Mount* mnt);
// Convert from FD to KernelHandle, and acquire the handle.
- KernelHandle* AcquireHandle(int fd);
+ // Assumes |out_handle| is non-NULL.
+ Error AcquireHandle(int fd, KernelHandle** out_handle);
+ // Assumes |handle| is non-NULL.
void ReleaseHandle(KernelHandle* 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);
+ // Assumes |handle| is non-NULL;
void FreeAndReassignFD(int fd, KernelHandle* handle);
void FreeFD(int fd);
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 6d996d3ae2..2f49395ee0 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -25,8 +25,8 @@
#include "nacl_io/osstat.h"
#include "nacl_io/path.h"
#include "nacl_io/pepper_interface.h"
-#include "utils/auto_lock.h"
-#include "utils/ref_object.h"
+#include "sdk_util/auto_lock.h"
+#include "sdk_util/ref_object.h"
#ifndef MAXPATHLEN
#define MAXPATHLEN 256
@@ -36,16 +36,9 @@
#define USR_ID 1002
#define GRP_ID 1003
+KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL) {}
-
-KernelProxy::KernelProxy()
- : dev_(0),
- ppapi_(NULL) {
-}
-
-KernelProxy::~KernelProxy() {
- delete ppapi_;
-}
+KernelProxy::~KernelProxy() { delete ppapi_; }
void KernelProxy::Init(PepperInterface* ppapi) {
ppapi_ = ppapi;
@@ -58,11 +51,12 @@ void KernelProxy::Init(PepperInterface* ppapi) {
factories_["httpfs"] = MountHttp::Create<MountHttp>;
factories_["passthroughfs"] = MountPassthrough::Create<MountPassthrough>;
- // Create passthrough mount at root
- StringMap_t smap;
- mounts_["/"] = MountPassthrough::Create<MountPassthrough>(
- dev_++, smap, ppapi_);
- mounts_["/dev"] = MountDev::Create<MountDev>(dev_++, smap, ppapi_);
+ int result;
+ result = mount("", "/", "passthroughfs", 0, NULL);
+ assert(result == 0);
+
+ result = mount("", "/dev", "dev", 0, NULL);
+ assert(result == 0);
// Open the first three in order to get STDIN, STDOUT, STDERR
open("/dev/stdin", O_RDONLY);
@@ -70,19 +64,32 @@ void KernelProxy::Init(PepperInterface* ppapi) {
open("/dev/stderr", O_WRONLY);
}
-int KernelProxy::open(const char *path, int oflags) {
+int KernelProxy::open(const char* path, int oflags) {
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Mount* mnt;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- MountNode* node = mnt->Open(rel, oflags);
- if (node == NULL) {
+ MountNode* node = NULL;
+ error = mnt->Open(rel, oflags, &node);
+ if (error) {
+ errno = error;
+ ReleaseMount(mnt);
+ return -1;
+ }
+
+ KernelHandle* handle = new KernelHandle(mnt, node);
+ error = handle->Init(oflags);
+ if (error) {
+ errno = error;
ReleaseMount(mnt);
return -1;
}
- KernelHandle* handle = new KernelHandle(mnt, node, oflags);
int fd = AllocateFD(handle);
mnt->AcquireNode(node);
@@ -93,9 +100,12 @@ int KernelProxy::open(const char *path, int oflags) {
}
int KernelProxy::close(int fd) {
- KernelHandle* handle = AcquireHandle(fd);
-
- if (NULL == handle) return -1;
+ KernelHandle* 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.
@@ -115,8 +125,12 @@ int KernelProxy::close(int fd) {
}
int KernelProxy::dup(int oldfd) {
- KernelHandle* handle = AcquireHandle(oldfd);
- if (NULL == handle) return -1;
+ KernelHandle* handle;
+ Error error = AcquireHandle(oldfd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
int newfd = AllocateFD(handle);
ReleaseHandle(handle);
@@ -126,17 +140,21 @@ int KernelProxy::dup(int oldfd) {
int KernelProxy::dup2(int oldfd, int newfd) {
// If it's the same file handle, just return
- if (oldfd == newfd) return newfd;
+ if (oldfd == newfd)
+ return newfd;
- KernelHandle* old_handle = AcquireHandle(oldfd);
- if (NULL == old_handle) return -1;
+ KernelHandle* old_handle;
+ Error error = AcquireHandle(oldfd, &old_handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
FreeAndReassignFD(newfd, old_handle);
ReleaseHandle(old_handle);
return newfd;
}
-
char* KernelProxy::getcwd(char* buf, size_t size) {
AutoLock lock(&process_lock_);
if (size <= 0) {
@@ -171,42 +189,64 @@ char* KernelProxy::getwd(char* buf) {
return getcwd(buf, MAXPATHLEN);
}
-int KernelProxy::chmod(const char *path, mode_t mode) {
+int KernelProxy::chmod(const char* path, mode_t mode) {
int fd = KernelProxy::open(path, O_RDWR);
- if (-1 == fd) return -1;
+ if (-1 == fd)
+ return -1;
- int ret = fchmod(fd, mode);
+ int result = fchmod(fd, mode);
close(fd);
- return ret;
+ return result;
}
-int KernelProxy::mkdir(const char *path, mode_t mode) {
+int KernelProxy::mkdir(const char* path, mode_t mode) {
+ Mount* mnt;
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ int result = 0;
+ error = mnt->Mkdir(rel, mode);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int val = mnt->Mkdir(rel, mode);
ReleaseMount(mnt);
- return val;
+ return result;
}
-int KernelProxy::rmdir(const char *path) {
+int KernelProxy::rmdir(const char* path) {
+ Mount* mnt;
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ int result = 0;
+ error = mnt->Rmdir(rel);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int val = mnt->Rmdir(rel);
ReleaseMount(mnt);
- return val;
+ return result;
}
-int KernelProxy::stat(const char *path, struct stat *buf) {
+int KernelProxy::stat(const char* path, struct stat* buf) {
int fd = open(path, O_RDONLY);
- if (-1 == fd) return -1;
+ if (-1 == fd)
+ return -1;
- int ret = fstat(fd, buf);
+ int result = fstat(fd, buf);
close(fd);
- return ret;
+ return result;
}
int KernelProxy::chdir(const char* path) {
@@ -215,19 +255,21 @@ int KernelProxy::chdir(const char* path) {
return -1;
bool is_dir = (statbuf.st_mode & S_IFDIR) != 0;
- if (is_dir) {
- AutoLock lock(&process_lock_);
- cwd_ = GetAbsPathLocked(path).Join();
- return 0;
+ if (!is_dir) {
+ errno = ENOTDIR;
+ return -1;
}
- errno = ENOTDIR;
- return -1;
+ AutoLock lock(&process_lock_);
+ cwd_ = GetAbsPathLocked(path).Join();
+ return 0;
}
-int KernelProxy::mount(const char *source, const char *target,
- const char *filesystemtype, unsigned long mountflags,
- const void *data) {
+int KernelProxy::mount(const char* source,
+ const char* target,
+ const char* filesystemtype,
+ unsigned long mountflags,
+ const void* data) {
// See if it's already mounted
std::string abs_targ;
@@ -255,8 +297,8 @@ int KernelProxy::mount(const char *source, const char *target,
smap["TARGET"] = abs_targ;
if (data) {
- char* str = strdup(static_cast<const char *>(data));
- char* ptr = strtok(str,",");
+ char* str = strdup(static_cast<const char*>(data));
+ char* ptr = strtok(str, ",");
char* val;
while (ptr != NULL) {
val = strchr(ptr, '=');
@@ -271,16 +313,18 @@ int KernelProxy::mount(const char *source, const char *target,
free(str);
}
- Mount* mnt = factory->second(dev_++, smap, ppapi_);
- if (mnt) {
- mounts_[abs_targ] = mnt;
- return 0;
+ Mount* mnt = NULL;
+ Error error = factory->second(dev_++, smap, ppapi_, &mnt);
+ if (error) {
+ errno = error;
+ return -1;
}
- errno = EINVAL;
- return -1;
+
+ mounts_[abs_targ] = mnt;
+ return 0;
}
-int KernelProxy::umount(const char *path) {
+int KernelProxy::umount(const char* path) {
Path abs_path;
// Scope this lock to prevent holding both process and kernel locks
@@ -307,125 +351,204 @@ int KernelProxy::umount(const char *path) {
return 0;
}
-ssize_t KernelProxy::read(int fd, void *buf, size_t nbytes) {
- KernelHandle* handle = AcquireHandle(fd);
-
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ssize_t KernelProxy::read(int fd, void* buf, size_t nbytes) {
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
AutoLock lock(&handle->lock_);
- ssize_t cnt = handle->node_->Read(handle->offs_, buf, nbytes);
- if (cnt > 0) handle->offs_ += cnt;
+ int cnt = 0;
+ error = handle->node_->Read(handle->offs_, buf, nbytes, &cnt);
+ if (error)
+ errno = error;
+
+ if (cnt > 0)
+ handle->offs_ += cnt;
ReleaseHandle(handle);
return cnt;
}
-ssize_t KernelProxy::write(int fd, const void *buf, size_t nbytes) {
- KernelHandle* handle = AcquireHandle(fd);
-
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ssize_t KernelProxy::write(int fd, const void* buf, size_t nbytes) {
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
AutoLock lock(&handle->lock_);
- ssize_t cnt = handle->node_->Write(handle->offs_, buf, nbytes);
- if (cnt > 0) handle->offs_ += cnt;
+ int cnt = 0;
+ error = handle->node_->Write(handle->offs_, buf, nbytes, &cnt);
+ if (error)
+ errno = error;
+
+ if (cnt > 0)
+ handle->offs_ += cnt;
ReleaseHandle(handle);
return cnt;
}
int KernelProxy::fstat(int fd, struct stat* buf) {
- KernelHandle* handle = AcquireHandle(fd);
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ int result = 0;
+ error = handle->node_->GetStat(buf);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int ret = handle->node_->GetStat(buf);
ReleaseHandle(handle);
- return ret;
+ return result;
}
int KernelProxy::getdents(int fd, void* buf, unsigned int count) {
- KernelHandle* handle = AcquireHandle(fd);
-
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
AutoLock lock(&handle->lock_);
- int cnt = handle->node_->GetDents(handle->offs_,
- static_cast<dirent *>(buf), count);
+ int cnt = 0;
+ error = handle->node_
+ ->GetDents(handle->offs_, static_cast<dirent*>(buf), count, &cnt);
+ if (error)
+ errno = error;
- if (cnt > 0) handle->offs_ += cnt;
+ if (cnt > 0)
+ handle->offs_ += cnt;
ReleaseHandle(handle);
return cnt;
}
int KernelProxy::ftruncate(int fd, off_t length) {
- KernelHandle* handle = AcquireHandle(fd);
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
- int ret = handle->node_->FTruncate(length);
+ int result = 0;
+ error = handle->node_->FTruncate(length);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
ReleaseHandle(handle);
- return ret;
+ return result;
}
int KernelProxy::fsync(int fd) {
- KernelHandle* handle = AcquireHandle(fd);
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
- int ret = handle->node_->FSync();
+ int result = 0;
+ error = handle->node_->FSync();
+ if (error) {
+ errno = error;
+ result = -1;
+ }
ReleaseHandle(handle);
- return ret;
+ return result;
}
int KernelProxy::isatty(int fd) {
- KernelHandle* handle = AcquireHandle(fd);
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
- int ret = handle->node_->IsaTTY();
+ int result = 0;
+ error = handle->node_->IsaTTY();
+ if (error) {
+ errno = error;
+ result = -1;
+ }
ReleaseHandle(handle);
- return ret;
+ return result;
}
off_t KernelProxy::lseek(int fd, off_t offset, int whence) {
- KernelHandle* handle = AcquireHandle(fd);
-
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
AutoLock lock(&handle->lock_);
- int ret = handle->Seek(offset, whence);
+ off_t new_offset;
+ error = handle->Seek(offset, whence, &new_offset);
+ if (error) {
+ errno = error;
+ new_offset = -1;
+ }
ReleaseHandle(handle);
- return ret;
+ return new_offset;
}
int KernelProxy::unlink(const char* path) {
+ Mount* mnt;
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ int result = 0;
+ error = mnt->Unlink(rel);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int val = mnt->Unlink(rel);
ReleaseMount(mnt);
- return val;
+ return result;
}
int KernelProxy::remove(const char* path) {
+ Mount* mnt;
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ int result = 0;
+ error = mnt->Remove(rel);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int val = mnt->Remove(rel);
ReleaseMount(mnt);
- return val;
+ return result;
}
// TODO(noelallen): Needs implementation.
@@ -449,22 +572,29 @@ int KernelProxy::symlink(const char* oldpath, const char* newpath) {
return -1;
}
-void* KernelProxy::mmap(void* addr, size_t length, int prot, int flags, int fd,
+void* KernelProxy::mmap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ int fd,
size_t offset) {
// We shouldn't be getting anonymous mmaps here.
assert((flags & MAP_ANONYMOUS) == 0);
assert(fd != -1);
- KernelHandle* handle = AcquireHandle(fd);
-
- if (NULL == handle)
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
return MAP_FAILED;
+ }
void* new_addr;
{
AutoLock lock(&handle->lock_);
- new_addr = handle->node_->MMap(addr, length, prot, flags, offset);
- if (new_addr == MAP_FAILED) {
+ error = handle->node_->MMap(addr, length, prot, flags, offset, &new_addr);
+ if (error) {
+ errno = error;
ReleaseHandle(handle);
return MAP_FAILED;
}
@@ -510,23 +640,34 @@ int KernelProxy::munmap(void* addr, size_t length) {
}
int KernelProxy::open_resource(const char* path) {
+ Mount* mnt;
Path rel;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
-
- MountNode* node = mnt->OpenResource(rel);
- if (node == NULL) {
- node = mnt->Open(rel, O_RDONLY);
- if (node == NULL) {
+ MountNode* node = NULL;
+ 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;
}
}
- // OpenResource failed, try Open().
+ KernelHandle* handle = new KernelHandle(mnt, node);
+ error = handle->Init(O_RDONLY);
+ if (error) {
+ errno = error;
+ ReleaseMount(mnt);
+ return -1;
+ }
- KernelHandle* handle = new KernelHandle(mnt, node, O_RDONLY);
int fd = AllocateFD(handle);
mnt->AcquireNode(node);
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 6c7b6b31e9..e8c251a32a 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
@@ -24,9 +24,12 @@ class PepperInterface;
// KernelProxy provide one-to-one mapping for libc kernel calls. Calls to the
// proxy will result in IO access to the provided Mount and MountNode objects.
+//
+// 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).
class KernelProxy : protected KernelObject {
public:
- typedef Mount* (*MountFactory_t)(int, StringMap_t&, PepperInterface*);
+ 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;
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 87dca82eea..322fe72154 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
@@ -7,7 +7,7 @@
#include <sys/types.h>
#include <stdlib.h>
-#include "utils/macros.h"
+#include "sdk_util/macros.h"
#if defined(__GLIBC__)
#include <sys/cdefs.h>
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_real.h b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_real.h
index 7d7dd418c0..c4ff5e0e94 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_real.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_real.h
@@ -6,7 +6,7 @@
#define LIBRARIES_NACL_IO_KERNEL_WRAP_REAL_H_
#include "nacl_io/ostypes.h"
-#include "utils/macros.h"
+#include "sdk_util/macros.h"
EXTERN_C_BEGIN
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 2954618a57..81d621cfa2 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -2,8 +2,7 @@
'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'],
'SEARCH': [
'.',
- 'pepper',
- '../utils'
+ 'pepper'
],
'TARGETS': [
{
@@ -25,6 +24,7 @@
"mount_node.cc",
"mount_node_dir.cc",
"mount_node_html5fs.cc",
+ "mount_node_http.cc",
"mount_node_mem.cc",
"mount_passthrough.cc",
"nacl_io.cc",
@@ -37,6 +37,7 @@
'HEADERS': [
{
'FILES': [
+ "error.h",
"inode_pool.h",
"kernel_handle.h",
"kernel_intercept.h",
@@ -52,6 +53,7 @@
"mount_node_dir.h",
"mount_node.h",
"mount_node_html5fs.h",
+ "mount_node_http.h",
"mount_node_mem.h",
"mount_passthrough.h",
"nacl_io.h",
@@ -73,14 +75,6 @@
"undef_macros.h",
],
'DEST': 'include/nacl_io/pepper',
- },
- {
- 'FILES': [
- "auto_lock.h",
- "macros.h",
- "ref_object.h"
- ],
- 'DEST': 'include/utils',
}
],
'DEST': 'src',
diff --git a/native_client_sdk/src/libraries/nacl_io/mount.cc b/native_client_sdk/src/libraries/nacl_io/mount.cc
index 8b583db6fa..76fe3a7848 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount.cc
@@ -13,23 +13,21 @@
#include "nacl_io/mount_node_mem.h"
#include "nacl_io/osstat.h"
#include "nacl_io/path.h"
-#include "utils/auto_lock.h"
-#include "utils/ref_object.h"
+#include "sdk_util/auto_lock.h"
+#include "sdk_util/ref_object.h"
#if defined(WIN32)
#include <windows.h>
#endif
-Mount::Mount()
- : dev_(0) {
-}
+Mount::Mount() : dev_(0) {}
Mount::~Mount() {}
-bool Mount::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+Error Mount::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
dev_ = dev;
ppapi_ = ppapi;
- return true;
+ return 0;
}
void Mount::Destroy() {}
@@ -44,22 +42,30 @@ void Mount::ReleaseNode(MountNode* node) {
node->Release();
}
+Error Mount::OpenResource(const Path& path, MountNode** out_node) {
+ *out_node = NULL;
+ return EINVAL;
+}
+
int Mount::OpenModeToPermission(int mode) {
int out;
switch (mode & 3) {
- case O_RDONLY: out = S_IREAD;
- case O_WRONLY: out = S_IWRITE;
- case O_RDWR: out = S_IREAD | S_IWRITE;
+ case O_RDONLY:
+ out = S_IREAD;
+ case O_WRONLY:
+ out = S_IWRITE;
+ case O_RDWR:
+ out = S_IREAD | S_IWRITE;
}
return out;
}
-
void Mount::OnNodeCreated(MountNode* node) {
node->stat_.st_ino = inode_pool_.Acquire();
node->stat_.st_dev = dev_;
}
void Mount::OnNodeDestroyed(MountNode* node) {
- if (node->stat_.st_ino) inode_pool_.Release(node->stat_.st_ino);
-} \ No newline at end of file
+ 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 622dae0207..ddf1fd5c76 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount.h
@@ -8,18 +8,20 @@
#include <map>
#include <string>
+#include "nacl_io/error.h"
#include "nacl_io/inode_pool.h"
#include "nacl_io/mount_node.h"
#include "nacl_io/path.h"
-#include "utils/macros.h"
-#include "utils/ref_object.h"
+#include "sdk_util/macros.h"
+#include "sdk_util/ref_object.h"
class MountNode;
class PepperInterface;
typedef std::map<std::string, std::string> StringMap_t;
-
+// 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).
class Mount : public RefObject {
protected:
// The protected functions are only used internally and will not
@@ -30,38 +32,49 @@ class Mount : public RefObject {
// Init must be called by the factory before the mount is used.
// This function must assign a root node, or replace FindNode.
// |ppapi| can be NULL. If so, this mount cannot make any pepper calls.
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
public:
template <class M>
- static Mount* Create(int dev, StringMap_t& args, PepperInterface* ppapi);
+ // Assumes that |out_mount| is non-NULL.
+ static Error Create(int dev,
+ StringMap_t& args,
+ PepperInterface* ppapi,
+ Mount** out_mount);
PepperInterface* ppapi() { return ppapi_; }
- // All paths are expected to containing a leading "/"
+ // 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 "/".
+
// Open a node at |path| with the specified open flags. The resulting
// MountNode is created with a ref count of 1.
- virtual MountNode *Open(const Path& path, int o_flags) = 0;
+ // Assumes that |out_node| is non-NULL.
+ virtual Error Open(const Path& path, int o_flags, MountNode** out_node) = 0;
// OpenResource is only used to read files from the NaCl NMF file. No mount
// except MountPassthrough should implement it.
- virtual MountNode *OpenResource(const Path& path) { return NULL; }
+ // Assumes that |out_node| is non-NULL.
+ virtual Error OpenResource(const Path& path, MountNode** out_node);
// Unlink, Mkdir, Rmdir will affect the both the RefCount
// and the nlink number in the stat object.
- virtual int Unlink(const Path& path) = 0;
- virtual int Mkdir(const Path& path, int permissions) = 0;
- virtual int Rmdir(const Path& path) = 0;
- virtual int Remove(const Path& path) = 0;
+ virtual Error Unlink(const Path& path) = 0;
+ virtual Error Mkdir(const Path& path, int permissions) = 0;
+ virtual Error Rmdir(const Path& path) = 0;
+ virtual Error Remove(const Path& path) = 0;
// Convert from R,W,R/W open flags to STAT permission flags
static int OpenModeToPermission(int mode);
- void OnNodeCreated(MountNode* node) ;
+ // Assumes that |node| is non-NULL.
+ void OnNodeCreated(MountNode* node);
+ // Assumes that |node| is non-NULL.
void OnNodeDestroyed(MountNode* node);
protected:
@@ -81,16 +94,22 @@ class Mount : public RefObject {
DISALLOW_COPY_AND_ASSIGN(Mount);
};
-
-template <class M>
/*static*/
-Mount* Mount::Create(int dev, StringMap_t& args, PepperInterface* ppapi) {
+template <class M>
+Error Mount::Create(int dev,
+ StringMap_t& args,
+ PepperInterface* ppapi,
+ Mount** out_mount) {
Mount* mnt = new M();
- if (mnt->Init(dev, args, ppapi) == false) {
+ Error error = mnt->Init(dev, args, ppapi);
+ if (error) {
delete mnt;
- return NULL;
+ *out_mount = NULL;
+ return error;
}
- return mnt;
+
+ *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 83d2e55423..11893ea09e 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
@@ -14,31 +14,26 @@
#include "nacl_io/mount_node.h"
#include "nacl_io/mount_node_dir.h"
#include "nacl_io/pepper_interface.h"
-#include "utils/auto_lock.h"
+#include "sdk_util/auto_lock.h"
#if defined(__native_client__)
-# include <irt.h>
+#include <irt.h>
#elif defined(WIN32)
-# include <stdlib.h>
+#include <stdlib.h>
#endif
-
namespace {
-void ReleaseAndNullNode(MountNode** node) {
- if (*node)
- (*node)->Release();
- *node = NULL;
-}
-
-
class RealNode : public MountNode {
public:
RealNode(Mount* mount, int fd);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
- virtual int GetStat(struct stat* stat);
+ 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);
+ virtual Error GetStat(struct stat* stat);
protected:
int fd_;
@@ -48,43 +43,56 @@ class NullNode : public MountNode {
public:
explicit NullNode(Mount* mount);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ 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);
};
class ConsoleNode : public NullNode {
public:
ConsoleNode(Mount* mount, PP_LogLevel level);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
-private:
+ private:
PP_LogLevel level_;
};
-
class TtyNode : public NullNode {
public:
explicit TtyNode(Mount* mount);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
};
-
class ZeroNode : public MountNode {
public:
explicit ZeroNode(Mount* mount);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ 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);
};
class UrandomNode : public MountNode {
public:
explicit UrandomNode(Mount* mount);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ 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:
#if defined(__native_client__)
@@ -93,132 +101,141 @@ class UrandomNode : public MountNode {
#endif
};
-RealNode::RealNode(Mount* mount, int fd)
- : MountNode(mount),
- fd_(fd) {
+RealNode::RealNode(Mount* mount, int fd) : MountNode(mount), fd_(fd) {
stat_.st_mode = S_IFCHR;
}
-int RealNode::Read(size_t offs, void* buf, size_t count) {
+Error RealNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+
size_t readcnt;
int err = _real_read(fd_, buf, count, &readcnt);
- if (err) {
- errno = err;
- return -1;
- }
- return static_cast<int>(readcnt);
+ if (err)
+ return err;
+
+ *out_bytes = static_cast<int>(readcnt);
+ return 0;
}
-int RealNode::Write(size_t offs, const void* buf, size_t count) {
+Error RealNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
size_t writecnt;
int err = _real_write(fd_, buf, count, &writecnt);
- if (err) {
- errno = err;
- return -1;
- }
- return static_cast<int>(writecnt);
-}
+ if (err)
+ return err;
-int RealNode::GetStat(struct stat* stat) {
- int err = _real_fstat(fd_, stat);
- if (err) {
- errno = err;
- return -1;
- }
+ *out_bytes = static_cast<int>(writecnt);
return 0;
}
-NullNode::NullNode(Mount* mount)
- : MountNode(mount) {
- stat_.st_mode = S_IFCHR;
-}
+Error RealNode::GetStat(struct stat* stat) { return _real_fstat(fd_, stat); }
-int NullNode::Read(size_t offs, void* buf, size_t count) {
+NullNode::NullNode(Mount* mount) : MountNode(mount) { stat_.st_mode = S_IFCHR; }
+
+Error NullNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
return 0;
}
-int NullNode::Write(size_t offs, const void* buf, size_t count) {
- return count;
+Error NullNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = count;
+ return 0;
}
ConsoleNode::ConsoleNode(Mount* mount, PP_LogLevel level)
- : NullNode(mount),
- level_(level) {
+ : NullNode(mount), level_(level) {
stat_.st_mode = S_IFCHR;
}
-int ConsoleNode::Write(size_t offs, const void* buf, size_t count) {
+Error ConsoleNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
ConsoleInterface* con_intr = mount_->ppapi()->GetConsoleInterface();
VarInterface* var_intr = mount_->ppapi()->GetVarInterface();
- if (var_intr && con_intr) {
- 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);
- con_intr->Log(mount_->ppapi()->GetInstance(), level_, val);
- return count;
- }
+ if (!(var_intr && con_intr))
+ return ENOSYS;
+
+ 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);
+ con_intr->Log(mount_->ppapi()->GetInstance(), level_, val);
+
+ *out_bytes = count;
return 0;
}
+TtyNode::TtyNode(Mount* mount) : NullNode(mount) {}
-TtyNode::TtyNode(Mount* mount)
- : NullNode(mount) {
-}
+Error TtyNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
-int TtyNode::Write(size_t offs, const void* buf, size_t count) {
MessagingInterface* msg_intr = mount_->ppapi()->GetMessagingInterface();
VarInterface* var_intr = mount_->ppapi()->GetVarInterface();
- if (var_intr && msg_intr) {
- 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);
- msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val);
- return count;
- }
- return 0;
-}
+ if (!(var_intr && msg_intr))
+ return ENOSYS;
+ 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);
+ msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val);
-ZeroNode::ZeroNode(Mount* mount)
- : MountNode(mount) {
- stat_.st_mode = S_IFCHR;
+ *out_bytes = count;
+ return 0;
}
-int ZeroNode::Read(size_t offs, void* buf, size_t count) {
+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) {
memset(buf, 0, count);
- return count;
+ *out_bytes = count;
+ return 0;
}
-int ZeroNode::Write(size_t offs, const void* buf, size_t count) {
- return count;
+Error ZeroNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = count;
+ return 0;
}
-UrandomNode::UrandomNode(Mount* mount)
- : MountNode(mount) {
+UrandomNode::UrandomNode(Mount* mount) : MountNode(mount) {
stat_.st_mode = S_IFCHR;
#if defined(__native_client__)
- size_t result = nacl_interface_query(NACL_IRT_RANDOM_v0_1, &random_interface_,
- sizeof(random_interface_));
+ size_t result = nacl_interface_query(
+ NACL_IRT_RANDOM_v0_1, &random_interface_, sizeof(random_interface_));
interface_ok_ = result != 0;
#endif
}
-int UrandomNode::Read(size_t offs, void* buf, size_t count) {
+Error UrandomNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+
#if defined(__native_client__)
- if (interface_ok_) {
- size_t nread;
- int result = (*random_interface_.get_random_bytes)(buf, count, &nread);
- if (result != 0) {
- errno = result;
- return 0;
- }
+ if (!interface_ok_)
+ return EBADF;
- return count;
- }
+ size_t nread;
+ int error = (*random_interface_.get_random_bytes)(buf, count, &nread);
+ if (error)
+ return error;
- errno = EBADF;
+ *out_bytes = count;
return 0;
#elif defined(WIN32)
char* out = static_cast<char*>(buf);
@@ -227,8 +244,8 @@ int UrandomNode::Read(size_t offs, void* buf, size_t count) {
unsigned int random_int;
errno_t err = rand_s(&random_int);
if (err) {
- errno = err;
- return count - bytes_left;
+ *out_bytes = count - bytes_left;
+ return err;
}
int bytes_to_copy = std::min(bytes_left, sizeof(random_int));
@@ -237,107 +254,84 @@ int UrandomNode::Read(size_t offs, void* buf, size_t count) {
bytes_left -= bytes_to_copy;
}
- return count;
+ *out_bytes = count;
+ return 0;
#endif
}
-int UrandomNode::Write(size_t offs, const void* buf, size_t count) {
- return count;
+Error UrandomNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = count;
+ return 0;
}
-
-
} // namespace
-MountNode *MountDev::Open(const Path& path, int mode) {
+Error MountDev::Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = NULL;
+
AutoLock lock(&lock_);
// Don't allow creating any files.
if (mode & O_CREAT)
- return NULL;
+ return EINVAL;
- MountNode* node = root_->FindChild(path.Join());
- if (node)
- node->Acquire();
- return node;
-}
+ MountNode* node = NULL;
+ int error = root_->FindChild(path.Join(), &node);
+ if (error)
+ return error;
-int MountDev::Unlink(const Path& path) {
- errno = EINVAL;
- return -1;
+ node->Acquire();
+ *out_node = node;
+ return 0;
}
-int MountDev::Mkdir(const Path& path, int permissions) {
- errno = EINVAL;
- return -1;
-}
+Error MountDev::Unlink(const Path& path) { return EINVAL; }
-int MountDev::Rmdir(const Path& path) {
- errno = EINVAL;
- return -1;
-}
+Error MountDev::Mkdir(const Path& path, int permissions) { return EINVAL; }
-int MountDev::Remove(const Path& path) {
- errno = EINVAL;
- return -1;
-}
+Error MountDev::Rmdir(const Path& path) { return EINVAL; }
-MountDev::MountDev()
- : null_node_(NULL),
- zero_node_(NULL),
- random_node_(NULL),
- console0_node_(NULL),
- console1_node_(NULL),
- console2_node_(NULL),
- console3_node_(NULL),
- tty_node_(NULL) {
-}
+Error MountDev::Remove(const Path& path) { return EINVAL; }
-bool MountDev::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
- if (!Mount::Init(dev, args, ppapi))
- return false;
+MountDev::MountDev() {}
+
+#define INITIALIZE_DEV_NODE(path, klass) \
+ error = root_->AddChild(path, 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) \
+ return error;
+
+Error MountDev::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+ Error error = Mount::Init(dev, args, ppapi);
+ if (error)
+ return error;
root_ = new MountNodeDir(this);
- null_node_ = new NullNode(this);
- root_->AddChild("/null", null_node_);
- zero_node_ = new ZeroNode(this);
- root_->AddChild("/zero", zero_node_);
- random_node_ = new UrandomNode(this);
- root_->AddChild("/urandom", random_node_);
-
- console0_node_ = new ConsoleNode(this, PP_LOGLEVEL_TIP);
- root_->AddChild("/console0", console0_node_);
- console1_node_ = new ConsoleNode(this, PP_LOGLEVEL_LOG);
- root_->AddChild("/console1", console1_node_);
- console2_node_ = new ConsoleNode(this, PP_LOGLEVEL_WARNING);
- root_->AddChild("/console2", console2_node_);
- console3_node_ = new ConsoleNode(this, PP_LOGLEVEL_ERROR);
- root_->AddChild("/console3", console3_node_);
-
- tty_node_ = new TtyNode(this);
- root_->AddChild("/tty", tty_node_);
-
- stdin_node_ = new RealNode(this, 0);
- root_->AddChild("/stdin", stdin_node_);
- stdout_node_ = new RealNode(this, 1);
- root_->AddChild("/stdout", stdout_node_);
- stderr_node_ = new RealNode(this, 2);
- root_->AddChild("/stderr", stderr_node_);
-
- return true;
+
+ INITIALIZE_DEV_NODE("/null", NullNode);
+ INITIALIZE_DEV_NODE("/zero", ZeroNode);
+ INITIALIZE_DEV_NODE("/urandom", UrandomNode);
+ INITIALIZE_DEV_NODE_1("/console0", ConsoleNode, PP_LOGLEVEL_TIP);
+ INITIALIZE_DEV_NODE_1("/console1", ConsoleNode, PP_LOGLEVEL_LOG);
+ INITIALIZE_DEV_NODE_1("/console2", ConsoleNode, PP_LOGLEVEL_WARNING);
+ INITIALIZE_DEV_NODE_1("/console3", ConsoleNode, PP_LOGLEVEL_ERROR);
+ INITIALIZE_DEV_NODE("/tty", TtyNode);
+ INITIALIZE_DEV_NODE_1("/stdin", RealNode, 0);
+ INITIALIZE_DEV_NODE_1("/stdout", RealNode, 1);
+ INITIALIZE_DEV_NODE_1("/stderr", RealNode, 2);
+
+ return 0;
}
void MountDev::Destroy() {
- ReleaseAndNullNode(&stdin_node_);
- ReleaseAndNullNode(&stdout_node_);
- ReleaseAndNullNode(&stderr_node_);
- ReleaseAndNullNode(&tty_node_);
- ReleaseAndNullNode(&console3_node_);
- ReleaseAndNullNode(&console2_node_);
- ReleaseAndNullNode(&console1_node_);
- ReleaseAndNullNode(&console0_node_);
- ReleaseAndNullNode(&random_node_);
- ReleaseAndNullNode(&zero_node_);
- ReleaseAndNullNode(&null_node_);
- ReleaseAndNullNode(&root_);
+ 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 ff3d99c124..7ad7daa3b9 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_dev.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.h
@@ -11,32 +11,21 @@ class MountNode;
class MountDev : public Mount {
public:
- virtual MountNode *Open(const Path& path, int mode);
+ virtual Error Open(const Path& path, int mode, MountNode** out_node);
- virtual int Unlink(const Path& path);
- virtual int Mkdir(const Path& path, int permissions);
- virtual int Rmdir(const Path& path);
- virtual int Remove(const Path& path);
+ virtual Error Unlink(const Path& path);
+ virtual Error Mkdir(const Path& path, int permissions);
+ virtual Error Rmdir(const Path& path);
+ virtual Error Remove(const Path& path);
protected:
MountDev();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
private:
MountNode* root_;
- MountNode* null_node_;
- MountNode* zero_node_;
- MountNode* random_node_;
- MountNode* console0_node_;
- MountNode* console1_node_;
- MountNode* console2_node_;
- MountNode* console3_node_;
- MountNode* tty_node_;
- MountNode* stderr_node_;
- MountNode* stdin_node_;
- MountNode* stdout_node_;
friend class Mount;
};
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 9b995359ae..0008284253 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
@@ -12,7 +12,7 @@
#include <string.h>
#include <algorithm>
#include "nacl_io/mount_node_html5fs.h"
-#include "utils/auto_lock.h"
+#include "sdk_util/auto_lock.h"
namespace {
@@ -24,96 +24,85 @@ int64_t strtoull(const char* nptr, char** endptr, int base) {
} // namespace
-MountNode *MountHtml5Fs::Open(const Path& path, int mode) {
- if (BlockUntilFilesystemOpen() != PP_OK) {
- errno = ENODEV;
- return NULL;
- }
+Error MountHtml5Fs::Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = NULL;
+
+ Error error = BlockUntilFilesystemOpen();
+ if (error)
+ return error;
- PP_Resource fileref = ppapi()->GetFileRefInterface()->Create(
- filesystem_resource_, path.Join().c_str());
+ PP_Resource fileref = ppapi()->GetFileRefInterface()
+ ->Create(filesystem_resource_, path.Join().c_str());
if (!fileref)
- return NULL;
+ return ENOSYS;
MountNodeHtml5Fs* node = new MountNodeHtml5Fs(this, fileref);
- if (!node->Init(mode)) {
+ error = node->Init(mode);
+ if (error) {
node->Release();
- return NULL;
+ return error;
}
- return node;
+ *out_node = node;
+ return 0;
}
-int MountHtml5Fs::Unlink(const Path& path) {
- return Remove(path);
-}
+Error MountHtml5Fs::Unlink(const Path& path) { return Remove(path); }
-int MountHtml5Fs::Mkdir(const Path& path, int permissions) {
- if (BlockUntilFilesystemOpen() != PP_OK) {
- errno = ENODEV;
- return -1;
- }
+Error MountHtml5Fs::Mkdir(const Path& path, int permissions) {
+ Error error = BlockUntilFilesystemOpen();
+ if (error)
+ return error;
ScopedResource fileref_resource(
- ppapi(), ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
- path.Join().c_str()));
- if (!fileref_resource.pp_resource()) {
- errno = EINVAL;
- return -1;
- }
+ ppapi(),
+ ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
+ path.Join().c_str()));
+ if (!fileref_resource.pp_resource())
+ return EIO;
int32_t result = ppapi()->GetFileRefInterface()->MakeDirectory(
fileref_resource.pp_resource(), PP_FALSE, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
return 0;
}
-int MountHtml5Fs::Rmdir(const Path& path) {
- return Remove(path);
-}
+Error MountHtml5Fs::Rmdir(const Path& path) { return Remove(path); }
-int MountHtml5Fs::Remove(const Path& path) {
- if (BlockUntilFilesystemOpen() != PP_OK) {
- errno = ENODEV;
- return -1;
- }
+Error MountHtml5Fs::Remove(const Path& path) {
+ Error error = BlockUntilFilesystemOpen();
+ if (error)
+ return error;
ScopedResource fileref_resource(
- ppapi(), ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
- path.Join().c_str()));
- if (!fileref_resource.pp_resource()) {
- errno = EINVAL;
- return -1;
- }
+ ppapi(),
+ ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
+ path.Join().c_str()));
+ if (!fileref_resource.pp_resource())
+ return ENOSYS;
- int32_t result = ppapi()->GetFileRefInterface()->Delete(
- fileref_resource.pp_resource(),
- PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ int32_t result = ppapi()->GetFileRefInterface()
+ ->Delete(fileref_resource.pp_resource(), PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
return 0;
}
-
MountHtml5Fs::MountHtml5Fs()
: filesystem_resource_(0),
filesystem_open_has_result_(false),
- filesystem_open_result_(PP_OK) {
-}
+ filesystem_open_error_(0) {}
-bool MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
- if (!Mount::Init(dev, args, ppapi))
- return false;
+Error MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+ Error error = Mount::Init(dev, args, ppapi);
+ if (error)
+ return error;
if (!ppapi)
- return false;
+ return ENOSYS;
pthread_cond_init(&filesystem_open_cond_, NULL);
@@ -121,7 +110,7 @@ bool MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
PP_FileSystemType filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
int64_t expected_size = 0;
for (StringMap_t::iterator iter = args.begin(), end = args.end(); iter != end;
- ++iter) {
+ ++iter) {
if (iter->first == "type") {
if (iter->second == "PERSISTENT") {
filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
@@ -134,33 +123,32 @@ bool MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
}
// Initialize filesystem.
- filesystem_resource_ = ppapi->GetFileSystemInterface()->Create(
- ppapi_->GetInstance(), filesystem_type);
-
+ filesystem_resource_ = ppapi->GetFileSystemInterface()
+ ->Create(ppapi_->GetInstance(), filesystem_type);
if (filesystem_resource_ == 0)
- return false;
+ return ENOSYS;
// We can't block the main thread, so make an asynchronous call if on main
// thread. If we are off-main-thread, then don't make an asynchronous call;
// otherwise we require a message loop.
bool main_thread = ppapi->IsMainThread();
- PP_CompletionCallback cc = main_thread ?
- PP_MakeCompletionCallback(&MountHtml5Fs::FilesystemOpenCallbackThunk,
- this) :
- PP_BlockUntilComplete();
+ PP_CompletionCallback cc =
+ main_thread ? PP_MakeCompletionCallback(
+ &MountHtml5Fs::FilesystemOpenCallbackThunk, this)
+ : PP_BlockUntilComplete();
- int32_t result = ppapi->GetFileSystemInterface()->Open(
- filesystem_resource_, expected_size, cc);
+ int32_t result = ppapi->GetFileSystemInterface()
+ ->Open(filesystem_resource_, expected_size, cc);
if (!main_thread) {
filesystem_open_has_result_ = true;
- filesystem_open_result_ = result;
+ filesystem_open_error_ = PPErrorToErrno(result);
- return filesystem_open_result_ == PP_OK;
+ return filesystem_open_error_;
} else {
// We have to assume the call to Open will succeed; there is no better
// result to return here.
- return true;
+ return 0;
}
}
@@ -169,12 +157,12 @@ void MountHtml5Fs::Destroy() {
pthread_cond_destroy(&filesystem_open_cond_);
}
-int32_t MountHtml5Fs::BlockUntilFilesystemOpen() {
+Error MountHtml5Fs::BlockUntilFilesystemOpen() {
AutoLock lock(&lock_);
while (!filesystem_open_has_result_) {
pthread_cond_wait(&filesystem_open_cond_, &lock_);
}
- return filesystem_open_result_;
+ return filesystem_open_error_;
}
// static
@@ -187,6 +175,6 @@ void MountHtml5Fs::FilesystemOpenCallbackThunk(void* user_data,
void MountHtml5Fs::FilesystemOpenCallback(int32_t result) {
AutoLock lock(&lock_);
filesystem_open_has_result_ = true;
- filesystem_open_result_ = 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 a6633be8af..e872dae353 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
@@ -11,23 +11,23 @@
class MountNode;
-class MountHtml5Fs: public Mount {
+class MountHtml5Fs : public Mount {
public:
- virtual MountNode *Open(const Path& path, int mode);
- virtual int Unlink(const Path& path);
- virtual int Mkdir(const Path& path, int permissions);
- virtual int Rmdir(const Path& path);
- virtual int Remove(const Path& path);
+ virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error Unlink(const Path& path);
+ virtual Error Mkdir(const Path& path, int permissions);
+ virtual Error Rmdir(const Path& path);
+ virtual Error Remove(const Path& path);
PP_Resource filesystem_resource() { return filesystem_resource_; }
protected:
MountHtml5Fs();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
- int32_t BlockUntilFilesystemOpen();
+ Error BlockUntilFilesystemOpen();
private:
static void FilesystemOpenCallbackThunk(void* user_data, int32_t result);
@@ -35,7 +35,7 @@ class MountHtml5Fs: public Mount {
PP_Resource filesystem_resource_;
bool filesystem_open_has_result_; // protected by lock_.
- int32_t filesystem_open_result_; // protected by lock_.
+ Error filesystem_open_error_; // protected by lock_.
pthread_cond_t filesystem_open_cond_;
friend class Mount;
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 9a6579ed07..7b4316e842 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_http.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_http.cc
@@ -4,30 +4,30 @@
*/
#include "nacl_io/mount_http.h"
+
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <ppapi/c/pp_errors.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
+
#include <vector>
-#include "nacl_io/mount_node_dir.h"
-#include "nacl_io/osinttypes.h"
-#include "utils/auto_lock.h"
-#if defined(WIN32)
-#define snprintf _snprintf
-#endif
+#include <ppapi/c/pp_errors.h>
+#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"
namespace {
-typedef std::vector<char *> StringList_t;
-size_t SplitString(char *str, const char *delim, StringList_t* list) {
- char *item = strtok(str, delim);
+typedef std::vector<char*> StringList_t;
+size_t SplitString(char* str, const char* delim, StringList_t* list) {
+ char* item = strtok(str, delim);
list->clear();
while (item) {
@@ -38,13 +38,7 @@ size_t SplitString(char *str, const char *delim, StringList_t* list) {
return list->size();
}
-
-// If we're attempting to read a partial request, but the server returns a full
-// request, we need to read all of the data up to the start of our partial
-// request into a dummy buffer. This is the maximum size of that buffer.
-const size_t MAX_READ_BUFFER_SIZE = 64 * 1024;
-const int32_t STATUSCODE_OK = 200;
-const int32_t STATUSCODE_PARTIAL_CONTENT = 206;
+} // namespace
std::string NormalizeHeaderKey(const std::string& s) {
// Capitalize the first letter and any letter following a hyphen:
@@ -60,557 +54,64 @@ std::string NormalizeHeaderKey(const std::string& s) {
return result;
}
-StringMap_t ParseHeaders(const char* headers, int32_t headers_length) {
- enum State {
- FINDING_KEY,
- SKIPPING_WHITESPACE,
- FINDING_VALUE,
- };
-
- StringMap_t result;
- std::string key;
- std::string value;
-
- State state = FINDING_KEY;
- const char* start = headers;
- for (int i = 0; i < headers_length; ++i) {
- switch (state) {
- case FINDING_KEY:
- if (headers[i] == ':') {
- // Found key.
- key.assign(start, &headers[i] - start);
- key = NormalizeHeaderKey(key);
- state = SKIPPING_WHITESPACE;
- }
- break;
-
- case SKIPPING_WHITESPACE:
- if (headers[i] == ' ') {
- // Found whitespace, keep going...
- break;
- }
-
- // Found a non-whitespace, mark this as the start of the value.
- start = &headers[i];
- state = FINDING_VALUE;
- // Fallthrough to start processing value without incrementing i.
-
- case FINDING_VALUE:
- if (headers[i] == '\n') {
- // Found value.
- value.assign(start, &headers[i] - start);
- result[key] = value;
- start = &headers[i + 1];
- state = FINDING_KEY;
- }
- break;
- }
- }
-
- return result;
-}
-
-bool ParseContentLength(const StringMap_t& headers, size_t* content_length) {
- StringMap_t::const_iterator iter = headers.find("Content-Length");
- if (iter == headers.end())
- return false;
-
- *content_length = strtoul(iter->second.c_str(), NULL, 10);
- return true;
-}
-
-bool ParseContentRange(const StringMap_t& headers, size_t* read_start,
- size_t* read_end, size_t* entity_length) {
- StringMap_t::const_iterator iter = headers.find("Content-Range");
- if (iter == headers.end())
- return false;
-
- // The key should look like "bytes ##-##/##" or "bytes ##-##/*". The last
- // value is the entity length, which can potentially be * (i.e. unknown).
- int read_start_int;
- int read_end_int;
- int entity_length_int;
- int result = sscanf(iter->second.c_str(), "bytes %"SCNuS"-%"SCNuS"/%"SCNuS,
- &read_start_int, &read_end_int, &entity_length_int);
-
- // The Content-Range header specifies an inclusive range: e.g. the first ten
- // bytes is "bytes 0-9/*". Convert it to a half-open range by incrementing
- // read_end.
- if (result == 2) {
- *read_start = read_start_int;
- *read_end = read_end_int + 1;
- *entity_length = 0;
- return true;
- } else if (result == 3) {
- *read_start = read_start_int;
- *read_end = read_end_int + 1;
- *entity_length = entity_length_int;
- return true;
- }
-
- return false;
-}
-
-} // namespace
-
-
-class MountNodeHttp : public MountNode {
- public:
- virtual int FSync();
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count);
- virtual int GetStat(struct stat* stat);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int FTruncate(off_t size);
- virtual int Write(size_t offs, const void* buf, size_t count);
- virtual size_t GetSize();
-
- void SetCachedSize(off_t size);
-
- protected:
- MountNodeHttp(Mount* mount, const std::string& url, bool cache_content);
-
- private:
- bool OpenUrl(const char* method,
- StringMap_t* request_headers,
- PP_Resource* out_loader,
- PP_Resource* out_request,
- PP_Resource* out_response,
- int32_t* out_statuscode,
- StringMap_t* out_response_headers);
-
- int DownloadToCache();
- int ReadPartialFromCache(size_t offs, void* buf, size_t count);
- int DownloadPartial(size_t offs, void* buf, size_t count);
- int DownloadToBuffer(PP_Resource loader, void* buf, size_t count);
-
- std::string url_;
- std::vector<char> buffer_;
-
- bool cache_content_;
- bool has_cached_size_;
- std::vector<char> cached_data_;
-
- friend class MountHttp;
-};
-
-void MountNodeHttp::SetCachedSize(off_t size) {
- has_cached_size_ = true;
- stat_.st_size = size;
-}
-
-int MountNodeHttp::FSync() {
- errno = ENOSYS;
- return -1;
-}
-
-int MountNodeHttp::GetDents(size_t offs, struct dirent* pdir, size_t count) {
- errno = ENOSYS;
- return -1;
-}
-
-int MountNodeHttp::GetStat(struct stat* stat) {
- AutoLock lock(&lock_);
-
- // Assume we need to 'HEAD' if we do not know the size, otherwise, assume
- // that the information is constant. We can add a timeout if needed.
- MountHttp* mount = static_cast<MountHttp*>(mount_);
- if (stat_.st_size == 0 || !mount->cache_stat_) {
- StringMap_t headers;
- PP_Resource loader;
- PP_Resource request;
- PP_Resource response;
- int32_t statuscode;
- StringMap_t response_headers;
- if (!OpenUrl("HEAD", &headers, &loader, &request, &response, &statuscode,
- &response_headers)) {
- // errno is already set by OpenUrl.
- return -1;
- }
-
- ScopedResource scoped_loader(mount_->ppapi(), loader);
- ScopedResource scoped_request(mount_->ppapi(), request);
- ScopedResource scoped_response(mount_->ppapi(), response);
-
-
- size_t entity_length;
- if (ParseContentLength(response_headers, &entity_length)) {
- SetCachedSize(static_cast<off_t>(entity_length));
- } else if (cache_content_ && !has_cached_size_) {
- DownloadToCache();
- } else {
- // Don't use SetCachedSize here -- it is actually unknown.
- stat_.st_size = 0;
- }
-
- stat_.st_atime = 0; // TODO(binji): Use "Last-Modified".
- stat_.st_mtime = 0;
- stat_.st_ctime = 0;
- }
-
- // Fill the stat structure if provided
- if (stat) {
- memcpy(stat, &stat_, sizeof(stat_));
- }
- return 0;
-}
-
-int MountNodeHttp::Read(size_t offs, void* buf, size_t count) {
- AutoLock lock(&lock_);
- if (cache_content_) {
- if (cached_data_.empty()) {
- if (DownloadToCache() < 0)
- return -1;
- }
-
- return ReadPartialFromCache(offs, buf, count);
- }
-
- return DownloadPartial(offs, buf, count);
-}
-
-int MountNodeHttp::FTruncate(off_t size) {
- errno = ENOSYS;
- return -1;
-}
-
-int MountNodeHttp::Write(size_t offs, const void* buf, size_t count) {
- // TODO(binji): support POST?
- errno = ENOSYS;
- return -1;
-}
-
-size_t MountNodeHttp::GetSize() {
- // TODO(binji): This value should be cached properly; i.e. obey the caching
- // headers returned by the server.
- AutoLock lock(&lock_);
- if (!has_cached_size_) {
- // Even if DownloadToCache fails, the best result we can return is what
- // was written to stat_.st_size.
- if (cache_content_)
- DownloadToCache();
- }
-
- return stat_.st_size;
-}
-
-MountNodeHttp::MountNodeHttp(Mount* mount, const std::string& url,
- bool cache_content)
- : MountNode(mount),
- url_(url),
- cache_content_(cache_content),
- has_cached_size_(false) {
-}
-
-bool MountNodeHttp::OpenUrl(const char* method,
- StringMap_t* request_headers,
- PP_Resource* out_loader,
- PP_Resource* out_request,
- PP_Resource* out_response,
- int32_t* out_statuscode,
- StringMap_t* out_response_headers) {
- // Assume lock_ is already held.
-
- PepperInterface* ppapi = mount_->ppapi();
-
- MountHttp* mount_http = static_cast<MountHttp*>(mount_);
- ScopedResource request(ppapi,
- mount_http->MakeUrlRequestInfo(url_, method,
- request_headers));
- if (!request.pp_resource()) {
- errno = EINVAL;
- return false;
- }
-
- URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
- URLResponseInfoInterface* response_interface =
- ppapi->GetURLResponseInfoInterface();
- VarInterface* var_interface = ppapi->GetVarInterface();
-
- ScopedResource loader(ppapi, loader_interface->Create(ppapi->GetInstance()));
- if (!loader.pp_resource()) {
- errno = EINVAL;
- return false;
- }
-
- int32_t result = loader_interface->Open(
- loader.pp_resource(), request.pp_resource(), PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return false;
- }
-
- ScopedResource response(
- ppapi,
- loader_interface->GetResponseInfo(loader.pp_resource()));
- if (!response.pp_resource()) {
- errno = EINVAL;
- return false;
- }
-
- // Get response statuscode.
- PP_Var statuscode = response_interface->GetProperty(
- response.pp_resource(),
- PP_URLRESPONSEPROPERTY_STATUSCODE);
-
- if (statuscode.type != PP_VARTYPE_INT32) {
- errno = EINVAL;
- return false;
- }
-
- *out_statuscode = statuscode.value.as_int;
-
- // Only accept OK or Partial Content.
- if (*out_statuscode != STATUSCODE_OK &&
- *out_statuscode != STATUSCODE_PARTIAL_CONTENT) {
- errno = EINVAL;
- return false;
- }
-
- // Get response headers.
- PP_Var response_headers_var = response_interface->GetProperty(
- response.pp_resource(),
- PP_URLRESPONSEPROPERTY_HEADERS);
-
- uint32_t response_headers_length;
- const char* response_headers_str = var_interface->VarToUtf8(
- response_headers_var,
- &response_headers_length);
-
- *out_loader = loader.Release();
- *out_request = request.Release();
- *out_response = response.Release();
- *out_response_headers = ParseHeaders(response_headers_str,
- response_headers_length);
-
- return true;
-}
-
-int MountNodeHttp::DownloadToCache() {
- StringMap_t headers;
- PP_Resource loader;
- PP_Resource request;
- PP_Resource response;
- int32_t statuscode;
- StringMap_t response_headers;
- if (!OpenUrl("GET", &headers, &loader, &request, &response, &statuscode,
- &response_headers)) {
- // errno is already set by OpenUrl.
- return -1;
- }
-
- PepperInterface* ppapi = mount_->ppapi();
- ScopedResource scoped_loader(ppapi, loader);
- ScopedResource scoped_request(ppapi, request);
- ScopedResource scoped_response(ppapi, response);
-
- size_t content_length = 0;
- if (ParseContentLength(response_headers, &content_length)) {
- cached_data_.resize(content_length);
- int real_size = DownloadToBuffer(loader, cached_data_.data(),
- content_length);
- if (real_size < 0)
- return -1;
-
- SetCachedSize(real_size);
- cached_data_.resize(real_size);
- return real_size;
- }
-
- // We don't know how big the file is. Read in chunks.
- cached_data_.resize(MAX_READ_BUFFER_SIZE);
- size_t total_bytes_read = 0;
- size_t bytes_to_read = MAX_READ_BUFFER_SIZE;
- while (true) {
- char* buf = cached_data_.data() + total_bytes_read;
- int bytes_read = DownloadToBuffer(loader, buf, bytes_to_read);
- if (bytes_read < 0)
- return -1;
-
- total_bytes_read += bytes_read;
-
- if (bytes_read < bytes_to_read) {
- SetCachedSize(total_bytes_read);
- cached_data_.resize(total_bytes_read);
- return total_bytes_read;
- }
-
- cached_data_.resize(total_bytes_read + bytes_to_read);
- }
-}
-
-int MountNodeHttp::ReadPartialFromCache(size_t offs, void* buf, size_t count) {
- if (offs > cached_data_.size()) {
- errno = EINVAL;
- return -1;
- }
-
- count = std::min(count, cached_data_.size() - offs);
- memcpy(buf, &cached_data_.data()[offs], count);
- return count;
-}
-
-int MountNodeHttp::DownloadPartial(size_t offs, void* buf, size_t count) {
- StringMap_t headers;
-
- char buffer[100];
- // Range request is inclusive: 0-99 returns 100 bytes.
- snprintf(&buffer[0], sizeof(buffer), "bytes=%"PRIuS"-%"PRIuS,
- offs, offs + count - 1);
- headers["Range"] = buffer;
-
- PP_Resource loader;
- PP_Resource request;
- PP_Resource response;
- int32_t statuscode;
- StringMap_t response_headers;
- if (!OpenUrl("GET", &headers, &loader, &request, &response, &statuscode,
- &response_headers)) {
- // errno is already set by OpenUrl.
- return -1;
- }
-
- PepperInterface* ppapi = mount_->ppapi();
- ScopedResource scoped_loader(ppapi, loader);
- ScopedResource scoped_request(ppapi, request);
- ScopedResource scoped_response(ppapi, response);
-
- size_t read_start = 0;
- if (statuscode == STATUSCODE_OK) {
- // No partial result, read everything starting from the part we care about.
- size_t content_length;
- if (ParseContentLength(response_headers, &content_length)) {
- if (offs >= content_length) {
- errno = EINVAL;
- return 0;
- }
+Error MountHttp::Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = NULL;
- // Clamp count, if trying to read past the end of the file.
- if (offs + count > content_length) {
- count = content_length - offs;
- }
- }
- } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) {
- // Determine from the headers where we are reading.
- size_t read_end;
- size_t entity_length;
- if (ParseContentRange(response_headers, &read_start, &read_end,
- &entity_length)) {
- if (read_start > offs || read_start > read_end) {
- // If this error occurs, the server is returning bogus values.
- errno = EINVAL;
- return -1;
- }
+ assert(url_root_.empty() || url_root_[url_root_.length() - 1] == '/');
- // Clamp count, if trying to read past the end of the file.
- count = std::min(read_end - read_start, count);
- } else {
- // Partial Content without Content-Range. Assume that the server gave us
- // exactly what we asked for. This can happen even when the server
- // returns 200 -- the cache may return 206 in this case, but not modify
- // the headers.
- read_start = offs;
- }
+ NodeMap_t::iterator iter = node_cache_.find(path.Join());
+ if (iter != node_cache_.end()) {
+ *out_node = iter->second;
+ return 0;
}
- if (read_start < offs) {
- // We aren't yet at the location where we want to start reading. Read into
- // our dummy buffer until then.
- size_t bytes_to_read = offs - read_start;
- if (buffer_.size() < bytes_to_read)
- buffer_.resize(std::min(bytes_to_read, MAX_READ_BUFFER_SIZE));
-
- while (bytes_to_read > 0) {
- int32_t bytes_read = DownloadToBuffer(loader, buffer_.data(),
- buffer_.size());
- if (bytes_read < 0)
- return -1;
+ // 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());
- bytes_to_read -= bytes_read;
- }
+ MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_);
+ Error error = node->Init(mode);
+ if (error) {
+ node->Release();
+ return error;
}
- return DownloadToBuffer(loader, buf, count);
-}
-
-int MountNodeHttp::DownloadToBuffer(PP_Resource loader, void* buf,
- size_t count) {
- PepperInterface* ppapi = mount_->ppapi();
- URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
-
- char* out_buffer = static_cast<char*>(buf);
- size_t bytes_to_read = count;
- while (bytes_to_read > 0) {
- int32_t bytes_read = loader_interface->ReadResponseBody(
- loader, out_buffer, bytes_to_read, PP_BlockUntilComplete());
-
- if (bytes_read == 0) {
- // This is not an error -- it may just be that we were trying to read
- // more data than exists.
- return count - bytes_to_read;
- }
-
- if (bytes_read < 0) {
- errno = PPErrorToErrno(bytes_read);
- return -1;
- }
-
- assert(bytes_read <= bytes_to_read);
- bytes_to_read -= bytes_read;
- out_buffer += bytes_read;
+ error = node->GetStat(NULL);
+ if (error) {
+ node->Release();
+ return error;
}
- return count;
-}
-
-MountNode *MountHttp::Open(const Path& path, int 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()) {
- return iter->second;
+ MountNodeDir* parent;
+ error = FindOrCreateDir(path.Parent(), &parent);
+ if (error) {
+ node->Release();
+ return error;
}
- // 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_);
- if (!node->Init(mode) || (0 != node->GetStat(NULL))) {
+ error = parent->AddChild(path.Basename(), node);
+ if (error) {
node->Release();
- return NULL;
+ return error;
}
- MountNodeDir* parent = FindOrCreateDir(path.Parent());
node_cache_[path.Join()] = node;
- parent->AddChild(path.Basename(), node);
- return node;
-}
-int MountHttp::Unlink(const Path& path) {
- errno = ENOSYS;
- return -1;
+ *out_node = node;
+ return 0;
}
-int MountHttp::Mkdir(const Path& path, int permissions) {
- errno = ENOSYS;
- return -1;
-}
+Error MountHttp::Unlink(const Path& path) { return ENOSYS; }
-int MountHttp::Rmdir(const Path& path) {
- errno = ENOSYS;
- return -1;
-}
+Error MountHttp::Mkdir(const Path& path, int permissions) { return ENOSYS; }
-int MountHttp::Remove(const Path& path) {
- errno = ENOSYS;
- return -1;
-}
+Error MountHttp::Rmdir(const Path& path) { return ENOSYS; }
+
+Error MountHttp::Remove(const Path& path) { return ENOSYS; }
-PP_Resource MountHttp::MakeUrlRequestInfo(
- const std::string& url,
- const char* method,
- StringMap_t* additional_headers) {
+PP_Resource MountHttp::MakeUrlRequestInfo(const std::string& url,
+ const char* method,
+ StringMap_t* additional_headers) {
URLRequestInfoInterface* interface = ppapi_->GetURLRequestInfoInterface();
VarInterface* var_interface = ppapi_->GetVarInterface();
@@ -618,21 +119,23 @@ PP_Resource MountHttp::MakeUrlRequestInfo(
if (!request_info)
return 0;
- interface->SetProperty(
- request_info, PP_URLREQUESTPROPERTY_URL,
- var_interface->VarFromUtf8(url.c_str(), url.length()));
- interface->SetProperty(request_info, PP_URLREQUESTPROPERTY_METHOD,
+ interface->SetProperty(request_info,
+ PP_URLREQUESTPROPERTY_URL,
+ var_interface->VarFromUtf8(url.c_str(), url.length()));
+ interface->SetProperty(request_info,
+ PP_URLREQUESTPROPERTY_METHOD,
var_interface->VarFromUtf8(method, strlen(method)));
interface->SetProperty(request_info,
PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS,
PP_MakeBool(allow_cors_ ? PP_TRUE : PP_FALSE));
- interface->SetProperty(request_info, PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS,
+ interface->SetProperty(request_info,
+ PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS,
PP_MakeBool(allow_credentials_ ? PP_TRUE : PP_FALSE));
// Merge the mount headers with the request headers. If the field is already
// set it |additional_headers|, don't use the one from headers_.
for (StringMap_t::iterator iter = headers_.begin(); iter != headers_.end();
- ++iter) {
+ ++iter) {
const std::string& key = NormalizeHeaderKey(iter->first);
if (additional_headers->find(key) == additional_headers->end()) {
additional_headers->insert(std::make_pair(key, iter->second));
@@ -642,12 +145,14 @@ PP_Resource MountHttp::MakeUrlRequestInfo(
// Join the headers into one string.
std::string headers;
for (StringMap_t::iterator iter = additional_headers->begin();
- iter != additional_headers->end(); ++iter) {
+ iter != additional_headers->end();
+ ++iter) {
headers += iter->first + ": " + iter->second + '\n';
}
interface->SetProperty(
- request_info, PP_URLREQUESTPROPERTY_HEADERS,
+ request_info,
+ PP_URLREQUESTPROPERTY_HEADERS,
var_interface->VarFromUtf8(headers.c_str(), headers.length()));
return request_info;
@@ -657,12 +162,12 @@ MountHttp::MountHttp()
: allow_cors_(false),
allow_credentials_(false),
cache_stat_(true),
- cache_content_(true) {
-}
+ cache_content_(true) {}
-bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
- if (!Mount::Init(dev, args, ppapi))
- return false;
+Error MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+ Error error = Mount::Init(dev, args, ppapi);
+ if (error)
+ return error;
// Parse mount args.
for (StringMap_t::iterator iter = args.begin(); iter != args.end(); ++iter) {
@@ -674,11 +179,18 @@ bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
url_root_ += '/';
}
} else if (iter->first == "manifest") {
- char *text = LoadManifest(iter->second);
- if (text != NULL) {
- ParseManifest(text);
+ char* text;
+ error = LoadManifest(iter->second, &text);
+ if (error)
+ return error;
+
+ error = ParseManifest(text);
+ if (error) {
delete[] text;
+ return error;
}
+
+ delete[] text;
} else if (iter->first == "allow_cross_origin_requests") {
allow_cors_ = iter->second == "true";
} else if (iter->first == "allow_credentials") {
@@ -693,34 +205,53 @@ bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
}
}
- return true;
+ return 0;
}
-void MountHttp::Destroy() {
-}
+void MountHttp::Destroy() {}
+
+Error MountHttp::FindOrCreateDir(const Path& path, MountNodeDir** out_node) {
+ *out_node = NULL;
-MountNodeDir* MountHttp::FindOrCreateDir(const Path& path) {
std::string strpath = path.Join();
NodeMap_t::iterator iter = node_cache_.find(strpath);
if (iter != node_cache_.end()) {
- return static_cast<MountNodeDir*>(iter->second);
+ *out_node = static_cast<MountNodeDir*>(iter->second);
+ return 0;
}
- // If the node does not exist, create it, and add it to the node cache
+ // If the node does not exist, create it.
MountNodeDir* node = new MountNodeDir(this);
- node->Init(S_IREAD);
- node_cache_[strpath] = node;
+ Error error = node->Init(S_IREAD);
+ if (error) {
+ node->Release();
+ return error;
+ }
// If not the root node, find the parent node and add it to the parent
if (!path.Top()) {
- MountNodeDir* parent = FindOrCreateDir(path.Parent());
- parent->AddChild(path.Basename(), node);
+ MountNodeDir* parent;
+ error = FindOrCreateDir(path.Parent(), &parent);
+ if (error) {
+ node->Release();
+ return error;
+ }
+
+ error = parent->AddChild(path.Basename(), node);
+ if (error) {
+ node->Release();
+ return error;
+ }
}
- return node;
+ // Add it to the node cache.
+ node_cache_[strpath] = node;
+
+ *out_node = node;
+ return 0;
}
-bool MountHttp::ParseManifest(char *text) {
+Error MountHttp::ParseManifest(char* text) {
StringList_t lines;
SplitString(text, "\n", &lines);
@@ -741,62 +272,102 @@ bool MountHttp::ParseManifest(char *text) {
// Ignore EXEC bit
int mode = S_IFREG;
switch (modestr[0]) {
- case '-': mode = S_IFREG; break;
- case 'c': mode = S_IFCHR; break;
+ case '-':
+ mode = S_IFREG;
+ break;
+ case 'c':
+ mode = S_IFCHR;
+ break;
default:
fprintf(stderr, "Unable to parse type %s for %s.\n", modestr, name);
- return false;
+ return EINVAL;
}
switch (modestr[1]) {
- case '-': break;
- case 'r': mode |= S_IREAD; break;
+ case '-':
+ break;
+ case 'r':
+ mode |= S_IREAD;
+ break;
default:
fprintf(stderr, "Unable to parse read %s for %s.\n", modestr, name);
- return false;
+ return EINVAL;
}
switch (modestr[2]) {
- case '-': break;
- case 'w': mode |= S_IWRITE; break;
+ case '-':
+ break;
+ case 'w':
+ mode |= S_IWRITE;
+ break;
default:
fprintf(stderr, "Unable to parse write %s for %s.\n", modestr, name);
- return false;
+ return EINVAL;
}
Path path(name);
- std::string url = url_root_ + (path.IsAbsolute() ?
- path.Range(1, path.Size()) :
- path.Join());
+ std::string url =
+ url_root_ +
+ (path.IsAbsolute() ? path.Range(1, path.Size()) : path.Join());
MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_);
- node->Init(mode);
+ Error error = node->Init(mode);
+ if (error) {
+ node->Release();
+ return error;
+ }
+
node->SetCachedSize(atoi(lenstr));
- MountNodeDir* dir_node = FindOrCreateDir(path.Parent());
- dir_node->AddChild(path.Basename(), node);
+ MountNodeDir* dir_node;
+ error = FindOrCreateDir(path.Parent(), &dir_node);
+ if (error) {
+ node->Release();
+ return error;
+ }
+
+ error = dir_node->AddChild(path.Basename(), node);
+ if (error) {
+ node->Release();
+ return error;
+ }
std::string pname = path.Join();
node_cache_[pname] = node;
}
}
- return true;
+ return 0;
}
-char *MountHttp::LoadManifest(const std::string& manifest_name) {
+Error MountHttp::LoadManifest(const std::string& manifest_name,
+ char** out_manifest) {
Path manifest_path(manifest_name);
- MountNode* manifest_node = Open(manifest_path, O_RDONLY);
+ MountNode* manifest_node = NULL;
+ *out_manifest = NULL;
- if (manifest_node) {
- char *text = new char[manifest_node->GetSize() + 1];
- off_t len = manifest_node->Read(0, text, manifest_node->GetSize());
+ int error = Open(manifest_path, O_RDONLY, &manifest_node);
+ if (error)
+ return error;
+
+ size_t size;
+ error = manifest_node->GetSize(&size);
+ if (error) {
manifest_node->Release();
+ return error;
+ }
- text[len] = 0;
- return text;
+ char* text = new char[size + 1];
+ int len;
+ error = manifest_node->Read(0, text, size, &len);
+ if (error) {
+ manifest_node->Release();
+ return error;
}
- fprintf(stderr, "Could not open manifest: %s\n", manifest_name.c_str());
- return NULL;
+ manifest_node->Release();
+ text[len] = 0;
+
+ *out_manifest = text;
+ return 0;
}
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 3a842a041e..e10f1afcfe 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_http.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_http.h
@@ -15,15 +15,17 @@ 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;
- virtual MountNode *Open(const Path& path, int mode);
- virtual int Unlink(const Path& path);
- virtual int Mkdir(const Path& path, int permissions);
- virtual int Rmdir(const Path& path);
- virtual int Remove(const Path& path);
+ virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error Unlink(const Path& path);
+ virtual Error Mkdir(const Path& path, int permissions);
+ virtual Error Rmdir(const Path& path);
+ virtual Error Remove(const Path& path);
PP_Resource MakeUrlRequestInfo(const std::string& url,
const char* method,
@@ -32,11 +34,11 @@ class MountHttp : public Mount {
protected:
MountHttp();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
- MountNodeDir* FindOrCreateDir(const Path& path);
- char *LoadManifest(const std::string& path);
- bool ParseManifest(char *text);
+ Error FindOrCreateDir(const Path& path, MountNodeDir** out_node);
+ Error LoadManifest(const std::string& path, char** out_manifest);
+ Error ParseManifest(char *text);
private:
std::string url_root_;
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 fa3035cbcc..356600b4ec 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
@@ -14,22 +14,24 @@
#include "nacl_io/mount_node_mem.h"
#include "nacl_io/osstat.h"
#include "nacl_io/path.h"
-#include "utils/auto_lock.h"
-#include "utils/ref_object.h"
+#include "sdk_util/auto_lock.h"
+#include "sdk_util/ref_object.h"
-// TODO(noelallen) : Grab/Redefine these in the kernel object once available.
-#define USR_ID 1002
-#define GRP_ID 1003
+MountMem::MountMem() : root_(NULL), max_ino_(0) {}
-MountMem::MountMem()
- : root_(NULL),
- max_ino_(0) {
-}
+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);
+ error = root_->Init(S_IREAD | S_IWRITE);
+ if (error) {
+ root_->Release();
+ return error;
+ }
-bool MountMem::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
- Mount::Init(dev, args, ppapi);
- root_ = AllocatePath(S_IREAD | S_IWRITE);
- return (bool) (root_ != NULL);
+ return 0;
}
void MountMem::Destroy() {
@@ -38,173 +40,156 @@ void MountMem::Destroy() {
root_ = NULL;
}
-MountNode* MountMem::AllocatePath(int mode) {
- MountNode *ptr = new MountNodeDir(this);
- if (!ptr->Init(mode)) {
- ptr->Release();
- return NULL;
- }
- return ptr;
-}
-
-MountNode* MountMem::AllocateData(int mode) {
- MountNode* ptr = new MountNodeMem(this);
- if (!ptr->Init(mode)) {
- ptr->Release();
- return NULL;
- }
- return ptr;
-}
-
-MountNode* MountMem::FindNode(const Path& path, int type) {
+Error MountMem::FindNode(const Path& path, int type, MountNode** out_node) {
MountNode* node = root_;
// If there is no root there, we have an error.
- if (node == NULL) {
- errno = ENOTDIR;
- return NULL;
- }
+ if (node == NULL)
+ return ENOTDIR;
// We are expecting an "absolute" path from this mount point.
- if (!path.IsAbsolute()) {
- errno = EINVAL;
- return NULL;
- }
+ if (!path.IsAbsolute())
+ return EINVAL;
// Starting at the root, traverse the path parts.
for (size_t index = 1; node && index < path.Size(); index++) {
// If not a directory, then we have an error so return.
- if (!node->IsaDir()) {
- errno = ENOTDIR;
- return NULL;
- }
+ if (!node->IsaDir())
+ return ENOTDIR;
// Find the child node
- node = node->FindChild(path.Part(index));
+ Error error = node->FindChild(path.Part(index), &node);
+ if (error)
+ return error;
}
- // node should be root, a found child, or a failed 'FindChild'
- // which already has the correct errno set.
- if (NULL == node) return NULL;
-
// If a directory is expected, but it's not a directory, then fail.
- if ((type & S_IFDIR) && !node->IsaDir()) {
- errno = ENOTDIR;
- return NULL;
- }
+ if ((type & S_IFDIR) && !node->IsaDir())
+ return ENOTDIR;
// If a file is expected, but it's not a file, then fail.
- if ((type & S_IFREG) && node->IsaDir()) {
- errno = EISDIR;
- return NULL;
- }
+ if ((type & S_IFREG) && node->IsaDir())
+ return EISDIR;
// We now have a valid object of the expected type, so return it.
- return node;
+ *out_node = node;
+ return 0;
}
-MountNode* MountMem::Open(const Path& path, int mode) {
+Error MountMem::Open(const Path& path, int mode, MountNode** out_node) {
AutoLock lock(&lock_);
- MountNode* node = FindNode(path);
+ MountNode* node = NULL;
+ *out_node = NULL;
- if (NULL == node) {
- // Now first find the parent directory to see if we can add it
- MountNode* parent = FindNode(path.Parent(), S_IFDIR);
- if (NULL == parent) return NULL;
+ 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 NULL;
+ if ((mode & O_CREAT) == 0)
+ return ENOENT;
- // Otherwise, create it with a single reference
- mode = OpenModeToPermission(mode);
- node = AllocateData(mode);
- if (NULL == node) return NULL;
+ // Now first find the parent directory to see if we can add it
+ MountNode* parent = NULL;
+ error = FindNode(path.Parent(), S_IFDIR, &parent);
+ if (error)
+ return error;
+
+ // Create it with a single reference
+ node = new MountNodeMem(this);
+ error = node->Init(OpenModeToPermission(mode));
+ if (error) {
+ node->Release();
+ return error;
+ }
- if (parent->AddChild(path.Basename(), node) == -1) {
+ error = parent->AddChild(path.Basename(), node);
+ if (error) {
// Or if it fails, release it
node->Release();
- return NULL;
+ return error;
}
- return node;
+
+ *out_node = node;
+ return 0;
}
+ // Directories can only be opened read-only.
+ if (node->IsaDir() && (mode & 3) != O_RDONLY)
+ return EISDIR;
+
// If we were expected to create it exclusively, fail
- if (mode & O_EXCL) {
- errno = EEXIST;
- return NULL;
- }
+ if (mode & O_EXCL)
+ return EEXIST;
// Verify we got the requested permissions.
int req_mode = OpenModeToPermission(mode);
int obj_mode = node->GetMode() & OpenModeToPermission(O_RDWR);
- if ((obj_mode & req_mode) != req_mode) {
- errno = EACCES;
- return NULL;
- }
+ if ((obj_mode & req_mode) != req_mode)
+ return EACCES;
// We opened it, so ref count it before passing it back.
node->Acquire();
- return node;
+ *out_node = node;
+ return 0;
}
-int MountMem::Mkdir(const Path& path, int mode) {
+Error MountMem::Mkdir(const Path& path, int mode) {
AutoLock lock(&lock_);
// We expect a Mount "absolute" path
- if (!path.IsAbsolute()) {
- errno = ENOENT;
- return -1;
- }
+ if (!path.IsAbsolute())
+ return ENOENT;
// The root of the mount is already created by the mount
- if (path.Size() == 1) {
- errno = EEXIST;
- return -1;
- }
-
- MountNode* parent = FindNode(path.Parent(), S_IFDIR);
- MountNode* node;
+ if (path.Size() == 1)
+ return EEXIST;
- // If we failed to find the parent, the error code is already set.
- if (NULL == parent) return -1;
+ MountNode* parent = NULL;
+ int error = FindNode(path.Parent(), S_IFDIR, &parent);
+ if (error)
+ return error;
- node = parent->FindChild(path.Basename());
- if (NULL != node) {
- errno = EEXIST;
- return -1;
- }
+ MountNode* node = NULL;
+ error = parent->FindChild(path.Basename(), &node);
+ if (!error)
+ return EEXIST;
- // Otherwise, create a new node and attempt to add it
- mode = OpenModeToPermission(mode);
+ if (error != ENOENT)
+ return error;
// 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 = AllocatePath(S_IREAD | S_IWRITE);
- if (NULL == node) return -1;
+ node = new MountNodeDir(this);
+ error = node->Init(S_IREAD | S_IWRITE);
+ if (error) {
+ node->Release();
+ return error;
+ }
- if (parent->AddChild(path.Basename(), node) == -1) {
+ error = parent->AddChild(path.Basename(), node);
+ if (error) {
node->Release();
- return -1;
+ return error;
}
node->Release();
return 0;
}
-int MountMem::Unlink(const Path& path) {
+Error MountMem::Unlink(const Path& path) {
return RemoveInternal(path, REMOVE_FILE);
}
-int MountMem::Rmdir(const Path& path) {
+Error MountMem::Rmdir(const Path& path) {
return RemoveInternal(path, REMOVE_DIR);
}
-int MountMem::Remove(const Path& path) {
+Error MountMem::Remove(const Path& path) {
return RemoveInternal(path, REMOVE_ALL);
}
-int MountMem::RemoveInternal(const Path& path, int remove_type) {
+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;
@@ -212,40 +197,33 @@ int MountMem::RemoveInternal(const Path& path, int remove_type) {
if (dir_only) {
// We expect a Mount "absolute" path
- if (!path.IsAbsolute()) {
- errno = ENOENT;
- return -1;
- }
+ if (!path.IsAbsolute())
+ return ENOENT;
// The root of the mount is already created by the mount
- if (path.Size() == 1) {
- errno = EEXIST;
- return -1;
- }
+ if (path.Size() == 1)
+ return EEXIST;
}
- MountNode* parent = FindNode(path.Parent(), S_IFDIR);
-
- // If we failed to find the parent, the error code is already set.
- if (NULL == parent) return -1;
+ MountNode* parent = NULL;
+ int error = FindNode(path.Parent(), S_IFDIR, &parent);
+ if (error)
+ return error;
// Verify we find a child which is a directory.
- MountNode* child = parent->FindChild(path.Basename());
- if (NULL == child) {
- errno = ENOENT;
- return -1;
- }
- if (dir_only && !child->IsaDir()) {
- errno = ENOTDIR;
- return -1;
- }
- if (file_only && child->IsaDir()) {
- errno = EISDIR;
- return -1;
- }
- if (remove_dir && child->ChildCount() > 0) {
- errno = ENOTEMPTY;
- return -1;
- }
+ MountNode* child = NULL;
+ error = parent->FindChild(path.Basename(), &child);
+ if (error)
+ return error;
+
+ if (dir_only && !child->IsaDir())
+ return ENOTDIR;
+
+ if (file_only && child->IsaDir())
+ return EISDIR;
+
+ if (remove_dir && child->ChildCount() > 0)
+ return ENOTEMPTY;
+
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 dc75e81769..930e9c734a 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_mem.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_mem.h
@@ -14,35 +14,33 @@ class MountMem : public Mount {
protected:
MountMem();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ 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
// required to use correct locking as needed.
- MountNode *AllocateData(int mode);
- MountNode *AllocatePath(int mode);
// Allocate or free an INODE number.
int AllocateINO();
void FreeINO(int ino);
// Find a Node specified node optionally failing if type does not match.
- virtual MountNode* FindNode(const Path& path, int type = 0);
+ virtual Error FindNode(const Path& path, int type, MountNode** out_node);
public:
- virtual MountNode *Open(const Path& path, int mode);
- virtual int Unlink(const Path& path);
- virtual int Mkdir(const Path& path, int perm);
- virtual int Rmdir(const Path& path);
- virtual int Remove(const Path& path);
+ virtual Error Open(const Path& path, int mode, MountNode** 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:
static const int REMOVE_DIR = 1;
static const int REMOVE_FILE = 2;
static const int REMOVE_ALL = REMOVE_DIR | REMOVE_FILE;
- int RemoveInternal(const Path& path, int remove_type);
+ Error RemoveInternal(const Path& path, int remove_type);
MountNode* root_;
size_t max_ino_;
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 ff722b44eb..34de7a8164 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
@@ -13,13 +13,12 @@
#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/mount.h"
#include "nacl_io/osmman.h"
-#include "utils/auto_lock.h"
+#include "sdk_util/auto_lock.h"
static const int USR_ID = 1001;
static const int GRP_ID = 1002;
-MountNode::MountNode(Mount* mount)
- : mount_(mount) {
+MountNode::MountNode(Mount* mount) : mount_(mount) {
memset(&stat_, 0, sizeof(stat_));
stat_.st_gid = GRP_ID;
stat_.st_uid = USR_ID;
@@ -32,12 +31,11 @@ MountNode::MountNode(Mount* mount)
stat_.st_ino = 1;
}
-MountNode::~MountNode() {
-}
+MountNode::~MountNode() {}
-bool MountNode::Init(int perm) {
+Error MountNode::Init(int perm) {
stat_.st_mode |= perm;
- return true;
+ return 0;
}
void MountNode::Destroy() {
@@ -46,119 +44,110 @@ void MountNode::Destroy() {
}
}
-int MountNode::FSync() {
- return 0;
-}
+Error MountNode::FSync() { return 0; }
-int MountNode::FTruncate(off_t length) {
- errno = EINVAL;
- return -1;
+Error MountNode::FTruncate(off_t length) {
+ return EINVAL;
}
-int MountNode::GetDents(size_t offs, struct dirent* pdir, size_t count) {
- errno = ENOTDIR;
- return -1;
+Error MountNode::GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+ return ENOTDIR;
}
-int MountNode::GetStat(struct stat* pstat) {
+Error MountNode::GetStat(struct stat* pstat) {
AutoLock lock(&lock_);
memcpy(pstat, &stat_, sizeof(stat_));
return 0;
}
-int MountNode::Ioctl(int request, char* arg) {
- errno = EINVAL;
- return -1;
+Error MountNode::Ioctl(int request, char* arg) {
+ return EINVAL;
}
-int MountNode::Read(size_t offs, void* buf, size_t count) {
- errno = EINVAL;
- return -1;
+Error MountNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+ return EINVAL;
}
-int MountNode::Write(size_t offs, const void* buf, size_t count) {
- errno = EINVAL;
- return -1;
+Error MountNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+ return EINVAL;
}
-void* MountNode::MMap(void* addr, size_t length, int prot, int flags,
- size_t offset) {
+Error MountNode::MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr) {
+ *out_addr = NULL;
+
// Never allow mmap'ing PROT_EXEC. The passthrough node supports this, but we
// don't. Fortunately, glibc will fallback if this fails, so dlopen will
// continue to work.
- if (prot & PROT_EXEC) {
- errno = EPERM;
- return MAP_FAILED;
- }
+ if (prot & PROT_EXEC)
+ return EPERM;
// This default mmap support is just enough to make dlopen work.
// This implementation just reads from the mount into the mmap'd memory area.
void* new_addr = addr;
- int err = _real_mmap(&new_addr, length, prot | PROT_WRITE, flags |
- MAP_ANONYMOUS, -1, 0);
+ int mmap_error = _real_mmap(
+ &new_addr, length, prot | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
if (new_addr == MAP_FAILED) {
_real_munmap(new_addr, length);
- errno = err;
- return MAP_FAILED;
+ return mmap_error;
}
- ssize_t cnt = Read(offset, new_addr, length);
- if (cnt == -1) {
+ int bytes_read;
+ Error read_error = Read(offset, new_addr, length, &bytes_read);
+ if (read_error) {
_real_munmap(new_addr, length);
- errno = ENOSYS;
- return MAP_FAILED;
+ return read_error;
}
- return new_addr;
-}
-
-int MountNode::GetLinks() {
- return stat_.st_nlink;
+ *out_addr = new_addr;
+ return 0;
}
-int MountNode::GetMode() {
- return stat_.st_mode & ~S_IFMT;
-}
+int MountNode::GetLinks() { return stat_.st_nlink; }
-size_t MountNode::GetSize() {
- return stat_.st_size;
-}
+int MountNode::GetMode() { return stat_.st_mode & ~S_IFMT; }
-int MountNode::GetType() {
- return stat_.st_mode & S_IFMT;
+Error MountNode::GetSize(size_t* out_size) {
+ *out_size = stat_.st_size;
+ return 0;
}
-bool MountNode::IsaDir() {
- return (stat_.st_mode & S_IFDIR) != 0;
-}
+int MountNode::GetType() { return stat_.st_mode & S_IFMT; }
-bool MountNode::IsaFile() {
- return (stat_.st_mode & S_IFREG) != 0;
-}
+bool MountNode::IsaDir() { return (stat_.st_mode & S_IFDIR) != 0; }
-bool MountNode::IsaTTY() {
- return (stat_.st_mode & S_IFCHR) != 0;
-}
+bool MountNode::IsaFile() { return (stat_.st_mode & S_IFREG) != 0; }
+bool MountNode::IsaTTY() { return (stat_.st_mode & S_IFCHR) != 0; }
-int MountNode:: AddChild(const std::string& name, MountNode* node) {
- errno = ENOTDIR;
- return -1;
+Error MountNode::AddChild(const std::string& name, MountNode* node) {
+ return ENOTDIR;
}
-int MountNode::RemoveChild(const std::string& name) {
- errno = ENOTDIR;
- return -1;
+Error MountNode::RemoveChild(const std::string& name) {
+ return ENOTDIR;
}
-MountNode* MountNode::FindChild(const std::string& name) {
- errno = ENOTDIR;
- return NULL;
+Error MountNode::FindChild(const std::string& name, MountNode** out_node) {
+ *out_node = NULL;
+ return ENOTDIR;
}
int MountNode::ChildCount() {
- errno = ENOTDIR;
- return -1;
+ return 0;
}
void MountNode::Link() {
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 36a937e5fb..0acce66f80 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.h
@@ -7,13 +7,16 @@
#include <string>
+#include "nacl_io/error.h"
#include "nacl_io/osstat.h"
-#include "utils/ref_object.h"
+#include "sdk_util/ref_object.h"
struct dirent;
struct stat;
class Mount;
+// 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).
class MountNode : public RefObject {
protected:
explicit MountNode(Mount* mount);
@@ -21,27 +24,46 @@ class MountNode : public RefObject {
protected:
// Initialize with node specific flags, in this case stat permissions.
- virtual bool Init(int flags);
+ virtual Error Init(int flags);
virtual void Destroy();
public:
// Normal OS operations on a node (file), can be called by the kernel
// directly so it must lock and unlock appropriately. These functions
// must not be called by the mount.
- virtual int FSync();
- virtual int FTruncate(off_t length);
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count);
- virtual int GetStat(struct stat* stat);
- virtual int Ioctl(int request, char* arg);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
- virtual void* MMap(void* addr, size_t length, int prot, int flags,
- size_t offset);
+ virtual Error FSync();
+ // It is expected that the derived MountNode will fill with 0 when growing
+ // the file.
+ virtual Error FTruncate(off_t length);
+ // Assume that |out_bytes| is non-NULL.
+ virtual Error GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes);
+ // Assume that |stat| is non-NULL.
+ virtual Error GetStat(struct stat* stat);
+ // Assume that |arg| is non-NULL.
+ virtual Error Ioctl(int request, char* arg);
+ // Assume that |buf| and |out_bytes| are non-NULL.
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ // Assume that |buf| and |out_bytes| are non-NULL.
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
+ // Assume that |addr| and |out_addr| are non-NULL.
+ virtual Error MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr);
virtual int GetLinks();
virtual int GetMode();
virtual int GetType();
- virtual size_t GetSize();
+ // Assume that |out_size| is non-NULL.
+ virtual Error GetSize(size_t *out_size);
virtual bool IsaDir();
virtual bool IsaFile();
virtual bool IsaTTY();
@@ -51,18 +73,20 @@ class MountNode : public RefObject {
// must be held while these calls are made.
// Adds or removes a directory entry updating the link numbers and refcount
- virtual int AddChild(const std::string& name, MountNode *node);
- virtual int RemoveChild(const std::string& name);
+ // Assumes that |node| is non-NULL.
+ virtual Error AddChild(const std::string& name, MountNode* node);
+ virtual Error RemoveChild(const std::string& name);
// Find a child and return it without updating the refcount
- virtual MountNode* FindChild(const std::string& name);
+ // Assumes that |out_node| is non-NULL.
+ virtual Error FindChild(const std::string& name, MountNode** out_node);
virtual int ChildCount();
// Update the link count
virtual void Link();
virtual void Unlink();
-protected:
+ protected:
struct stat stat_;
Mount* 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 7a33bfd684..6f7feab44a 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
@@ -9,78 +9,82 @@
#include "nacl_io/osdirent.h"
#include "nacl_io/osstat.h"
-#include "utils/macros.h"
-#include "utils/auto_lock.h"
+#include "sdk_util/auto_lock.h"
+#include "sdk_util/macros.h"
-MountNodeDir::MountNodeDir(Mount* mount)
- : MountNode(mount),
- cache_(NULL) {
+MountNodeDir::MountNodeDir(Mount* mount) : MountNode(mount), cache_(NULL) {
stat_.st_mode |= S_IFDIR;
}
MountNodeDir::~MountNodeDir() {
+ for (MountNodeMap_t::iterator it = map_.begin(); it != map_.end(); ++it) {
+ it->second->Unlink();
+ }
free(cache_);
}
-int MountNodeDir::Read(size_t offs, void *buf, size_t count) {
- errno = EISDIR;
- return -1;
+Error MountNodeDir::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+ return EISDIR;
}
-int MountNodeDir::FTruncate(off_t size) {
- errno = EISDIR;
- return -1;
-}
+Error MountNodeDir::FTruncate(off_t size) { return EISDIR; }
-int MountNodeDir::Write(size_t offs, void *buf, size_t count) {
- errno = EISDIR;
- return -1;
+Error MountNodeDir::Write(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+ return EISDIR;
}
-int MountNodeDir::GetDents(size_t offs, struct dirent* pdir, size_t size) {
+Error MountNodeDir::GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t size,
+ int* out_bytes) {
+ *out_bytes = 0;
+
AutoLock lock(&lock_);
// If the buffer pointer is invalid, fail
- if (NULL == pdir) {
- errno = EINVAL;
- return -1;
- }
+ if (NULL == pdir)
+ return EINVAL;
// If the buffer is too small, fail
- if (size < sizeof(struct dirent)) {
- errno = EINVAL;
- return -1;
- }
+ if (size < sizeof(struct dirent))
+ return EINVAL;
// Force size to a multiple of dirent
size -= size % sizeof(struct dirent);
size_t max = map_.size() * sizeof(struct dirent);
- if (cache_ == NULL) BuildCache();
+ if (cache_ == NULL)
+ BuildCache();
- if (offs >= max) return 0;
- if (offs + size >= max) size = max - offs;
+ if (offs >= max) {
+ // OK, trying to read past the end.
+ return 0;
+ }
- memcpy(pdir, ((char *) cache_) + offs, size);
- return size;
+ if (offs + size >= max)
+ size = max - offs;
+
+ memcpy(pdir, ((char*)cache_) + offs, size);
+ *out_bytes = size;
+ return 0;
}
-int MountNodeDir::AddChild(const std::string& name, MountNode* node) {
+Error MountNodeDir::AddChild(const std::string& name, MountNode* node) {
AutoLock lock(&lock_);
- if (name.empty()) {
- errno = ENOENT;
- return -1;
- }
- if (name.length() >= MEMBER_SIZE(struct dirent, d_name)) {
- errno = ENAMETOOLONG;
- return -1;
- }
+ if (name.empty())
+ return ENOENT;
+
+ if (name.length() >= MEMBER_SIZE(struct dirent, d_name))
+ return ENAMETOOLONG;
MountNodeMap_t::iterator it = map_.find(name);
- if (it != map_.end()) {
- errno = EEXIST;
- return -1;
- }
+ if (it != map_.end())
+ return EEXIST;
node->Link();
map_[name] = node;
@@ -88,7 +92,7 @@ int MountNodeDir::AddChild(const std::string& name, MountNode* node) {
return 0;
}
-int MountNodeDir::RemoveChild(const std::string& name) {
+Error MountNodeDir::RemoveChild(const std::string& name) {
AutoLock lock(&lock_);
MountNodeMap_t::iterator it = map_.find(name);
if (it != map_.end()) {
@@ -97,18 +101,19 @@ int MountNodeDir::RemoveChild(const std::string& name) {
ClearCache();
return 0;
}
- errno = ENOENT;
- return -1;
+ return ENOENT;
}
-MountNode* MountNodeDir::FindChild(const std::string& name) {
+Error MountNodeDir::FindChild(const std::string& name, MountNode** out_node) {
+ *out_node = NULL;
+
AutoLock lock(&lock_);
MountNodeMap_t::iterator it = map_.find(name);
- if (it != map_.end()) {
- return it->second;
- }
- errno = ENOENT;
- return NULL;
+ if (it == map_.end())
+ return ENOENT;
+
+ *out_node = it->second;
+ return 0;
}
int MountNodeDir::ChildCount() {
@@ -123,7 +128,7 @@ void MountNodeDir::ClearCache() {
void MountNodeDir::BuildCache() {
if (map_.size()) {
- cache_ = (struct dirent *) malloc(sizeof(struct dirent) * map_.size());
+ 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;
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 b6af58dda2..a2ab67ecfa 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
@@ -25,15 +25,18 @@ class MountNodeDir : public MountNode {
public:
typedef std::map<std::string, MountNode*> MountNodeMap_t;
- virtual int FTruncate(off_t size);
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count);
- virtual int Read(size_t offs, void *buf, size_t count);
- virtual int Write(size_t offs, void *buf, size_t count);
+ virtual Error FTruncate(off_t size);
+ virtual Error GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes);
+ virtual Error Read(size_t offs, void *buf, size_t count, int* out_bytes);
+ 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 int AddChild(const std::string& name, MountNode *node);
- virtual int RemoveChild(const std::string& name);
- virtual MountNode* FindChild(const std::string& name);
+ virtual Error AddChild(const std::string& name, MountNode *node);
+ virtual Error RemoveChild(const std::string& name);
+ virtual Error FindChild(const std::string& name, MountNode** 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 fb0d5ed2fb..8be2a4f74b 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
@@ -17,7 +17,7 @@
#include "nacl_io/mount.h"
#include "nacl_io/osdirent.h"
#include "nacl_io/pepper_interface.h"
-#include "utils/auto_lock.h"
+#include "sdk_util/auto_lock.h"
namespace {
@@ -55,56 +55,61 @@ int32_t ModeToOpenFlags(int mode) {
break;
}
- if (mode & O_CREAT) open_flags |= PP_FILEOPENFLAG_CREATE;
- if (mode & O_TRUNC) open_flags |= PP_FILEOPENFLAG_TRUNCATE;
- if (mode & O_EXCL) open_flags |= PP_FILEOPENFLAG_EXCLUSIVE;
+ if (mode & O_CREAT)
+ open_flags |= PP_FILEOPENFLAG_CREATE;
+ if (mode & O_TRUNC)
+ open_flags |= PP_FILEOPENFLAG_TRUNCATE;
+ if (mode & O_EXCL)
+ open_flags |= PP_FILEOPENFLAG_EXCLUSIVE;
return open_flags;
}
} // namespace
-int MountNodeHtml5Fs::FSync() {
- int32_t result = mount_->ppapi()->GetFileIoInterface()->Flush(
- fileio_resource_, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+Error MountNodeHtml5Fs::FSync() {
+ // Cannot call Flush on a directory; simply do nothing.
+ if (IsDirectory())
+ return 0;
+ int32_t result = mount_->ppapi()->GetFileIoInterface()
+ ->Flush(fileio_resource_, PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
return 0;
}
-int MountNodeHtml5Fs::GetDents(size_t offs, struct dirent* pdir, size_t size) {
+Error MountNodeHtml5Fs::GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t size,
+ int* out_bytes) {
+ *out_bytes = 0;
+
// If the buffer pointer is invalid, fail
- if (NULL == pdir) {
- errno = EINVAL;
- return -1;
- }
+ if (NULL == pdir)
+ return EINVAL;
// If the buffer is too small, fail
- if (size < sizeof(struct dirent)) {
- errno = EINVAL;
- return -1;
- }
+ if (size < sizeof(struct dirent))
+ return EINVAL;
- OutputBuffer output_buf = { NULL, 0 };
- PP_ArrayOutput output = { &GetOutputBuffer, &output_buf };
- int32_t result =
- mount_->ppapi()->GetFileRefInterface()->ReadDirectoryEntries(
- fileref_resource_, output, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ // If this is not a directory, fail
+ if (!IsDirectory())
+ return ENOTDIR;
+
+ OutputBuffer output_buf = {NULL, 0};
+ PP_ArrayOutput output = {&GetOutputBuffer, &output_buf};
+ int32_t result = mount_->ppapi()->GetFileRefInterface()->ReadDirectoryEntries(
+ fileref_resource_, output, PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
std::vector<struct dirent> dirents;
- PP_DirectoryEntry* entries =
- static_cast<PP_DirectoryEntry*>(output_buf.data);
+ PP_DirectoryEntry* entries = static_cast<PP_DirectoryEntry*>(output_buf.data);
for (int i = 0; i < output_buf.element_count; ++i) {
- PP_Var file_name_var = mount_->ppapi()->GetFileRefInterface()->GetName(
- entries[i].file_ref);
+ PP_Var file_name_var =
+ mount_->ppapi()->GetFileRefInterface()->GetName(entries[i].file_ref);
// Release the file reference.
mount_->ppapi()->ReleaseResource(entries[i].file_ref);
@@ -113,18 +118,18 @@ int MountNodeHtml5Fs::GetDents(size_t offs, struct dirent* pdir, size_t size) {
continue;
uint32_t file_name_length;
- const char* file_name = mount_->ppapi()->GetVarInterface()->VarToUtf8(
- file_name_var, &file_name_length);
+ const char* file_name = mount_->ppapi()->GetVarInterface()
+ ->VarToUtf8(file_name_var, &file_name_length);
if (!file_name)
continue;
file_name_length = std::min(
static_cast<size_t>(file_name_length),
- sizeof(static_cast<struct dirent*>(0)->d_name) - 1); // -1 for NULL.
+ sizeof(static_cast<struct dirent*>(0)->d_name) - 1); // -1 for NULL.
dirents.push_back(dirent());
struct dirent& direntry = dirents.back();
- direntry.d_ino = 0; // TODO(binji): Is this needed?
+ direntry.d_ino = 1; // Must be > 0.
direntry.d_off = sizeof(struct dirent);
direntry.d_reclen = sizeof(struct dirent);
strncpy(direntry.d_name, file_name, file_name_length);
@@ -138,33 +143,40 @@ int MountNodeHtml5Fs::GetDents(size_t offs, struct dirent* pdir, size_t size) {
size -= size % sizeof(struct dirent);
size_t max = dirents.size() * sizeof(struct dirent);
- if (offs >= max) return 0;
- if (offs + size >= max) size = max - offs;
+ if (offs >= max)
+ return 0;
+
+ if (offs + size >= max)
+ size = max - offs;
memcpy(pdir, reinterpret_cast<char*>(dirents.data()) + offs, size);
+ *out_bytes = size;
return 0;
}
-int MountNodeHtml5Fs::GetStat(struct stat* stat) {
+Error MountNodeHtml5Fs::GetStat(struct stat* stat) {
AutoLock lock(&lock_);
PP_FileInfo info;
- int32_t result = mount_->ppapi()->GetFileIoInterface()->Query(
- fileio_resource_, &info, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ int32_t result = mount_->ppapi()->GetFileRefInterface()->Query(
+ fileref_resource_, &info, PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
// Fill in known info here.
memcpy(stat, &stat_, sizeof(stat_));
// Fill in the additional info from ppapi.
switch (info.type) {
- case PP_FILETYPE_REGULAR: stat->st_mode |= S_IFREG; break;
- case PP_FILETYPE_DIRECTORY: stat->st_mode |= S_IFDIR; break;
+ case PP_FILETYPE_REGULAR:
+ stat->st_mode |= S_IFREG;
+ break;
+ case PP_FILETYPE_DIRECTORY:
+ stat->st_mode |= S_IFDIR;
+ break;
case PP_FILETYPE_OTHER:
- default: break;
+ default:
+ break;
}
stat->st_size = static_cast<off_t>(info.size);
stat->st_atime = info.last_access_time;
@@ -174,78 +186,107 @@ int MountNodeHtml5Fs::GetStat(struct stat* stat) {
return 0;
}
-int MountNodeHtml5Fs::Read(size_t offs, void* buf, size_t count) {
- int32_t result = mount_->ppapi()->GetFileIoInterface()->Read(
- fileio_resource_, offs, static_cast<char*>(buf),
- static_cast<int32_t>(count),
- PP_BlockUntilComplete());
- if (result < 0) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+Error MountNodeHtml5Fs::Read(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ if (IsDirectory())
+ return EISDIR;
- return result;
+ int32_t result =
+ mount_->ppapi()->GetFileIoInterface()->Read(fileio_resource_,
+ offs,
+ static_cast<char*>(buf),
+ static_cast<int32_t>(count),
+ PP_BlockUntilComplete());
+ if (result < 0)
+ return PPErrorToErrno(result);
+
+ *out_bytes = result;
+ return 0;
}
-int MountNodeHtml5Fs::FTruncate(off_t size) {
- int32_t result = mount_->ppapi()->GetFileIoInterface()->SetLength(
- fileio_resource_, size, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+Error MountNodeHtml5Fs::FTruncate(off_t size) {
+ if (IsDirectory())
+ return EISDIR;
+ int32_t result = mount_->ppapi()->GetFileIoInterface()
+ ->SetLength(fileio_resource_, size, PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
return 0;
}
-int MountNodeHtml5Fs::Write(size_t offs, const void* buf, size_t count) {
- int32_t result = mount_->ppapi()->GetFileIoInterface()->Write(
- fileio_resource_, offs, static_cast<const char*>(buf),
- static_cast<int32_t>(count), PP_BlockUntilComplete());
- if (result < 0) {
- errno = PPErrorToErrno(result);
- return -1;
- }
-
- return result;
+Error MountNodeHtml5Fs::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ if (IsDirectory())
+ return EISDIR;
+
+ int32_t result = mount_->ppapi()->GetFileIoInterface()
+ ->Write(fileio_resource_,
+ offs,
+ static_cast<const char*>(buf),
+ static_cast<int32_t>(count),
+ PP_BlockUntilComplete());
+ if (result < 0)
+ return PPErrorToErrno(result);
+
+ *out_bytes = result;
+ return 0;
}
-size_t MountNodeHtml5Fs::GetSize() {
+Error MountNodeHtml5Fs::GetSize(size_t* out_size) {
+ *out_size = 0;
+
AutoLock lock(&lock_);
PP_FileInfo info;
- int32_t result = mount_->ppapi()->GetFileIoInterface()->Query(
- fileio_resource_, &info, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ int32_t result = mount_->ppapi()->GetFileIoInterface()
+ ->Query(fileio_resource_, &info, PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
- return static_cast<size_t>(info.size);
+ *out_size = static_cast<size_t>(info.size);
+ return 0;
}
MountNodeHtml5Fs::MountNodeHtml5Fs(Mount* mount, PP_Resource fileref_resource)
: MountNode(mount),
fileref_resource_(fileref_resource),
- fileio_resource_(0) {
-}
-
-bool MountNodeHtml5Fs::Init(int perm) {
- if (!MountNode::Init(Mount::OpenModeToPermission(perm)))
- return false;
-
- fileio_resource_= mount_->ppapi()->GetFileIoInterface()->Create(
- mount_->ppapi()->GetInstance());
+ fileio_resource_(0) {}
+
+Error MountNodeHtml5Fs::Init(int perm) {
+ Error error = MountNode::Init(Mount::OpenModeToPermission(perm));
+ if (error)
+ return error;
+
+ // 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());
+ // If this is a directory, do not get a FileIO.
+ if (file_info.type == PP_FILETYPE_DIRECTORY)
+ return 0;
+
+ fileio_resource_ = mount_->ppapi()->GetFileIoInterface()
+ ->Create(mount_->ppapi()->GetInstance());
if (!fileio_resource_)
- return false;
+ return ENOSYS;
- int32_t open_result = mount_->ppapi()->GetFileIoInterface()->Open(
- fileio_resource_, fileref_resource_, ModeToOpenFlags(perm),
- PP_BlockUntilComplete());
+ int32_t open_result =
+ mount_->ppapi()->GetFileIoInterface()->Open(fileio_resource_,
+ fileref_resource_,
+ ModeToOpenFlags(perm),
+ PP_BlockUntilComplete());
if (open_result != PP_OK)
- return false;
-
- return true;
+ return PPErrorToErrno(open_result);
+ return 0;
}
void MountNodeHtml5Fs::Destroy() {
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h
index 58b4d13d7e..832d3d40ce 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h
@@ -15,25 +15,36 @@ class MountNodeHtml5Fs : public MountNode {
// Normal OS operations on a node (file), can be called by the kernel
// directly so it must lock and unlock appropriately. These functions
// must not be called by the mount.
- virtual int FSync();
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count);
- virtual int GetStat(struct stat* stat);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int FTruncate(off_t size);
- virtual int Write(size_t offs, const void* buf, size_t count);
-
- virtual size_t GetSize();
+ virtual Error FSync();
+ virtual Error GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes);
+ virtual Error GetStat(struct stat* stat);
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ virtual Error FTruncate(off_t size);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
+
+ virtual Error GetSize(size_t *out_size);
protected:
MountNodeHtml5Fs(Mount* mount, PP_Resource fileref);
// Init with standard open flags
- virtual bool Init(int o_mode);
+ virtual Error Init(int o_mode);
virtual void Destroy();
private:
PP_Resource fileref_resource_;
- PP_Resource fileio_resource_;
+ PP_Resource fileio_resource_; // 0 if the file is a directory.
+
+ // Returns true if this node is a directory.
+ bool IsDirectory() const {
+ return !fileio_resource_;
+ }
friend class MountHtml5Fs;
};
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
new file mode 100644
index 0000000000..5005ff48d3
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_http.cc
@@ -0,0 +1,523 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "nacl_io/mount_node_http.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ppapi/c/pp_errors.h>
+
+#include "nacl_io/mount_http.h"
+#include "nacl_io/osinttypes.h"
+
+#if defined(WIN32)
+#define snprintf _snprintf
+#endif
+
+namespace {
+
+// If we're attempting to read a partial request, but the server returns a full
+// request, we need to read all of the data up to the start of our partial
+// request into a dummy buffer. This is the maximum size of that buffer.
+const size_t MAX_READ_BUFFER_SIZE = 64 * 1024;
+const int32_t STATUSCODE_OK = 200;
+const int32_t STATUSCODE_PARTIAL_CONTENT = 206;
+
+StringMap_t ParseHeaders(const char* headers, int32_t headers_length) {
+ enum State {
+ FINDING_KEY,
+ SKIPPING_WHITESPACE,
+ FINDING_VALUE,
+ };
+
+ StringMap_t result;
+ std::string key;
+ std::string value;
+
+ State state = FINDING_KEY;
+ const char* start = headers;
+ for (int i = 0; i < headers_length; ++i) {
+ switch (state) {
+ case FINDING_KEY:
+ if (headers[i] == ':') {
+ // Found key.
+ key.assign(start, &headers[i] - start);
+ key = NormalizeHeaderKey(key);
+ state = SKIPPING_WHITESPACE;
+ }
+ break;
+
+ case SKIPPING_WHITESPACE:
+ if (headers[i] == ' ') {
+ // Found whitespace, keep going...
+ break;
+ }
+
+ // Found a non-whitespace, mark this as the start of the value.
+ start = &headers[i];
+ state = FINDING_VALUE;
+ // Fallthrough to start processing value without incrementing i.
+
+ case FINDING_VALUE:
+ if (headers[i] == '\n') {
+ // Found value.
+ value.assign(start, &headers[i] - start);
+ result[key] = value;
+ start = &headers[i + 1];
+ state = FINDING_KEY;
+ }
+ break;
+ }
+ }
+
+ return result;
+}
+
+bool ParseContentLength(const StringMap_t& headers, size_t* content_length) {
+ StringMap_t::const_iterator iter = headers.find("Content-Length");
+ if (iter == headers.end())
+ return false;
+
+ *content_length = strtoul(iter->second.c_str(), NULL, 10);
+ return true;
+}
+
+bool ParseContentRange(const StringMap_t& headers,
+ size_t* read_start,
+ size_t* read_end,
+ size_t* entity_length) {
+ StringMap_t::const_iterator iter = headers.find("Content-Range");
+ if (iter == headers.end())
+ return false;
+
+ // The key should look like "bytes ##-##/##" or "bytes ##-##/*". The last
+ // value is the entity length, which can potentially be * (i.e. unknown).
+ int read_start_int;
+ int read_end_int;
+ int entity_length_int;
+ int result = sscanf(iter->second.c_str(),
+ "bytes %" SCNuS "-%" SCNuS "/%" SCNuS,
+ &read_start_int,
+ &read_end_int,
+ &entity_length_int);
+
+ // The Content-Range header specifies an inclusive range: e.g. the first ten
+ // bytes is "bytes 0-9/*". Convert it to a half-open range by incrementing
+ // read_end.
+ if (result == 2) {
+ *read_start = read_start_int;
+ *read_end = read_end_int + 1;
+ *entity_length = 0;
+ return true;
+ } else if (result == 3) {
+ *read_start = read_start_int;
+ *read_end = read_end_int + 1;
+ *entity_length = entity_length_int;
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+void MountNodeHttp::SetCachedSize(off_t size) {
+ has_cached_size_ = true;
+ stat_.st_size = size;
+}
+
+Error MountNodeHttp::FSync() { return ENOSYS; }
+
+Error MountNodeHttp::GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+ return ENOSYS;
+}
+
+Error MountNodeHttp::GetStat(struct stat* stat) {
+ AutoLock lock(&lock_);
+
+ // Assume we need to 'HEAD' if we do not know the size, otherwise, assume
+ // that the information is constant. We can add a timeout if needed.
+ MountHttp* mount = static_cast<MountHttp*>(mount_);
+ if (stat_.st_size == 0 || !mount->cache_stat_) {
+ StringMap_t headers;
+ PP_Resource loader;
+ PP_Resource request;
+ PP_Resource response;
+ int32_t statuscode;
+ StringMap_t response_headers;
+ Error error = OpenUrl("HEAD",
+ &headers,
+ &loader,
+ &request,
+ &response,
+ &statuscode,
+ &response_headers);
+ if (error)
+ return error;
+
+ ScopedResource scoped_loader(mount_->ppapi(), loader);
+ ScopedResource scoped_request(mount_->ppapi(), request);
+ ScopedResource scoped_response(mount_->ppapi(), response);
+
+ size_t entity_length;
+ if (ParseContentLength(response_headers, &entity_length)) {
+ SetCachedSize(static_cast<off_t>(entity_length));
+ } else if (cache_content_ && !has_cached_size_) {
+ error = DownloadToCache();
+ // TODO(binji): this error should not be dropped, but it requires a bit
+ // of a refactor of the tests. See crbug.com/245431
+ // if (error)
+ // return error;
+ } else {
+ // Don't use SetCachedSize here -- it is actually unknown.
+ stat_.st_size = 0;
+ }
+
+ stat_.st_atime = 0; // TODO(binji): Use "Last-Modified".
+ stat_.st_mtime = 0;
+ stat_.st_ctime = 0;
+ }
+
+ // Fill the stat structure if provided
+ if (stat)
+ memcpy(stat, &stat_, sizeof(stat_));
+
+ return 0;
+}
+
+Error MountNodeHttp::Read(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ AutoLock lock(&lock_);
+ if (cache_content_) {
+ if (cached_data_.empty()) {
+ Error error = DownloadToCache();
+ if (error)
+ return error;
+ }
+
+ return ReadPartialFromCache(offs, buf, count, out_bytes);
+ }
+
+ return DownloadPartial(offs, buf, count, out_bytes);
+}
+
+Error MountNodeHttp::FTruncate(off_t size) { return ENOSYS; }
+
+Error MountNodeHttp::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ // TODO(binji): support POST?
+ *out_bytes = 0;
+ return ENOSYS;
+}
+
+Error MountNodeHttp::GetSize(size_t* out_size) {
+ *out_size = 0;
+
+ // TODO(binji): This value should be cached properly; i.e. obey the caching
+ // headers returned by the server.
+ AutoLock lock(&lock_);
+ if (!has_cached_size_) {
+ // Even if DownloadToCache fails, the best result we can return is what
+ // was written to stat_.st_size.
+ if (cache_content_) {
+ Error error = DownloadToCache();
+ if (error)
+ return error;
+ }
+ }
+
+ *out_size = stat_.st_size;
+ return 0;
+}
+
+MountNodeHttp::MountNodeHttp(Mount* mount,
+ const std::string& url,
+ bool cache_content)
+ : MountNode(mount),
+ url_(url),
+ cache_content_(cache_content),
+ has_cached_size_(false) {}
+
+Error MountNodeHttp::OpenUrl(const char* method,
+ StringMap_t* request_headers,
+ PP_Resource* out_loader,
+ PP_Resource* out_request,
+ PP_Resource* out_response,
+ int32_t* out_statuscode,
+ StringMap_t* out_response_headers) {
+ // Assume lock_ is already held.
+ PepperInterface* ppapi = mount_->ppapi();
+
+ MountHttp* mount_http = static_cast<MountHttp*>(mount_);
+ ScopedResource request(
+ ppapi, mount_http->MakeUrlRequestInfo(url_, method, request_headers));
+ if (!request.pp_resource())
+ return EINVAL;
+
+ URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
+ URLResponseInfoInterface* response_interface =
+ ppapi->GetURLResponseInfoInterface();
+ VarInterface* var_interface = ppapi->GetVarInterface();
+
+ ScopedResource loader(ppapi, loader_interface->Create(ppapi->GetInstance()));
+ if (!loader.pp_resource())
+ return EINVAL;
+
+ int32_t result = loader_interface->Open(
+ loader.pp_resource(), request.pp_resource(), PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
+
+ ScopedResource response(
+ ppapi, loader_interface->GetResponseInfo(loader.pp_resource()));
+ if (!response.pp_resource())
+ return EINVAL;
+
+ // Get response statuscode.
+ PP_Var statuscode = response_interface->GetProperty(
+ response.pp_resource(), PP_URLRESPONSEPROPERTY_STATUSCODE);
+
+ if (statuscode.type != PP_VARTYPE_INT32)
+ return EINVAL;
+
+ *out_statuscode = statuscode.value.as_int;
+
+ // Only accept OK or Partial Content.
+ if (*out_statuscode != STATUSCODE_OK &&
+ *out_statuscode != STATUSCODE_PARTIAL_CONTENT) {
+ return EINVAL;
+ }
+
+ // Get response headers.
+ PP_Var response_headers_var = response_interface->GetProperty(
+ response.pp_resource(), PP_URLRESPONSEPROPERTY_HEADERS);
+
+ uint32_t response_headers_length;
+ const char* response_headers_str =
+ var_interface->VarToUtf8(response_headers_var, &response_headers_length);
+
+ *out_loader = loader.Release();
+ *out_request = request.Release();
+ *out_response = response.Release();
+ *out_response_headers =
+ ParseHeaders(response_headers_str, response_headers_length);
+
+ return 0;
+}
+
+Error MountNodeHttp::DownloadToCache() {
+ StringMap_t headers;
+ PP_Resource loader;
+ PP_Resource request;
+ PP_Resource response;
+ int32_t statuscode;
+ StringMap_t response_headers;
+ Error error = OpenUrl("GET",
+ &headers,
+ &loader,
+ &request,
+ &response,
+ &statuscode,
+ &response_headers);
+ if (error)
+ return error;
+
+ PepperInterface* ppapi = mount_->ppapi();
+ ScopedResource scoped_loader(ppapi, loader);
+ ScopedResource scoped_request(ppapi, request);
+ ScopedResource scoped_response(ppapi, response);
+
+ size_t content_length = 0;
+ if (ParseContentLength(response_headers, &content_length)) {
+ cached_data_.resize(content_length);
+ int real_size;
+ error = DownloadToBuffer(
+ loader, cached_data_.data(), content_length, &real_size);
+ if (error)
+ return error;
+
+ SetCachedSize(real_size);
+ cached_data_.resize(real_size);
+ return 0;
+ }
+
+ // We don't know how big the file is. Read in chunks.
+ cached_data_.resize(MAX_READ_BUFFER_SIZE);
+ size_t total_bytes_read = 0;
+ size_t bytes_to_read = MAX_READ_BUFFER_SIZE;
+ while (true) {
+ char* buf = cached_data_.data() + total_bytes_read;
+ int bytes_read;
+ error = DownloadToBuffer(loader, buf, bytes_to_read, &bytes_read);
+ if (error)
+ return error;
+
+ total_bytes_read += bytes_read;
+
+ if (bytes_read < bytes_to_read) {
+ SetCachedSize(total_bytes_read);
+ cached_data_.resize(total_bytes_read);
+ return 0;
+ }
+
+ cached_data_.resize(total_bytes_read + bytes_to_read);
+ }
+}
+
+Error MountNodeHttp::ReadPartialFromCache(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ if (offs > cached_data_.size())
+ return EINVAL;
+
+ count = std::min(count, cached_data_.size() - offs);
+ memcpy(buf, &cached_data_.data()[offs], count);
+
+ *out_bytes = count;
+ return 0;
+}
+
+Error MountNodeHttp::DownloadPartial(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ StringMap_t headers;
+
+ char buffer[100];
+ // Range request is inclusive: 0-99 returns 100 bytes.
+ snprintf(&buffer[0],
+ sizeof(buffer),
+ "bytes=%" PRIuS "-%" PRIuS,
+ offs,
+ offs + count - 1);
+ headers["Range"] = buffer;
+
+ PP_Resource loader;
+ PP_Resource request;
+ PP_Resource response;
+ int32_t statuscode;
+ StringMap_t response_headers;
+ Error error = OpenUrl("GET",
+ &headers,
+ &loader,
+ &request,
+ &response,
+ &statuscode,
+ &response_headers);
+ if (error)
+ return error;
+
+ PepperInterface* ppapi = mount_->ppapi();
+ ScopedResource scoped_loader(ppapi, loader);
+ ScopedResource scoped_request(ppapi, request);
+ ScopedResource scoped_response(ppapi, response);
+
+ size_t read_start = 0;
+ if (statuscode == STATUSCODE_OK) {
+ // No partial result, read everything starting from the part we care about.
+ size_t content_length;
+ if (ParseContentLength(response_headers, &content_length)) {
+ if (offs >= content_length)
+ return EINVAL;
+
+ // Clamp count, if trying to read past the end of the file.
+ if (offs + count > content_length) {
+ count = content_length - offs;
+ }
+ }
+ } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) {
+ // Determine from the headers where we are reading.
+ size_t read_end;
+ size_t entity_length;
+ if (ParseContentRange(
+ response_headers, &read_start, &read_end, &entity_length)) {
+ if (read_start > offs || read_start > read_end) {
+ // If this error occurs, the server is returning bogus values.
+ return EINVAL;
+ }
+
+ // Clamp count, if trying to read past the end of the file.
+ count = std::min(read_end - read_start, count);
+ } else {
+ // Partial Content without Content-Range. Assume that the server gave us
+ // exactly what we asked for. This can happen even when the server
+ // returns 200 -- the cache may return 206 in this case, but not modify
+ // the headers.
+ read_start = offs;
+ }
+ }
+
+ if (read_start < offs) {
+ // We aren't yet at the location where we want to start reading. Read into
+ // our dummy buffer until then.
+ size_t bytes_to_read = offs - read_start;
+ if (buffer_.size() < bytes_to_read)
+ buffer_.resize(std::min(bytes_to_read, MAX_READ_BUFFER_SIZE));
+
+ while (bytes_to_read > 0) {
+ int32_t bytes_read;
+ Error error =
+ DownloadToBuffer(loader, buffer_.data(), buffer_.size(), &bytes_read);
+ if (error)
+ return error;
+
+ bytes_to_read -= bytes_read;
+ }
+ }
+
+ return DownloadToBuffer(loader, buf, count, out_bytes);
+}
+
+Error MountNodeHttp::DownloadToBuffer(PP_Resource loader,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ PepperInterface* ppapi = mount_->ppapi();
+ URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
+
+ char* out_buffer = static_cast<char*>(buf);
+ size_t bytes_to_read = count;
+ while (bytes_to_read > 0) {
+ int32_t bytes_read = loader_interface->ReadResponseBody(
+ loader, out_buffer, bytes_to_read, PP_BlockUntilComplete());
+
+ if (bytes_read == 0) {
+ // This is not an error -- it may just be that we were trying to read
+ // more data than exists.
+ *out_bytes = count - bytes_to_read;
+ return 0;
+ }
+
+ if (bytes_read < 0)
+ return PPErrorToErrno(bytes_read);
+
+ assert(bytes_read <= bytes_to_read);
+ bytes_to_read -= bytes_read;
+ out_buffer += bytes_read;
+ }
+
+ *out_bytes = count;
+ return 0;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_http.h b/native_client_sdk/src/libraries/nacl_io/mount_node_http.h
new file mode 100644
index 0000000000..6b174681d1
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_http.h
@@ -0,0 +1,70 @@
+/* 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_NODE_HTTP_H_
+#define LIBRARIES_NACL_IO_MOUNT_NODE_HTTP_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "nacl_io/error.h"
+#include "nacl_io/mount_node.h"
+#include "nacl_io/pepper_interface.h"
+
+typedef std::map<std::string, std::string> StringMap_t;
+
+class MountNodeHttp : public MountNode {
+ public:
+ virtual Error FSync();
+ virtual Error GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes);
+ virtual Error GetStat(struct stat* stat);
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ virtual Error FTruncate(off_t size);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
+ virtual Error GetSize(size_t* out_size);
+
+ void SetCachedSize(off_t size);
+
+ protected:
+ MountNodeHttp(Mount* mount, const std::string& url, bool cache_content);
+
+ private:
+ Error OpenUrl(const char* method,
+ StringMap_t* request_headers,
+ PP_Resource* out_loader,
+ PP_Resource* out_request,
+ PP_Resource* out_response,
+ int32_t* out_statuscode,
+ StringMap_t* out_response_headers);
+
+ Error DownloadToCache();
+ Error ReadPartialFromCache(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes);
+ Error DownloadPartial(size_t offs, void* buf, size_t count, int* out_bytes);
+ Error DownloadToBuffer(PP_Resource loader,
+ void* buf,
+ size_t count,
+ int* out_bytes);
+
+ std::string url_;
+ std::vector<char> buffer_;
+
+ bool cache_content_;
+ bool has_cached_size_;
+ std::vector<char> cached_data_;
+
+ friend class MountHttp;
+};
+
+#endif // LIBRARIES_NACL_IO_MOUNT_NODE_HTTP_H_
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 0fa82baeba..d324079700 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
@@ -8,74 +8,88 @@
#include <string.h>
#include "nacl_io/osstat.h"
-#include "utils/auto_lock.h"
+#include "sdk_util/auto_lock.h"
#define BLOCK_SIZE (1 << 16)
#define BLOCK_MASK (BLOCK_SIZE - 1)
-MountNodeMem::MountNodeMem(Mount *mount)
- : MountNode(mount),
- data_(NULL),
- capacity_(0) {
+MountNodeMem::MountNodeMem(Mount* mount)
+ : MountNode(mount), data_(NULL), capacity_(0) {
stat_.st_mode |= S_IFREG;
}
-MountNodeMem::~MountNodeMem() {
- free(data_);
-}
+MountNodeMem::~MountNodeMem() { free(data_); }
+
+Error MountNodeMem::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
-int MountNodeMem::Read(size_t offs, void *buf, size_t count) {
AutoLock lock(&lock_);
- if (count == 0) return 0;
- if (offs + count > GetSize()) {
- count = GetSize() - offs;
+ if (count == 0)
+ return 0;
+
+ size_t size = stat_.st_size;
+
+ if (offs + count > size) {
+ count = size - offs;
}
memcpy(buf, &data_[offs], count);
- return static_cast<int>(count);
+ *out_bytes = static_cast<int>(count);
+ return 0;
}
-int MountNodeMem::Write(size_t offs, const void *buf, size_t count) {
+Error MountNodeMem::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
AutoLock lock(&lock_);
- if (count == 0) return 0;
+ if (count == 0)
+ return 0;
+
+ if (count + offs > stat_.st_size) {
+ Error error = FTruncate(count + offs);
+ if (error)
+ return error;
- if (count + offs > GetSize()) {
- FTruncate(count + offs);
- count = GetSize() - offs;
+ count = stat_.st_size - offs;
}
memcpy(&data_[offs], buf, count);
- return static_cast<int>(count);
+ *out_bytes = static_cast<int>(count);
+ return 0;
}
-int MountNodeMem::FTruncate(off_t size) {
- size_t need = (size + BLOCK_MASK) & ~BLOCK_MASK;
+Error MountNodeMem::FTruncate(off_t new_size) {
+ size_t need = (new_size + BLOCK_MASK) & ~BLOCK_MASK;
+ size_t old_size = stat_.st_size;
// If the current capacity is correct, just adjust and return
if (need == capacity_) {
- stat_.st_size = static_cast<off_t>(size);
+ stat_.st_size = static_cast<off_t>(new_size);
return 0;
}
// Attempt to realloc the block
- char *newdata = static_cast<char *>(realloc(data_, need));
+ char* newdata = static_cast<char*>(realloc(data_, need));
if (newdata != NULL) {
// Zero out new space.
- if (size > GetSize())
- memset(newdata + GetSize(), 0, size - GetSize());
+ if (new_size > old_size)
+ memset(newdata + old_size, 0, new_size - old_size);
data_ = newdata;
capacity_ = need;
- stat_.st_size = static_cast<off_t>(size);
+ stat_.st_size = static_cast<off_t>(new_size);
return 0;
}
// If we failed, then adjust size according to what we keep
- if (size > capacity_) size = capacity_;
+ if (new_size > capacity_)
+ new_size = capacity_;
// Update the size and return the new size
- stat_.st_size = static_cast<off_t>(size);
- errno = EIO;
- return -1;
+ stat_.st_size = static_cast<off_t>(new_size);
+ return EIO;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_mem.h b/native_client_sdk/src/libraries/nacl_io/mount_node_mem.h
index 07acfe16d7..6457014293 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_mem.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_mem.h
@@ -16,9 +16,12 @@ class MountNodeMem : public MountNode {
public:
// Normal read/write operations on a file
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
- virtual int FTruncate(off_t size);
+ 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);
+ virtual Error FTruncate(off_t size);
private:
char* data_;
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 82660d68ea..268cbea7a5 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
@@ -9,14 +9,10 @@
class MountNodePassthrough : public MountNode {
public:
explicit MountNodePassthrough(Mount* mount, int real_fd)
- : MountNode(mount),
- real_fd_(real_fd) {
- }
+ : MountNode(mount), real_fd_(real_fd) {}
protected:
- virtual bool Init(int flags) {
- return true;
- }
+ virtual Error Init(int flags) { return 0; }
virtual void Destroy() {
if (real_fd_)
@@ -26,77 +22,74 @@ class MountNodePassthrough : public MountNode {
public:
// Normal read/write operations on a file
- virtual int Read(size_t offs, void* buf, size_t count) {
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+
off_t new_offset;
int err = _real_lseek(real_fd_, offs, 0, &new_offset);
- if (err) {
- errno = err;
- return -1;
- }
+ if (err)
+ return err;
size_t nread;
err = _real_read(real_fd_, buf, count, &nread);
- if (err) {
- errno = err;
- return -1;
- }
+ if (err)
+ return err;
- return static_cast<int>(nread);
+ *out_bytes = static_cast<int>(nread);
+ return 0;
}
- virtual int Write(size_t offs, const void* buf, size_t count) {
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
off_t new_offset;
int err = _real_lseek(real_fd_, offs, 0, &new_offset);
- if (err) {
- errno = err;
- return -1;
- }
+ if (err)
+ return err;
size_t nwrote;
err = _real_write(real_fd_, buf, count, &nwrote);
- if (err) {
- errno = err;
- return -1;
- }
+ if (err)
+ return err;
- return static_cast<int>(nwrote);
+ *out_bytes = static_cast<int>(nwrote);
+ return 0;
}
- virtual int FTruncate(off_t size) {
+ virtual Error FTruncate(off_t size) {
// TODO(binji): what to do here?
- return -1;
+ return ENOSYS;
}
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count) {
+ virtual Error GetDents(size_t offs, struct dirent* pdir, size_t count) {
size_t nread;
int err = _real_getdents(real_fd_, pdir, count, &nread);
- if (err) {
- errno = err;
- return -1;
- }
-
+ if (err)
+ return err;
return nread;
}
- virtual int GetStat(struct stat* stat) {
+ virtual Error GetStat(struct stat* stat) {
int err = _real_fstat(real_fd_, stat);
- if (err) {
- errno = err;
- return -1;
- }
-
+ if (err)
+ return err;
return 0;
}
- void* MMap(void* addr, size_t length, int prot, int flags, size_t offset) {
- void* new_addr = addr;
- int err = _real_mmap(&new_addr, length, prot, flags, real_fd_, offset);
- if (err) {
- errno = err;
- return (void*)-1;
- }
-
- return new_addr;
+ Error MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr) {
+ *out_addr = addr;
+ int err = _real_mmap(out_addr, length, prot, flags, real_fd_, offset);
+ if (err)
+ return err;
+ return 0;
}
private:
@@ -105,70 +98,56 @@ class MountNodePassthrough : public MountNode {
int real_fd_;
};
-MountPassthrough::MountPassthrough() {
-}
+MountPassthrough::MountPassthrough() {}
-bool MountPassthrough::Init(int dev, StringMap_t& args,
- PepperInterface* ppapi) {
- Mount::Init(dev, args, ppapi);
- return true;
+Error MountPassthrough::Init(int dev,
+ StringMap_t& args,
+ PepperInterface* ppapi) {
+ return Mount::Init(dev, args, ppapi);
}
-void MountPassthrough::Destroy() {
-}
+void MountPassthrough::Destroy() {}
+
+Error MountPassthrough::Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = NULL;
-MountNode *MountPassthrough::Open(const Path& path, int mode) {
int real_fd;
- int err = _real_open(path.Join().c_str(), mode, 0666, &real_fd);
- if (err) {
- errno = err;
- return NULL;
- }
+ int error = _real_open(path.Join().c_str(), mode, 0666, &real_fd);
+ if (error)
+ return error;
MountNodePassthrough* node = new MountNodePassthrough(this, real_fd);
- return node;
+ *out_node = node;
+ return 0;
}
-MountNode *MountPassthrough::OpenResource(const Path& path) {
+Error MountPassthrough::OpenResource(const Path& path, MountNode** out_node) {
+ *out_node = NULL;
+
int real_fd;
- int err = _real_open_resource(path.Join().c_str(), &real_fd);
- if (err) {
- errno = err;
- return NULL;
- }
+ int error = _real_open_resource(path.Join().c_str(), &real_fd);
+ if (error)
+ return error;
MountNodePassthrough* node = new MountNodePassthrough(this, real_fd);
- return node;
+ *out_node = node;
+ return 0;
}
-int MountPassthrough::Unlink(const Path& path) {
+Error MountPassthrough::Unlink(const Path& path) {
// Not implemented by NaCl.
- errno = ENOSYS;
- return -1;
+ return ENOSYS;
}
-int MountPassthrough::Mkdir(const Path& path, int perm) {
- int err = _real_mkdir(path.Join().c_str(), perm);
- if (err) {
- errno = err;
- return -1;
- }
-
- return 0;
+Error MountPassthrough::Mkdir(const Path& path, int perm) {
+ return _real_mkdir(path.Join().c_str(), perm);
}
-int MountPassthrough::Rmdir(const Path& path) {
- int err = _real_rmdir(path.Join().c_str());
- if (err) {
- errno = err;
- return -1;
- }
-
- return 0;
+Error MountPassthrough::Rmdir(const Path& path) {
+ return _real_rmdir(path.Join().c_str());
}
-int MountPassthrough::Remove(const Path& path) {
+Error MountPassthrough::Remove(const Path& path) {
// Not implemented by NaCl.
- errno = ENOSYS;
- return -1;
+ 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 00a0eec98f..b143abf007 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
@@ -11,16 +11,16 @@ class MountPassthrough : public Mount {
protected:
MountPassthrough();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
public:
- virtual MountNode *Open(const Path& path, int mode);
- virtual MountNode *OpenResource(const Path& path);
- virtual int Unlink(const Path& path);
- virtual int Mkdir(const Path& path, int perm);
- virtual int Rmdir(const Path& path);
- virtual int Remove(const Path& path);
+ virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error OpenResource(const Path& path, MountNode** 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;
diff --git a/native_client_sdk/src/libraries/nacl_io/nacl_io.h b/native_client_sdk/src/libraries/nacl_io/nacl_io.h
index f9343538ca..b408bb9385 100644
--- a/native_client_sdk/src/libraries/nacl_io/nacl_io.h
+++ b/native_client_sdk/src/libraries/nacl_io/nacl_io.h
@@ -9,7 +9,7 @@
#include <ppapi/c/ppb.h>
#include "nacl_io/kernel_wrap.h"
-#include "utils/macros.h"
+#include "sdk_util/macros.h"
EXTERN_C_BEGIN
diff --git a/native_client_sdk/src/libraries/nacl_io/nacl_mounts.vcproj b/native_client_sdk/src/libraries/nacl_io/nacl_mounts.vcproj
index 875a16f99f..d57c84fbaa 100644
--- a/native_client_sdk/src/libraries/nacl_io/nacl_mounts.vcproj
+++ b/native_client_sdk/src/libraries/nacl_io/nacl_mounts.vcproj
@@ -41,7 +41,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="../win;../utils"
+ AdditionalIncludeDirectories="../win;../sdk_util"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="true"
BasicRuntimeChecks="3"
diff --git a/native_client_sdk/src/libraries/nacl_io/osdirent.h b/native_client_sdk/src/libraries/nacl_io/osdirent.h
index 22dcd616f9..39a3b957bb 100644
--- a/native_client_sdk/src/libraries/nacl_io/osdirent.h
+++ b/native_client_sdk/src/libraries/nacl_io/osdirent.h
@@ -8,7 +8,7 @@
#if defined(WIN32)
#include <sys/types.h>
-#include "utils/macros.h"
+#include "sdk_util/macros.h"
struct dirent {
_ino_t d_ino;
diff --git a/native_client_sdk/src/libraries/nacl_io/path.h b/native_client_sdk/src/libraries/nacl_io/path.h
index 7ac41f2f25..fcbaa33d67 100644
--- a/native_client_sdk/src/libraries/nacl_io/path.h
+++ b/native_client_sdk/src/libraries/nacl_io/path.h
@@ -8,7 +8,7 @@
#include <string>
#include <vector>
-#include "utils/macros.h"
+#include "sdk_util/macros.h"
typedef std::vector<std::string> StringArray_t;
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h b/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
index 679573607d..5bab3b23c4 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
@@ -39,12 +39,14 @@ BEGIN_INTERFACE(FileIoInterface, PPB_FileIO, PPB_FILEIO_INTERFACE_1_0)
const char*, int32_t, PP_CompletionCallback)
END_INTERFACE(FileIoInterface, PPB_FileIO)
-BEGIN_INTERFACE(FileRefInterface, PPB_FileRef, PPB_FILEREF_INTERFACE_1_0)
+BEGIN_INTERFACE(FileRefInterface, PPB_FileRef, PPB_FILEREF_INTERFACE_1_1)
METHOD2(FileRefInterface, PP_Resource, Create, PP_Resource, const char*)
METHOD2(FileRefInterface, int32_t, Delete, PP_Resource, PP_CompletionCallback)
METHOD1(FileRefInterface, PP_Var, GetName, PP_Resource)
METHOD3(FileRefInterface, int32_t, MakeDirectory, PP_Resource, PP_Bool,
PP_CompletionCallback)
+ METHOD3(FileRefInterface, int32_t, Query, PP_Resource, PP_FileInfo*,
+ PP_CompletionCallback)
METHOD3(FileRefInterface, int32_t, ReadDirectoryEntries, PP_Resource,
const PP_ArrayOutput&, PP_CompletionCallback)
END_INTERFACE(FileRefInterface, PPB_FileRef)
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface.h b/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
index 512fd6fdbf..31915a4e76 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
@@ -21,7 +21,7 @@
#include <ppapi/c/ppb_url_response_info.h>
#include <ppapi/c/ppb_var.h>
-#include <utils/macros.h>
+#include <sdk_util/macros.h>
// Note: To add a new interface:
//
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 a47ed63744..df934a56a2 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/example.dsc
+++ b/native_client_sdk/src/libraries/nacl_io_test/example.dsc
@@ -1,5 +1,4 @@
{
- # TODO(binji): pnacl doesn't build right now because gtest doesn't build yet.
'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'],
# Need to add ../../examples for common.js
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 268c6f51a6..9e6f4832a7 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
@@ -23,22 +23,21 @@ namespace {
class MountRefMock : public Mount {
public:
MountRefMock(int* mount_count, int* handle_count)
- : mount_count(mount_count),
- handle_count(handle_count) {
+ : mount_count(mount_count), handle_count(handle_count) {
(*mount_count)++;
}
- ~MountRefMock() {
- (*mount_count)--;
- }
+ ~MountRefMock() { (*mount_count)--; }
public:
- MountNode* Open(const Path& path, int mode) { return NULL; }
- int Close(MountNode* node) { return 0; }
- int Unlink(const Path& path) { return 0; }
- int Mkdir(const Path& path, int permissions) { return 0; }
- int Rmdir(const Path& path) { return 0; }
- int Remove(const Path& path) { return 0; }
+ Error Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = 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;
@@ -47,8 +46,8 @@ class MountRefMock : public Mount {
class KernelHandleRefMock : public KernelHandle {
public:
- KernelHandleRefMock(Mount* mnt, MountNode* node, int flags)
- : KernelHandle(mnt, node, flags) {
+ KernelHandleRefMock(Mount* mnt, MountNode* node)
+ : KernelHandle(mnt, node) {
MountRefMock* mock_mount = static_cast<MountRefMock*>(mnt);
(*mock_mount->handle_count)++;
}
@@ -61,9 +60,7 @@ class KernelHandleRefMock : public KernelHandle {
class KernelObjectTest : public ::testing::Test {
public:
- KernelObjectTest()
- : mount_count(0),
- handle_count(0) {
+ KernelObjectTest() : mount_count(0), handle_count(0) {
proxy = new KernelObject;
mnt = new MountRefMock(&mount_count, &handle_count);
}
@@ -81,10 +78,10 @@ class KernelObjectTest : public ::testing::Test {
} // namespace
-
TEST_F(KernelObjectTest, Referencing) {
- KernelHandle* handle = new KernelHandleRefMock(mnt, NULL, 0);
- KernelHandle* handle2 = new KernelHandleRefMock(mnt, NULL, 0);
+ KernelHandle* handle = new KernelHandleRefMock(mnt, NULL);
+ KernelHandle* handle2 = new KernelHandleRefMock(mnt, NULL);
+ KernelHandle* result_handle = NULL;
// Objects should have one ref when we start
EXPECT_EQ(1, mnt->RefCount());
@@ -111,14 +108,16 @@ TEST_F(KernelObjectTest, Referencing) {
EXPECT_EQ(2, fd3);
// We should find the handle by either fd
- EXPECT_EQ(handle, proxy->AcquireHandle(fd1));
- EXPECT_EQ(handle, proxy->AcquireHandle(fd2));
+ 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(NULL, proxy->AcquireHandle(-1));
- EXPECT_EQ(EBADF, errno);
- EXPECT_EQ(NULL, proxy->AcquireHandle(100));
- EXPECT_EQ(EBADF, errno);
+ 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());
@@ -155,27 +154,35 @@ TEST_F(KernelObjectTest, Referencing) {
}
TEST_F(KernelObjectTest, FreeAndReassignFD) {
+ KernelHandle* result_handle = NULL;
+
EXPECT_EQ(0, handle_count);
- KernelHandle* handle = new KernelHandleRefMock(mnt, NULL, 0);
+ 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((KernelHandle*)NULL, proxy->AcquireHandle(0));
- EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(1));
- EXPECT_EQ(handle, proxy->AcquireHandle(2));
+ 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(handle, proxy->AcquireHandle(0));
- EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(1));
- EXPECT_EQ(handle, proxy->AcquireHandle(2));
+ 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);
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 d6816535e4..40f4ef7a15 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
@@ -21,11 +21,9 @@
#include "gtest/gtest.h"
-
class KernelProxyTest : public ::testing::Test {
public:
- KernelProxyTest()
- : kp_(new KernelProxy) {
+ KernelProxyTest() : kp_(new KernelProxy) {
ki_init(kp_);
// Unmount the passthrough FS and mount a memfs.
EXPECT_EQ(0, kp_->umount("/"));
@@ -41,7 +39,6 @@ class KernelProxyTest : public ::testing::Test {
KernelProxy* kp_;
};
-
TEST_F(KernelProxyTest, WorkingDirectory) {
char text[1024];
@@ -50,7 +47,7 @@ TEST_F(KernelProxyTest, WorkingDirectory) {
EXPECT_STREQ("/", text);
char* alloc = ki_getwd(NULL);
- EXPECT_EQ((char *) NULL, alloc);
+ EXPECT_EQ((char*)NULL, alloc);
EXPECT_EQ(EFAULT, errno);
text[0] = 0;
@@ -113,7 +110,8 @@ TEST_F(KernelProxyTest, MemMountIO) {
EXPECT_NE(-1, fd3);
len = ki_read(fd3, text, sizeof(text));
- if (len > -0) text[len] = 0;
+ if (len > 0)
+ text[len] = 0;
EXPECT_EQ(5, len);
EXPECT_STREQ("HELLO", text);
EXPECT_EQ(0, ki_close(fd1));
@@ -124,7 +122,8 @@ TEST_F(KernelProxyTest, MemMountIO) {
EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
len = ki_read(fd3, text, sizeof(text));
- if (len >= 0) text[len] = 0;
+ if (len >= 0)
+ text[len] = 0;
EXPECT_EQ(5, len);
EXPECT_STREQ("WORLD", text);
@@ -132,7 +131,8 @@ TEST_F(KernelProxyTest, MemMountIO) {
fd2 = ki_open("/foo/bar", O_RDONLY);
EXPECT_NE(-1, fd2);
len = ki_read(fd2, text, sizeof(text));
- if (len > 0) text[len] = 0;
+ if (len > 0)
+ text[len] = 0;
EXPECT_EQ(10, len);
EXPECT_STREQ("HELLOWORLD", text);
}
@@ -197,17 +197,17 @@ TEST_F(KernelProxyTest, MemMountDup) {
// fd, new_fd, dup_fd -> "/bar"
}
-
StringMap_t g_StringMap;
class MountMockInit : public MountMem {
public:
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
g_StringMap = args;
if (args.find("false") != args.end())
- return false;
- return true;
- };
+ return EINVAL;
+ return 0;
+ }
+ ;
};
class KernelProxyMountMock : public KernelProxy {
@@ -219,10 +219,7 @@ class KernelProxyMountMock : public KernelProxy {
class KernelProxyMountTest : public ::testing::Test {
public:
- KernelProxyMountTest()
- : kp_(new KernelProxyMountMock) {
- ki_init(kp_);
- }
+ KernelProxyMountTest() : kp_(new KernelProxyMountMock) { ki_init(kp_); }
~KernelProxyMountTest() {
ki_uninit();
@@ -245,28 +242,38 @@ TEST_F(KernelProxyMountTest, MountInit) {
EXPECT_EQ("y", g_StringMap["x"]);
}
-
namespace {
int g_MMapCount = 0;
class MountNodeMockMMap : public MountNode {
public:
- MountNodeMockMMap(Mount* mount)
- : MountNode(mount),
- node_mmap_count_(0) {
- Init(0);
+ MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) {
+ EXPECT_EQ(0, Init(0));
}
- virtual void* MMap(void* addr, size_t length, int prot, int flags,
- size_t offset) {
+ virtual Error MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr) {
node_mmap_count_++;
switch (g_MMapCount++) {
- case 0: return reinterpret_cast<void*>(0x1000);
- case 1: return reinterpret_cast<void*>(0x2000);
- case 2: return reinterpret_cast<void*>(0x3000);
- default: return MAP_FAILED;
+ case 0:
+ *out_addr = reinterpret_cast<void*>(0x1000);
+ break;
+ case 1:
+ *out_addr = reinterpret_cast<void*>(0x2000);
+ break;
+ case 2:
+ *out_addr = reinterpret_cast<void*>(0x3000);
+ break;
+ default:
+ return EPERM;
}
+
+ return 0;
}
private:
@@ -275,16 +282,20 @@ class MountNodeMockMMap : public MountNode {
class MountMockMMap : public Mount {
public:
- virtual MountNode* Open(const Path& path, int mode) {
+ virtual Error Open(const Path& path, int mode, MountNode** out_node) {
MountNodeMockMMap* node = new MountNodeMockMMap(this);
- return node;
+ *out_node = node;
+ return 0;
}
- virtual MountNode* OpenResource(const Path& path) { return NULL; }
- virtual int Unlink(const Path& path) { return -1; }
- virtual int Mkdir(const Path& path, int permissions) { return -1; }
- virtual int Rmdir(const Path& path) { return -1; }
- virtual int Remove(const Path& path) { return -1; }
+ virtual Error OpenResource(const Path& path, MountNode** out_node) {
+ *out_node = 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; }
};
class KernelProxyMockMMap : public KernelProxy {
@@ -296,10 +307,7 @@ class KernelProxyMockMMap : public KernelProxy {
class KernelProxyMMapTest : public ::testing::Test {
public:
- KernelProxyMMapTest()
- : kp_(new KernelProxyMockMMap) {
- ki_init(kp_);
- }
+ KernelProxyMMapTest() : kp_(new KernelProxyMockMMap) { ki_init(kp_); }
~KernelProxyMMapTest() {
ki_uninit();
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 f6f010c84d..34d8472ff2 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
@@ -81,6 +81,10 @@ class KernelWrapTest : public ::testing::Test {
.WillOnce(Return(0))
.WillOnce(Return(1))
.WillOnce(Return(2));
+ // And will call mount / and /dev.
+ EXPECT_CALL(mock, mount(_, _, _, _, _))
+ .WillOnce(Return(0))
+ .WillOnce(Return(0));
ki_init(&mock);
}
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 ce3ab2d3c9..e92a20aa5d 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
@@ -3,6 +3,7 @@
* found in the LICENSE file.
*/
+#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <gmock/gmock.h>
@@ -93,7 +94,7 @@ class MountHtml5FsNodeTest : public MountHtml5FsTest {
virtual void SetUp();
virtual void TearDown();
- void SetUpNodeExpectations();
+ void SetUpNodeExpectations(PP_FileType file_type);
void InitFilesystem();
void InitNode();
@@ -131,22 +132,32 @@ void MountHtml5FsNodeTest::TearDown() {
}
}
-void MountHtml5FsNodeTest::SetUpNodeExpectations() {
+void MountHtml5FsNodeTest::SetUpNodeExpectations(PP_FileType file_type) {
// Open.
EXPECT_CALL(*fileref_, Create(filesystem_resource_, StrEq(&path_[0])))
.WillOnce(Return(fileref_resource_));
- EXPECT_CALL(*fileio_, Create(instance_)).WillOnce(Return(fileio_resource_));
- int32_t open_flags = PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE |
- PP_FILEOPENFLAG_CREATE;
- EXPECT_CALL(*fileio_,
- Open(fileio_resource_, fileref_resource_, open_flags, _))
- .WillOnce(Return(int32_t(PP_OK)));
+ PP_FileInfo info;
+ memset(&info, 0, sizeof(PP_FileInfo));
+ info.type = file_type;
+ EXPECT_CALL(*fileref_, Query(fileref_resource_, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(info),
+ Return(int32_t(PP_OK))));
+ if (file_type != PP_FILETYPE_DIRECTORY) {
+ EXPECT_CALL(*fileio_, Create(instance_)).WillOnce(Return(fileio_resource_));
+ int32_t open_flags = PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE |
+ PP_FILEOPENFLAG_CREATE;
+ EXPECT_CALL(*fileio_,
+ Open(fileio_resource_, fileref_resource_, open_flags, _))
+ .WillOnce(Return(int32_t(PP_OK)));
+
+ // Close.
+ EXPECT_CALL(*fileio_, Close(fileio_resource_));
+ EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource_));
+ EXPECT_CALL(*fileio_, Flush(fileio_resource_, _));
+ }
// Close.
- EXPECT_CALL(*fileio_, Close(fileio_resource_));
EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource_));
- EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource_));
- EXPECT_CALL(*fileio_, Flush(fileio_resource_, _));
}
void MountHtml5FsNodeTest::InitFilesystem() {
@@ -155,7 +166,7 @@ void MountHtml5FsNodeTest::InitFilesystem() {
}
void MountHtml5FsNodeTest::InitNode() {
- node_ = mnt_->Open(Path(path_), O_CREAT | O_RDWR);
+ ASSERT_EQ(0, mnt_->Open(Path(path_), O_CREAT | O_RDWR, &node_));
ASSERT_NE((MountNode*)NULL, node_);
}
@@ -163,17 +174,34 @@ void MountHtml5FsNodeTest::InitNode() {
// creation of the mount blocks until the filesystem is ready.
class MountHtml5FsNodeSyncTest : public MountHtml5FsNodeTest {
public:
+ void SetUpForFileType(PP_FileType file_type);
+
virtual void SetUp();
};
-void MountHtml5FsNodeSyncTest::SetUp() {
+void MountHtml5FsNodeSyncTest::SetUpForFileType(PP_FileType file_type) {
MountHtml5FsNodeTest::SetUp();
SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
InitFilesystem();
- SetUpNodeExpectations();
+ SetUpNodeExpectations(file_type);
InitNode();
}
+void MountHtml5FsNodeSyncTest::SetUp() {
+ SetUpForFileType(PP_FILETYPE_REGULAR);
+}
+
+// Node test where the filesystem is opened synchronously, and the node is a
+// directory.
+class MountHtml5FsNodeSyncDirTest : public MountHtml5FsNodeSyncTest {
+ public:
+ virtual void SetUp();
+};
+
+void MountHtml5FsNodeSyncDirTest::SetUp() {
+ SetUpForFileType(PP_FILETYPE_DIRECTORY);
+}
+
void ReadDirectoryEntriesAction(const PP_ArrayOutput& output) {
const int fileref_resource_1 = 238;
const int fileref_resource_2 = 239;
@@ -224,7 +252,7 @@ void MountHtml5FsNodeAsyncTest::SetUp() {
// true => asynchronous filesystem open.
SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0, true);
InitFilesystem();
- SetUpNodeExpectations();
+ SetUpNodeExpectations(PP_FILETYPE_REGULAR);
// Signal the other thread to try opening a Node.
pthread_mutex_lock(&mutex_);
@@ -350,7 +378,8 @@ TEST_F(MountHtml5FsNodeSyncTest, Write) {
EXPECT_CALL(*fileio_, Write(fileio_resource_, offset, &buffer[0], count, _))
.WillOnce(Return(count));
- int result = node_->Write(offset, &buffer, count);
+ int result = 0;
+ EXPECT_EQ(0, node_->Write(offset, &buffer, count, &result));
EXPECT_EQ(count, result);
}
@@ -362,7 +391,8 @@ TEST_F(MountHtml5FsNodeSyncTest, Read) {
EXPECT_CALL(*fileio_, Read(fileio_resource_, offset, &buffer[0], count, _))
.WillOnce(Return(count));
- int result = node_->Read(offset, &buffer, count);
+ int result = 0;
+ EXPECT_EQ(0, node_->Read(offset, &buffer, count, &result));
EXPECT_EQ(count, result);
}
@@ -380,7 +410,7 @@ TEST_F(MountHtml5FsNodeSyncTest, GetStat) {
info.last_access_time = access_time;
info.last_modified_time = modified_time;
- EXPECT_CALL(*fileio_, Query(fileio_resource_, _, _))
+ EXPECT_CALL(*fileref_, Query(fileref_resource_, _, _))
.WillOnce(DoAll(SetArgPointee<1>(info),
Return(int32_t(PP_OK))));
@@ -405,6 +435,76 @@ TEST_F(MountHtml5FsNodeSyncTest, FTruncate) {
}
TEST_F(MountHtml5FsNodeSyncTest, GetDents) {
+ struct dirent dirents[2];
+ memset(&dirents[0], 0, sizeof(dirents));
+
+ // Should fail for regular files.
+ int result_bytes = 0;
+ EXPECT_EQ(ENOTDIR, node_->GetDents(0, &dirents[0], sizeof(dirent) * 2,
+ &result_bytes));
+ ASSERT_EQ(0, result_bytes);
+}
+
+TEST_F(MountHtml5FsNodeSyncDirTest, OpenAndClose) {
+}
+
+TEST_F(MountHtml5FsNodeSyncDirTest, Write) {
+ const int offset = 10;
+ const int count = 20;
+ const char buffer[30] = {0};
+
+ // Should fail for directories.
+ int result_bytes = 0;
+ EXPECT_EQ(EISDIR, node_->Write(offset, &buffer, count, &result_bytes));
+ ASSERT_EQ(0, result_bytes);
+}
+
+TEST_F(MountHtml5FsNodeSyncDirTest, Read) {
+ const int offset = 10;
+ const int count = 20;
+ char buffer[30] = {0};
+
+ // Should fail for directories.
+ int result_bytes = 0;
+ EXPECT_EQ(EISDIR, node_->Read(offset, &buffer, count, &result_bytes));
+ ASSERT_EQ(0, result_bytes);
+}
+
+TEST_F(MountHtml5FsNodeSyncDirTest, GetStat) {
+ const int creation_time = 1000;
+ const int access_time = 2000;
+ const int modified_time = 3000;
+
+ PP_FileInfo info;
+ info.size = 0;
+ info.type = PP_FILETYPE_DIRECTORY;
+ info.system_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
+ info.creation_time = creation_time;
+ info.last_access_time = access_time;
+ info.last_modified_time = modified_time;
+
+ EXPECT_CALL(*fileref_, Query(fileref_resource_, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(info),
+ Return(int32_t(PP_OK))));
+
+ struct stat statbuf;
+ int result = node_->GetStat(&statbuf);
+
+ EXPECT_EQ(0, result);
+ EXPECT_EQ(S_IFDIR | S_IWRITE | S_IREAD, statbuf.st_mode);
+ EXPECT_EQ(0, statbuf.st_size);
+ EXPECT_EQ(access_time, statbuf.st_atime);
+ EXPECT_EQ(modified_time, statbuf.st_mtime);
+ EXPECT_EQ(creation_time, statbuf.st_ctime);
+}
+
+TEST_F(MountHtml5FsNodeSyncDirTest, FTruncate) {
+ const int size = 123;
+ // Should fail for directories.
+ EXPECT_EQ(EISDIR, node_->FTruncate(size));
+}
+
+TEST_F(MountHtml5FsNodeSyncDirTest, GetDents) {
const int fileref_resource_1 = 238;
const int fileref_resource_2 = 239;
@@ -441,9 +541,20 @@ TEST_F(MountHtml5FsNodeSyncTest, GetDents) {
struct dirent dirents[2];
memset(&dirents[0], 0, sizeof(dirents));
- int result = node_->GetDents(0, &dirents[0], sizeof(dirent) * 2);
-
- EXPECT_EQ(0, result);
- EXPECT_STREQ(&fileref_name_cstr_1[0], &dirents[0].d_name[0]);
- EXPECT_STREQ(&fileref_name_cstr_2[0], &dirents[1].d_name[0]);
+ // +2 to test a size that is not a multiple of sizeof(dirent).
+ // Expect it to round down.
+ int result_bytes = 0;
+ EXPECT_EQ(
+ 0,
+ node_->GetDents(0, &dirents[0], sizeof(dirent) * 2 + 2, &result_bytes));
+
+ ASSERT_EQ(sizeof(dirent) * 2, result_bytes);
+ EXPECT_LT(0, dirents[0].d_ino); // 0 is an invalid inode number.
+ EXPECT_EQ(sizeof(dirent), dirents[0].d_off);
+ EXPECT_EQ(sizeof(dirent), dirents[0].d_reclen);
+ EXPECT_STREQ(fileref_name_cstr_1, dirents[0].d_name);
+ EXPECT_LT(0, dirents[1].d_ino); // 0 is an invalid inode number.
+ EXPECT_EQ(sizeof(dirent), dirents[1].d_off);
+ 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 350874d34d..ced8d06a6c 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
@@ -29,7 +29,7 @@ using ::testing::StrEq;
class MountHttpMock : public MountHttp {
public:
MountHttpMock(StringMap_t map, PepperInterfaceMock* ppapi) {
- EXPECT_TRUE(Init(1, map, ppapi));
+ EXPECT_EQ(0, Init(1, map, ppapi));
}
~MountHttpMock() {
@@ -71,25 +71,34 @@ TEST_F(MountHttpTest, MountEmpty) {
TEST_F(MountHttpTest, ParseManifest) {
StringMap_t args;
+ size_t result_size = 0;
+
mnt_ = new MountHttpMock(args, &ppapi_);
char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
- EXPECT_TRUE(mnt_->ParseManifest(manifest));
+ EXPECT_EQ(0, mnt_->ParseManifest(manifest));
- MountNodeDir* root = mnt_->FindOrCreateDir(Path("/"));
+ MountNodeDir* root = NULL;
+ EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/"), &root));
+ ASSERT_NE((MountNode*)NULL, root);
EXPECT_EQ(2, root->ChildCount());
- MountNodeDir* dir = mnt_->FindOrCreateDir(Path("/mydir"));
+ MountNodeDir* dir = NULL;
+ EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/mydir"), &dir));
+ ASSERT_NE((MountNode*)NULL, dir);
EXPECT_EQ(1, dir->ChildCount());
MountNode* node = mnt_->GetMap()["/mydir/foo"];
- EXPECT_TRUE(node);
- EXPECT_EQ(123, node->GetSize());
+ 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 = mnt_->Open(Path("/mydir/foo"), O_RDONLY);
- MountNode* bar = mnt_->Open(Path("/thatdir/bar"), O_RDWR);
+ MountNode* foo = NULL;
+ EXPECT_EQ(0, mnt_->Open(Path("/mydir/foo"), O_RDONLY, &foo));
+ MountNode* bar = NULL;
+ EXPECT_EQ(0, mnt_->Open(Path("/thatdir/bar"), O_RDWR, &bar));
struct stat sfoo;
struct stat sbar;
@@ -248,7 +257,7 @@ void MountHttpNodeTest::SetResponseBody(const char* body) {
}
void MountHttpNodeTest::OpenNode() {
- node_ = mnt_->Open(Path(path_), O_RDONLY);
+ ASSERT_EQ(0, mnt_->Open(Path(path_), O_RDONLY, &node_));
ASSERT_NE((MountNode*)NULL, node_);
}
@@ -266,7 +275,9 @@ void MountHttpNodeTest::TearDown() {
delete mnt_;
}
-TEST_F(MountHttpNodeTest, OpenAndClose) {
+TEST_F(MountHttpNodeTest, OpenAndCloseNoCache) {
+ StringMap_t smap;
+ smap["cache_content"] = "false";
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -275,6 +286,9 @@ TEST_F(MountHttpNodeTest, OpenAndClose) {
}
TEST_F(MountHttpNodeTest, ReadCached) {
+ size_t result_size = 0;
+ int result_bytes = 0;
+
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -282,7 +296,8 @@ TEST_F(MountHttpNodeTest, ReadCached) {
OpenNode();
ResetMocks();
- EXPECT_EQ(42, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(42, result_size);
char buf[10];
memset(&buf[0], 0, sizeof(buf));
@@ -291,20 +306,24 @@ TEST_F(MountHttpNodeTest, ReadCached) {
ExpectHeaders("");
SetResponse(200, "Content-Length: 42\n");
SetResponseBody("Here is some response text. And some more.");
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("Here is s", &buf[0]);
ResetMocks();
// Further reads should be cached.
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("Here is s", &buf[0]);
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("me respon", &buf[0]);
- EXPECT_EQ(42, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(42, result_size);
}
TEST_F(MountHttpNodeTest, ReadCachedNoContentLength) {
+ size_t result_size = 0;
+ int result_bytes = 0;
+
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -319,25 +338,30 @@ TEST_F(MountHttpNodeTest, ReadCachedNoContentLength) {
// GetSize will Read() because it didn't get the content length from the HEAD
// request.
- EXPECT_EQ(42, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(42, result_size);
char buf[10];
memset(&buf[0], 0, sizeof(buf));
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("Here is s", &buf[0]);
ResetMocks();
// Further reads should be cached.
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("Here is s", &buf[0]);
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("me respon", &buf[0]);
- EXPECT_EQ(42, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(42, result_size);
}
TEST_F(MountHttpNodeTest, ReadCachedUnderrun) {
+ size_t result_size = 0;
+ int result_bytes = 0;
+
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -345,7 +369,8 @@ TEST_F(MountHttpNodeTest, ReadCachedUnderrun) {
OpenNode();
ResetMocks();
- EXPECT_EQ(100, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(100, result_size);
char buf[10];
memset(&buf[0], 0, sizeof(buf));
@@ -354,14 +379,19 @@ TEST_F(MountHttpNodeTest, ReadCachedUnderrun) {
ExpectHeaders("");
SetResponse(200, "Content-Length: 100\n");
SetResponseBody("abcdefghijklmnopqrstuvwxyz");
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(sizeof(buf) - 1, result_bytes);
EXPECT_STREQ("abcdefghi", &buf[0]);
ResetMocks();
- EXPECT_EQ(26, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(26, result_size);
}
TEST_F(MountHttpNodeTest, ReadCachedOverrun) {
+ size_t result_size = 0;
+ int result_bytes = 0;
+
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -369,7 +399,8 @@ TEST_F(MountHttpNodeTest, ReadCachedOverrun) {
OpenNode();
ResetMocks();
- EXPECT_EQ(15, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(15, result_size);
char buf[10];
memset(&buf[0], 0, sizeof(buf));
@@ -378,14 +409,18 @@ TEST_F(MountHttpNodeTest, ReadCachedOverrun) {
ExpectHeaders("");
SetResponse(200, "Content-Length: 15\n");
SetResponseBody("01234567890123456789");
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(5, result_bytes);
EXPECT_STREQ("01234", &buf[0]);
ResetMocks();
- EXPECT_EQ(15, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(15, result_size);
}
TEST_F(MountHttpNodeTest, ReadPartial) {
+ int result_bytes = 0;
+
StringMap_t args;
args["cache_content"] = "false";
SetMountArgs(args);
@@ -402,7 +437,8 @@ TEST_F(MountHttpNodeTest, ReadPartial) {
ExpectHeaders("Range: bytes=0-8\n");
SetResponse(206, "Content-Length: 9\nContent-Range: bytes=0-8\n");
SetResponseBody("012345678");
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(sizeof(buf) - 1, result_bytes);
EXPECT_STREQ("012345678", &buf[0]);
ResetMocks();
@@ -411,11 +447,14 @@ TEST_F(MountHttpNodeTest, ReadPartial) {
ExpectHeaders("Range: bytes=10-18\n");
SetResponse(206, "Content-Length: 9\nContent-Range: bytes=10-18\n");
SetResponseBody("abcdefghi");
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(sizeof(buf) - 1, result_bytes);
EXPECT_STREQ("abcdefghi", &buf[0]);
}
TEST_F(MountHttpNodeTest, ReadPartialNoServerSupport) {
+ int result_bytes = 0;
+
StringMap_t args;
args["cache_content"] = "false";
SetMountArgs(args);
@@ -432,6 +471,7 @@ TEST_F(MountHttpNodeTest, ReadPartialNoServerSupport) {
ExpectHeaders("Range: bytes=10-18\n");
SetResponse(200, "Content-Length: 20\n");
SetResponseBody("0123456789abcdefghij");
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(sizeof(buf) - 1, result_bytes);
EXPECT_STREQ("abcdefghi", &buf[0]);
}
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 2de13cd468..bc6fa65ed6 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
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+#include "nacl_io/error.h"
#include "nacl_io/kernel_proxy.h"
#include "nacl_io/mount_node.h"
#include "nacl_io/mount_node_dir.h"
@@ -14,31 +15,25 @@
#include "gtest/gtest.h"
-#define NULL_NODE ((MountNode *) NULL)
+#define NULL_NODE ((MountNode*) NULL)
static int s_AllocNum = 0;
class MockMemory : public MountNodeMem {
public:
- MockMemory() : MountNodeMem(NULL) {
- s_AllocNum++;
- }
+ MockMemory() : MountNodeMem(NULL) { s_AllocNum++; }
- ~MockMemory() {
- s_AllocNum--;
- }
+ ~MockMemory() { s_AllocNum--; }
- bool Init(int mode) {
- return MountNodeMem::Init(mode);
- }
- int AddChild(const std::string& name, MountNode *node) {
+ Error Init(int mode) { return MountNodeMem::Init(mode); }
+ Error AddChild(const std::string& name, MountNode* node) {
return MountNodeMem::AddChild(name, node);
}
- int RemoveChild(const std::string& name) {
+ Error RemoveChild(const std::string& name) {
return MountNodeMem::RemoveChild(name);
}
- MountNode* FindChild(const std::string& name) {
- return MountNodeMem::FindChild(name);
+ Error FindChild(const std::string& name, MountNode** out_node) {
+ return MountNodeMem::FindChild(name, out_node);
}
void Link() { MountNodeMem::Link(); }
void Unlink() { MountNodeMem::Unlink(); }
@@ -49,25 +44,19 @@ class MockMemory : public MountNodeMem {
class MockDir : public MountNodeDir {
public:
- MockDir() : MountNodeDir(NULL) {
- s_AllocNum++;
- }
+ MockDir() : MountNodeDir(NULL) { s_AllocNum++; }
- ~MockDir() {
- s_AllocNum--;
- }
+ ~MockDir() { s_AllocNum--; }
- bool Init(int mode) {
- return MountNodeDir::Init(mode);
- }
- int AddChild(const std::string& name, MountNode *node) {
+ Error Init(int mode) { return MountNodeDir::Init(mode); }
+ Error AddChild(const std::string& name, MountNode* node) {
return MountNodeDir::AddChild(name, node);
}
- int RemoveChild(const std::string& name) {
+ Error RemoveChild(const std::string& name) {
return MountNodeDir::RemoveChild(name);
}
- MountNode* FindChild(const std::string& name) {
- return MountNodeDir::FindChild(name);
+ Error FindChild(const std::string& name, MountNode** out_node) {
+ return MountNodeDir::FindChild(name, out_node);
}
void Link() { MountNodeDir::Link(); }
void Unlink() { MountNodeDir::Unlink(); }
@@ -77,9 +66,12 @@ class MockDir : public MountNodeDir {
};
TEST(MountNodeTest, File) {
- MockMemory *file = new MockMemory;
+ MockMemory* file = new MockMemory;
+ MountNode* result_node = NULL;
+ size_t result_size = 0;
+ int result_bytes = 0;
- EXPECT_TRUE(file->Init(S_IREAD | S_IWRITE));
+ EXPECT_EQ(0, file->Init(S_IREAD | S_IWRITE));
// Test properties
EXPECT_EQ(0, file->GetLinks());
@@ -97,12 +89,18 @@ TEST(MountNodeTest, File) {
buf1[a] = a;
memset(buf2, 0, sizeof(buf2));
- EXPECT_EQ(0, file->GetSize());
- EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2)));
- EXPECT_EQ(0, file->GetSize());
- EXPECT_EQ(sizeof(buf1), file->Write(0, buf1, sizeof(buf1)));
- EXPECT_EQ(sizeof(buf1), file->GetSize());
- EXPECT_EQ(sizeof(buf1), file->Read(0, buf2, sizeof(buf2)));
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(0, result_size);
+ EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes));
+ EXPECT_EQ(0, result_bytes);
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(0, result_size);
+ EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes));
+ EXPECT_EQ(sizeof(buf1), result_bytes);
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(sizeof(buf1), result_size);
+ EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes));
+ EXPECT_EQ(sizeof(buf1), result_bytes);
EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
struct stat s;
@@ -112,20 +110,21 @@ TEST(MountNodeTest, File) {
// Directory operations should fail
struct dirent d;
- EXPECT_EQ(-1, file->GetDents(0, &d, sizeof(d)));
- EXPECT_EQ(errno, ENOTDIR);
- EXPECT_EQ(-1, file->AddChild("", file));
- EXPECT_EQ(errno, ENOTDIR);
- EXPECT_EQ(-1, file->RemoveChild(""));
- EXPECT_EQ(errno, ENOTDIR);
- EXPECT_EQ(NULL_NODE, file->FindChild(""));
- EXPECT_EQ(errno, ENOTDIR);
+ EXPECT_EQ(ENOTDIR, file->GetDents(0, &d, sizeof(d), &result_bytes));
+ EXPECT_EQ(ENOTDIR, file->AddChild("", file));
+ EXPECT_EQ(ENOTDIR, file->RemoveChild(""));
+ EXPECT_EQ(ENOTDIR, file->FindChild("", &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
delete file;
}
TEST(MountNodeTest, Directory) {
- MockDir *root = new MockDir();
+ MockDir* root = new MockDir();
+ MountNode* result_node = NULL;
+ size_t result_size = 0;
+ int result_bytes = 0;
+
root->Init(S_IREAD | S_IWRITE);
// Test properties
@@ -139,15 +138,14 @@ TEST(MountNodeTest, Directory) {
// IO operations should fail
char buf1[1024];
- EXPECT_EQ(0, root->GetSize());
- EXPECT_EQ(-1, root->Read(0, buf1, sizeof(buf1)));
- EXPECT_EQ(errno, EISDIR);
- EXPECT_EQ(-1, root->Write(0, buf1, sizeof(buf1)));
- EXPECT_EQ(errno, EISDIR);
+ EXPECT_EQ(0, root->GetSize(&result_size));
+ EXPECT_EQ(0, result_size);
+ EXPECT_EQ(EISDIR, root->Read(0, buf1, sizeof(buf1), &result_bytes));
+ EXPECT_EQ(EISDIR, root->Write(0, buf1, sizeof(buf1), &result_bytes));
// Test directory operations
MockMemory* file = new MockMemory;
- EXPECT_TRUE(file->Init(S_IREAD | S_IWRITE));
+ EXPECT_EQ(0, file->Init(S_IREAD | S_IWRITE));
EXPECT_EQ(1, root->RefCount());
EXPECT_EQ(1, file->RefCount());
@@ -157,25 +155,28 @@ TEST(MountNodeTest, Directory) {
// Test that the directory is there
struct dirent d;
- EXPECT_EQ(sizeof(d), root->GetDents(0, &d, sizeof(d)));
+ EXPECT_EQ(0, root->GetDents(0, &d, sizeof(d), &result_bytes));
+ EXPECT_EQ(sizeof(d), result_bytes);
EXPECT_LT(0, d.d_ino); // 0 is an invalid inode number.
EXPECT_EQ(sizeof(d), d.d_off);
EXPECT_EQ(sizeof(d), d.d_reclen);
EXPECT_EQ(0, strcmp("F1", d.d_name));
- EXPECT_EQ(0, root->GetDents(sizeof(d), &d, sizeof(d)));
+ EXPECT_EQ(0, root->GetDents(sizeof(d), &d, sizeof(d), &result_bytes));
+ EXPECT_EQ(0, result_bytes);
EXPECT_EQ(0, root->AddChild("F2", file));
EXPECT_EQ(2, file->GetLinks());
EXPECT_EQ(3, file->RefCount());
- EXPECT_EQ(-1, root->AddChild("F1", file));
- EXPECT_EQ(EEXIST, errno);
+ EXPECT_EQ(EEXIST, root->AddChild("F1", file));
EXPECT_EQ(2, file->GetLinks());
EXPECT_EQ(2, s_AllocNum);
- EXPECT_NE(NULL_NODE, root->FindChild("F1"));
- EXPECT_NE(NULL_NODE, root->FindChild("F2"));
- EXPECT_EQ(NULL_NODE, root->FindChild("F3"));
- EXPECT_EQ(errno, ENOENT);
+ EXPECT_EQ(0, root->FindChild("F1", &result_node));
+ EXPECT_NE(NULL_NODE, result_node);
+ EXPECT_EQ(0, root->FindChild("F2", &result_node));
+ EXPECT_NE(NULL_NODE, result_node);
+ EXPECT_EQ(ENOENT, root->FindChild("F3", &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
EXPECT_EQ(2, s_AllocNum);
EXPECT_EQ(0, root->RemoveChild("F1"));
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 1604ccafd3..245d13daf4 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
@@ -22,12 +22,10 @@ class MountMemMock : public MountMem {
public:
MountMemMock() {
StringMap_t map;
- Init(1, map, NULL);
- };
-
- int num_nodes() {
- return (int) inode_pool_.size();
+ EXPECT_EQ(0, Init(1, map, NULL));
}
+
+ int num_nodes() { return (int) inode_pool_.size(); }
};
class MountDevMock : public MountDev {
@@ -36,20 +34,20 @@ class MountDevMock : public MountDev {
StringMap_t map;
Init(1, map, NULL);
}
- int num_nodes() {
- return (int) inode_pool_.size();
- }
+ int num_nodes() { return (int) inode_pool_.size(); }
};
} // namespace
-
-#define NULL_NODE ((MountNode *) NULL)
+#define NULL_NODE ((MountNode*) NULL)
TEST(MountTest, Sanity) {
MountMemMock* mnt = new MountMemMock();
MountNode* file;
MountNode* root;
+ MountNode* result_node;
+ size_t result_size = 0;
+ int result_bytes = 0;
char buf1[1024];
@@ -57,43 +55,54 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(1, mnt->num_nodes());
// Fail to open non existent file
- EXPECT_EQ(NULL_NODE, mnt->Open(Path("/foo"), O_RDWR));
- EXPECT_EQ(errno, ENOENT);
+ EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &result_node));
+ EXPECT_EQ(NULL, result_node);
// Create a file
- file = mnt->Open(Path("/foo"), O_RDWR | O_CREAT);
+ EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &file));
EXPECT_NE(NULL_NODE, file);
- if (file == NULL) return;
+ if (file == NULL)
+ return;
EXPECT_EQ(2, file->RefCount());
EXPECT_EQ(2, mnt->num_nodes());
+ // Open the root directory for write should fail.
+ EXPECT_EQ(EISDIR, mnt->Open(Path("/"), O_RDWR, &root));
+
// Open the root directory
- root = mnt->Open(Path("/"), O_RDWR);
+ EXPECT_EQ(0, mnt->Open(Path("/"), O_RDONLY, &root));
EXPECT_NE(NULL_NODE, root);
if (NULL != root) {
struct dirent dirs[2];
- int len = root->GetDents(0, dirs, sizeof(dirs));
+ int len;
+ EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len));
EXPECT_EQ(sizeof(struct dirent), len);
}
// Fail to re-create the same file
- EXPECT_EQ(NULL_NODE, mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL));
- EXPECT_EQ(errno, EEXIST);
+ EXPECT_EQ(EEXIST,
+ mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
EXPECT_EQ(2, mnt->num_nodes());
// Fail to create a directory with the same name
- EXPECT_EQ(-1, mnt->Mkdir(Path("/foo"), O_RDWR));
- EXPECT_EQ(errno, EEXIST);
+ EXPECT_EQ(EEXIST, mnt->Mkdir(Path("/foo"), O_RDWR));
// Attempt to READ/WRITE
- EXPECT_EQ(0, file->GetSize());
- EXPECT_EQ(sizeof(buf1), file->Write(0, buf1, sizeof(buf1)));
- EXPECT_EQ(sizeof(buf1), file->GetSize());
- EXPECT_EQ(sizeof(buf1), file->Read(0, buf1, sizeof(buf1)));
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(0, result_size);
+ EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes));
+ EXPECT_EQ(sizeof(buf1), result_bytes);
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(sizeof(buf1), result_size);
+ EXPECT_EQ(0, file->Read(0, buf1, sizeof(buf1), &result_bytes));
+ EXPECT_EQ(sizeof(buf1), result_bytes);
// Attempt to open the same file
- EXPECT_EQ(file, mnt->Open(Path("/foo"), O_RDWR | O_CREAT));
- EXPECT_EQ(sizeof(buf1), file->GetSize());
+ 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());
@@ -102,9 +111,8 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(2, mnt->num_nodes());
EXPECT_EQ(0, mnt->Unlink(Path("/foo")));
EXPECT_EQ(2, mnt->num_nodes());
- EXPECT_EQ(-1, mnt->Unlink(Path("/foo")));
+ EXPECT_EQ(ENOENT, mnt->Unlink(Path("/foo")));
EXPECT_EQ(2, mnt->num_nodes());
- EXPECT_EQ(errno, ENOENT);
mnt->ReleaseNode(file);
EXPECT_EQ(1, mnt->num_nodes());
@@ -112,13 +120,13 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(0, mnt->Mkdir(Path("/foo"), O_RDWR));
// Create a file (exclusively)
- file = mnt->Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL);
+ EXPECT_EQ(0, mnt->Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
EXPECT_NE(NULL_NODE, file);
- if (NULL == file) return;
+ if (NULL == file)
+ return;
// Attempt to delete the directory
- EXPECT_EQ(-1, mnt->Rmdir(Path("/foo")));
- EXPECT_EQ(errno, ENOTEMPTY);
+ EXPECT_EQ(ENOTEMPTY, mnt->Rmdir(Path("/foo")));
// Unlink the file, then delete the directory
EXPECT_EQ(0, mnt->Unlink(Path("/foo/bar")));
@@ -128,60 +136,71 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(1, mnt->num_nodes());
// Verify the directory is gone
- file = mnt->Open(Path("/foo"), O_RDWR);
+ EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &file));
EXPECT_EQ(NULL_NODE, file);
- EXPECT_EQ(errno, ENOENT);
}
TEST(MountTest, MemMountRemove) {
MountMemMock* mnt = new MountMemMock();
MountNode* file;
+ MountNode* result_node;
EXPECT_EQ(0, mnt->Mkdir(Path("/dir"), O_RDWR));
- file = mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL);
+ EXPECT_EQ(0, mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
EXPECT_NE(NULL_NODE, file);
mnt->ReleaseNode(file);
EXPECT_EQ(0, mnt->Remove(Path("/dir")));
EXPECT_EQ(0, mnt->Remove(Path("/file")));
- EXPECT_EQ(NULL_NODE, mnt->Open(Path("/dir/foo"), O_CREAT | O_RDWR));
- EXPECT_EQ(ENOENT, errno);
- EXPECT_EQ(NULL_NODE, mnt->Open(Path("/file"), O_RDONLY));
- EXPECT_EQ(ENOENT, errno);
+ EXPECT_EQ(ENOENT,
+ mnt->Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
+ EXPECT_EQ(ENOENT, mnt->Open(Path("/file"), O_RDONLY, &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
}
TEST(MountTest, DevNull) {
MountDevMock* mnt = new MountDevMock();
- MountNode* dev_null = mnt->Open(Path("/null"), O_RDWR);
+ MountNode* dev_null = NULL;
+ int result_bytes = 0;
+
+ ASSERT_EQ(0, mnt->Open(Path("/null"), O_RDWR, &dev_null));
ASSERT_NE(NULL_NODE, dev_null);
// Writing to /dev/null should write everything.
const char msg[] = "Dummy test message.";
- EXPECT_EQ(strlen(msg), dev_null->Write(0, &msg[0], strlen(msg)));
+ EXPECT_EQ(0, dev_null->Write(0, &msg[0], strlen(msg), &result_bytes));
+ EXPECT_EQ(strlen(msg), result_bytes);
// Reading from /dev/null should read nothing.
const int kBufferLength = 100;
char buffer[kBufferLength];
- EXPECT_EQ(0, dev_null->Read(0, &buffer[0], 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 = mnt->Open(Path("/zero"), O_RDWR);
+ MountNode* dev_zero = NULL;
+ int result_bytes = 0;
+
+ ASSERT_EQ(0, mnt->Open(Path("/zero"), O_RDWR, &dev_zero));
ASSERT_NE(NULL_NODE, dev_zero);
// Writing to /dev/zero should write everything.
const char msg[] = "Dummy test message.";
- EXPECT_EQ(strlen(msg), dev_zero->Write(0, &msg[0], strlen(msg)));
+ EXPECT_EQ(0, dev_zero->Write(0, &msg[0], strlen(msg), &result_bytes));
+ EXPECT_EQ(strlen(msg), result_bytes);
// Reading from /dev/zero should read all zeroes.
const int kBufferLength = 100;
char buffer[kBufferLength];
// First fill with all 1s.
memset(&buffer[0], 0x1, kBufferLength);
- EXPECT_EQ(kBufferLength, dev_zero->Read(0, &buffer[0], kBufferLength));
+ EXPECT_EQ(0, dev_zero->Read(0, &buffer[0], kBufferLength, &result_bytes));
+ EXPECT_EQ(kBufferLength, result_bytes);
char zero_buffer[kBufferLength];
memset(&zero_buffer[0], 0, kBufferLength);
@@ -191,12 +210,16 @@ TEST(MountTest, DevZero) {
TEST(MountTest, DevUrandom) {
MountDevMock* mnt = new MountDevMock();
- MountNode* dev_urandom = mnt->Open(Path("/urandom"), O_RDWR);
+ MountNode* dev_urandom = NULL;
+ int result_bytes = 0;
+
+ ASSERT_EQ(0, mnt->Open(Path("/urandom"), O_RDWR, &dev_urandom));
ASSERT_NE(NULL_NODE, dev_urandom);
- // Writing to /dev/zero should write everything.
+ // Writing to /dev/urandom should write everything.
const char msg[] = "Dummy test message.";
- EXPECT_EQ(strlen(msg), dev_urandom->Write(0, &msg[0], strlen(msg)));
+ EXPECT_EQ(0, dev_urandom->Write(0, &msg[0], strlen(msg), &result_bytes));
+ EXPECT_EQ(strlen(msg), result_bytes);
// Reading from /dev/urandom should read random bytes.
const int kSampleBatches = 1000;
@@ -207,7 +230,9 @@ TEST(MountTest, DevUrandom) {
unsigned char buffer[kSampleBatchSize];
for (int batch = 0; batch < kSampleBatches; ++batch) {
- int bytes_read = dev_urandom->Read(0, &buffer[0], kSampleBatchSize);
+ int bytes_read = 0;
+ EXPECT_EQ(0,
+ dev_urandom->Read(0, &buffer[0], kSampleBatchSize, &bytes_read));
EXPECT_EQ(kSampleBatchSize, bytes_read);
for (int i = 0; i < bytes_read; ++i) {
diff --git a/native_client_sdk/src/libraries/ppapi_cpp/library.dsc b/native_client_sdk/src/libraries/ppapi_cpp/library.dsc
index 2914c92a59..e6ffb6c26c 100644
--- a/native_client_sdk/src/libraries/ppapi_cpp/library.dsc
+++ b/native_client_sdk/src/libraries/ppapi_cpp/library.dsc
@@ -18,6 +18,7 @@
'audio.cc',
'audio_config.cc',
'core.cc',
+ 'directory_entry.cc',
'file_io.cc',
'file_ref.cc',
'file_system.cc',
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 50b9201a4d..8646c3a110 100644
--- a/native_client_sdk/src/libraries/ppapi_cpp_private/library.dsc
+++ b/native_client_sdk/src/libraries/ppapi_cpp_private/library.dsc
@@ -12,6 +12,7 @@
'file_io_private.cc',
'host_resolver_private.cc',
'net_address_private.cc',
+ 'pass_file_handle.cc',
'tcp_socket_private.cc',
'tcp_server_socket_private.cc',
'udp_socket_private.cc',
diff --git a/native_client_sdk/src/libraries/ppapi_main/library.dsc b/native_client_sdk/src/libraries/ppapi_main/library.dsc
deleted file mode 100644
index c65e93036f..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/library.dsc
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- 'TOOLS': ['newlib', 'glibc', 'pnacl'],
- 'TARGETS': [
- {
- 'NAME': 'ppapi_main',
- 'TYPE': 'static-lib',
- 'SOURCES' : [
- "ppapi_instance.cc",
- "ppapi_instance2d.cc",
- "ppapi_instance3d.cc",
- "ppapi_main.cc",
- "ppapi_queue.cc",
- ],
- }
- ],
- 'HEADERS': [
- {
- 'FILES': [
- "ppapi_event.h",
- "ppapi_instance.h",
- "ppapi_instance2d.h",
- "ppapi_instance3d.h",
- "ppapi_main.h",
- "ppapi_queue.h",
- ],
- 'DEST': 'include/ppapi_main',
- },
- ],
- 'DEST': 'src',
- 'NAME': 'ppapi_main',
-}
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_event.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_event.h
deleted file mode 100644
index d991192fe6..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_event.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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_MAIN_PPAPI_EVENT_H_
-#define PPAPI_MAIN_PPAPI_EVENT_H_
-
-#include "ppapi/c/pp_input_event.h"
-#include "ppapi/c/pp_point.h"
-#include "ppapi/c/pp_touch_point.h"
-#include "ppapi/c/ppb_input_event.h"
-
-#include "utils/macros.h"
-
-EXTERN_C_BEGIN
-
-/*
- * Event Structures
- *
- * The following event structures are based on the equivalent structs
- * defined in ppapi/c/ppb_input_event.h.
- *
- */
-
-// Generic Event
-typedef struct {
- PP_InputEvent_Type event_type;
- PP_TimeTicks time_ticks;
- uint32_t modifiers;
-} PPAPIEvent;
-
-
-// Key Code Up/Down
-typedef struct {
- PPAPIEvent event;
-
- uint32_t key_code;
-} PPAPIKeyEvent;
-
-
-// Cooked Character Event
-typedef struct {
- PPAPIEvent event;
-
- char text[5];
-} PPAPICharEvent;
-
-
-// Mouse Event
-typedef struct {
- PPAPIEvent event;
-
- PP_InputEvent_MouseButton button;
- struct PP_Point location;
- struct PP_Point delta;
-} PPAPIMouseEvent;
-
-
-// Wheel Event
-typedef struct {
- PPAPIEvent event;
-
- PP_InputEvent_MouseButton button;
- struct PP_FloatPoint delta;
- uint32_t by_page;
-} PPAPIWheelEvent;
-
-
-// Touch Event
-#define MAX_TOUCH_POINTS 4
-typedef struct {
- PPAPIEvent event;
-
- uint32_t point_count;
- struct PP_TouchPoint points[MAX_TOUCH_POINTS];
-} PPAPITouchEvent;
-
-EXTERN_C_END
-
-#endif // PPAPI_MAIN_PPAPI_EVENT_H_
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.cc b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.cc
deleted file mode 100644
index 2816c74817..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.cc
+++ /dev/null
@@ -1,375 +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 <fcntl.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <cstdlib>
-#include <cstring>
-#include <map>
-#include <string>
-#include <vector>
-
-#include "nacl_io/kernel_wrap.h"
-#include "nacl_io/nacl_io.h"
-
-#include "ppapi/cpp/input_event.h"
-#include "ppapi/cpp/message_loop.h"
-#include "ppapi/cpp/rect.h"
-#include "ppapi/cpp/size.h"
-#include "ppapi/cpp/touch_point.h"
-#include "ppapi/cpp/var.h"
-
-#include "ppapi_main/ppapi_event.h"
-#include "ppapi_main/ppapi_instance.h"
-#include "ppapi_main/ppapi_main.h"
-
-
-PPAPIInstance* PPAPI_GetInstance() {
- return static_cast<PPAPIInstance*>(PPAPI_GetInstanceObject());
-}
-
-struct StartInfo {
- PPAPIInstance* inst_;
- uint32_t argc_;
- const char** argv_;
-};
-
-
-//
-// The starting point for 'main'. We create this thread to hide the real
-// main pepper thread which must never be blocked.
-//
-void* PPAPIInstance::MainThreadThunk(void *info) {
- StartInfo* si = static_cast<StartInfo*>(info);
- int ret = si->inst_->MainThread(si->argc_, si->argv_);
-
- printf("Main thread returned with %d.\n", ret);
- for (uint32_t i = 0; i < si->argc_; i++) {
- delete[] si->argv_[i];
- }
- delete[] si->argv_;
- delete si;
-
- return NULL;
-}
-
-//
-// Enabled with pm_use_main=False this creates a second thread where we
-// send all input, view change, buffer swap, etc... messages. This allows us
-// avoid blocking the main pepper thread which would otherwise recieves these
-// messages, and may need to lock to act on them.
-//
-void *PPAPIInstance::EventThreadThunk(void *this_ptr) {
- PPAPIInstance *pInst = static_cast<PPAPIInstance*>(this_ptr);
- return pInst->EventThread();
-}
-
-
-//
-// The default implementation supports running a 'C' main.
-//
-int PPAPIInstance::MainThread(int argc, const char *argv[]) {
- return ppapi_main(argc, argv);
-}
-
-
-//
-// The default implementation just waits to processes forwarded events.
-//
-void* PPAPIInstance::EventThread() {
- render_loop_.AttachToCurrentThread();
- render_loop_.Run();
- printf("Event thread exiting.\n");
- return NULL;
-}
-
-
-PPAPIInstance::PPAPIInstance(PP_Instance instance, const char *args[])
- : pp::Instance(instance),
- main_loop_(this),
- has_focus_(false),
- fullscreen_(this),
- is_context_bound_(false),
- callback_factory_(this),
- use_main_thread_(true),
- render_loop_(this) {
-
- // Place PPAPI_MAIN_USE arguments into properties map
- while (*args) {
- std::string key = *args++;
- std::string val = *args++;
- properties_[key] = val;
- }
-
- RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE |
- PP_INPUTEVENT_CLASS_KEYBOARD |
- PP_INPUTEVENT_CLASS_WHEEL |
- PP_INPUTEVENT_CLASS_TOUCH);
-}
-
-PPAPIInstance::~PPAPIInstance() {}
-
-
-bool PPAPIInstance::Init(uint32_t arg,
- const char* argn[],
- const char* argv[]) {
- StartInfo* si = new StartInfo;
-
-
- si->inst_ = this;
- si->argc_ = 1;
- si->argv_ = new const char *[arg*2+1];
- si->argv_[0] = NULL;
-
- // Process arguments passed into Module INIT from JavaScript
- for (uint32_t i=0; i < arg; i++) {
- if (argv[i]) {
- printf("ARG %s=%s\n", argn[i], argv[i]);
- } else {
- printf("ARG %s\n", argn[i]);
- }
-
- // If we start with PM prefix set the instance argument map
- if (0 == strncmp(argn[i], "pm_", 3)) {
- std::string key = argn[i];
- std::string val = argv[i];
- properties_[key] = val;
- 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;
- }
- }
- }
-
- // If src was not found, set the first arg to something
- if (NULL == si->argv_[0]) {
- char *name = new char[5];
- strcpy(name, "NMF?");
- si->argv_[0] = name;
- }
-
-
- if (ProcessProperties()) {
- pthread_t main_thread;
- int ret = pthread_create(&main_thread, NULL, MainThreadThunk,
- static_cast<void*>(si));
- return ret == 0;
- }
-
- return false;
-}
-
-const char* PPAPIInstance::GetProperty(const char* key, const char* def) {
- PropertyMap_t::iterator it = properties_.find(key);
- if (it != properties_.end()) {
- return it->second.c_str();
- }
- return def;
-}
-
-bool PPAPIInstance::ProcessProperties() {
- const char* stdin_path = GetProperty("pm_stdin", "/dev/stdin");
- const char* stdout_path = GetProperty("pm_stdout", "/dev/stdout");
- const char* stderr_path = GetProperty("pm_stderr", "/dev/console3");
- const char* queue_size = GetProperty("pm_queue_size", "1024");
-
- // Build the event Queue with a minimum size of 4
- uint32_t queue_size_int = atoi(queue_size);
- if (queue_size_int < 4) queue_size_int = 4;
- event_queue_.SetSize(queue_size_int);
-
- // Enable NaCl IO to map STDIN, STDOUT, and STDERR
- nacl_io_init_ppapi(PPAPI_GetInstanceId(), PPAPI_GetInterface);
- int fd0 = open(stdin_path, O_RDONLY);
- dup2(fd0, 0);
-
- int fd1 = open(stdout_path, O_WRONLY);
- dup2(fd1, 1);
-
- int fd2 = open(stderr_path, O_WRONLY);
- dup2(fd2, 2);
-
- setvbuf(stderr, NULL, _IOLBF, 0);
- setvbuf(stdout, NULL, _IOLBF, 0);
-
- const char *use_main_str = GetProperty("pm_use_main", "true");
- use_main_thread_ = !strcasecmp(use_main_str, "true");
-
- // Create seperate thread for processing events.
- printf("Events on main thread = %s.\n", use_main_str);
- if (!use_main_thread_) {
- pthread_t event_thread;
- int ret = pthread_create(&event_thread, NULL, EventThreadThunk,
- static_cast<void*>(this));
- return ret == 0;
- }
- return true;
-}
-
-void PPAPIInstance::HandleMessage(const pp::Var& message) {
-}
-
-bool PPAPIInstance::HandleInputEvent(const pp::InputEvent& event) {
- PPAPIEvent* event_ptr;
-
- // Remove a stale message if one is available
- event_ptr = static_cast<PPAPIEvent*>(event_queue_.RemoveStaleMessage());
- delete event_ptr;
-
- switch (event.GetType()) {
- case PP_INPUTEVENT_TYPE_MOUSEDOWN:
- case PP_INPUTEVENT_TYPE_MOUSEUP:
- case PP_INPUTEVENT_TYPE_MOUSEMOVE:
- case PP_INPUTEVENT_TYPE_MOUSEENTER:
- case PP_INPUTEVENT_TYPE_MOUSELEAVE: {
- pp::MouseInputEvent mouse_event(event);
- PPAPIMouseEvent* mouse_ptr = new PPAPIMouseEvent;
- mouse_ptr->button = mouse_event.GetButton();
- mouse_ptr->location = mouse_event.GetPosition().pp_point();
- mouse_ptr->delta = mouse_event.GetMovement().pp_point();
- event_ptr = &mouse_ptr->event;
- break;
- }
-
- case PP_INPUTEVENT_TYPE_WHEEL: {
- pp::WheelInputEvent wheel_event(event);
- PPAPIWheelEvent* wheel_ptr = new PPAPIWheelEvent;
- wheel_ptr->by_page =
- static_cast<uint32_t>(wheel_event.GetScrollByPage());
- wheel_ptr->delta = wheel_event.GetDelta().pp_float_point();
- event_ptr = &wheel_ptr->event;
- break;
- }
-
- case PP_INPUTEVENT_TYPE_CHAR: {
- pp::KeyboardInputEvent key_event(event);
- PPAPICharEvent* char_ptr = new PPAPICharEvent;
- strncpy(char_ptr->text,
- key_event.GetCharacterText().DebugString().c_str(),
- sizeof(char_ptr->text));
- event_ptr = &char_ptr->event;
- break;
- }
-
- case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
- case PP_INPUTEVENT_TYPE_KEYDOWN:
- case PP_INPUTEVENT_TYPE_KEYUP: {
- pp::KeyboardInputEvent key_event(event);
- PPAPIKeyEvent* key_ptr = new PPAPIKeyEvent;
- key_ptr->key_code = key_event.GetKeyCode();
- event_ptr = &key_ptr->event;
- break;
- }
-
- case PP_INPUTEVENT_TYPE_TOUCHSTART:
- case PP_INPUTEVENT_TYPE_TOUCHMOVE:
- case PP_INPUTEVENT_TYPE_TOUCHEND:
- case PP_INPUTEVENT_TYPE_TOUCHCANCEL: {
- pp::TouchInputEvent touch_event(event);
- PPAPITouchEvent* touch_ptr = new PPAPITouchEvent;
- touch_ptr->point_count =
- touch_event.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES);
- for (uint32_t cnt = 0; cnt < touch_ptr->point_count; cnt++) {
- pp::TouchPoint *pnt = (pp::TouchPoint*) &touch_ptr->points[cnt];
- *pnt = touch_event.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES ,cnt);
- }
- event_ptr = &touch_ptr->event;
- break;
- }
-
- default:
- fprintf(stderr, "Unhandled event type %d\n", event.GetType());
- return false;
- }
-
- event_ptr->event_type = event.GetType();
- event_ptr->time_ticks = event.GetTimeStamp();
- event_ptr->modifiers = event.GetModifiers();
- if (!event_queue_.AddNewMessage(event_ptr)) {
- printf("Warning: Event Queue is full, dropping message.\n");
- }
- return true;
-}
-
-PPAPIEvent* PPAPIInstance::AcquireInputEvent() {
- return static_cast<PPAPIEvent*>(event_queue_.AcquireTopMessage());
-}
-
-void PPAPIInstance::ReleaseInputEvent(PPAPIEvent* event) {
- event_queue_.ReleaseTopMessage(event);
-}
-
-void PPAPIInstance::DidChangeView(const pp::View& view) {
- pp::Size new_size = view.GetRect().size();
- printf("View changed: %dx%d\n", new_size.width(), new_size.height());
-
- // Build or update the 3D context when the view changes.
- if (use_main_thread_) {
- // If using the main thread, update the context immediately
- BuildContext(0, new_size);
- } else {
- // If using a seperate thread, then post the message so we can build the
- // context on the correct thread.
- render_loop_.PostWork(callback_factory_.NewCallback(
- &PPAPIInstance::BuildContext, new_size));
- }
-}
-
-void PPAPIInstance::DidChangeFocus(bool focus) {
- has_focus_ = focus;
-}
-
-bool PPAPIInstance::ToggleFullscreen() {
- // Ignore switch if in transition
- if (!is_context_bound_)
- return false;
-
- if (fullscreen_.IsFullscreen()) {
- if (!fullscreen_.SetFullscreen(false)) {
- printf("Could not leave fullscreen mode\n");
- return false;
- }
- } else {
- if (!fullscreen_.SetFullscreen(true)) {
- printf("Could not enter fullscreen mode\n");
- return false;
- }
- }
- return true;
-}
-
-// The default implementation calls the 'C' render function.
-void PPAPIInstance::Render(PP_Resource ctx, uint32_t width, uint32_t height) {
-}
-
-void PPAPIInstance::Flushed(int32_t result) {
-}
-
-void PPAPIInstance::BuildContext(int32_t result, const pp::Size& new_size) {
- size_ = new_size;
- printf("Resized: %dx%d.\n", size_.width(), size_.height());
-}
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.h
deleted file mode 100644
index 1172cd8c45..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance.h
+++ /dev/null
@@ -1,106 +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 PPAPI_MAIN_PPAPI_INSTANCE_H_
-#define PPAPI_MAIN_PPAPI_INSTANCE_H_
-
-#include <map>
-
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/cpp/fullscreen.h"
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/message_loop.h"
-#include "ppapi/cpp/mouse_lock.h"
-
-#include "ppapi/utility/completion_callback_factory.h"
-
-#include "ppapi_main/ppapi_event.h"
-#include "ppapi_main/ppapi_queue.h"
-
-
-typedef std::map<std::string, std::string> PropertyMap_t;
-
-class PPAPIInstance : public pp::Instance {
- public:
- PPAPIInstance(PP_Instance instance, const char *args[]);
- virtual ~PPAPIInstance();
-
- //
- // Callback functions triggered by Pepepr
- //
-
- // Called by the browser when the NaCl module is loaded and all ready to go.
- virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
-
- // Called whenever the in-browser window changes size.
- virtual void DidChangeView(const pp::View& view);
-
- // Called by the browser when the NaCl canvas gets or loses focus.
- virtual void DidChangeFocus(bool has_focus);
-
- // Called by the browser to handle the postMessage() call in Javascript.
- virtual void HandleMessage(const pp::Var& message);
-
- // Called by the browser to handle incoming input events.
- virtual bool HandleInputEvent(const pp::InputEvent& event);
-
- // Called when the graphics flush completes
- virtual void Flushed(int result);
-
- // Called when we need to rebuild the Graphics device context. This usually
- // happens as a result of DidChangeView.
- virtual void BuildContext(int32_t result, const pp::Size& new_size);
-
- // Called with the current graphics context, current size and width, when
- // the application is ready to render, either due to a newly build
- // Context, or a successful Flush of the previous frame.
- virtual void Render(PP_Resource ctx, uint32_t width, uint32_t height);
-
- //
- // Thread entry points
- //
- virtual int MainThread(int argc, const char* argv[]);
- virtual void* EventThread();
-
- //
- // Request API
- //
- bool ToggleFullscreen();
- virtual PPAPIEvent* AcquireInputEvent();
- virtual void ReleaseInputEvent(PPAPIEvent* event);
- static PPAPIInstance* GetInstance();
-
- protected:
- // Called to run ppapi_main.
- static void* MainThreadThunk(void *start_info);
-
- // Called if message processing and rendering happens off the main thread.
- static void* EventThreadThunk(void *this_ptr);
-
- // Called by Init to processes default and embed tag arguments prior to
- // launching the 'ppapi_main' thread.
- virtual bool ProcessProperties();
-
- // Returns value based on KEY or default.
- const char* GetProperty(const char* key, const char* def = NULL);
-
- protected:
- pp::MessageLoop main_loop_;
- pp::Fullscreen fullscreen_;
- pp::MessageLoop render_loop_;
- pp::CompletionCallbackFactory<PPAPIInstance> callback_factory_;
-
- PropertyMap_t properties_;
- PPAPIQueue event_queue_;
-
- pp::Size size_;
- bool has_focus_;
- bool is_context_bound_;
- bool was_fullscreen_;
- bool mouse_locked_;
- bool use_main_thread_;
-};
-
-
-#endif // PPAPI_MAIN_PPAPI_INSTANCE_H_
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance2d.cc b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance2d.cc
deleted file mode 100644
index f6e54be62e..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance2d.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdio.h>
-
-#include "ppapi/cpp/graphics_2d.h"
-#include "ppapi/cpp/message_loop.h"
-#include "ppapi/cpp/size.h"
-#include "ppapi/cpp/var.h"
-
-#include "ppapi/utility/completion_callback_factory.h"
-
-#include "ppapi_main/ppapi_instance2d.h"
-#include "ppapi_main/ppapi_main.h"
-
-
-void* PPAPI_CreateInstance2D(PP_Instance inst, const char *args[]) {
- return static_cast<void*>(new PPAPIInstance2D(inst, args));
-}
-
-
-PPAPIInstance2D* PPAPIInstance2D::GetInstance2D() {
- return static_cast<PPAPIInstance2D*>(PPAPI_GetInstanceObject());
-}
-
-
-void PPAPIInstance2D::Flushed(int result) {
- if (result != 0) {
- printf("Flush result=%d.\n", result);
- }
-
- if (is_context_bound_) {
- Render(device_context_.pp_resource(), size_.width(), size_.height());
-
- int result;
- result = device_context_.Flush(callback_factory_.NewCallback(
- &PPAPIInstance::Flushed));
- if (result == PP_OK_COMPLETIONPENDING) return;
- printf("Failed Flush with %d.\n", result);
- }
-
- // Failed to draw, so add a callback for the future. This could
- // an application choice or the browser dealing with an event such as
- // fullscreen toggle. We add a delay of 100ms (to prevent burnning CPU
- // in cases where the context will not be available for a while.
- pp::MessageLoop::GetCurrent().PostWork(callback_factory_.NewCallback(
- &PPAPIInstance::Flushed), 100);
-}
-
-void PPAPIInstance2D::BuildContext(int32_t result, const pp::Size& new_size) {
- printf("Building context.\n");
-
- size_ = new_size;
- device_context_ = pp::Graphics2D(this, size_ ,true);
- printf("Got Context!\n");
-
- is_context_bound_ = BindGraphics(device_context_);
- printf("Context is bound=%d\n", is_context_bound_);
-
- if (is_context_bound_) {
- PPAPIBuildContext(size_.width(), size_.height());
- device_context_.Flush(callback_factory_.NewCallback(
- &PPAPIInstance::Flushed));
- } else {
- fprintf(stderr, "Failed to bind context for %dx%d.\n", size_.width(),
- size_.height());
- }
-}
-
-// The default implementation calls the 'C' render function.
-void PPAPIInstance2D::Render(PP_Resource ctx, uint32_t width,
- uint32_t height) {
- PPAPIRender(ctx, width, height);
-}
-
-PPAPIInstance2D::PPAPIInstance2D(PP_Instance instance, const char *args[])
- : PPAPIInstance(instance, args) {
-}
-
-
-PPAPIInstance2D::~PPAPIInstance2D() {
- if (is_context_bound_) {
- is_context_bound_ = false;
- // Cleanup code?
- }
-}
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance2d.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance2d.h
deleted file mode 100644
index ac600c2c27..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance2d.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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_MAIN_PPAPI_INSTANCE2D_H_
-#define PPAPI_MAIN_PPAPI_INSTANCE2D_H_
-
-#include "ppapi/c/pp_instance.h"
-
-#include "ppapi/cpp/graphics_2d.h"
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/size.h"
-
-#include "ppapi_main/ppapi_instance.h"
-
-
-class PPAPIInstance2D : public PPAPIInstance {
- public:
- PPAPIInstance2D(PP_Instance instance, const char *args[]);
- virtual ~PPAPIInstance2D();
-
- // Called when we need to rebuild the context
- virtual void BuildContext(int32_t result, const pp::Size& new_size);
-
- // Called whenever a swap takes place
- virtual void Flushed(int result);
-
- virtual void Render(PP_Resource ctx, uint32_t width, uint32_t height);
- static PPAPIInstance2D* GetInstance2D();
-
- protected:
- pp::Graphics2D device_context_;
-};
-
-
-#endif // PPAPI_MAIN_PPAPI_INSTANCE2D_H_
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.cc b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.cc
deleted file mode 100644
index 43cad475d3..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.cc
+++ /dev/null
@@ -1,144 +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 <stdio.h>
-
-#include "GLES2/gl2.h"
-
-#include "ppapi/cpp/graphics_3d.h"
-#include "ppapi/cpp/size.h"
-#include "ppapi/gles2/gl2ext_ppapi.h"
-#include "ppapi/utility/completion_callback_factory.h"
-
-#include "ppapi_main/ppapi_instance.h"
-#include "ppapi_main/ppapi_instance3d.h"
-#include "ppapi_main/ppapi_main.h"
-
-
-void* PPAPI_CreateInstance3D(PP_Instance inst, const char *args[]) {
- return static_cast<void*>(new PPAPIInstance3D(inst, args));
-}
-
-
-int32_t *PPAPIGet3DAttribs(uint32_t width, uint32_t height) {
- static int32_t attribs[] = {
- PP_GRAPHICS3DATTRIB_WIDTH, 0,
- PP_GRAPHICS3DATTRIB_HEIGHT, 0,
- PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
- PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
- PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8,
- PP_GRAPHICS3DATTRIB_SAMPLES, 0,
- PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
- PP_GRAPHICS3DATTRIB_NONE
- };
-
- attribs[1] = width;
- attribs[3] = height;
-
- printf("Building attribs for %dx%d.\n", width, height);
- return attribs;
-}
-
-void PPAPIBuildContext(uint32_t width, uint32_t height) {
- glViewport(0, 0, width, height);
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- printf("Built Context %d, %d.\n", width, height);
-}
-
-
-PPAPIInstance3D* PPAPIInstance3D::GetInstance3D() {
- return static_cast<PPAPIInstance3D*>(PPAPI_GetInstanceObject());
-}
-
-void PPAPIInstance3D::Flushed(int result) {
- if (result != 0) {
- printf("Swapped result=%d.\n", result);
- }
-
- if (is_context_bound_) {
- Render(device_context_.pp_resource(), size_.width(), size_.height());
-
- int result;
- result = device_context_.SwapBuffers(callback_factory_.NewCallback(
- &PPAPIInstance::Flushed));
- if (result == PP_OK_COMPLETIONPENDING) return;
- printf("Failed swap with %d.\n", result);
- }
-
- // Failed to draw, so add a callback for the future. This could
- // an application choice or the browser dealing with an event such as
- // fullscreen toggle. We add a delay of 100ms (to prevent burnning CPU
- // in cases where the context will not be available for a while.
- pp::MessageLoop::GetCurrent().PostWork(callback_factory_.NewCallback(
- &PPAPIInstance::Flushed), 100);
-}
-
-void PPAPIInstance3D::BuildContext(int32_t result, const pp::Size& new_size) {
- printf("Building context.\n");
-
- // If already bound, try to resize to avoid the need to rebuild the context.
- if (is_context_bound_) {
- // If the size is correct, then just skip this request.
- if (new_size == size_) {
- printf("Skipped building context, same size as bound.\n");
- return;
- }
- int err = device_context_.ResizeBuffers(new_size.width(),
- new_size.height());
-
- // Resized the context, we are done
- if (err == PP_OK) {
- size_ = new_size;
- fprintf(stderr, "Resized context from %dx%d to %dx%d",
- size_.width(), size_.height(), new_size.width(),
- new_size.height());
- PPAPIBuildContext(size_.width(), size_.height());
- return;
- }
-
- // Failed to resize, fall through and start from scratch
- fprintf(stderr, "Failed to resize buffer from %dx%d to %dx%d",
- size_.width(), size_.height(), new_size.width(), new_size.height());
-
- is_context_bound_ = false;
- }
-
- printf("Calling create context....\n");
- size_ = new_size;
- device_context_ = pp::Graphics3D(this, PPAPIGet3DAttribs(size_.width(),
- size_.height()));
- printf("Got Context!\n");
- is_context_bound_ = BindGraphics(device_context_);
- printf("Context is bound=%d\n", is_context_bound_);
-
- // Set the context regardless to make sure we have a valid one
- glSetCurrentContextPPAPI(device_context_.pp_resource());
- if (is_context_bound_) {
- PPAPIBuildContext(size_.width(), size_.height());
- device_context_.SwapBuffers(callback_factory_.NewCallback(
- &PPAPIInstance::Flushed));
- } else {
- fprintf(stderr, "Failed to bind context for %dx%d.\n", size_.width(),
- size_.height());
- }
-}
-
-// The default implementation calls the 'C' render function.
-void PPAPIInstance3D::Render(PP_Resource ctx, uint32_t width,
- uint32_t height) {
- PPAPIRender(ctx, width, height);
-}
-
-PPAPIInstance3D::PPAPIInstance3D(PP_Instance instance, const char *args[])
- : PPAPIInstance(instance, args) {
- glInitializePPAPI(pp::Module::Get()->get_browser_interface());
-}
-
-
-PPAPIInstance3D::~PPAPIInstance3D() {
- if (is_context_bound_) {
- is_context_bound_ = false;
- // Cleanup code?
- }
-}
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.h
deleted file mode 100644
index 410b952170..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_instance3d.h
+++ /dev/null
@@ -1,40 +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 PPAPI_MAIN_PPAPI_INSTANCE3D_H_
-#define PPAPI_MAIN_PPAPI_INSTANCE3D_H_
-
-#include <map>
-
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_resource.h"
-
-#include "ppapi/cpp/graphics_3d.h"
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/size.h"
-
-#include "ppapi_main/ppapi_instance.h"
-
-
-class PPAPIInstance3D : public PPAPIInstance {
- public:
- PPAPIInstance3D(PP_Instance instance, const char *args[]);
- virtual ~PPAPIInstance3D();
-
- // Called when we need to rebuild the context
- virtual void BuildContext(int32_t result, const pp::Size& new_size);
-
- // Called whenever a swap takes place
- virtual void Flushed(int result);
-
- virtual void Render(PP_Resource ctx, uint32_t width, uint32_t height);
- static PPAPIInstance3D* GetInstance3D();
-
- protected:
- pp::Graphics3D device_context_;
-
-};
-
-
-#endif // PPAPI_MAIN_PPAPI_INSTANCE3D_H_
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_main.cc b/native_client_sdk/src/libraries/ppapi_main/ppapi_main.cc
deleted file mode 100644
index 3d666c910f..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_main.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 "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_module.h"
-
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/module.h"
-
-#include "ppapi_main/ppapi_instance.h"
-#include "ppapi_main/ppapi_instance3d.h"
-#include "ppapi_main/ppapi_main.h"
-
-
-static pp::Instance* s_Instance = NULL;
-
-
-// Helpers to access PPAPI interfaces
-void* PPAPI_GetInstanceObject() {
- return s_Instance;
-}
-
-PP_Instance PPAPI_GetInstanceId() {
- return s_Instance->pp_instance();
-}
-
-const void* PPAPI_GetInterface(const char *name) {
- return pp::Module::Get()->GetBrowserInterface(name);
-}
-
-void* PPAPI_CreateInstance(PP_Instance inst, const char *args[]) {
- return static_cast<void*>(new PPAPIInstance(inst, args));
-}
-
-PPAPIEvent* PPAPI_AcquireEvent() {
- return static_cast<PPAPIInstance*>(s_Instance)->AcquireInputEvent();
-}
-
-void PPAPI_ReleaseEvent(PPAPIEvent* event) {
- static_cast<PPAPIInstance*>(s_Instance)->ReleaseInputEvent(event);
-}
-
-
-/// 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 PPAPIMainModule : public pp::Module {
- public:
- PPAPIMainModule() : pp::Module() {}
- virtual ~PPAPIMainModule() {}
-
- virtual pp::Instance* CreateInstance(PP_Instance instance) {
- s_Instance = static_cast<pp::Instance*>(UserCreateInstance(instance));
- return s_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 PPAPIMainModule();
-}
-
-} // namespace pp
-
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_main.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_main.h
deleted file mode 100644
index 2f2c4e31d8..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_main.h
+++ /dev/null
@@ -1,62 +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 PPAPI_MAIN_PPAPI_MAIN_H_
-#define PPAPI_MAIN_PPAPI_MAIN_H_
-
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi_main/ppapi_event.h"
-
-#include "utils/macros.h"
-
-EXTERN_C_BEGIN
-
-// Prototype for 'main' which will get called on startup
-int ppapi_main(int argc, const char *argv[]);
-
-// Provided by "main" module, use one of the macros below
-void* UserCreateInstance(PP_Instance inst);
-
-// Helpers to access PPAPI interfaces
-void* PPAPI_GetInstanceObject();
-PP_Instance PPAPI_GetInstanceId();
-const void* PPAPI_GetInterface(const char *name);
-
-// Provided by library for basic instance types
-void* PPAPI_CreateInstance(PP_Instance inst, const char *args[]);
-void* PPAPI_CreateInstance2D(PP_Instance inst, const char *args[]);
-void* PPAPI_CreateInstance3D(PP_Instance inst, const char *args[]);
-
-// Event APIs
-PPAPIEvent* PPAPI_AcquireEvent();
-void PPAPI_ReleaseEvent(PPAPIEvent* event);
-
-// Functions for Graphic Instances
-int32_t *PPAPIGet3DAttribs(uint32_t width, uint32_t height);
-void PPAPIBuildContext(uint32_t width, uint32_t height);
-void PPAPIRender(PP_Resource ctx, uint32_t width, uint32_t height);
-
-
-EXTERN_C_END
-
-#define PPAPI_MAIN_DEFAULT_ARGS NULL, NULL
-
-#define PPAPI_MAIN_USE(factory, ...) \
-void* UserCreateInstance(PP_Instance inst) { \
- static const char *params[] = { __VA_ARGS__ }; \
- return factory(inst, params); \
-}
-
-#define PPAPI_MAIN_WITH_DEFAULT_ARGS \
- PPAPI_MAIN_USE(PPAPI_CreateInstance, PPAPI_MAIN_DEFAULT_ARGS)
-
-#define PPAPI_MAIN_3D_WITH_DEFAULT_ARGS \
- PPAPI_MAIN_USE(PPAPI_CreateInstance3D, PPAPI_MAIN_DEFAULT_ARGS)
-
-#define PPAPI_MAIN_WITH_ARGS(...) \
- PPAPI_MAIN_USE(PPAPI_CreateInstance, __VA_ARGS__)
-
-
-#endif // PPAPI_MAIN_PPAPI_MAIN_H_
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.cc b/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.cc
deleted file mode 100644
index 9ecce6680e..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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 <stdlib.h>
-#include <string.h>
-
-#include "ppapi_main/ppapi_queue.h"
-
-PPAPIQueue::PPAPIQueue()
- : read_(0),
- write_(0),
- freed_(0),
- size_(0),
- array_(NULL) { }
-
-PPAPIQueue::~PPAPIQueue() {
- // Messages may be leaked if the queue is not empty.
- assert(read_ == write_);
-
- delete[] array_;
-}
-
-bool PPAPIQueue::SetSize(uint32_t queue_size) {
- assert(queue_size > 0);
-
- if (array_) return false;
-
- array_ = new void*[queue_size];
- size_ = queue_size;
-
- memset(array_, 0, sizeof(void*) * queue_size);
- return true;
-}
-
-bool PPAPIQueue::AddNewMessage(void* msg) {
- // Writing a NULL message is illegal
- assert(array_ != NULL);
- assert(msg != NULL);
-
- // If the slot not empty, the queue must be full. Calling RemoveStaleMessage
- // may create space by freeing messages that have already been read.
- if (array_[write_] != NULL) return false;
-
- // Write to the spot
- array_[write_] = msg;
-
- // Fence to make sure the payload and payload pointer are visible.
- // Since Win32 is x86 which provides ordered writes, we don't need to
- // synchronize in that case.
-#ifndef WIN32
- __sync_synchronize();
-#endif
-
- // Increment the write pointer, to signal it's readable.
- write_ = (write_ + 1) % size_;
- return true;
-}
-
-void* PPAPIQueue::RemoveStaleMessage() {
- assert(array_ != NULL);
-
- // If freed and read pointer are equal, this hasn't been read yet
- if (freed_ == read_) return NULL;
-
- assert(array_[freed_] != NULL);
-
- void* ret = array_[freed_];
- array_[freed_] = NULL;
-
- freed_ = (freed_ + 1) % size_;
- return ret;
-}
-
-void* PPAPIQueue::AcquireTopMessage() {
- // Assert that we aren't already reading a message.
- assert(last_msg_ == NULL);
-
- // If read and write pointers are equal, the queue is empty.
- if (read_ == write_) return NULL;
-
- // Track the last message to look for illegal API use.
- last_msg_ = array_[read_];
- return last_msg_;
-}
-
-void PPAPIQueue::ReleaseTopMessage(void* msg) {
- // Verify we currently acquire message.
- assert(msg != NULL);
- assert(msg == last_msg_);
-
- last_msg_ = NULL;
-
- // Signal that the message can be freed.
- read_ = (read_ + 1) % size_;
-}
diff --git a/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.h b/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.h
deleted file mode 100644
index f022dcf0b3..0000000000
--- a/native_client_sdk/src/libraries/ppapi_main/ppapi_queue.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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_MAIN_PPAPI_QUEUE_H
-#define PPAPI_MAIN_PPAPI_QUEUE_H
-
-#include <stdint.h>
-
-//
-// PPAPIQueue
-//
-// PPAPIQueue is a single producer/single consumer lockless queue. This
-// implementation is PPAPI friendly because it prevents the main thread from
-// ever needing to lock. In addition, allocation and destruction of messages
-// happens on the same thread, allowing for lockless message allocation as well.
-//
-// Messages pass through four states in order:
-// AddNewMessage - The message is added to the queue by the producer
-// and the memory is fenced to ensure it is visible. Once the fence
-// returns, the write pointer is incremented to signal it's available to
-// the consumer. NOTE: NULL messages are illegal.
-//
-// AcquireTopMessage - Next the message is acquired by the consumer thread.
-// At this point, the consumer is considered to be examining the payload so
-// we do not increment the read pointer yet to prevent deletion. NOTE: it
-// is illegal to acquire the next message until the previous one is released.
-//
-// ReleaseTopMessage - Now the consumer signals that it is no longer looking
-// at the message by incremented the read pointer. The producer is free to
-// release or reuse the payload.
-//
-// RemoveStaleMessage - The message is no longer visible to the consumer, so
-// it is returned to the producer to be reused or destroyed. It's location
-// in the queue is set to NULL to signal that a new message may be added in
-// that slot.
-//
-class PPAPIQueue {
- public:
- PPAPIQueue();
- ~PPAPIQueue();
-
- //
- // Producer API
- //
- // First, the producer must set the queue size before any operation can
- // take place. Next, before adding a message, clear space in the queue,
- // by removing stale messages. Adding a new message will return TRUE if
- // space is available, otherwise FALSE is returned and it's up to the
- // application developer to decide what to do.
- //
- bool SetSize(uint32_t queue_size);
- bool AddNewMessage(void* msg);
- void* RemoveStaleMessage();
-
- //
- // Consumer API
- //
- // The reader will attempt to Acquire the top message, if one is not
- // available NULL will be returned. Once the consumer is done with the
- // message, ReleaseTopMessage is called to signal that the payload is no
- // longer visible to the consumer and can be recycled or destroyed.
- // Since messages are freed in order, it is required that messages are
- // consumed in order. For this reason, it is illegal to call Acquire again
- // after a non-NULL message pointer is returned, until Release is called on
- // the old message. This means the consumer can only look at one message
- // at a time. To look at multiple messages at once, the consumer would
- // need to make a copy and release the top message.
- //
- void* AcquireTopMessage();
- void ReleaseTopMessage(void* msg);
-
- private:
- uint32_t read_;
- uint32_t write_;
- uint32_t freed_;
- uint32_t size_;
- void* last_msg_;
- void** array_;
-};
-
-
-#endif // PPAPI_MAIN_PPAPI_QUEUE_H
diff --git a/native_client_sdk/src/libraries/ppapi_simple/library.dsc b/native_client_sdk/src/libraries/ppapi_simple/library.dsc
new file mode 100644
index 0000000000..613a585227
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/library.dsc
@@ -0,0 +1,28 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
+ 'TARGETS': [
+ {
+ 'NAME' : 'ppapi_simple',
+ 'TYPE' : 'lib',
+ 'SOURCES' : [
+ "ps.cc",
+ "ps_event.cc",
+ "ps_instance.cc",
+ "ps_main.cc",
+ ],
+ }
+ ],
+ 'HEADERS': [
+ {
+ 'FILES': [
+ "ps.h",
+ "ps_event.h",
+ "ps_instance.h",
+ "ps_main.h",
+ ],
+ 'DEST': 'include/ppapi_simple',
+ },
+ ],
+ 'DEST': 'src',
+ 'NAME': 'ppapi_simple',
+}
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps.cc b/native_client_sdk/src/libraries/ppapi_simple/ps.cc
new file mode 100644
index 0000000000..eba3c4030b
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps.cc
@@ -0,0 +1,51 @@
+/* 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 "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_module.h"
+
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+
+#include "ppapi_simple/ps.h"
+
+static pp::Instance* s_Instance = NULL;
+
+PP_Instance PSGetInstanceId() {
+ return s_Instance->pp_instance();
+}
+
+const void* PSGetInterface(const char *name) {
+ return pp::Module::Get()->GetBrowserInterface(name);
+}
+
+
+// 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 PSModule : public pp::Module {
+ public:
+ PSModule() : pp::Module() {}
+ virtual ~PSModule() {}
+
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ s_Instance = static_cast<pp::Instance*>(PSUserCreateInstance(instance));
+ return s_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 PSModule();
+}
+
+} // namespace pp
+
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps.h b/native_client_sdk/src/libraries/ppapi_simple/ps.h
new file mode 100644
index 0000000000..1d7b2543ae
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps.h
@@ -0,0 +1,113 @@
+// 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_H_
+#define PPAPI_SIMPLE_PS_H_
+
+#include "ppapi/c/pp_instance.h"
+#include "sdk_util/macros.h"
+
+EXTERN_C_BEGIN
+
+/**
+ * The ppapi_simple library simplifies the use of the Pepper interfaces by
+ * providing a more traditional 'C' or 'C++' style framework. The library
+ * creates an PSInstance derived object based on the ppapi_cpp library and
+ * initializes the nacl_io library to provide a POSIX friendly I/O environment.
+ *
+ * In order to provide a standard blocking environment, the library will hide
+ * the actual "Pepper Thread" which is the thread that standard events
+ * such as window resize, mouse keyboard, or other inputs arrive. To prevent
+ * blocking, instead we enqueue these events onto a thread safe linked list
+ * and expect them to be processed on a new thread. In addition, the library
+ * will automatically start a new thread on which can be used effectively
+ * as a "main" entry point.
+ *
+ * For C style development, the PPAPI_SIMPLE_REGISTER_MAIN(XX) macros provide a
+ * mechanism to register the entry an point for "main". All events are pushed
+ * onto an event queue which can then be pulled from this new thread.
+ * NOTE: The link will still need libstdc++ and libppapi_cpp since the library
+ * is still creating a C++ object which does the initialization work and
+ * forwards the events.
+ *
+ * For C++ style development, use the ppapi_simple_instance.h,
+ * ppapi_simple_instance_2d.h, and ppapi_simple_instance_3d.h headers as
+ * a base class, and overload the appropriate virtual functions such as
+ * Main, ChangeContext, or Render.
+ */
+
+/**
+ * PSGetInstanceId
+ *
+ * Return the PP_Instance id of this instance of the module. This is required
+ * by most of the Pepper resource creation routines.
+ */
+PP_Instance PSGetInstanceId();
+
+
+/**
+ * PSGetInterface
+ *
+ * Return the Pepper instance referred to by 'name'. Will return a pointer
+ * to the interface, or NULL if not found or not available.
+ */
+const void* PSGetInterface(const char *name);
+
+
+/**
+ * PSUserCreateInstance
+ *
+ * Prototype for the user provided function which creates and configures
+ * the instance object. This function is defined by one of the macros below,
+ * or by the equivalent macro in one of the other headers. For 'C'
+ * development, one of the basic instances which support C callback are used.
+ * For C++, this function should instantiate the user defined instance. See
+ * the two macros below.
+ */
+extern void* PSUserCreateInstance(PP_Instance inst);
+
+
+/**
+ * PPAPI_SIMPLE_DECLARE_PARAMS
+ *
+ * Macro for creating the param string array. Used by the Factory macros
+ * to enable wrapping of the param array with terminating NULL, NULL.
+ */
+#define PPAPI_SIMPLE_DECLARE_PARAMS(params, ...) \
+ static const char* params[] = { __VA_ARGS__ };
+
+
+/**
+ * PPAPI_SIMPLE_USE_MAIN
+ *
+ * For use with C projects, this macro calls the provided factory with
+ * configuration information and optional extra arguments which are passed to
+ * the 'main' function. See the appropriate ppapi_simple_main(XX).h header.
+ */
+#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); \
+}
+
+
+/**
+ * PPAPI_SIMPLE_USE_CLASS
+ *
+ * For use with C++ projects, this macro instantiates the provided class
+ * passing it back to the generic module initialization code. Simply derive
+ * a class from the appropriate ppapi_simple_instance(XX).h and pass the
+ * class name here.
+ */
+#define PPAPI_SIMPLE_USE_CLASS(classname, ...) \
+void* PSUserCreateInstance(PP_Instance inst) { \
+ PPAPI_SIMPLE_DECLARE_PARAMS(params, ##__VA_ARGS__, NULL, NULL) \
+ return (void *) new classname(inst, params); \
+}
+
+EXTERN_C_END
+
+
+#endif // PPAPI_SIMPLE_PPAPI_SIMPLE_H
+
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_event.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_event.cc
new file mode 100644
index 0000000000..ac68fe9b59
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_event.cc
@@ -0,0 +1,45 @@
+/* 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 "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_module.h"
+
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_instance.h"
+#include "ppapi_simple/ps_main.h"
+
+
+void PSEventPost(PSEventType type) {
+ PSInstance::GetInstance()->PostEvent(type);
+}
+
+void PSEventPostBool(PSEventType type, PP_Bool state) {
+ PSInstance::GetInstance()->PostEvent(type, state);
+}
+
+void PSEventPostVar(PSEventType type, struct PP_Var var) {
+ PSInstance::GetInstance()->PostEvent(type, var);
+}
+
+void PSEventPostResource(PSEventType type, PP_Resource resource) {
+ PSInstance::GetInstance()->PostEvent(type, resource);
+}
+
+PSEvent* PSEventTryAcquire() {
+ return PSInstance::GetInstance()->TryAcquireEvent();
+}
+
+PSEvent* PSEventWaitAcquire() {
+ return PSInstance::GetInstance()->WaitAcquireEvent();
+}
+
+void PSEventRelease(PSEvent* event) {
+ PSInstance::GetInstance()->ReleaseEvent(event);
+}
+
+void PSEventSetFilter(PSEventTypeMask filter) {
+ PSInstance::GetInstance()->SetEnabledEvents(filter);
+}
+
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_event.h b/native_client_sdk/src/libraries/ppapi_simple/ps_event.h
new file mode 100644
index 0000000000..563832c703
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_event.h
@@ -0,0 +1,95 @@
+// 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_
+
+#include "ppapi/c/pp_bool.h"
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/pp_var.h"
+
+#include "sdk_util/macros.h"
+
+EXTERN_C_BEGIN
+
+/**
+ * PSEvent
+ *
+ * The PSEvent system provides an in-order event processing mechanism.
+ * As Pepper events such as input, or focus and view changes arrive on the
+ * main pepper thread, they are placed on various FIFOs based on event type.
+ * For any given event type, only a single thread will process those events.
+ *
+ * By default, the "EventThread" will receive all messages. However any thread
+ * can call PSRequestEventsType to request that all new events of that type
+ * are placed on that particular thread's queue.
+ *
+ * This allows the developer to choose which threads handle which event types
+ * while keeping all events belonging to a particular thread in order. This
+ * is useful, for example, in the case of graphics to synchronize the size
+ * of the graphics context, with mouse clicks to correctly interpret location.
+ */
+
+
+typedef enum {
+ /* Mask off all events. */
+ PSE_NONE = 0,
+
+ /* From HandleInputEvent, conatins an input resource. */
+ PSE_INSTANCE_HANDLEINPUT = 1,
+
+ /* From HandleMessage, contains a PP_Var. */
+ PSE_INSTANCE_HANDLEMESSAGE = 2,
+
+ /* From DidChangeView, contains a view resource */
+ PSE_INSTANCE_DIDCHANGEVIEW = 4,
+
+ /* From DidChangeFocus, contains a PP_Bool with the current focus state. */
+ PSE_INSTANCE_DIDCHANGEFOCUS = 8,
+
+ /* When the 3D context is lost, no resource. */
+ PSE_GRAPHICS3D_GRAPHICS3DCONTEXTLOST = 16,
+
+ /* When the mouse lock is lost. */
+ PSE_MOUSELOCK_MOUSELOCKLOST = 32,
+
+ /* Enable all events. */
+ PSE_ALL = -1,
+} PSEventType;
+
+typedef uint32_t PSEventTypeMask;
+
+// Generic Event
+typedef struct {
+ PSEventType type;
+ union {
+ PP_Bool as_bool;
+ PP_Resource as_resource;
+ struct PP_Var as_var;
+ };
+} PSEvent;
+
+
+/**
+ * Function for queuing, acquiring, and releasing events.
+ */
+PSEvent* PSEventTryAcquire();
+PSEvent* PSEventWaitAcquire();
+void PSEventRelease(PSEvent* event);
+void PSEventSetFilter(PSEventTypeMask mask);
+
+/**
+ * Creates and adds an event of the specified type to the event queue if
+ * that event type is not currently filtered.
+ */
+void PSEventPost(PSEventType type);
+void PSEventPostBool(PSEventType type, PP_Bool state);
+void PSEventPostVar(PSEventType type, struct PP_Var var);
+void PSEventPostResource(PSEventType type, PP_Resource resource);
+
+EXTERN_C_END
+
+#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
new file mode 100644
index 0000000000..120378765f
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
@@ -0,0 +1,357 @@
+// 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 <fcntl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <cstdlib>
+#include <cstring>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "nacl_io/kernel_wrap.h"
+#include "nacl_io/nacl_io.h"
+
+#include "ppapi/c/ppb_var.h"
+
+#include "ppapi/cpp/input_event.h"
+#include "ppapi/cpp/message_loop.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/size.h"
+#include "ppapi/cpp/touch_point.h"
+#include "ppapi/cpp/var.h"
+
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_instance.h"
+#include "ppapi_simple/ps_main.h"
+
+static PSInstance* s_InstanceObject = NULL;
+
+PSInstance* PSInstance::GetInstance() {
+ return s_InstanceObject;
+}
+
+struct StartInfo {
+ PSInstance* inst_;
+ uint32_t argc_;
+ const char** argv_;
+};
+
+
+// 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");
+ StartInfo* si = static_cast<StartInfo*>(info);
+ si->inst_->main_loop_ = new pp::MessageLoop(si->inst_);
+ si->inst_->main_loop_->AttachToCurrentThread();
+
+ int ret = si->inst_->MainThread(si->argc_, si->argv_);
+ for (uint32_t i = 0; i < si->argc_; i++) {
+ delete[] si->argv_[i];
+ }
+ delete[] si->argv_;
+ delete si;
+
+ return NULL;
+}
+
+// The default implementation supports running a 'C' main.
+int PSInstance::MainThread(int argc, const 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;
+ }
+
+ Error("No main defined.\n");
+ return 0;
+}
+
+PSInstance::PSInstance(PP_Instance instance, const char *argv[])
+ : pp::Instance(instance),
+ main_loop_(NULL),
+ verbosity_(PSV_LOG),
+ events_enabled_(PSE_NONE) {
+ // Set the single Instance object
+ s_InstanceObject = this;
+
+#ifdef DEBUG
+ SetVerbosity(PSV_LOG);
+#endif
+
+ // Place PPAPI_MAIN_USE arguments into properties map
+ while (*argv) {
+ std::string key = *argv++;
+ std::string val = *argv++;
+ properties_[key] = val;
+ }
+
+ RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE |
+ 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() {}
+
+void PSInstance::SetMain(PSMainFunc_t main) {
+ main_cb_ = main;
+}
+
+bool PSInstance::Init(uint32_t arg,
+ const char* argn[],
+ const char* argv[]) {
+ StartInfo* si = new StartInfo;
+
+ si->inst_ = this;
+ si->argc_ = 1;
+ si->argv_ = new const char *[arg*2+1];
+ 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]);
+ }
+
+ // If we start with PM prefix set the instance argument map
+ if (0 == strncmp(argn[i], "ps_", 3)) {
+ std::string key = argn[i];
+ std::string val = argv[i];
+ properties_[key] = val;
+ 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;
+ }
+ }
+ }
+
+ // If src was not found, set the first arg to something
+ if (NULL == si->argv_[0]) {
+ char *name = new char[5];
+ strcpy(name, "NMF?");
+ 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;
+ }
+
+ Log("Skipping create thread.\n");
+ return false;
+}
+
+const char* PSInstance::GetProperty(const char* key, const char* def) {
+ PropertyMap_t::iterator it = properties_.find(key);
+ if (it != properties_.end()) {
+ return it->second.c_str();
+ }
+ return def;
+}
+
+// Processes the properties passed fixed at compile time via the
+// initialization macro, or via dynamically set embed attributes
+// through instance DidCreate.
+bool PSInstance::ProcessProperties() {
+ // Get the default values
+ const char* stdin_path = GetProperty("ps_stdin", "/dev/stdin");
+ 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);
+
+ // Reset verbosity if passed in
+ if (verbosity) SetVerbosity(static_cast<Verbosity>(atoi(verbosity)));
+
+ // Enable NaCl IO to map STDIN, STDOUT, and STDERR
+ nacl_io_init_ppapi(PSGetInstanceId(), PSGetInterface);
+ int fd0 = open(stdin_path, O_RDONLY);
+ dup2(fd0, 0);
+
+ int fd1 = open(stdout_path, O_WRONLY);
+ dup2(fd1, 1);
+
+ int fd2 = open(stderr_path, O_WRONLY);
+ dup2(fd2, 2);
+
+ // Set line buffering on stdout and stderr
+ setvbuf(stderr, NULL, _IOLBF, 0);
+ setvbuf(stdout, NULL, _IOLBF, 0);
+ return true;
+}
+
+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::Warn(const char *fmt, ...) {
+ if (verbosity_ >= PSV_WARN) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stdout, fmt, ap);
+ }
+}
+
+void PSInstance::Error(const char *fmt, ...) {
+ if (verbosity_ >= PSV_ERROR) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ }
+}
+
+void PSInstance::SetEnabledEvents(uint32_t mask) {
+ events_enabled_ = mask;
+}
+
+void PSInstance::PostEvent(PSEventType type) {
+ assert(PSE_GRAPHICS3D_GRAPHICS3DCONTEXTLOST == type ||
+ PSE_MOUSELOCK_MOUSELOCKLOST == type);
+
+ if (events_enabled_ & type) {
+ PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent));
+ memset(env, 0, sizeof(*env));
+ env->type = type;
+ event_queue_.Enqueue(env);
+ }
+}
+
+void PSInstance::PostEvent(PSEventType type, PP_Bool bool_value) {
+ assert(PSE_INSTANCE_DIDCHANGEFOCUS == type);
+
+ if (events_enabled_ & type) {
+ PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent));
+ memset(env, 0, sizeof(*env));
+ env->type = type;
+ env->as_bool = bool_value;
+ event_queue_.Enqueue(env);
+ }
+}
+
+void PSInstance::PostEvent(PSEventType type, PP_Resource resource) {
+ assert(PSE_INSTANCE_HANDLEINPUT == type ||
+ PSE_INSTANCE_DIDCHANGEVIEW == type);
+
+ if (events_enabled_ & type) {
+ if (resource) {
+ ppb_core_->AddRefResource(resource);
+ }
+ PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent));
+ memset(env, 0, sizeof(*env));
+ env->type = type;
+ env->as_resource = resource;
+ event_queue_.Enqueue(env);
+ }
+}
+
+void PSInstance::PostEvent(PSEventType type, const PP_Var& var) {
+ assert(PSE_INSTANCE_HANDLEMESSAGE == type);
+
+ if (events_enabled_ & type) {
+ ppb_var_->AddRef(var);
+ PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent));
+ memset(env, 0, sizeof(*env));
+ env->type = type;
+ env->as_var = var;
+ event_queue_.Enqueue(env);
+ }
+}
+
+PSEvent* PSInstance::TryAcquireEvent() {
+ return event_queue_.Dequeue(false);
+}
+
+PSEvent* PSInstance::WaitAcquireEvent() {
+ return event_queue_.Dequeue(true);
+}
+
+void PSInstance::ReleaseEvent(PSEvent* event) {
+ if (event) {
+ switch(event->type) {
+ case PSE_INSTANCE_HANDLEMESSAGE:
+ ppb_var_->Release(event->as_var);
+ break;
+ case PSE_INSTANCE_HANDLEINPUT:
+ case PSE_INSTANCE_DIDCHANGEVIEW:
+ if (event->as_resource) {
+ ppb_core_->ReleaseResource(event->as_resource);
+ }
+ break;
+ default:
+ break;
+ }
+ free(event);
+ }
+}
+
+void PSInstance::HandleMessage(const pp::Var& message) {
+ Log("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;
+}
+
+void PSInstance::DidChangeView(const pp::View& view) {
+ pp::Size new_size = view.GetRect().size();
+ Log("Got View change: %d,%d\n", new_size.width(), new_size.height());
+ PostEvent(PSE_INSTANCE_DIDCHANGEVIEW, view.pp_resource());
+}
+
+void PSInstance::DidChangeFocus(bool focus) {
+ Log("Got Focus change: %s\n", focus ? "FOCUS ON" : "FOCUS OFF");
+ PostEvent(PSE_INSTANCE_DIDCHANGEFOCUS, focus ? PP_TRUE : PP_FALSE);
+}
+
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
new file mode 100644
index 0000000000..d888dd7044
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
@@ -0,0 +1,121 @@
+// 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_INSTANCE_H_
+#define PPAPI_SIMPLE_PS_INSTANCE_H_
+
+#include <map>
+
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_stdint.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_var.h"
+#include "ppapi/c/ppb_view.h"
+
+#include "ppapi/cpp/fullscreen.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/message_loop.h"
+#include "ppapi/cpp/mouse_lock.h"
+
+#include "ppapi/utility/completion_callback_factory.h"
+
+#include "ppapi_simple/ps_event.h"
+#include "ppapi_simple/ps_main.h"
+
+#include "sdk_util/thread_safe_queue.h"
+
+
+typedef std::map<std::string, std::string> PropertyMap_t;
+
+class PSInstance : public pp::Instance {
+ public:
+ enum Verbosity {
+ PSV_SILENT,
+ PSV_ERROR,
+ PSV_WARN,
+ PSV_LOG,
+ };
+
+ // Returns a pointer to the global instance
+ static PSInstance* GetInstance();
+
+ PSInstance(PP_Instance inst, const char *argv[]);
+ virtual ~PSInstance();
+
+ // Set a function which will be called on a new thread once initialized.
+ // NOTE: This must be called by the Factory, once Init is called, this
+ // function will have no effect.
+ void SetMain(PSMainFunc_t func);
+
+ // Returns value based on KEY or default.
+ const char* GetProperty(const char* key, const char* def = NULL);
+
+ // Started on Init, a thread which can be safely blocked.
+ virtual int MainThread(int argc, const char* argv[]);
+
+ // Logging Functions
+ void SetVerbosity(Verbosity verbosity);
+ void Log(const char *fmt, ...);
+ void Warn(const char *fmt, ...);
+ void Error(const char *fmt, ...);
+
+ // Event Functions
+ void SetEnabledEvents(uint32_t mask);
+ void PostEvent(PSEventType type);
+ void PostEvent(PSEventType type, PP_Bool bool_value);
+ void PostEvent(PSEventType type, PP_Resource resource);
+ void PostEvent(PSEventType type, const PP_Var& var);
+
+ PSEvent* TryAcquireEvent();
+ PSEvent* WaitAcquireEvent();
+ void ReleaseEvent(PSEvent* event);
+
+ protected:
+ // Callback functions triggered by Pepper
+ //
+ // These functions are called on the main pepper thread, so they must
+ // not block.
+ //
+ // Called by the browser when the NaCl module is loaded and all ready to go.
+ // 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[]);
+
+ // 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);
+
+ // Called by the browser when the NaCl canvas gets or loses focus.
+ virtual void DidChangeFocus(bool has_focus);
+
+ // Called by the browser to handle the postMessage() call in Javascript.
+ virtual void HandleMessage(const pp::Var& message);
+
+ // Called by the browser to handle incoming input events. Events are Q'd
+ // and can later be processed on a sperate processing thread.
+ virtual bool HandleInputEvent(const pp::InputEvent& event);
+
+ // Called by Init to processes default and embed tag arguments prior to
+ // launching the 'ppapi_main' thread.
+ virtual bool ProcessProperties();
+
+ private:
+ static void* MainThreadThunk(void *start_info);
+
+ protected:
+ pp::MessageLoop* main_loop_;
+
+ PropertyMap_t properties_;
+ ThreadSafeQueue<PSEvent> event_queue_;
+ uint32_t events_enabled_;
+ Verbosity verbosity_;
+
+ PSMainFunc_t main_cb_;
+
+ const PPB_Core* ppb_core_;
+ const PPB_Var* ppb_var_;
+ const PPB_View* ppb_view_;
+};
+
+#endif // PPAPI_MAIN_PS_INSTANCE_H_
+
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_main.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_main.cc
new file mode 100644
index 0000000000..302aeaf44b
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_main.cc
@@ -0,0 +1,17 @@
+/* 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 "ppapi/c/pp_instance.h"
+#include "ppapi/c/pp_module.h"
+
+#include "ppapi_simple/ps_instance.h"
+#include "ppapi_simple/ps_main.h"
+
+
+void* PSMainCreate(PP_Instance inst, PSMainFunc_t func, const char* argv[]) {
+ PSInstance* pInst = new PSInstance(inst, argv);
+ pInst->SetMain(func);
+ return pInst;
+}
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_main.h b/native_client_sdk/src/libraries/ppapi_simple/ps_main.h
new file mode 100644
index 0000000000..6bd66e291a
--- /dev/null
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_main.h
@@ -0,0 +1,38 @@
+// 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_
+
+#include "ppapi_simple/ps.h"
+#include "ppapi_simple/ps_event.h"
+
+EXTERN_C_BEGIN
+
+typedef int (*PSMainFunc_t)(int argc, const char *argv[]);
+
+/**
+ * PSMainCreate
+ *
+ * Constructs an instance SimpleInstance and configures it to call into
+ * the provided "main" function.
+ */
+void* PSMainCreate(PP_Instance inst, PSMainFunc_t func, const char **argv);
+
+
+/**
+ * PPAPI_SIMPLE_REGISTER_MAIN
+ *
+ * Constructs a PSInstance ojbect and configures it to use call the provided
+ * 'main' function on it's own thread once initialization is complete.
+ */
+
+
+#define PPAPI_SIMPLE_REGISTER_MAIN(main, ...) \
+ PPAPI_SIMPLE_USE_MAIN(PSMainCreate, main, ##__VA_ARGS__)
+
+EXTERN_C_END
+
+#endif /* PPAPI_SIMPLE_PPAPI_SIMPLE_MAIN_H_ */
+
diff --git a/native_client_sdk/src/libraries/utils/auto_lock.h b/native_client_sdk/src/libraries/sdk_util/auto_lock.h
index 19dd66f84d..88215d0cb3 100644
--- a/native_client_sdk/src/libraries/utils/auto_lock.h
+++ b/native_client_sdk/src/libraries/sdk_util/auto_lock.h
@@ -3,8 +3,8 @@
* found in the LICENSE file.
*/
-#ifndef LIBRARIES_UTILS_AUTO_LOCK_H_
-#define LIBRARIES_UTILS_AUTO_LOCK_H_
+#ifndef LIBRARIES_SDK_UTIL_AUTO_LOCK_H_
+#define LIBRARIES_SDK_UTIL_AUTO_LOCK_H_
#include <pthread.h>
@@ -27,4 +27,5 @@ class AutoLock {
pthread_mutex_t* lock_;
};
-#endif // LIBRARIES_UTILS_AUTO_LOCK_H_
+#endif // LIBRARIES_SDK_UTIL_AUTO_LOCK_H_
+
diff --git a/native_client_sdk/src/libraries/sdk_util/library.dsc b/native_client_sdk/src/libraries/sdk_util/library.dsc
new file mode 100644
index 0000000000..0491d980ea
--- /dev/null
+++ b/native_client_sdk/src/libraries/sdk_util/library.dsc
@@ -0,0 +1,29 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'],
+ 'SEARCH': [
+ '.'
+ ],
+ 'TARGETS': [
+ {
+ 'NAME' : 'sdk_util',
+ 'TYPE' : 'lib',
+ 'SOURCES' : [
+ 'thread_pool.cc'
+ ]
+ }
+ ],
+ 'HEADERS': [
+ {
+ 'FILES': [
+ 'auto_lock.h',
+ 'macros.h',
+ 'ref_object.h',
+ 'thread_pool.h',
+ 'thread_safe_queue.h'
+ ],
+ 'DEST': 'include/sdk_util',
+ }
+ ],
+ 'DEST': 'src',
+ 'NAME': 'sdk_util',
+}
diff --git a/native_client_sdk/src/libraries/utils/macros.h b/native_client_sdk/src/libraries/sdk_util/macros.h
index 718d83fce9..fd15dc38c8 100644
--- a/native_client_sdk/src/libraries/utils/macros.h
+++ b/native_client_sdk/src/libraries/sdk_util/macros.h
@@ -2,8 +2,8 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-#ifndef LIBRARIES_UTILS_MACROS_H_
-#define LIBRARIES_UTILS_MACROS_H_
+#ifndef LIBRARIES_SDK_UTIL_MACROS_H_
+#define LIBRARIES_SDK_UTIL_MACROS_H_
/**
* A macro to disallow the evil copy constructor and operator= functions
@@ -46,4 +46,5 @@
force_link_##x = 1; \
}
-#endif /* LIBRARIES_UTILS_MACROS_H_ */
+#endif /* LIBRARIES_SDK_UTIL_MACROS_H_ */
+
diff --git a/native_client_sdk/src/libraries/utils/ref_object.h b/native_client_sdk/src/libraries/sdk_util/ref_object.h
index d3eb9f87c4..4e81f32df6 100644
--- a/native_client_sdk/src/libraries/utils/ref_object.h
+++ b/native_client_sdk/src/libraries/sdk_util/ref_object.h
@@ -3,8 +3,8 @@
* found in the LICENSE file.
*/
-#ifndef LIBRARIES_UTILS_REF_OBJECT
-#define LIBRARIES_UTILS_REF_OBJECT
+#ifndef LIBRARIES_SDK_UTIL_REF_OBJECT
+#define LIBRARIES_SDK_UTIL_REF_OBJECT
#include <stdlib.h>
#include "pthread.h"
@@ -45,4 +45,5 @@ class RefObject {
int ref_count_;
};
-#endif // LIBRARIES_UTILS_REF_OBJECT
+#endif // LIBRARIES_SDK_UTIL_REF_OBJECT
+
diff --git a/native_client_sdk/src/libraries/sdk_util/thread_pool.cc b/native_client_sdk/src/libraries/sdk_util/thread_pool.cc
new file mode 100644
index 0000000000..e7d2e5cb6b
--- /dev/null
+++ b/native_client_sdk/src/libraries/sdk_util/thread_pool.cc
@@ -0,0 +1,144 @@
+// 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 "sdk_util/thread_pool.h"
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sdk_util/auto_lock.h"
+
+// Initializes mutex, semaphores and a pool of threads. If 0 is passed for
+// num_threads, all work will be performed on the dispatch thread.
+ThreadPool::ThreadPool(int num_threads)
+ : threads_(NULL), counter_(0), num_threads_(num_threads), exiting_(false),
+ user_data_(NULL), user_work_function_(NULL) {
+ if (num_threads_ > 0) {
+ int status;
+ status = sem_init(&work_sem_, 0, 0);
+ if (-1 == status) {
+ fprintf(stderr, "Failed to initialize semaphore!\n");
+ exit(-1);
+ }
+ status = sem_init(&done_sem_, 0, 0);
+ if (-1 == status) {
+ fprintf(stderr, "Failed to initialize semaphore!\n");
+ exit(-1);
+ }
+ threads_ = new pthread_t[num_threads_];
+ for (int i = 0; i < num_threads_; i++) {
+ status = pthread_create(&threads_[i], NULL, WorkerThreadEntry, this);
+ if (0 != status) {
+ fprintf(stderr, "Failed to create thread!\n");
+ exit(-1);
+ }
+ }
+ }
+}
+
+// Post exit request, wait for all threads to join, and cleanup.
+ThreadPool::~ThreadPool() {
+ if (num_threads_ > 0) {
+ PostExitAndJoinAll();
+ delete[] threads_;
+ sem_destroy(&done_sem_);
+ sem_destroy(&work_sem_);
+ }
+}
+
+// Setup work parameters. This function is called from the dispatch thread,
+// when all worker threads are sleeping.
+void ThreadPool::Setup(int counter, WorkFunction work, void *data) {
+ counter_ = counter;
+ user_work_function_ = work;
+ user_data_ = data;
+}
+
+// Return decremented task counter. This function
+// can be called from multiple threads at any given time.
+int ThreadPool::DecCounter() {
+#if defined(__native_client__)
+ // Use fast atomic sub & fetch.
+ return __sync_sub_and_fetch(&counter_, 1);
+#else
+ // Fallback to a more platform independent pthread mutex via AutoLock.
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ AutoLock lock(&mutex);
+ return --counter_;
+#endif
+}
+
+// Set exit flag, post and join all the threads in the pool. This function is
+// called only from the dispatch thread, and only when all worker threads are
+// sleeping.
+void ThreadPool::PostExitAndJoinAll() {
+ exiting_ = true;
+ // Wake up all the sleeping worker threads.
+ for (int i = 0; i < num_threads_; ++i)
+ sem_post(&work_sem_);
+ void* retval;
+ for (int i = 0; i < num_threads_; ++i)
+ pthread_join(threads_[i], &retval);
+}
+
+// Main work loop - one for each worker thread.
+void ThreadPool::WorkLoop() {
+ while (true) {
+ // Wait for work. If no work is availble, this thread will sleep here.
+ sem_wait(&work_sem_);
+ if (exiting_) break;
+ while (true) {
+ // Grab a task index to work on from the counter.
+ int task_index = DecCounter();
+ if (task_index < 0)
+ break;
+ user_work_function_(task_index, user_data_);
+ }
+ // Post to dispatch thread work is done.
+ sem_post(&done_sem_);
+ }
+}
+
+// pthread entry point for a worker thread.
+void* ThreadPool::WorkerThreadEntry(void* thiz) {
+ static_cast<ThreadPool*>(thiz)->WorkLoop();
+ return NULL;
+}
+
+// DispatchMany() will dispatch a set of tasks across worker threads.
+// Note: This function will block until all work has completed.
+void ThreadPool::DispatchMany(int num_tasks, WorkFunction work, void* data) {
+ // On entry, all worker threads are sleeping.
+ Setup(num_tasks, work, data);
+
+ // Wake up the worker threads & have them process tasks.
+ for (int i = 0; i < num_threads_; i++)
+ sem_post(&work_sem_);
+
+ // Worker threads are now awake and busy.
+
+ // This dispatch thread will now sleep-wait for the worker threads to finish.
+ for (int i = 0; i < num_threads_; i++)
+ sem_wait(&done_sem_);
+ // On exit, all tasks are done and all worker threads are sleeping again.
+}
+
+// DispatchHere will dispatch all tasks on this thread.
+void ThreadPool::DispatchHere(int num_tasks, WorkFunction work, void* data) {
+ for (int i = 0; i < num_tasks; i++)
+ work(i, data);
+}
+
+// Dispatch() will invoke the user supplied work function across
+// one or more threads for each task.
+// Note: This function will block until all work has completed.
+void ThreadPool::Dispatch(int num_tasks, WorkFunction work, void* data) {
+ if (num_threads_ > 0)
+ DispatchMany(num_tasks, work, data);
+ else
+ DispatchHere(num_tasks, work, data);
+}
+
diff --git a/native_client_sdk/src/libraries/sdk_util/thread_pool.h b/native_client_sdk/src/libraries/sdk_util/thread_pool.h
new file mode 100644
index 0000000000..760b3f715d
--- /dev/null
+++ b/native_client_sdk/src/libraries/sdk_util/thread_pool.h
@@ -0,0 +1,45 @@
+// 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.
+
+// Simple thread pool class
+
+#ifndef LIBRARIES_SDK_UTIL_THREAD_POOL_H_
+#define LIBRARIES_SDK_UTIL_THREAD_POOL_H_
+
+#include <pthread.h>
+#include <semaphore.h>
+
+// typdef helper for work function
+typedef void (*WorkFunction)(int task_index, void* data);
+
+// ThreadPool is a class to manage num_threads and assign
+// them num_tasks of work at a time. Each call
+// to Dispatch(..) will block until all tasks complete.
+// If 0 is passed in for num_threads, all tasks will be
+// issued on the dispatch thread.
+
+class ThreadPool {
+ public:
+ void Dispatch(int num_tasks, WorkFunction work, void* data);
+ explicit ThreadPool(int num_threads);
+ ~ThreadPool();
+ private:
+ int DecCounter();
+ void Setup(int counter, WorkFunction work, void* data);
+ void DispatchMany(int num_tasks, WorkFunction work, void* data);
+ void DispatchHere(int num_tasks, WorkFunction work, void* data);
+ void WorkLoop();
+ static void* WorkerThreadEntry(void* data);
+ void PostExitAndJoinAll();
+ pthread_t* threads_;
+ int counter_;
+ const int num_threads_;
+ bool exiting_;
+ void* user_data_;
+ WorkFunction user_work_function_;
+ sem_t work_sem_;
+ sem_t done_sem_;
+};
+#endif // LIBRARIES_SDK_UTIL_THREAD_POOL_H_
+
diff --git a/native_client_sdk/src/libraries/sdk_util/thread_safe_queue.h b/native_client_sdk/src/libraries/sdk_util/thread_safe_queue.h
new file mode 100644
index 0000000000..545b7c4589
--- /dev/null
+++ b/native_client_sdk/src/libraries/sdk_util/thread_safe_queue.h
@@ -0,0 +1,63 @@
+// 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_SDK_UTIL_THREAD_SAFE_QUEUE_H_
+#define LIBRARIES_SDK_UTIL_THREAD_SAFE_QUEUE_H_
+
+#include <pthread.h>
+
+#include <list>
+
+#include "sdk_util/auto_lock.h"
+#include "sdk_util/macros.h"
+
+
+// ThreadSafeQueue
+//
+// A simple template to support multithreaded and optionally blocking access
+// to a Queue of object pointers.
+//
+template<class T> class ThreadSafeQueue {
+ public:
+ ThreadSafeQueue() {
+ pthread_mutex_init(&mutex_, NULL);
+ pthread_cond_init(&cond_, NULL);
+ }
+
+ ~ThreadSafeQueue() {
+ pthread_mutex_destroy(&mutex_);
+ pthread_cond_destroy(&cond_);
+ }
+
+ void Enqueue(T* item) {
+ AutoLock lock(&mutex_);
+ list_.push_back(item);
+
+ pthread_cond_signal(&cond_);
+ }
+
+ T* Dequeue(bool block) {
+ AutoLock lock(&mutex_);
+
+ // If blocking enabled, wait until we queue is non-empty
+ if (block) {
+ while (list_.empty()) pthread_cond_wait(&cond_, &mutex_);
+ }
+
+ if (list_.empty()) return NULL;
+
+ T* item = list_.front();
+ list_.pop_front();
+ return item;
+ }
+
+ private:
+ std::list<T*> list_;
+ pthread_cond_t cond_;
+ pthread_mutex_t mutex_;
+ DISALLOW_COPY_AND_ASSIGN(ThreadSafeQueue);
+};
+
+#endif // LIBRARIES_SDK_UTIL_THREAD_SAFE_QUEUE_H_
+
diff --git a/native_client_sdk/src/tools/create_nmf.py b/native_client_sdk/src/tools/create_nmf.py
index 5cf2e1472d..a9aad544cb 100755
--- a/native_client_sdk/src/tools/create_nmf.py
+++ b/native_client_sdk/src/tools/create_nmf.py
@@ -610,10 +610,16 @@ def GetDefaultLibPath(config):
osname = getos.GetPlatform()
libpath = [
+ # Core toolchain libraries
'toolchain/%s_x86_glibc/x86_64-nacl/lib' % osname,
'toolchain/%s_x86_glibc/x86_64-nacl/lib32' % osname,
+ # naclports installed libraries
+ 'toolchain/%s_x86_glibc/x86_64-nacl/usr/lib' % osname,
+ 'toolchain/%s_x86_glibc/i686-nacl/usr/lib' % osname,
+ # SDK bundle libraries
'lib/glibc_x86_32/%s' % config,
'lib/glibc_x86_64/%s' % config,
+ # naclports bundle libraries
'ports/lib/glibc_x86_32/%s' % config,
'ports/lib/glibc_x86_64/%s' % config,
]
@@ -666,10 +672,10 @@ def main(argv):
DebugPrint.debug_mode = True
if options.toolchain is not None:
- print 'warning: option -t/--toolchain is deprecated.'
+ sys.stderr.write('warning: option -t/--toolchain is deprecated.\n')
if len(args) < 1:
- raise Error('No nexe files specified. See --help for more info')
+ parser.error('No nexe files specified. See --help for more info')
canonicalized = ParseExtraFiles(options.extra_files, sys.stderr)
if canonicalized is None:
@@ -679,7 +685,7 @@ def main(argv):
for ren in options.name:
parts = ren.split(',')
if len(parts) != 2:
- raise Error('Expecting --name=<orig_arch.so>,<new_name.so>')
+ parser.error('Expecting --name=<orig_arch.so>,<new_name.so>')
remap[parts[0]] = parts[1]
if options.path_prefix:
@@ -689,9 +695,9 @@ def main(argv):
for libpath in options.lib_path:
if not os.path.exists(libpath):
- raise Error('Specified library path does not exist: %s' % libpath)
- if not os.path.isdir(libpath):
- raise Error('Specified library is not a directory: %s' % libpath)
+ sys.stderr.write('Specified library path does not exist: %s\n' % libpath)
+ elif not os.path.isdir(libpath):
+ sys.stderr.write('Specified library is not a directory: %s\n' % libpath)
if not options.no_default_libpath:
# Add default libraries paths to the end of the search path.
diff --git a/native_client_sdk/src/tools/host_vc.mk b/native_client_sdk/src/tools/host_vc.mk
index 945fee3892..d41629b22d 100644
--- a/native_client_sdk/src/tools/host_vc.mk
+++ b/native_client_sdk/src/tools/host_vc.mk
@@ -27,13 +27,13 @@ $(error Unable to find cl.exe in PATH while building Windows host build)
endif
-ifeq ('Debug','$(CONFIG)')
-WIN_OPT_FLAGS ?= /Od /MTd /Z7 -D NACL_SDK_DEBUG
-else
+ifeq ($(CONFIG),Release)
WIN_OPT_FLAGS ?= /O2 /MT /Z7
+else
+WIN_OPT_FLAGS ?= /Od /MTd /Z7 -DNACL_SDK_DEBUG
endif
-WIN_FLAGS ?= -D WIN32 -D _WIN32 -D PTW32_STATIC_LIB
+WIN_FLAGS ?= -DWIN32 -D_WIN32 -DPTW32_STATIC_LIB
#
diff --git a/native_client_sdk/src/tools/nacl_gcc.mk b/native_client_sdk/src/tools/nacl_gcc.mk
index 1460637e20..a68d230fde 100644
--- a/native_client_sdk/src/tools/nacl_gcc.mk
+++ b/native_client_sdk/src/tools/nacl_gcc.mk
@@ -47,13 +47,14 @@ ARM_NM ?= $(TC_PATH)/$(OSNAME)_arm_$(TOOLCHAIN)/bin/arm-nacl-nm
# Architecture-specific flags
-X86_32_CFLAGS ?= -DNACL_ARCH=x86_32
-X86_64_CFLAGS ?= -DNACL_ARCH=x86_64
-ARM_CFLAGS ?= -DNACL_ARCH=arm
+X86_32_CFLAGS ?=
+X86_64_CFLAGS ?=
+ARM_CFLAGS ?=
+
+X86_32_CXXFLAGS ?=
+X86_64_CXXFLAGS ?=
+ARM_CXXFLAGS ?=
-X86_32_CXXFLAGS ?= -DNACL_ARCH=x86_32
-X86_64_CXXFLAGS ?= -DNACL_ARCH=x86_64
-ARM_CXXFLAGS ?= -DNACL_ARCH=arm
#
# Compile Macro