view add_windows_support.patch @ 548:e23547d65872

windows wip, get time mono running but it doesn't seem to return the right values
author Louis Opter <louis@opter.org>
date Fri, 28 Apr 2017 21:36:23 -0700
parents 469dd784cbd4
children f24201b2e31b
line wrap: on
line source

# HG changeset patch
# Parent  6588e9c430a568518ddf3d59be33ecefbe8abe70
lightsd: add windows support

diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,12 @@
 
 ### Platform checks ############################################################
 
+INCLUDE(CheckFunctionExists)
+INCLUDE(CheckVariableExists)
+INCLUDE(TestBigEndian)
+
+TEST_BIG_ENDIAN(BIG_ENDIAN_SYSTEM)
+
 # TODO: we need at least 2.0.19-stable because of the logging defines
 FIND_PACKAGE(Event2 REQUIRED COMPONENTS core)
 FIND_PACKAGE(Endian REQUIRED)
@@ -37,16 +43,10 @@
     INCLUDE(UseLATEX)
 ENDIF ()
 
-INCLUDE(CheckFunctionExists)
-INCLUDE(CheckVariableExists)
-INCLUDE(TestBigEndian)
-
 INCLUDE(CompatReallocArray)
 INCLUDE(CompatSetProctitle)
 INCLUDE(CompatTimeMonotonic)
 
-TEST_BIG_ENDIAN(BIG_ENDIAN_SYSTEM)
-
 ### Global definitions #########################################################
 
 INCLUDE(AddAllSubdirectories)
@@ -54,11 +54,13 @@
 
 SET(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
 
-SET(CMAKE_C_FLAGS "-pipe ${CMAKE_C_FLAGS}")
-STRING(STRIP "${CMAKE_C_FLAGS}" CMAKE_C_FLAGS)
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}}")
 STRING(STRIP "${CMAKE_C_FLAGS}" CMAKE_C_FLAGS)
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wall -Wstrict-prototypes -std=c99")
+IF (CMAKE_C_COMPILER_ID MATCHES "MSVC")
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Wall")
+ELSE ()
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wall -Wstrict-prototypes -std=c99 -pipe")
+ENDIF ()
 SET(CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE} "")
 
 IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
@@ -74,6 +76,14 @@
     ADD_DEFINITIONS("-D_DARWIN_C_SOURCE=1")
 ENDIF ()
 
+IF (MSVC)
+    ADD_DEFINITIONS(
+        "-D_CRT_SECURE_NO_WARNINGS"
+        "-DWIN32_LEAN_AND_MEAN"
+        "-DNOMINMAX"
+    )
+ENDIF ()
+
 ADD_DEFINITIONS(
     "-DLGTD_BIG_ENDIAN_SYSTEM=${BIG_ENDIAN_SYSTEM}"
     "-DLGTD_SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P}"
@@ -99,8 +109,8 @@
 
 INCLUDE_DIRECTORIES(
     ${EVENT2_INCLUDE_DIR}
+    ${LIGHTSD_BINARY_DIR}
     ${LIGHTSD_BINARY_DIR}/compat
-    ${LIGHTSD_BINARY_DIR}/compat/generic
 )
 
 ADD_SUBDIRECTORY(compat)
diff --git a/CMakeScripts/CompatTimeMonotonic.cmake b/CMakeScripts/CompatTimeMonotonic.cmake
--- a/CMakeScripts/CompatTimeMonotonic.cmake
+++ b/CMakeScripts/CompatTimeMonotonic.cmake
@@ -1,6 +1,5 @@
 IF (NOT TIME_MONOTONIC_LIBRARY)
     SET(COMPAT_TIME_MONOTONIC_IMPL "${LIGHTSD_SOURCE_DIR}/compat/${CMAKE_SYSTEM_NAME}/time_monotonic.c")
-    SET(COMPAT_TIME_MONOTONIC_H "${LIGHTSD_SOURCE_DIR}/compat/${CMAKE_SYSTEM_NAME}/time_monotonic.h")
     SET(GENERIC_TIME_MONOTONIC_IMPL "${LIGHTSD_SOURCE_DIR}/compat/generic/time_monotonic.c")
     SET(GENERIC_TIME_MONOTONIC_H "${LIGHTSD_SOURCE_DIR}/compat/generic/time_monotonic.h")
     SET(TIME_MONOTONIC_LIBRARY time_monotonic CACHE INTERNAL "lgtd_time_monotonic implementation")
@@ -44,7 +43,7 @@
         )
     ELSEIF (EXISTS "${COMPAT_TIME_MONOTONIC_IMPL}")
         MESSAGE(STATUS "Looking for clock_gettime - not found, using built-in compatibilty file")
-        FILE(COPY "${COMPAT_TIME_MONOTONIC_H}" DESTINATION "${LIGHTSD_BINARY_DIR}/core/")
+        FILE(COPY "${GENERIC_TIME_MONOTONIC_H}" DESTINATION "${LIGHTSD_BINARY_DIR}/core/")
         SET(
             TIME_MONOTONIC_IMPL "${COMPAT_TIME_MONOTONIC_IMPL}"
             CACHE INTERNAL "lgtd_time_monotonic (${CMAKE_SYSTEM_NAME} specific source)"
diff --git a/CMakeScripts/FindEndian.cmake b/CMakeScripts/FindEndian.cmake
--- a/CMakeScripts/FindEndian.cmake
+++ b/CMakeScripts/FindEndian.cmake
@@ -12,10 +12,15 @@
     IF (HAVE_ENDIAN_H)
         MESSAGE(STATUS "Looking for endian.h - found")
         SET(ENDIAN_H_PATH "using native headers" CACHE INTERNAL "endian.h path")
-    ELSEIF (EXISTS "${COMPAT_ENDIAN_H}")
+    ELSEIF (EXISTS "${COMPAT_ENDIAN_H}" OR EXISTS "${COMPAT_ENDIAN_H}.in")
         MESSAGE(STATUS "Looking for endian.h - not found, using built-in compatibility file")
-        FILE(COPY "${COMPAT_ENDIAN_H}" DESTINATION "${LIGHTSD_BINARY_DIR}/compat/")
-        SET(ENDIAN_H_PATH "${COMPAT_ENDIAN_H}" CACHE INTERNAL "endian.h path")
+        IF (EXISTS "${COMPAT_ENDIAN_H}")
+            FILE(COPY "${COMPAT_ENDIAN_H}" DESTINATION "${LIGHTSD_BINARY_DIR}/compat/")
+            SET(ENDIAN_H_PATH "${COMPAT_ENDIAN_H}" CACHE INTERNAL "endian.h path")
+        ELSE ()
+            CONFIGURE_FILE("${COMPAT_ENDIAN_H}.in" "${LIGHTSD_BINARY_DIR}/compat/endian.h")
+            SET(ENDIAN_H_PATH "${COMPAT_ENDIAN_H}.in" CACHE INTERNAL "endian.h path")
+        ENDIF ()
     ELSE ()
         MESSAGE(STATUS "Looking for endian.h - not found")
     ENDIF ()
diff --git a/CMakeScripts/FindEvent2.cmake b/CMakeScripts/FindEvent2.cmake
--- a/CMakeScripts/FindEvent2.cmake
+++ b/CMakeScripts/FindEvent2.cmake
@@ -1,14 +1,21 @@
 FIND_PATH(
     EVENT2_INCLUDE_DIR
     event2/event.h
-    # OpenBSD has libevent1 in /usr/lib, always try /usr/local first:
-    HINTS /usr/local/
+    HINTS
+    /usr/local/ # OpenBSD has libevent1 in /usr/lib, always try /usr/local first
+    $ENV{EVENT2_DIR}/include # Windows...
 )
 
 FOREACH (COMPONENT ${Event2_FIND_COMPONENTS})
     STRING(TOUPPER ${COMPONENT} UPPER_COMPONENT)
     FIND_LIBRARY(
-        EVENT2_${UPPER_COMPONENT}_LIBRARY event_${COMPONENT} HINTS /usr/local/
+        EVENT2_${UPPER_COMPONENT}_LIBRARY
+        event_${COMPONENT}
+        NAMES
+        libevent_${COMPONENT} # Windows
+        HINTS
+        /usr/local/
+        $ENV{EVENT2_DIR}
     )
     IF (EVENT2_${UPPER_COMPONENT}_LIBRARY)
         SET(Event2_${COMPONENT}_FOUND TRUE)
diff --git a/compat/Darwin/time_monotonic.h b/compat/Darwin/time_monotonic.h
deleted file mode 100644
--- a/compat/Darwin/time_monotonic.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2015, Louis Opter <kalessin@kalessin.fr>
-//
-// This file is part of lighstd.
-//
-// lighstd is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// lighstd is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with lighstd.  If not, see <http://www.gnu.org/licenses/>.
-
-#pragma once
-
-typedef uint64_t lgtd_time_mono_t;
-
-lgtd_time_mono_t lgtd_time_monotonic_msecs(void);
diff --git a/compat/Windows/endian.h.in b/compat/Windows/endian.h.in
new file mode 100644
--- /dev/null
+++ b/compat/Windows/endian.h.in
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <stdlib.h>
+
+#if @BIG_ENDIAN_SYSTEM@
+#   define htobe16(x) (x)
+#   define htole16(x) _byteswap_ushort(x)
+#   define be16toh(x) (x)
+#   define le16toh(x) _byteswap_ushort(x)
+
+#   define htobe32(x) (x)
+#   define htole32(x) _byteswap_ulong(x)
+#   define be32toh(x) (x)
+#   define le32toh(x) _byteswap_ulong(x)
+
+#   define htobe64(x) (x)
+#   define htole64(x) _byteswap_uint64(x)
+#   define be64toh(x) (x)
+#   define le64toh(x) _byteswap_uint64(x)
+#else
+#   define htobe16(x) _byteswap_ushort(x)
+#   define htole16(x) (x)
+#   define be16toh(x) _byteswap_ushort(x)
+#   define le16toh(x) (x)
+
+#   define htobe32(x) _byteswap_ulong(x)
+#   define htole32(x) (x)
+#   define be32toh(x) _byteswap_ulong(x)
+#   define le32toh(x) (x)
+
+#   define htobe64(x) _byteswap_uint64(x)
+#   define htole64(x) (x)
+#   define be64toh(x) _byteswap_uint64(x)
+#   define le64toh(x) (x)
+#endif
diff --git a/compat/Windows/time_monotonic.c b/compat/Windows/time_monotonic.c
new file mode 100644
--- /dev/null
+++ b/compat/Windows/time_monotonic.c
@@ -0,0 +1,69 @@
+// Copyright (c) 2017, Louis Opter <louis@opter.org>
+//
+// This file is part of lighstd.
+//
+// lighstd is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// lighstd is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with lighstd.  If not, see <http://www.gnu.org/licenses/>.
+
+#include <Windows.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "core/time_monotonic.h"
+
+enum { MSECS_IN_NSEC = 1000000 };
+
+lgtd_time_mono_t
+lgtd_time_monotonic_msecs(void)
+{
+    static LARGE_INTEGER frequency = { .QuadPart = 0 };
+    if (frequency.QuadPart == 0
+        && QueryPerformanceFrequency(&frequency) == false) {
+        LPSTR msg = NULL;
+        DWORD msg_len = FormatMessageA(
+            FORMAT_MESSAGE_ALLOCATE_BUFFER
+            | FORMAT_MESSAGE_FROM_SYSTEM
+            | FORMAT_MESSAGE_IGNORE_INSERTS,
+            NULL,
+            GetLastError(),
+            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+            // By default the message is stored in the buffer pointed by
+            // lpMsgBuf, but we use FORMAT_MESSAGE_ALLOCATE_BUFFER to have
+            // the buffer allocated for us.
+            // So instead you need to give the function a pointer on your
+            // pointer instead of your buffer and do an ugly cast:
+            (LPSTR)&msg,
+            0,
+            NULL
+        );
+        if (!msg_len) {
+            msg = "unknown error";
+        }
+        fprintf(stderr, "lightsd: QPC timer unavailable: %s.\r\n", msg);
+        exit(1);
+    }
+
+    LARGE_INTEGER time;
+    QueryPerformanceCounter(&time);
+    time.QuadPart = time.QuadPart * MSECS_IN_NSEC;
+    time.QuadPart = time.QuadPart / frequency.QuadPart;
+    return time.QuadPart;
+}
+
+void
+lgtd_sleep_monotonic_msecs(int msecs)
+{
+    Sleep(msecs);
+}
diff --git a/compat/generic/time_monotonic.c b/compat/generic/time_monotonic.c
--- a/compat/generic/time_monotonic.c
+++ b/compat/generic/time_monotonic.c
@@ -15,10 +15,13 @@
 // You should have received a copy of the GNU General Public License
 // along with lighstd.  If not, see <http://www.gnu.org/licenses/>.
 
+#include <assert.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <time.h>
 
-#include "time_monotonic.h"
+#include "core/time_monotonic.h"
+#include "core/lightsd.h"
 
 lgtd_time_mono_t
 lgtd_time_monotonic_msecs(void)
@@ -27,3 +30,23 @@
     clock_gettime(CLOCK_MONOTONIC, &tp);
     return tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
 }
+
+void
+lgtd_sleep_monotonic_msecs(int msecs)
+{
+    assert(msecs >= 0);
+
+    struct timespec remainder = LGTD_MSECS_TO_TIMESPEC(msecs),
+                    request = LGTD_MSECS_TO_TIMESPEC(msecs),
+                    *rmtp = &remainder,
+                    *rqtp = &request;
+    while (remainder.tv_sec > 0 && remainder.tv_usec > 0) {
+        int err = nanosleep(rqtp, rmtp);
+        if (err && errno != EINTR) {
+            const char *reason = strerror(errno);
+            fprintf(stderr, "lightsd: nanosleep failed: %s.\n", reason);
+            abort();
+        }
+        LGTD_SWAP(struct timespec *, rqtp, rmtp);
+    }
+}
diff --git a/compat/generic/time_monotonic.h b/compat/generic/time_monotonic.h
--- a/compat/generic/time_monotonic.h
+++ b/compat/generic/time_monotonic.h
@@ -20,3 +20,4 @@
 typedef uint64_t lgtd_time_mono_t;
 
 lgtd_time_mono_t lgtd_time_monotonic_msecs(void);
+void lgtd_sleep_monotonic_msecs(int);
diff --git a/core/lightsd.h b/core/lightsd.h
--- a/core/lightsd.h
+++ b/core/lightsd.h
@@ -35,7 +35,7 @@
 #pragma once
 
 #ifndef __attribute__
-# define __atttribute__(e)
+# define __attribute__(e)
 #endif
 
 #define LGTD_ABS(v) ((v) >= 0 ? (v) : (v) * -1)
@@ -43,11 +43,16 @@
 #define LGTD_MAX(a, b) ((a) > (b) ? (a) : (b))
 
 #define LGTD_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define LGTD_SWAP(type, a, b) do { type _tmp = a; a = b; b = _tmp; } while (0)
 
 #define LGTD_MSECS_TO_TIMEVAL(v) {  \
     .tv_sec = (v) / 1000,           \
     .tv_usec = ((v) % 1000) * 1000  \
 }
+#define LGTD_MSECS_TO_TIMESPEC(v) {  \
+    .tv_sec = (v) / 1000,            \
+    .tv_nsec = ((v) % 1E6) * 1000000 \
+}
 #define LGTD_NSECS_TO_USECS(v) ((v) / (unsigned int)1E6)
 #define LGTD_NSECS_TO_SECS(v) ((v) / (unsigned int)1E9)
 #define LGTD_SECS_TO_NSECS(v) ((v) * (unsigned int)1E9)
diff --git a/tests/compat/CMakeLists.txt b/tests/compat/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/tests/compat/CMakeLists.txt
@@ -0,0 +1,6 @@
+INCLUDE_DIRECTORIES(
+    ${LIGHTSD_SOURCE_DIR}
+    ${LIGHTSD_BINARY_DIR}
+)
+
+ADD_ALL_SUBDIRECTORIES()
diff --git a/tests/compat/time_monotonic/CMakeLists.txt b/tests/compat/time_monotonic/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/tests/compat/time_monotonic/CMakeLists.txt
@@ -0,0 +1,8 @@
+FUNCTION(ADD_TIME_MONOTONIC_TEST TEST_SOURCE)
+    ADD_TEST_FROM_C_SOURCES(${TEST_SOURCE} ${TIME_MONOTONIC_LIBRARY})
+ENDFUNCTION()
+
+FILE(GLOB TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "test_*.c")
+FOREACH(TEST ${TESTS})
+    ADD_TIME_MONOTONIC_TEST(${TEST})
+ENDFOREACH()
diff --git a/tests/compat/time_monotonic/test_time_monotonic_msecs.c b/tests/compat/time_monotonic/test_time_monotonic_msecs.c
new file mode 100644
--- /dev/null
+++ b/tests/compat/time_monotonic/test_time_monotonic_msecs.c
@@ -0,0 +1,17 @@
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "core/time_monotonic.h"
+#include "core/lightsd.h"
+
+int
+main(void)
+{
+    lgtd_time_mono_t elapsed = lgtd_time_monotonic_msecs();
+    lgtd_sleep_monotonic_msecs(50);
+    elapsed = lgtd_time_monotonic_msecs() - elapsed;
+    printf("slept for %jums\r\n", elapsed);
+    return elapsed - 40 > 10;
+}