2017-03-19 22:06:22 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
#include "platform.h"
|
|
|
|
|
2017-03-25 20:27:28 +00:00
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <io.h>
|
|
|
|
#include <Windows.h>
|
|
|
|
|
2017-03-19 22:06:22 +00:00
|
|
|
#include <cassert>
|
|
|
|
#include <iostream>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
DWORD CheckForError(std::vector<DWORD> allow) {
|
|
|
|
DWORD error = GetLastError();
|
2017-03-19 22:08:36 +00:00
|
|
|
if (error == ERROR_SUCCESS ||
|
|
|
|
std::find(allow.begin(), allow.end(), error) != allow.end())
|
2017-03-19 22:06:22 +00:00
|
|
|
return error;
|
|
|
|
|
|
|
|
// See http://stackoverflow.com/a/17387176
|
|
|
|
LPSTR message_buffer = nullptr;
|
|
|
|
size_t size = FormatMessageA(
|
2017-03-19 22:08:36 +00:00
|
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
(LPSTR)&message_buffer, 0, NULL);
|
2017-03-19 22:06:22 +00:00
|
|
|
std::string message(message_buffer, size);
|
|
|
|
LocalFree(message_buffer);
|
|
|
|
|
2017-03-19 22:08:36 +00:00
|
|
|
std::cerr << "Windows error code=" << error << ", message=" << message
|
|
|
|
<< std::endl;
|
2017-03-27 04:04:48 +00:00
|
|
|
|
2017-03-19 22:08:36 +00:00
|
|
|
assert(false); // debugger break
|
2017-03-19 22:06:22 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct PlatformMutexWin : public PlatformMutex {
|
|
|
|
HANDLE raw_mutex = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
PlatformMutexWin(const std::string& name) {
|
|
|
|
std::cerr << "[win] Creating mutex with name " << name << std::endl;
|
|
|
|
raw_mutex = CreateMutex(nullptr, false /*initial_owner*/, name.c_str());
|
2017-03-19 22:08:36 +00:00
|
|
|
CheckForError({ERROR_ALREADY_EXISTS});
|
2017-03-19 22:06:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~PlatformMutexWin() override {
|
|
|
|
CloseHandle(raw_mutex);
|
|
|
|
CheckForError({} /*allow*/);
|
|
|
|
raw_mutex = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PlatformScopedMutexLockWin : public PlatformScopedMutexLock {
|
|
|
|
HANDLE raw_mutex;
|
|
|
|
|
|
|
|
PlatformScopedMutexLockWin(HANDLE raw_mutex) : raw_mutex(raw_mutex) {
|
|
|
|
DWORD result = WaitForSingleObject(raw_mutex, INFINITE);
|
2017-03-21 06:03:59 +00:00
|
|
|
assert(result == WAIT_OBJECT_0);
|
|
|
|
CheckForError({ ERROR_NO_MORE_FILES, ERROR_ALREADY_EXISTS } /*allow*/);
|
2017-03-19 22:06:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~PlatformScopedMutexLockWin() override {
|
|
|
|
ReleaseMutex(raw_mutex);
|
2017-03-21 06:03:59 +00:00
|
|
|
CheckForError({ ERROR_NO_MORE_FILES, ERROR_ALREADY_EXISTS } /*allow*/);
|
2017-03-19 22:06:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PlatformSharedMemoryWin : public PlatformSharedMemory {
|
|
|
|
HANDLE shmem_;
|
|
|
|
|
|
|
|
PlatformSharedMemoryWin(const std::string& name, size_t capacity) {
|
2017-03-19 22:08:36 +00:00
|
|
|
std::cerr << "[win] Creating shared memory with name " << name
|
|
|
|
<< " and capacity " << capacity << std::endl;
|
2017-03-19 22:06:22 +00:00
|
|
|
this->name = name;
|
|
|
|
|
2017-03-19 22:08:36 +00:00
|
|
|
shmem_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
|
|
|
capacity, name.c_str());
|
|
|
|
CheckForError({ERROR_ALREADY_EXISTS} /*allow*/);
|
2017-03-19 22:06:22 +00:00
|
|
|
|
|
|
|
data = MapViewOfFile(shmem_, FILE_MAP_ALL_ACCESS, 0, 0, capacity);
|
2017-03-19 22:08:36 +00:00
|
|
|
CheckForError({ERROR_ALREADY_EXISTS} /*allow*/);
|
2017-03-19 22:06:22 +00:00
|
|
|
|
|
|
|
this->capacity = capacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
~PlatformSharedMemoryWin() override {
|
|
|
|
UnmapViewOfFile(data);
|
|
|
|
CheckForError({} /*allow*/);
|
|
|
|
|
|
|
|
data = nullptr;
|
|
|
|
capacity = 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
std::unique_ptr<PlatformMutex> CreatePlatformMutex(const std::string& name) {
|
|
|
|
return MakeUnique<PlatformMutexWin>(name);
|
|
|
|
}
|
|
|
|
|
2017-03-19 22:08:36 +00:00
|
|
|
std::unique_ptr<PlatformScopedMutexLock> CreatePlatformScopedMutexLock(
|
|
|
|
PlatformMutex* mutex) {
|
|
|
|
return MakeUnique<PlatformScopedMutexLockWin>(
|
|
|
|
static_cast<PlatformMutexWin*>(mutex)->raw_mutex);
|
2017-03-19 22:06:22 +00:00
|
|
|
}
|
|
|
|
|
2017-03-19 22:08:36 +00:00
|
|
|
std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(
|
|
|
|
const std::string& name,
|
|
|
|
size_t size) {
|
2017-03-19 22:06:22 +00:00
|
|
|
return MakeUnique<PlatformSharedMemoryWin>(name, size);
|
|
|
|
}
|
|
|
|
|
2017-03-25 20:27:28 +00:00
|
|
|
void PlatformInit() {
|
|
|
|
// We need to write to stdout in binary mode because in Windows, writing
|
|
|
|
// \n will implicitly write \r\n. Language server API will ignore a
|
|
|
|
// \r\r\n split request.
|
|
|
|
_setmode(_fileno(stdout), O_BINARY);
|
|
|
|
_setmode(_fileno(stdin), O_BINARY);
|
|
|
|
}
|
|
|
|
|
2017-03-19 22:06:22 +00:00
|
|
|
// See http://stackoverflow.com/a/19535628
|
|
|
|
std::string GetWorkingDirectory() {
|
|
|
|
char result[MAX_PATH];
|
|
|
|
return std::string(result, GetModuleFileName(NULL, result, MAX_PATH));
|
|
|
|
}
|
2017-03-28 05:27:06 +00:00
|
|
|
|
|
|
|
std::string NormalizePath(const std::string& path) {
|
|
|
|
DWORD retval = 0;
|
|
|
|
BOOL success = false;
|
|
|
|
TCHAR buffer[MAX_PATH] = TEXT("");
|
|
|
|
TCHAR buf[MAX_PATH] = TEXT("");
|
|
|
|
TCHAR** lpp_part = { NULL };
|
|
|
|
|
|
|
|
retval = GetFullPathName(path.c_str(), MAX_PATH, buffer, lpp_part);
|
|
|
|
// fail, return original
|
|
|
|
if (retval == 0)
|
|
|
|
return path;
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
2017-03-19 22:06:22 +00:00
|
|
|
#endif
|