Index: ppapi/tests/test_audio.cc |
diff --git a/ppapi/tests/test_audio.cc b/ppapi/tests/test_audio.cc |
index 4fea6e8646d31574c53e8db29713d261cedca0b5..e845759cd79f8ab16c040c7bb8852b409e9bc45c 100644 |
--- a/ppapi/tests/test_audio.cc |
+++ b/ppapi/tests/test_audio.cc |
@@ -12,10 +12,81 @@ |
#include "ppapi/tests/testing_instance.h" |
#include "ppapi/tests/test_utils.h" |
+#if defined(__native_client__) |
+#include "native_client/src/untrusted/irt/irt.h" |
+#include "ppapi/native_client/src/untrusted/irt_stub/thread_creator.h" |
+#endif |
+ |
#define ARRAYSIZE_UNSAFE(a) \ |
((sizeof(a) / sizeof(*(a))) / \ |
static_cast<size_t>(!(sizeof(a) % sizeof(*(a))))) |
+#if defined(__native_client__) |
+namespace { |
+ |
+void GetNaClIrtPpapiHook(struct nacl_irt_ppapihook* hooks) { |
+ nacl_interface_query(NACL_IRT_PPAPIHOOK_v0_1, hooks, sizeof(*hooks)); |
+} |
+ |
+struct PP_ThreadFunctions g_thread_funcs = {}; |
+ |
+void ThreadFunctionsGetter(const struct PP_ThreadFunctions* thread_funcs) { |
+ g_thread_funcs = *thread_funcs; |
+} |
+ |
+// In order to check if the thread_create is called, CountingThreadCreate() |
+// increments this variable. Callers can check if the function is actually |
+// called by looking at this value. |
+int g_num_thread_create_called = 0; |
Mark Seaborn
2014/04/18 15:28:20
Could you also check that thread_join() is called?
hidehiko
2014/04/18 18:16:30
Done.
|
+ |
+int CoutingThreadCreate(uintptr_t* tid, |
+ void (*func)(void* thread_argument), |
+ void* thread_argument) { |
+ ++g_num_thread_create_called; |
+ return g_thread_funcs.thread_create(tid, func, thread_argument); |
+} |
+ |
+// Sets NULL for PP_ThreadFunctions to emulate the situation that |
+// ppapi_register_thread_creator() is not yet called. |
+void SetNullThreadFunctions() { |
+ nacl_irt_ppapihook hooks; |
+ GetNaClIrtPpapiHook(&hooks); |
+ PP_ThreadFunctions thread_functions = {}; |
+ hooks.ppapi_register_thread_creator(&thread_functions); |
+} |
+ |
+void InjectCountingThreadFunctions() { |
+ // First of all, we extract the system default thread functions. |
+ // Internally, __nacl_register_thread_creator calls |
+ // hooks.ppapi_register_thread_creator with default PP_ThreadFunctions |
+ // instance. ThreadFunctionGetter stores it to g_thread_funcs. |
+ nacl_irt_ppapihook hooks = { NULL, ThreadFunctionsGetter }; |
+ __nacl_register_thread_creator(&hooks); |
+ |
+ // Here g_thread_funcs stores the thread functions. |
+ // Inject the CountingThreadCreate. |
+ PP_ThreadFunctions thread_functions = { |
+ CoutingThreadCreate, |
+ g_thread_funcs.thread_join, |
+ }; |
+ GetNaClIrtPpapiHook(&hooks); |
+ hooks.ppapi_register_thread_creator(&thread_functions); |
+} |
+ |
+// Resets the PP_ThreadFunctions on exit from the scope. |
+class ScopedThreadFunctionsResetter { |
+ public: |
+ ScopedThreadFunctionsResetter() {} |
+ ~ScopedThreadFunctionsResetter() { |
+ nacl_irt_ppapihook hooks; |
+ GetNaClIrtPpapiHook(&hooks); |
+ __nacl_register_thread_creator(&hooks); |
+ } |
+}; |
+ |
+} // namespace |
+#endif // __native_client__ |
+ |
REGISTER_TEST_CASE(Audio); |
TestAudio::TestAudio(TestingInstance* instance) |
@@ -53,6 +124,10 @@ void TestAudio::RunTests(const std::string& filter) { |
RUN_TEST(AudioCallback2, filter); |
RUN_TEST(AudioCallback3, filter); |
RUN_TEST(AudioCallback4, filter); |
+ |
+#if defined(__native_client__) |
+ RUN_TEST(AudioThreadCreator, filter); |
+#endif |
} |
// Test creating audio resources for all guaranteed sample rates and various |
@@ -319,6 +394,66 @@ std::string TestAudio::TestAudioCallback4() { |
PASS(); |
} |
+#if defined(__native_client__) |
+// Makes sure the behavior of the thread_create functions. |
+// To work PPB_Audio_Shared properly, the user code must call |
+// ppapi_register_thread_creator(). This test checks the error handling for the |
+// case when user code doesn't call ppapi_register_thread_creator(). Also, |
+// it checks whether the thread functions which is passed from the user code |
+// are actually used. |
+std::string TestAudio::TestAudioThreadCreator() { |
+ // We'll inject some thread functions in this test case. |
+ // Reset them at the end of this case. |
+ ScopedThreadFunctionsResetter thread_resetter; |
+ |
+ // First of all, set NULLs to the thread functions to emulate |
+ // the situation that ppapi_register_thread_creator() is not called |
+ // by user code. |
+ SetNullThreadFunctions(); |
+ |
+ PP_Resource ac = CreateAudioConfig(PP_AUDIOSAMPLERATE_44100, 1024); |
+ ASSERT_TRUE(ac); |
+ audio_callback_method_ = NULL; |
+ PP_Resource audio = audio_interface_->Create( |
+ instance_->pp_instance(), ac, AudioCallbackTrampoline, this); |
+ core_interface_->ReleaseResource(ac); |
+ ac = 0; |
+ |
+ // First, StartPlayback() fails, because no thread creating funciton |
+ // is available. |
+ ASSERT_FALSE(audio_interface_->StartPlayback(audio)); |
+ |
+ // Inject the thread counting function. In the injected function, |
+ // when called, g_num_thread_create_called is incremented. |
+ g_num_thread_create_called = 0; |
+ InjectCountingThreadFunctions(); |
+ |
+ audio_callback_event_.Reset(); |
+ test_done_ = false; |
+ |
+ audio_callback_method_ = &TestAudio::AudioCallbackTest; |
+ // This time, StartPlayback() should succeed. |
+ ASSERT_TRUE(audio_interface_->StartPlayback(audio)); |
+ |
+ // Wait for the audio callback to be called. |
+ audio_callback_event_.Wait(); |
+ ASSERT_TRUE(audio_interface_->StopPlayback(audio)); |
+ |
+ test_done_ = true; |
+ |
+ // Here, the injected thread_create function must have been called. |
+ ASSERT_EQ(1, g_num_thread_create_called); |
+ |
+ // If any more audio callbacks are generated, |
+ // we should crash (which is good). |
+ audio_callback_method_ = NULL; |
+ |
+ core_interface_->ReleaseResource(audio); |
+ |
+ PASS(); |
+} |
+#endif |
+ |
// TODO(raymes): Test that actually playback happens correctly, etc. |
static void Crash() { |