Commit c02dce53 authored by Kenton Varda's avatar Kenton Varda

Add KJ_WIN32 macro, the Windows equivalent of KJ_SYSCALL.

parent c79b6d09
......@@ -27,6 +27,13 @@
#if _WIN32
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
#define NOMINMAX 1
#define WIN32_LEAN_AND_MEAN 1
#define NOSERVICE 1
#define NOMCX 1
#define NOIME 1
#include <windows.h>
#include "windows-sanity.h"
#endif
namespace kj {
......@@ -125,6 +132,38 @@ Exception::Type typeOfErrno(int error) {
}
}
#if _WIN32
Exception::Type typeOfWin32Error(DWORD error) {
switch (error) {
// TODO(now): This needs more work.
case WSAETIMEDOUT:
return Exception::Type::OVERLOADED;
case WSAENOTCONN:
case WSAECONNABORTED:
case WSAECONNREFUSED:
case WSAECONNRESET:
case WSAEHOSTDOWN:
case WSAEHOSTUNREACH:
case WSAENETDOWN:
case WSAENETRESET:
case WSAENETUNREACH:
return Exception::Type::DISCONNECTED;
case WSAEOPNOTSUPP:
case WSAENOPROTOOPT:
case WSAENOTSOCK: // This is really saying "syscall not implemented for non-sockets".
return Exception::Type::UNIMPLEMENTED;
default:
return Exception::Type::FAILED;
}
}
#endif // _WIN32
enum DescriptionStyle {
LOG,
ASSERTION,
......@@ -132,7 +171,8 @@ enum DescriptionStyle {
};
static String makeDescriptionImpl(DescriptionStyle style, const char* code, int errorNumber,
const char* macroArgs, ArrayPtr<String> argValues) {
const char* sysErrorString, const char* macroArgs,
ArrayPtr<String> argValues) {
KJ_STACK_ARRAY(ArrayPtr<const char>, argNames, argValues.size(), 8, 64);
if (argValues.size() > 0) {
......@@ -205,13 +245,21 @@ static String makeDescriptionImpl(DescriptionStyle style, const char* code, int
#if __USE_GNU
char buffer[256];
if (style == SYSCALL) {
if (sysErrorString == nullptr) {
sysErrorArray = strerror_r(errorNumber, buffer, sizeof(buffer));
} else {
sysErrorArray = sysErrorString;
}
}
#else
char buffer[256];
if (style == SYSCALL) {
if (sysErrorString == nullptr) {
strerror_r(errorNumber, buffer, sizeof(buffer));
sysErrorArray = buffer;
} else {
sysErrorArray = sysErrorString;
}
}
#endif
......@@ -250,6 +298,7 @@ static String makeDescriptionImpl(DescriptionStyle style, const char* code, int
pos = _::fill(pos, codeArray, colon, sysErrorArray);
break;
}
for (size_t i = 0; i < argValues.size(); i++) {
if (i > 0 || style != LOG) {
pos = _::fill(pos, delim);
......@@ -269,7 +318,7 @@ static String makeDescriptionImpl(DescriptionStyle style, const char* code, int
void Debug::logInternal(const char* file, int line, LogSeverity severity, const char* macroArgs,
ArrayPtr<String> argValues) {
getExceptionCallback().logMessage(severity, trimSourceFilename(file).cStr(), line, 0,
makeDescriptionImpl(LOG, nullptr, 0, macroArgs, argValues));
makeDescriptionImpl(LOG, nullptr, 0, nullptr, macroArgs, argValues));
}
Debug::Fault::~Fault() noexcept(false) {
......@@ -292,18 +341,46 @@ void Debug::Fault::init(
const char* file, int line, Exception::Type type,
const char* condition, const char* macroArgs, ArrayPtr<String> argValues) {
exception = new Exception(type, file, line,
makeDescriptionImpl(ASSERTION, condition, 0, macroArgs, argValues));
makeDescriptionImpl(ASSERTION, condition, 0, nullptr, macroArgs, argValues));
}
void Debug::Fault::init(
const char* file, int line, int osErrorNumber,
const char* condition, const char* macroArgs, ArrayPtr<String> argValues) {
exception = new Exception(typeOfErrno(osErrorNumber), file, line,
makeDescriptionImpl(SYSCALL, condition, osErrorNumber, macroArgs, argValues));
makeDescriptionImpl(SYSCALL, condition, osErrorNumber, nullptr, macroArgs, argValues));
}
#if _WIN32
void Debug::Fault::init(
const char* file, int line, Win32Error osErrorNumber,
const char* condition, const char* macroArgs, ArrayPtr<String> argValues) {
LPVOID ptr;
// TODO(now): Use FormatMessageW() instead.
// TODO(now): Why doesn't this work for winsock errors?
DWORD result = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, osErrorNumber.number,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &ptr, 0, NULL);
if (result > 0) {
KJ_DEFER(LocalFree(ptr));
exception = new Exception(typeOfWin32Error(osErrorNumber.number), file, line,
makeDescriptionImpl(SYSCALL, condition, 0, reinterpret_cast<char*>(ptr),
macroArgs, argValues));
} else {
auto message = kj::str("win32 error code: ", osErrorNumber.number);
exception = new Exception(typeOfWin32Error(osErrorNumber.number), file, line,
makeDescriptionImpl(SYSCALL, condition, 0, message.cStr(),
macroArgs, argValues));
}
}
#endif
String Debug::makeDescriptionInternal(const char* macroArgs, ArrayPtr<String> argValues) {
return makeDescriptionImpl(LOG, nullptr, 0, macroArgs, argValues);
return makeDescriptionImpl(LOG, nullptr, 0, nullptr, macroArgs, argValues);
}
int Debug::getOsErrorNumber(bool nonblocking) {
......@@ -316,6 +393,12 @@ int Debug::getOsErrorNumber(bool nonblocking) {
: result;
}
#if _WIN32
Debug::Win32Error Debug::getWin32Error() {
return Win32Error(::GetLastError());
}
#endif
Debug::Context::Context(): logged(false) {}
Debug::Context::~Context() noexcept(false) {}
......
......@@ -165,6 +165,24 @@ namespace kj {
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#if _WIN32
#define KJ_WIN32(call, ...) \
if (::kj::_::Debug::isWin32Success(call)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_WINSOCK(call, ...) \
if ((call) != SOCKET_ERROR) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_FAIL_WIN32(code, errorNumber, ...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::Win32Error(errorNumber), code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#endif
#define KJ_UNIMPLEMENTED(...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
......@@ -223,6 +241,24 @@ namespace kj {
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
errorNumber, code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#if _WIN32
#define KJ_WIN32(call, ...) \
if (::kj::_::Debug::isWin32Success(call)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_WINSOCK(call, ...) \
if ((call) != SOCKET_ERROR) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#define KJ_FAIL_WIN32(code, errorNumber, ...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
::kj::_::Debug::Win32Error(errorNumber), code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
#endif
#define KJ_UNIMPLEMENTED(...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
......@@ -275,6 +311,14 @@ public:
typedef LogSeverity Severity; // backwards-compatibility
#if _WIN32
struct Win32Error {
// Hack for overloading purposes.
uint number;
inline explicit Win32Error(uint number): number(number) {}
};
#endif
static inline bool shouldLog(LogSeverity severity) { return severity >= minSeverity; }
// Returns whether messages of the given severity should be logged.
......@@ -289,16 +333,17 @@ public:
class Fault {
public:
template <typename... Params>
Fault(const char* file, int line, Exception::Type type,
const char* condition, const char* macroArgs, Params&&... params);
template <typename... Params>
Fault(const char* file, int line, int osErrorNumber,
template <typename Code, typename... Params>
Fault(const char* file, int line, Code code,
const char* condition, const char* macroArgs, Params&&... params);
Fault(const char* file, int line, Exception::Type type,
const char* condition, const char* macroArgs);
Fault(const char* file, int line, int osErrorNumber,
const char* condition, const char* macroArgs);
#if _WIN32
Fault(const char* file, int line, Win32Error osErrorNumber,
const char* condition, const char* macroArgs);
#endif
~Fault() noexcept(false);
KJ_NOINLINE KJ_NORETURN(void fatal());
......@@ -309,6 +354,10 @@ public:
const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
void init(const char* file, int line, int osErrorNumber,
const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
#if _WIN32
void init(const char* file, int line, Win32Error osErrorNumber,
const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
#endif
Exception* exception;
};
......@@ -326,6 +375,12 @@ public:
template <typename Call>
static SyscallResult syscall(Call&& call, bool nonblocking);
#if _WIN32
static bool isWin32Success(int boolean);
static bool isWin32Success(void* handle);
static Win32Error getWin32Error();
#endif
class Context: public ExceptionCallback {
public:
Context();
......@@ -394,21 +449,12 @@ inline void Debug::log<>(const char* file, int line, LogSeverity severity, const
logInternal(file, line, severity, macroArgs, nullptr);
}
template <typename... Params>
Debug::Fault::Fault(const char* file, int line, Exception::Type type,
const char* condition, const char* macroArgs, Params&&... params)
: exception(nullptr) {
String argValues[sizeof...(Params)] = {str(params)...};
init(file, line, type, condition, macroArgs,
arrayPtr(argValues, sizeof...(Params)));
}
template <typename... Params>
Debug::Fault::Fault(const char* file, int line, int osErrorNumber,
template <typename Code, typename... Params>
Debug::Fault::Fault(const char* file, int line, Code code,
const char* condition, const char* macroArgs, Params&&... params)
: exception(nullptr) {
String argValues[sizeof...(Params)] = {str(params)...};
init(file, line, osErrorNumber, condition, macroArgs,
init(file, line, code, condition, macroArgs,
arrayPtr(argValues, sizeof...(Params)));
}
......@@ -424,6 +470,22 @@ inline Debug::Fault::Fault(const char* file, int line, kj::Exception::Type type,
init(file, line, type, condition, macroArgs, nullptr);
}
#if _WIN32
inline Debug::Fault::Fault(const char* file, int line, Win32Error osErrorNumber,
const char* condition, const char* macroArgs)
: exception(nullptr) {
init(file, line, osErrorNumber, condition, macroArgs, nullptr);
}
inline bool Debug::isWin32Success(int boolean) {
return boolean;
}
inline bool Debug::isWin32Success(void* handle) {
// Assume null and INVALID_HANDLE_VALUE mean failure.
return handle != nullptr && handle != (void*)-1;
}
#endif
template <typename Call>
Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) {
while (call() < 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment