summaryrefslogtreecommitdiffstats
path: root/native_client_sdk/src/libraries
diff options
context:
space:
mode:
authorbradnelson@google.com <bradnelson@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-19 02:46:32 +0000
committerbradnelson@google.com <bradnelson@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-19 02:46:32 +0000
commit745945afe8e9fbfad7bb9ed442143172bf690073 (patch)
tree770e9c5f61e1204221fb4c2887cb863ad8b6688f /native_client_sdk/src/libraries
parentf0953ccbeb01a7a4ed1daa3cb84c2bc42adbed1f (diff)
downloadchromium_src-745945afe8e9fbfad7bb9ed442143172bf690073.zip
chromium_src-745945afe8e9fbfad7bb9ed442143172bf690073.tar.gz
chromium_src-745945afe8e9fbfad7bb9ed442143172bf690073.tar.bz2
Adding reduced version of sdk at 1387 to chrome tree.
BUG=None TEST=None R=noelallen@google.com TBR git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110822 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk/src/libraries')
-rw-r--r--native_client_sdk/src/libraries/build.scons41
-rw-r--r--native_client_sdk/src/libraries/c_salt/test/gtest_event_listener.cc100
-rw-r--r--native_client_sdk/src/libraries/c_salt/test/gtest_event_listener.h51
-rw-r--r--native_client_sdk/src/libraries/c_salt/test/gtest_instance.cc46
-rw-r--r--native_client_sdk/src/libraries/c_salt/test/gtest_instance.h34
-rw-r--r--native_client_sdk/src/libraries/c_salt/test/gtest_module.cc28
-rw-r--r--native_client_sdk/src/libraries/c_salt/test/gtest_nacl_environment.cc19
-rw-r--r--native_client_sdk/src/libraries/c_salt/test/gtest_nacl_environment.h39
-rw-r--r--native_client_sdk/src/libraries/c_salt/test/gtest_runner.cc76
-rw-r--r--native_client_sdk/src/libraries/c_salt/test/gtest_runner.h62
-rw-r--r--native_client_sdk/src/libraries/c_salt/threading/condition_lock.h89
-rw-r--r--native_client_sdk/src/libraries/c_salt/threading/pthread_ext.h15
-rw-r--r--native_client_sdk/src/libraries/c_salt/threading/ref_count.h46
-rw-r--r--native_client_sdk/src/libraries/c_salt/threading/scoped_mutex_lock.h32
-rw-r--r--native_client_sdk/src/libraries/c_salt/threading/thread_condition.h76
-rw-r--r--native_client_sdk/src/libraries/gtest/build.scons112
-rwxr-xr-xnative_client_sdk/src/libraries/scons38
-rwxr-xr-xnative_client_sdk/src/libraries/scons.bat43
18 files changed, 947 insertions, 0 deletions
diff --git a/native_client_sdk/src/libraries/build.scons b/native_client_sdk/src/libraries/build.scons
new file mode 100644
index 0000000..abc1abc
--- /dev/null
+++ b/native_client_sdk/src/libraries/build.scons
@@ -0,0 +1,41 @@
+#! -*- python -*-
+#
+# Copyright (c) 2011 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Build file for the NaCl SDK Libraries
+
+This file runs all the scons files in the various libraries sub-directories.
+Do not invoke this script directly, but instead use the scons or scons.bat
+wrapper function. E.g.
+
+Linux or Mac:
+ ./scons [Options...]
+
+Windows:
+ scons.bat [Options...]
+"""
+
+#------------------------------------------------------------------------------
+HELP_STRING = """
+===============================================================================
+Help for NaCl SDK Libraries
+===============================================================================
+
+* cleaning: ./scons -c
+* build a target: ./scons <target>
+* clean a target: ./scons -c <target>
+
+Supported targets:
+ * gtest_libs Build the gtest and gmock libraries.
+"""
+
+libraries_sconscripts = [
+ 'gtest/build.scons',
+ ]
+
+Help(HELP_STRING)
+
+SConscript(libraries_sconscripts)
diff --git a/native_client_sdk/src/libraries/c_salt/test/gtest_event_listener.cc b/native_client_sdk/src/libraries/c_salt/test/gtest_event_listener.cc
new file mode 100644
index 0000000..0afb3ed
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/test/gtest_event_listener.cc
@@ -0,0 +1,100 @@
+// Copyright 2011 The Native Client 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 "c_salt/test/gtest_event_listener.h"
+
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/var.h"
+
+namespace c_salt {
+
+GTestEventListener::GTestEventListener(pp::Instance* instance)
+ : instance_(instance),
+ factory_(this) {
+ assert(pp::Module::Get()->core()->IsMainThread());
+}
+
+void GTestEventListener::OnTestProgramStart(
+ const ::testing::UnitTest& unit_test) {
+ std::stringstream msg;
+ int num_tests = unit_test.test_to_run_count();
+ int num_test_cases = unit_test.test_case_to_run_count();
+
+ msg << "::start::" << num_tests << " test";
+ if (num_tests > 1) msg << 's';
+ msg << " from "<< num_test_cases << " test case";
+ if (num_test_cases > 1) msg << 's';
+ msg << '.';
+ PostMessage(msg.str());
+}
+
+void GTestEventListener::OnTestCaseStart(
+ const ::testing::TestCase& test_case) {
+ // not currently used
+}
+
+void GTestEventListener::OnTestStart(const ::testing::TestInfo& test_info) {
+ // not currently used
+}
+
+void GTestEventListener::OnTestPartResult(
+ const ::testing::TestPartResult& test_part_result) {
+ if (test_part_result.failed()) {
+ std::stringstream msg;
+ msg << "::test_failed::";
+ msg << test_part_result.file_name();
+ msg << "::" << test_part_result.line_number() << "::";
+ msg << test_part_result.summary();
+ PostMessage(msg.str());
+
+ msg.str("");
+ msg << "::failure_log::";
+ msg << test_part_result.summary();
+ PostMessage(msg.str());
+ }
+}
+
+void GTestEventListener::OnTestEnd(const ::testing::TestInfo& test_info) {
+ std::stringstream msg;
+ msg << "::test_end::";
+ msg << test_info.test_case_name() << "." << test_info.name();
+
+ msg << (test_info.result()->Failed() ? ": FAILED" : ": OK");
+ PostMessage(msg.str());
+}
+
+void GTestEventListener::OnTestCaseEnd(
+ const ::testing::TestCase& test_case) {
+ // not used
+}
+
+void GTestEventListener::OnTestProgramEnd(
+ const ::testing::UnitTest& unit_test) {
+ // Print info about what test and test cases ran.
+ int num_passed_tests = unit_test.successful_test_count();
+ int num_failed_tests = unit_test.failed_test_count();
+ std::stringstream msg;
+ msg << "::Result::";
+ msg << ((num_failed_tests > 0) ? "failed::" : "success::");
+ msg << num_passed_tests << "::" << num_failed_tests << "::";
+ PostMessage(msg.str());
+}
+
+void GTestEventListener::PostMessage(const std::string& str) {
+ if (pp::Module::Get()->core()->IsMainThread()) {
+ instance_->PostMessage(str);
+ } else {
+ pp::CompletionCallback cc = factory_.NewCallback(
+ &GTestEventListener::PostMessageCallback, str);
+ pp::Module::Get()->core()->CallOnMainThread(0, cc, PP_OK);
+ }
+}
+
+void GTestEventListener::PostMessageCallback(int32_t result,
+ const std::string& str) {
+ instance_->PostMessage(str);
+}
+
+} // namespace c_salt
+
diff --git a/native_client_sdk/src/libraries/c_salt/test/gtest_event_listener.h b/native_client_sdk/src/libraries/c_salt/test/gtest_event_listener.h
new file mode 100644
index 0000000..6419683
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/test/gtest_event_listener.h
@@ -0,0 +1,51 @@
+// Copyright 2011 The Native Client 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 C_SALT_TEST_GTEST_EVENT_LISTENER_H_
+#define C_SALT_TEST_GTEST_EVENT_LISTENER_H_
+
+#include <string>
+#include "c_salt/threading/ref_count.h"
+#include "gtest/gtest.h"
+#include "ppapi/cpp/completion_callback.h"
+
+namespace pp {
+class Instance;
+} // namespace pp
+
+namespace c_salt {
+
+// GTestEventListener is a gtest event listener that performs two functions:
+// 1. It redirects output to PostMessage rather than printf, so that test events
+// are dispatched to JS.
+// 2. Channels post-message dispatches to the main thread via callbacks, so that
+// it can be used from any thread.
+//
+// GTestEventListener formats gtest event messages to be parsed by javascript
+// helper functions found in gtest_runner.js
+class GTestEventListener : public ::testing::EmptyTestEventListener {
+ public:
+ explicit GTestEventListener(pp::Instance* instance);
+
+ // TestEventListener overrides.
+ virtual void OnTestProgramStart(const ::testing::UnitTest& unit_test);
+ virtual void OnTestCaseStart(const ::testing::TestCase& test_case);
+ virtual void OnTestStart(const ::testing::TestInfo& test_info);
+ virtual void OnTestPartResult(
+ const ::testing::TestPartResult& test_part_result);
+ virtual void OnTestEnd(const ::testing::TestInfo& test_info);
+ virtual void OnTestCaseEnd(const ::testing::TestCase& test_case);
+ virtual void OnTestProgramEnd(const ::testing::UnitTest& unit_test);
+
+ private:
+ void PostMessage(const std::string& str);
+ void PostMessageCallback(int32_t result, const std::string& str);
+
+ pp::Instance* instance_;
+ pp::CompletionCallbackFactory<GTestEventListener,
+ ::threading::RefCount> factory_;
+};
+
+} // namespace c_salt
+#endif // C_SALT_TEST_GTEST_EVENT_LISTENER_H_
+
diff --git a/native_client_sdk/src/libraries/c_salt/test/gtest_instance.cc b/native_client_sdk/src/libraries/c_salt/test/gtest_instance.cc
new file mode 100644
index 0000000..1445bd9
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/test/gtest_instance.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 The Native Client 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 "c_salt/test/gtest_instance.h"
+#include "c_salt/test/gtest_runner.h"
+#include "ppapi/cpp/var.h"
+
+namespace c_salt {
+
+GTestInstance::GTestInstance(PP_Instance instance)
+ : pp::Instance(instance) {
+}
+
+GTestInstance::~GTestInstance() {
+}
+
+bool GTestInstance::Init(uint32_t /* argc */, const char* /* argn */[],
+ const char* /* argv */[]) {
+ // Create a GTestRunner thread/singleton.
+ int local_argc = 0;
+ c_salt::GTestRunner::CreateGTestRunnerThread(this, local_argc, NULL);
+ return true;
+}
+
+void GTestInstance::HandleMessage(const pp::Var& var_message) {
+ if (!var_message.is_string()) {
+ PostMessage("Invalid message");
+ return;
+ }
+
+ std::string message = var_message.AsString();
+ if (message == "RunGTest") {
+ // This is our signal to start running the tests. Results from the tests
+ // are posted through GTestEventListener.
+ c_salt::GTestRunner::gtest_runner()->RunAllTests();
+ } else {
+ std::string return_var;
+ return_var = "Unknown message ";
+ return_var += message;
+ PostMessage(return_var);
+ }
+}
+
+} // namespace c_salt
+
diff --git a/native_client_sdk/src/libraries/c_salt/test/gtest_instance.h b/native_client_sdk/src/libraries/c_salt/test/gtest_instance.h
new file mode 100644
index 0000000..aa180f8
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/test/gtest_instance.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Native Client 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 C_SALT_TEST_GTEST_INSTANCE_H_
+#define C_SALT_TEST_GTEST_INSTANCE_H_
+
+#include "ppapi/cpp/instance.h"
+
+namespace c_salt {
+
+// GTestInstance is a NaCl instance specifically dedicated to running
+// gtest-based unit tests. It creates a GTestRunner thread/singleton pair as
+// part of its Init function and runs all registered gtests once it
+// receives a 'RunGTest' message in its post-message handler. Results from the
+// test are posted back to JS through GTestEventListener.
+//
+// All tests are run from a background thread and must be written accordingly.
+// Although that may complicate the test code a little, it allows the tests
+// to be synchronized. I.e. Each test is launched and the thread is blocked
+// until the outcome is known and reported.
+class GTestInstance : public pp::Instance {
+ public:
+ explicit GTestInstance(PP_Instance instance);
+ virtual ~GTestInstance();
+
+ // pp::Instance overrides.
+ virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
+ virtual void HandleMessage(const pp::Var& var_message);
+};
+
+} // namespace c_salt
+
+#endif // C_SALT_TEST_GTEST_INSTANCE_H_
+
diff --git a/native_client_sdk/src/libraries/c_salt/test/gtest_module.cc b/native_client_sdk/src/libraries/c_salt/test/gtest_module.cc
new file mode 100644
index 0000000..3cc0ad0
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/test/gtest_module.cc
@@ -0,0 +1,28 @@
+// Copyright 2011 The Native Client 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 "c_salt/test/gtest_instance.h"
+#include "ppapi/cpp/module.h"
+
+namespace c_salt {
+
+// GTestModule is a NaCl module dedicated to running gtest-based unit tests.
+// It creates an NaCl instance based on GTestInstance.
+class GTestModule : public pp::Module {
+ public:
+ GTestModule() : pp::Module() {}
+ ~GTestModule() {}
+
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new c_salt::GTestInstance(instance);
+ }
+};
+
+} // namespace c_salt
+
+namespace pp {
+Module* CreateModule() {
+ return new c_salt::GTestModule();
+}
+} // namespace pp
+
diff --git a/native_client_sdk/src/libraries/c_salt/test/gtest_nacl_environment.cc b/native_client_sdk/src/libraries/c_salt/test/gtest_nacl_environment.cc
new file mode 100644
index 0000000..416226b
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/test/gtest_nacl_environment.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2011 The Native Client 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 "c_salt/test/gtest_nacl_environment.h"
+
+namespace c_salt {
+
+pp::Instance* GTestNaclEnvironment::global_instance_ = NULL;
+
+void GTestNaclEnvironment::SetUp() {
+ // Check that the global instance is set before running the tests.
+ assert(global_instance_ != NULL);
+}
+
+void GTestNaclEnvironment::TearDown() {
+}
+
+} // namespace c_salt
+
diff --git a/native_client_sdk/src/libraries/c_salt/test/gtest_nacl_environment.h b/native_client_sdk/src/libraries/c_salt/test/gtest_nacl_environment.h
new file mode 100644
index 0000000..8183565
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/test/gtest_nacl_environment.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Native Client 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 C_SALT_TEST_GTEST_NACL_ENVIRONMENT_H_
+#define C_SALT_TEST_GTEST_NACL_ENVIRONMENT_H_
+
+#include <cassert>
+#include "gtest/gtest.h"
+
+namespace pp {
+class Instance;
+} // namespace pp
+
+namespace c_salt {
+
+// A custom environment for NaCl gtest.
+class GTestNaclEnvironment : public ::testing::Environment {
+ public:
+ // Set the global NaCl instance that will be shared by all the tests.
+ static void set_global_instance(pp::Instance* instance) {
+ global_instance_ = instance;
+ }
+
+ // Get the global NaCl instance.
+ static pp::Instance* global_instance() { return global_instance_; }
+
+ // Environment overrides.
+ virtual void SetUp();
+ virtual void TearDown();
+
+ private:
+ static pp::Instance* global_instance_;
+};
+
+} // namespace c_salt
+
+#endif // C_SALT_TEST_GTEST_NACL_ENVIRONMENT_H_
+
diff --git a/native_client_sdk/src/libraries/c_salt/test/gtest_runner.cc b/native_client_sdk/src/libraries/c_salt/test/gtest_runner.cc
new file mode 100644
index 0000000..d6afab0
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/test/gtest_runner.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Native Client 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 "c_salt/test/gtest_runner.h"
+
+#include <cassert>
+
+#include "c_salt/test/gtest_event_listener.h"
+#include "c_salt/test/gtest_nacl_environment.h"
+#include "gtest/gtest.h"
+
+namespace c_salt {
+
+pthread_t GTestRunner::g_test_runner_thread_ = NACL_PTHREAD_ILLEGAL_THREAD_ID;
+GTestRunner* GTestRunner::gtest_runner_ = NULL;
+
+void GTestRunner::CreateGTestRunnerThread(pp::Instance* instance,
+ int argc, char** argv) {
+ assert(g_test_runner_thread_ == NACL_PTHREAD_ILLEGAL_THREAD_ID);
+ if (g_test_runner_thread_ == NACL_PTHREAD_ILLEGAL_THREAD_ID) {
+ gtest_runner_ = new GTestRunner();
+ gtest_runner_->Init(instance, argc, argv);
+ pthread_create(&g_test_runner_thread_, NULL, ThreadFunc, NULL);
+ }
+}
+
+void GTestRunner::RunAllTests() {
+ status_signal_.Lock();
+ assert(status_ == kIdle);
+ status_ = kRunTests;
+ status_signal_.Signal();
+ status_signal_.Unlock();
+}
+
+void* GTestRunner::ThreadFunc(void* param) {
+ gtest_runner_->RunLoop();
+ delete gtest_runner_;
+ gtest_runner_ = NULL;
+ pthread_exit(NULL);
+ return NULL;
+}
+
+GTestRunner::GTestRunner() : status_(kIdle) { }
+
+void GTestRunner::Init(pp::Instance* instance, int argc, char** argv) {
+ // Init gtest.
+ testing::InitGoogleTest(&argc, argv);
+
+ // Add GTestEventListener to the list of listeners. That will cause the
+ // test output to go to nacltest.js through PostMessage.
+ ::testing::TestEventListeners& listeners =
+ ::testing::UnitTest::GetInstance()->listeners();
+ delete listeners.Release(listeners.default_result_printer());
+ listeners.Append(new c_salt::GTestEventListener(instance));
+
+ // We use our own gtest environment, mainly to make the nacl instance
+ // available to the individual unit tests.
+ c_salt::GTestNaclEnvironment* test_env = new c_salt::GTestNaclEnvironment();
+ test_env->set_global_instance(instance);
+ ::testing::AddGlobalTestEnvironment(test_env);
+}
+
+void GTestRunner::RunLoop() {
+ // Stay idle until RunAlltests is called.
+ status_signal_.Lock();
+ while (status_ == kIdle) {
+ status_signal_.Wait();
+ }
+
+ assert(status_ == kRunTests);
+ status_signal_.Unlock();
+ RUN_ALL_TESTS();
+}
+
+} // namespace c_salt
+
diff --git a/native_client_sdk/src/libraries/c_salt/test/gtest_runner.h b/native_client_sdk/src/libraries/c_salt/test/gtest_runner.h
new file mode 100644
index 0000000..d8c2a6e
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/test/gtest_runner.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Native Client 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 C_SALT_TEST_GTEST_RUNNER_H_
+#define C_SALT_TEST_GTEST_RUNNER_H_
+
+#include "c_salt/threading/pthread_ext.h"
+#include "c_salt/threading/thread_condition.h"
+
+namespace pp {
+class Instance;
+} // namespace pp
+
+namespace c_salt {
+
+// GTestRunner is a threaded singleton for running gtest-based unit tests.
+class GTestRunner {
+ public:
+ // Factory function to create the background gtest thread and associated
+ // GTestRunner singleton. It is an error to call the factory function more
+ // than once that raises an assert in debug mde.
+ //
+ // Parameters:
+ // instance: the NaCl instance.
+ // argc: arg count from pp::Instance::Init.
+ // argv: the arguments from pp::Instance::Init.
+ static void CreateGTestRunnerThread(pp::Instance* instance,
+ int argc, char** argv);
+
+ // Get the GTestRunner singleton.
+ // @return A pointer to the GTestRunner singleton.
+ static GTestRunner* gtest_runner() { return gtest_runner_; }
+
+ // Tell the GTestRunner to run all gtest unit tests.
+ void RunAllTests();
+
+ protected:
+ // The pthread thread function.
+ static void* ThreadFunc(void* param);
+
+ // Don't try to create instances directly. Use the factory function instead.
+ GTestRunner();
+ void Init(pp::Instance* instance, int argc, char** argv);
+
+ // The thread run loop exits once all test have run.
+ void RunLoop();
+
+ private:
+ // The status and associated status signal are used to control the state of
+ // the thread run loop.
+ enum Status { kIdle, kRunTests };
+ c_salt::threading::ThreadCondition status_signal_;
+ Status status_;
+
+ static pthread_t g_test_runner_thread_;
+ static GTestRunner* gtest_runner_;
+};
+
+} // namespace c_salt
+
+#endif // C_SALT_TEST_GTEST_RUNNER_H_
+
diff --git a/native_client_sdk/src/libraries/c_salt/threading/condition_lock.h b/native_client_sdk/src/libraries/c_salt/threading/condition_lock.h
new file mode 100644
index 0000000..1d6b962
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/threading/condition_lock.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2011 The Native Client 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 CONDITION_LOCK_H_
+#define CONDITION_LOCK_H_
+
+#include <pthread.h>
+
+namespace threading {
+// Class to manage a lock associated with a specific value. The calling thread
+// can ask to acquire the lock only when the lock is in a certain condition.
+class ConditionLock {
+ public:
+ ConditionLock() : condition_value_(0) {
+ InitLock();
+ }
+ explicit ConditionLock(int32_t condition_value)
+ : condition_value_(condition_value) {
+ InitLock();
+ }
+
+ virtual ~ConditionLock() {
+ pthread_cond_destroy(&condition_condition_);
+ pthread_mutex_destroy(&condition_lock_);
+ }
+
+ // Acquire the mutex without regard to the condition.
+ void Lock() {
+ pthread_mutex_lock(&condition_lock_);
+ }
+
+ // Acquire the mutex lock when the lock values are equal. Blocks the
+ // calling thread until the lock can be acquired and the condition is met.
+ void LockWhenCondition(int32_t condition_value) {
+ Lock();
+ while (condition_value != condition_value_) {
+ pthread_cond_wait(&condition_condition_, &condition_lock_);
+ }
+ // When this method returns, |contition_lock_| will be acquired. The
+ // calling thread must unlock it.
+ }
+
+ // Acquire the mutex lock when the lock values are _NOT_ equal. Blocks the
+ // calling thread until the lock can be acquired and the condition is met.
+ void LockWhenNotCondition(int32_t condition_value) {
+ Lock();
+ while (condition_value == condition_value_) {
+ pthread_cond_wait(&condition_condition_, &condition_lock_);
+ }
+ // When this method returns, |contition_lock_| will be acquired. The
+ // calling thread must unlock it.
+ }
+
+ // Release the lock without changing the condition. Signal the condition
+ // so that threads waiting in LockWhenCondtion() will wake up. If there are
+ // no threads waiting for the signal, this has the same effect as a simple
+ // mutex unlock.
+ void Unlock() {
+ pthread_cond_broadcast(&condition_condition_);
+ pthread_mutex_unlock(&condition_lock_);
+ }
+
+ // Release the lock, setting the condition's value. This assumes that
+ // |condition_lock_| has been acquired.
+ void UnlockWithCondition(unsigned int condition_value) {
+ condition_value_ = condition_value;
+ Unlock();
+ }
+
+ // Return the current condition value without any mutex protection.
+ int32_t condition_value() const {
+ return condition_value_;
+ }
+
+ private:
+ void InitLock() {
+ pthread_mutex_init(&condition_lock_, NULL);
+ pthread_cond_init(&condition_condition_, NULL);
+ }
+
+ pthread_mutex_t condition_lock_;
+ pthread_cond_t condition_condition_;
+ int32_t condition_value_;
+};
+} // namespace threading
+
+#endif // CONDITION_LOCK_H_
+
diff --git a/native_client_sdk/src/libraries/c_salt/threading/pthread_ext.h b/native_client_sdk/src/libraries/c_salt/threading/pthread_ext.h
new file mode 100644
index 0000000..2152549
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/threading/pthread_ext.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2011 The Native Client 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 PTHREAD_EXT_H_
+#define PTHREAD_EXT_H_
+
+// Include wrapper on pthread.h, with a few handy constants.
+
+#include <pthread.h>
+
+#define PTHREAD_MUTEX_SUCCESS 0
+
+#endif // PTHREAD_EXT_H_
+
diff --git a/native_client_sdk/src/libraries/c_salt/threading/ref_count.h b/native_client_sdk/src/libraries/c_salt/threading/ref_count.h
new file mode 100644
index 0000000..55d3db1
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/threading/ref_count.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 The Native Client 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 REF_COUNT_H_
+#define REF_COUNT_H_
+
+#include "c_salt/threading/pthread_ext.h"
+
+namespace threading {
+
+// A thread-safe reference counter for class CompletionCallbackFactory.
+class RefCount {
+ public:
+ RefCount() : ref_(0) {
+ pthread_mutex_init(&mutex_, NULL);
+ }
+ ~RefCount() {
+ pthread_mutex_destroy(&mutex_);
+ }
+
+ int32_t AddRef() {
+ int32_t ret_val = 0;
+ if (pthread_mutex_lock(&mutex_) == PTHREAD_MUTEX_SUCCESS) {
+ ret_val = ++ref_;
+ pthread_mutex_unlock(&mutex_);
+ }
+ return ret_val;
+ }
+
+ int32_t Release() {
+ int32_t ret_val = -1;
+ if (pthread_mutex_lock(&mutex_) == PTHREAD_MUTEX_SUCCESS) {
+ ret_val = --ref_;
+ pthread_mutex_unlock(&mutex_);
+ }
+ return ret_val;
+ }
+
+ private:
+ int32_t ref_;
+ pthread_mutex_t mutex_;
+};
+
+} // namespace threading
+#endif // REF_COUNT_H_
+
diff --git a/native_client_sdk/src/libraries/c_salt/threading/scoped_mutex_lock.h b/native_client_sdk/src/libraries/c_salt/threading/scoped_mutex_lock.h
new file mode 100644
index 0000000..03868ae
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/threading/scoped_mutex_lock.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Native Client 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 SCOPED_MUTEX_LOCK_H_
+#define SCOPED_MUTEX_LOCK_H_
+
+#include "c_salt/threading/pthread_ext.h"
+
+namespace threading {
+// A small helper RAII class that implements a scoped pthread_mutex lock.
+class ScopedMutexLock {
+ public:
+ explicit ScopedMutexLock(pthread_mutex_t* mutex) : mutex_(mutex) {
+ if (pthread_mutex_lock(mutex_) != PTHREAD_MUTEX_SUCCESS) {
+ mutex_ = NULL;
+ }
+ }
+ ~ScopedMutexLock() {
+ if (mutex_)
+ pthread_mutex_unlock(mutex_);
+ }
+ bool is_valid() const {
+ return mutex_ != NULL;
+ }
+ private:
+ pthread_mutex_t* mutex_; // Weak reference.
+};
+} // namespace threading
+
+#endif // SCOPED_MUTEX_LOCK_H_
+
diff --git a/native_client_sdk/src/libraries/c_salt/threading/thread_condition.h b/native_client_sdk/src/libraries/c_salt/threading/thread_condition.h
new file mode 100644
index 0000000..cacd4dae
--- /dev/null
+++ b/native_client_sdk/src/libraries/c_salt/threading/thread_condition.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Native Client 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 THREAD_CONDITION_H_
+#define THREAD_CONDITION_H_
+
+#include "c_salt/threading/pthread_ext.h"
+
+struct timespec;
+
+namespace c_salt {
+namespace threading {
+// A wrapper class for condition signaling. Contains a mutex and condition
+// pair.
+class ThreadCondition {
+ public:
+ // Initialize the mutex and the condition.
+ ThreadCondition() {
+ pthread_mutex_init(&cond_mutex_, NULL);
+ pthread_cond_init(&condition_, NULL);
+ }
+
+ virtual ~ThreadCondition() {
+ pthread_cond_destroy(&condition_);
+ pthread_mutex_destroy(&cond_mutex_);
+ }
+
+ // Lock the mutex, do this before signalling the condition.
+ void Lock() {
+ pthread_mutex_lock(&cond_mutex_);
+ }
+
+ // Unlock the mutex, do this after raising a signal or after returning from
+ // Wait().
+ void Unlock() {
+ pthread_mutex_unlock(&cond_mutex_);
+ }
+
+ // Signal the condition. This will cause Wait() to return.
+ void Signal() {
+ pthread_cond_broadcast(&condition_);
+ }
+
+ // Wait for a Signal(). Note that this can spuriously return, so you should
+ // have a guard bool to see if the condtion is really true. E.g., in the
+ // calling thread:
+ // cond_lock->Lock();
+ // cond_true = true;
+ // cond_lock->Signal();
+ // cond_lock->Unlock();
+ // In the worker thread:
+ // cond_lock->Lock();
+ // while (!cond_true) {
+ // cond_lock->Wait();
+ // }
+ // cond_lock->Unlock();
+ void Wait() {
+ pthread_cond_wait(&condition_, &cond_mutex_);
+ }
+
+ // Same as Wait, but wait at most until abs_time. Returns false if the system
+ // time exceeds abs_time before the condition is signaled.
+ bool TimedWait(struct timespec *abs_time) {
+ return (pthread_cond_timedwait(&condition_, &cond_mutex_, abs_time) == 0);
+ }
+
+ private:
+ pthread_mutex_t cond_mutex_;
+ pthread_cond_t condition_;
+};
+} // namespace threading
+} // namespace c_salt
+
+#endif // THREAD_CONDITION_H_
+
diff --git a/native_client_sdk/src/libraries/gtest/build.scons b/native_client_sdk/src/libraries/gtest/build.scons
new file mode 100644
index 0000000..55a124e
--- /dev/null
+++ b/native_client_sdk/src/libraries/gtest/build.scons
@@ -0,0 +1,112 @@
+# -*- python -*-
+# Copyright (c) 2011 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import build_utils
+import glob
+import os
+import shutil
+import subprocess
+import sys
+
+from SCons import Script
+
+# Directories used throughout this script.
+script_dir = os.path.abspath(os.getcwd())
+sdk_root_dir = os.getenv('NACL_SDK_ROOT')
+build_tools_dir = os.path.join(sdk_root_dir, 'build_tools')
+libraries_dir = os.path.join(sdk_root_dir, 'libraries')
+
+# Add the path to build_tools to the shell's python path.
+shell_env = os.environ.copy()
+python_paths = [build_tools_dir]
+python_paths += [shell_env.get('PYTHONPATH', '')]
+shell_env['PYTHONPATH'] = os.pathsep.join(python_paths)
+
+# Argv for the install-gtest python script.
+script_argv = [
+ '--toolchain=%s' % (
+ build_utils.NormalizeToolchain(base_dir=sdk_root_dir,
+ arch='x86',
+ variant='glibc')),
+ '--toolchain=%s' % (
+ build_utils.NormalizeToolchain(base_dir=sdk_root_dir,
+ arch='x86',
+ variant='newlib')),
+ '--working_dir=%s' % script_dir
+ ]
+
+# The scons build env.
+build_env = Script.Environment().Clone()
+
+# Where the src for gtest and gmock will be found after running the install
+# script. We keep them around as a sentinel, to indicate they they have been
+# installed. (See BuildGTestLibs below.)
+gtest_src = os.path.join(script_dir, 'gtest-1.5.0')
+gmock_src = os.path.join(script_dir, 'gmock-1.5.0')
+
+
+def BuildGTestLibs(env, target, source):
+ '''Build and install the gtest/gmock libraries.
+
+ This invokes the gtest_install.py script in the build_tools directory. In turn
+ that scripts downloads, untar, patches and build the gtest/gmock libraries.
+ Finally, the libraries and related include files are copied to the toolchain.
+
+ Args:
+ env: The construction Environment() that is building the examples.
+ target: The target that triggered this build. Not used.
+ source: The sources used for this build. Not used.
+ '''
+ # If our sentinel, the gtest source is present, do not build.
+ if os.path.exists(gtest_src):
+ return
+ # Remove any old gmock source if still present.
+ shutil.rmtree(gmock_src, ignore_errors=True)
+ # Invoke the gtest install script.
+ script = os.path.join(build_tools_dir, 'install_gtest', 'install_gtest.py')
+ py_command = [sys.executable, script]
+ subprocess.check_call(py_command + script_argv, env=shell_env)
+
+ # Clean up: remove left-over tgz files.
+ for f in glob.iglob(os.path.join(script_dir, '*.tgz')):
+ os.remove(f)
+
+
+def CleanGTestLibs(env, target, suite_name):
+ '''Clean the gtest/gmock libraries sources.
+
+ This does a partial clean up of the gtest/gmock projects. It removes the src
+ directories. However, the actual libraries and related includes in the
+ toolchains are not removed. It is however sufficient to trigger a full
+ rebuild of gtest/gmock.
+
+ Args:
+ env: The construction Environment() that is building the examples.
+ target: The target that triggered this build.
+ suite_name: A suite name that should cause this target to be cleaned.
+ '''
+ # Only do this in 'clean' mode.
+ if not build_env.GetOption('clean'):
+ return
+ # Only clean target if it's on the cmd line or it's a clean all.
+ clean_this = True
+ if len(COMMAND_LINE_TARGETS) > 0:
+ clean_this = False
+ for cl_target in COMMAND_LINE_TARGETS:
+ if cl_target == suite_name or cl_target == target:
+ clean_this = True
+ break
+ # Delete the src trees for gtest and gmock.
+ if clean_this:
+ shutil.rmtree(gmock_src, ignore_errors=True)
+ shutil.rmtree(gtest_src, ignore_errors=True)
+
+
+gtest_libs_builder = build_env.Alias('gtest_libs', [], BuildGTestLibs)
+build_env.AlwaysBuild(gtest_libs_builder)
+CleanGTestLibs(build_env, 'gtest_libs', 'bot')
+
+# ----------------------------------------------------------------------------
+build_env.Default('gtest_libs')
diff --git a/native_client_sdk/src/libraries/scons b/native_client_sdk/src/libraries/scons
new file mode 100755
index 0000000..053e32d
--- /dev/null
+++ b/native_client_sdk/src/libraries/scons
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# Copyright (c) 2011 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+readonly SCRIPT_DIR="$(dirname "$0")"
+readonly SCRIPT_DIR_ABS="$(cd "${SCRIPT_DIR}" ; pwd -P)"
+
+# NACL_SDK_ROOT must be set.
+if [ x"${NACL_SDK_ROOT}"x == "xx" ] ; then
+ echo "Error: NACL_SDK_ROOT is not set."
+ exit 1;
+fi
+
+# NACL_TARGET_PLATFORM is really the name of a folder with the base dir -
+# usually NACL_SDK_ROOT - within which the toolchain for the target platform
+# are found.
+# Replace the platform with the name of your target platform. For example, to
+# build applications that target the pepper_17 API, set
+# NACL_TARGET_PLATFORM="pepper_17"
+if [ x"${NACL_TARGET_PLATFORM}"x == "xx" ] ; then
+ export NACL_TARGET_PLATFORM="pepper_17"
+fi
+
+readonly NACL_PLATFORM_DIR="${NACL_SDK_ROOT}/${NACL_TARGET_PLATFORM}"
+readonly BASE_SCRIPT="${NACL_PLATFORM_DIR}/third_party/scons-2.0.1/script/scons"
+
+export SCONS_LIB_DIR="${NACL_PLATFORM_DIR}/third_party/scons-2.0.1/engine"
+export PYTHONPATH="${NACL_PLATFORM_DIR}/third_party/scons-2.0.1/engine:${NACL_PLATFORM_DIR}/build_tools"
+# We have to do this because scons overrides PYTHONPATH and does not preserve
+# what is provided by the OS. The custom variable name won't be overwritten.
+export PYMOX="${NACL_PLATFORM_DIR}/third_party/pymox"
+
+"${BASE_SCRIPT}" --file=build.scons \
+ --site-dir="${NACL_PLATFORM_DIR}/build_tools/nacl_sdk_scons" \
+ $*
+
diff --git a/native_client_sdk/src/libraries/scons.bat b/native_client_sdk/src/libraries/scons.bat
new file mode 100755
index 0000000..889a757
--- /dev/null
+++ b/native_client_sdk/src/libraries/scons.bat
@@ -0,0 +1,43 @@
+@echo off
+
+:: Copyright (c) 2011 The Native Client Authors. All rights reserved.
+:: Use of this source code is governed by a BSD-style license that can be
+:: found in the LICENSE file.
+
+setlocal
+
+:: NACL_SDK_ROOT must be set.
+if not defined NACL_SDK_ROOT (
+ echo Error: NACL_SDK_ROOT is not set.
+ echo Please set NACL_SDK_ROOT to the full path of the Native Client SDK.
+ echo For example:
+ echo set NACL_SDK_ROOT=D:\nacl_sdk
+ goto end
+)
+
+:: NACL_TARGET_PLATFORM is really the name of a folder with the base dir -
+:: usually NACL_SDK_ROOT - within which the toolchain for the target platform
+:: are found.
+:: Replace the platform with the name of your target platform. For example, to
+:: build applications that target the pepper_17 API, set
+:: NACL_TARGET_PLATFORM=pepper_17
+if not defined NACL_TARGET_PLATFORM (
+ set NACL_TARGET_PLATFORM=pepper_17
+)
+
+set NACL_PLATFORM_DIR=%NACL_SDK_ROOT%\%NACL_TARGET_PLATFORM%
+
+set SCONS_LIB_DIR=%NACL_PLATFORM_DIR%\third_party\scons-2.0.1\engine
+set PYTHONPATH=%NACL_PLATFORM_DIR%\third_party\scons-2.0.1\engine;%NACL_PLATFORM_DIR%\build_tools
+
+:: We have to do this because scons overrides PYTHONPATH and does not preserve
+:: what is provided by the OS. The custom variable name won't be overwritten.
+set PYMOX=%NACL_PLATFORM_DIR%\third_party\pymox
+
+:: Run the included copy of scons.
+python -O -OO "%NACL_PLATFORM_DIR%\third_party\scons-2.0.1\script\scons" ^
+--warn no-visual-c-missing ^
+--file=build.scons ^
+--site-dir="%NACL_PLATFORM_DIR%\build_tools\nacl_sdk_scons" %*
+
+:end