Chromium Code Reviews| Index: ppapi/tests/test_audio.cc |
| diff --git a/ppapi/tests/test_audio.cc b/ppapi/tests/test_audio.cc |
| index 4fea6e8646d31574c53e8db29713d261cedca0b5..67dbf7ef8490df3abf1e584e67627348808c3ba8 100644 |
| --- a/ppapi/tests/test_audio.cc |
| +++ b/ppapi/tests/test_audio.cc |
| @@ -11,11 +11,98 @@ |
| #include "ppapi/cpp/module.h" |
| #include "ppapi/tests/testing_instance.h" |
| #include "ppapi/tests/test_utils.h" |
| +#include "ppapi/native_client/src/untrusted/irt_stub/thread_creator.h" |
| +#include "native_client/src/include/elf_auxv.h" |
| + |
| +#include <unistd.h> |
| #define ARRAYSIZE_UNSAFE(a) \ |
| ((sizeof(a) / sizeof(*(a))) / \ |
| static_cast<size_t>(!(sizeof(a) % sizeof(*(a))))) |
| +extern char **environ; |
| + |
| +namespace { |
| + |
| +typedef uint32_t Elf32_Word; |
| + |
| +typedef struct { |
| + Elf32_Word a_type; // Entry type |
| + union { |
| + Elf32_Word a_val; // Integer value |
| + } a_un; |
| +} Elf32_auxv_t; |
| + |
| +Elf32_auxv_t* FindAuxv(void) { |
|
Mark Seaborn
2014/04/16 20:00:00
You should be able to use nacl_interface_query() i
hidehiko
2014/04/17 14:05:15
Great to know. Fixed.
|
| + // This presumes environ has its startup-time value on the stack. |
| + char **ep = environ; |
| + while (*ep != NULL) |
| + ++ep; |
| + return (Elf32_auxv_t *) (ep + 1); |
| +} |
| + |
| +TYPE_nacl_irt_query GrokAuxv(const Elf32_auxv_t* auxv) { |
| + for (const Elf32_auxv_t* av = auxv; av->a_type != AT_NULL; ++av) { |
| + if (av->a_type == AT_SYSINFO) |
| + return (TYPE_nacl_irt_query) av->a_un.a_val; |
| + } |
| + return NULL; |
| +} |
| + |
| +void GetNaClIrtPpapiHook(struct nacl_irt_ppapihook* hooks) { |
| + TYPE_nacl_irt_query query_func = GrokAuxv(FindAuxv()); |
| + query_func(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; |
| +} |
| + |
| +int g_num_thread_create_called = 0; |
| +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); |
| +} |
| + |
| +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. |
| + 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); |
| +} |
| + |
| +class ScopedThreadFunctionsResetter { |
| + public: |
| + ScopedThreadFunctionsResetter() {} |
| + ~ScopedThreadFunctionsResetter() { |
| + nacl_irt_ppapihook hooks; |
| + GetNaClIrtPpapiHook(&hooks); |
| + __nacl_register_thread_creator(&hooks); |
| + } |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(ScopedThreadFunctionsResetter); |
|
hidehiko
2014/04/17 14:05:15
Removed DISALLOW_COPY_AND_ASSIGN here, because, ac
|
| +}; |
| + |
| +} // namespace |
| + |
| REGISTER_TEST_CASE(Audio); |
| TestAudio::TestAudio(TestingInstance* instance) |
| @@ -53,6 +140,7 @@ void TestAudio::RunTests(const std::string& filter) { |
| RUN_TEST(AudioCallback2, filter); |
| RUN_TEST(AudioCallback3, filter); |
| RUN_TEST(AudioCallback4, filter); |
| + RUN_TEST(AudioThreadCreator, filter); |
| } |
| // Test creating audio resources for all guaranteed sample rates and various |
| @@ -319,6 +407,64 @@ std::string TestAudio::TestAudioCallback4() { |
| PASS(); |
| } |
| +// 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(); |
| +} |
| + |
| // TODO(raymes): Test that actually playback happens correctly, etc. |
| static void Crash() { |