diff options
author | bradnelson@google.com <bradnelson@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-19 02:46:32 +0000 |
---|---|---|
committer | bradnelson@google.com <bradnelson@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-19 02:46:32 +0000 |
commit | 745945afe8e9fbfad7bb9ed442143172bf690073 (patch) | |
tree | 770e9c5f61e1204221fb4c2887cb863ad8b6688f /native_client_sdk/src/libraries | |
parent | f0953ccbeb01a7a4ed1daa3cb84c2bc42adbed1f (diff) | |
download | chromium_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')
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( + >estEventListener::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 |