blob: e1c2355ae7e8e60656912e2ae96c7a489930c4ec [file] [log] [blame]
// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: morlovich@google.com (Maksim Orlovich)
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#include <cstddef>
#include <cstdlib>
#include <vector>
#include "pagespeed/kernel/base/abstract_shared_mem.h"
#include "pagespeed/kernel/base/function.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/sharedmem/shared_circular_buffer_test_base.h"
#include "pagespeed/kernel/sharedmem/shared_dynamic_string_map_test_base.h"
#include "pagespeed/kernel/sharedmem/shared_mem_cache_data_test_base.h"
#include "pagespeed/kernel/sharedmem/shared_mem_cache_test_base.h"
#include "pagespeed/kernel/sharedmem/shared_mem_lock_manager_test_base.h"
#include "pagespeed/kernel/sharedmem/shared_mem_statistics_test_base.h"
#include "pagespeed/kernel/sharedmem/shared_mem_test_base.h"
#include "pagespeed/kernel/thread/pthread_shared_mem.h"
namespace net_instaweb {
namespace {
// We test operation of pthread shared memory with both thread & process
// use, which is what PthreadSharedMemThreadEnv and PthreadSharedMemProcEnv
// provide.
class PthreadSharedMemEnvBase : public SharedMemTestEnv {
public:
virtual AbstractSharedMem* CreateSharedMemRuntime() {
return new PthreadSharedMem();
}
virtual void ShortSleep() {
usleep(1000);
}
};
class PthreadSharedMemThreadEnv : public PthreadSharedMemEnvBase {
public:
virtual bool CreateChild(Function* callback) {
pthread_t thread;
if (pthread_create(&thread, NULL, InvokeCallback, callback) != 0) {
return false;
}
child_threads_.push_back(thread);
return true;
}
virtual void WaitForChildren() {
for (size_t i = 0; i < child_threads_.size(); ++i) {
void* result = this; // non-NULL -> failure.
EXPECT_EQ(0, pthread_join(child_threads_[i], &result));
EXPECT_EQ(NULL, result) << "Child reported failure";
}
child_threads_.clear();
}
virtual void ChildFailed() {
// In case of failure, we exit the thread with a non-NULL status.
// We leak the callback object in that case, but this only gets called
// for test failures anyway.
pthread_exit(this);
}
private:
static void* InvokeCallback(void* raw_callback_ptr) {
Function* callback = static_cast<Function*>(raw_callback_ptr);
callback->CallRun();
return NULL; // Used to denote success
}
std::vector<pthread_t> child_threads_;
};
class PthreadSharedMemProcEnv : public PthreadSharedMemEnvBase {
public:
virtual bool CreateChild(Function* callback) {
pid_t ret = fork();
if (ret == -1) {
// Failure
callback->CallCancel();
return false;
} else if (ret == 0) {
// Child.
callback->CallRun();
std::exit(0);
} else {
// Parent.
child_processes_.push_back(ret);
callback->CallCancel();
return true;
}
}
virtual void WaitForChildren() {
for (size_t i = 0; i < child_processes_.size(); ++i) {
int status;
EXPECT_EQ(child_processes_[i], waitpid(child_processes_[i], &status, 0));
EXPECT_TRUE(WIFEXITED(status)) << "Child did not exit cleanly";
EXPECT_EQ(0, WEXITSTATUS(status)) << "Child reported failure";
}
child_processes_.clear();
}
virtual void ChildFailed() {
exit(-1);
}
private:
std::vector<pid_t> child_processes_;
};
INSTANTIATE_TYPED_TEST_CASE_P(PthreadProc, SharedCircularBufferTestTemplate,
PthreadSharedMemProcEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadProc, SharedDynamicStringMapTestTemplate,
PthreadSharedMemProcEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadProc, SharedMemCacheTestTemplate,
PthreadSharedMemProcEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadProc, SharedMemCacheDataTestTemplate,
PthreadSharedMemProcEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadProc, SharedMemLockManagerTestTemplate,
PthreadSharedMemProcEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadProc, SharedMemStatisticsTestTemplate,
PthreadSharedMemProcEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadProc, SharedMemTestTemplate,
PthreadSharedMemProcEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadThread, SharedCircularBufferTestTemplate,
PthreadSharedMemThreadEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadThread, SharedDynamicStringMapTestTemplate,
PthreadSharedMemThreadEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadThread, SharedMemCacheTestTemplate,
PthreadSharedMemThreadEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadThread, SharedMemCacheDataTestTemplate,
PthreadSharedMemThreadEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadThread, SharedMemLockManagerTestTemplate,
PthreadSharedMemThreadEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadThread, SharedMemStatisticsTestTemplate,
PthreadSharedMemThreadEnv);
INSTANTIATE_TYPED_TEST_CASE_P(PthreadThread, SharedMemTestTemplate,
PthreadSharedMemThreadEnv);
} // namespace
} // namespace net_instaweb