ccls/src/platform_win.cc

189 lines
5.2 KiB
C++
Raw Normal View History

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 <direct.h>
2017-03-25 20:27:28 +00:00
#include <fcntl.h>
#include <io.h>
#include <Windows.h>
2017-03-29 06:33:38 +00:00
#include <algorithm>
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 ||
2017-03-29 06:33:38 +00:00
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-29 06:33:38 +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
2017-03-29 06:33:38 +00:00
<< 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;
2017-03-19 22:06:22 +00:00
raw_mutex = CreateMutex(nullptr, false /*initial_owner*/, name.c_str());
2017-03-29 06:33:38 +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) {
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,
2017-03-29 06:33:38 +00:00
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-29 06:33:38 +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(
2017-03-29 06:33:38 +00:00
PlatformMutex* mutex) {
2017-03-19 22:08:36 +00:00
return MakeUnique<PlatformScopedMutexLockWin>(
2017-03-29 06:33:38 +00:00
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(
2017-03-29 06:33:38 +00:00
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;
2017-03-29 06:33:38 +00:00
std::string result = buffer;
std::replace(result.begin(), result.end(), '\\', '/');
//std::transform(result.begin(), result.end(), result.begin(), ::tolower);
2017-03-29 06:33:38 +00:00
return result;
}
bool TryMakeDirectory(const std::string& absolute_path) {
std::cerr << "!! TryMakeDirectory " << absolute_path << std::endl;
if (_mkdir(absolute_path.c_str()) == -1) {
// Success if the directory exists.
return errno == EEXIST;
}
return true;
}
// See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
void SetCurrentThreadName(const std::string& thread_name) {
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = thread_name.c_str();
info.dwThreadID = -1;
info.dwFlags = 0;
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except (EXCEPTION_EXECUTE_HANDLER) {}
}
2017-03-29 06:33:38 +00:00
std::vector<std::string> GetPlatformClangArguments() {
return {
"-fms-compatibility",
"-fdelayed-template-parsing"
};
2017-03-28 05:27:06 +00:00
}
2017-03-19 22:06:22 +00:00
#endif