2017-03-19 22:06:22 +00:00
|
|
|
#include "platform.h"
|
|
|
|
|
2017-04-18 02:59:48 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <iterator>
|
|
|
|
#include <sstream>
|
2017-09-22 01:14:57 +00:00
|
|
|
#include <string>
|
2017-03-19 22:06:22 +00:00
|
|
|
#include <thread>
|
2017-04-18 02:59:48 +00:00
|
|
|
#include <vector>
|
2017-03-19 22:06:22 +00:00
|
|
|
|
2017-03-25 20:24:42 +00:00
|
|
|
#include <doctest/doctest.h>
|
2017-03-19 22:06:22 +00:00
|
|
|
|
2017-04-18 02:59:48 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
// See http://stackoverflow.com/a/236803
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename Out>
|
|
|
|
void Split(const std::string& s, char delim, Out result) {
|
2017-04-18 02:59:48 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
ss.str(s);
|
|
|
|
std::string item;
|
|
|
|
while (std::getline(ss, item, delim)) {
|
|
|
|
if (!item.empty())
|
|
|
|
*(result++) = item;
|
|
|
|
}
|
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
std::vector<std::string> Split(const std::string& s, char delim) {
|
2017-04-18 02:59:48 +00:00
|
|
|
std::vector<std::string> elems;
|
|
|
|
Split(s, delim, std::back_inserter(elems));
|
|
|
|
return elems;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Join(const std::vector<std::string>& entries, char delim, int end) {
|
|
|
|
std::string result;
|
|
|
|
bool first = true;
|
|
|
|
for (int i = 0; i < end; ++i) {
|
|
|
|
if (!first)
|
|
|
|
result += delim;
|
|
|
|
first = false;
|
|
|
|
result += entries[i];
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2017-03-22 17:03:45 +00:00
|
|
|
PlatformMutex::~PlatformMutex() = default;
|
|
|
|
|
|
|
|
PlatformScopedMutexLock::~PlatformScopedMutexLock() = default;
|
|
|
|
|
|
|
|
PlatformSharedMemory::~PlatformSharedMemory() = default;
|
|
|
|
|
2017-04-18 02:59:48 +00:00
|
|
|
void MakeDirectoryRecursive(std::string path) {
|
|
|
|
path = NormalizePath(path);
|
|
|
|
|
|
|
|
if (TryMakeDirectory(path))
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::string prefix = "";
|
|
|
|
if (path[0] == '/')
|
|
|
|
prefix = "/";
|
|
|
|
|
|
|
|
std::vector<std::string> components = Split(path, '/');
|
|
|
|
|
|
|
|
// Find first parent directory which doesn't exist.
|
|
|
|
int first_success = -1;
|
2017-05-21 23:22:00 +00:00
|
|
|
for (int i = (int)components.size(); i > 0; --i) {
|
2017-04-18 02:59:48 +00:00
|
|
|
if (TryMakeDirectory(prefix + Join(components, '/', i))) {
|
|
|
|
first_success = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (first_success == -1) {
|
2017-09-22 01:14:57 +00:00
|
|
|
std::cerr << "Failed to make any parent directory for " << path
|
|
|
|
<< std::endl;
|
2017-04-18 02:59:48 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make all child directories.
|
|
|
|
for (int i = first_success + 1; i <= components.size(); ++i) {
|
|
|
|
if (TryMakeDirectory(prefix + Join(components, '/', i)) == false) {
|
2017-09-22 01:14:57 +00:00
|
|
|
std::cerr << "Failed making directory for " << path
|
|
|
|
<< " even after creating parent directories" << std::endl;
|
2017-04-18 02:59:48 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-19 22:06:22 +00:00
|
|
|
TEST_SUITE("Platform");
|
|
|
|
|
2017-04-18 02:59:48 +00:00
|
|
|
TEST_CASE("Split strings") {
|
|
|
|
std::vector<std::string> actual = Split("/a/b/c/", '/');
|
|
|
|
std::vector<std::string> expected{"a", "b", "c"};
|
|
|
|
REQUIRE(actual == expected);
|
|
|
|
}
|
|
|
|
|
2017-03-19 22:06:22 +00:00
|
|
|
TEST_CASE("Mutex lock/unlock (single process)") {
|
|
|
|
auto m1 = CreatePlatformMutex("indexer-platformmutexttest");
|
|
|
|
auto l1 = CreatePlatformScopedMutexLock(m1.get());
|
|
|
|
auto m2 = CreatePlatformMutex("indexer-platformmutexttest");
|
|
|
|
|
|
|
|
int value = 0;
|
|
|
|
|
|
|
|
volatile bool did_run = false;
|
|
|
|
std::thread t([&]() {
|
|
|
|
did_run = true;
|
|
|
|
auto l2 = CreatePlatformScopedMutexLock(m2.get());
|
|
|
|
value = 1;
|
|
|
|
});
|
|
|
|
while (!did_run)
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
|
|
|
|
|
// Other thread has had a chance to run, but it should not have
|
|
|
|
// written to value yet (ie, it should be waiting).
|
|
|
|
REQUIRE(value == 0);
|
|
|
|
|
|
|
|
// Release the lock, wait for other thread to finish. Verify it
|
|
|
|
// wrote the expected value.
|
|
|
|
l1.reset();
|
|
|
|
t.join();
|
|
|
|
REQUIRE(value == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_SUITE_END();
|