ccls/src/platform.cc

126 lines
3.1 KiB
C++
Raw Normal View History

2017-03-19 22:06:22 +00:00
#include "platform.h"
#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>
#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
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) {
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) {
std::vector<std::string> elems;
Split(s, delim, std::back_inserter(elems));
return elems;
}
2017-11-19 22:11:54 +00:00
std::string Join(const std::vector<std::string>& entries,
char delim,
size_t end) {
std::string result;
bool first = true;
for (size_t 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;
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;
for (size_t j = 0; j < components.size(); ++j) {
size_t i = components.size() - j;
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;
exit(1);
}
// Make all child directories.
for (size_t 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;
exit(1);
}
}
}
2017-11-19 18:05:06 +00:00
TEST_SUITE("Platform") {
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
2017-11-19 18:05:06 +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));
2017-03-19 22:06:22 +00:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
2017-11-19 18:05:06 +00:00
// 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);
2017-03-19 22:06:22 +00:00
2017-11-19 18:05:06 +00:00
// Release the lock, wait for other thread to finish. Verify it
// wrote the expected value.
l1.reset();
t.join();
REQUIRE(value == 1);
}
2017-03-19 22:06:22 +00:00
}