Mercurial > louis > mq > lightsd
view add_windows_support.patch @ 551:791cb4b91701
move things around add an improved demo script, add a systemd drop-in and harden the systemd configuration
author | Louis Opter <louis@opter.org> |
---|---|
date | Sun, 14 May 2017 13:29:30 -0700 |
parents | c0b49dd420bf |
children | b3de1b255605 |
line wrap: on
line source
# HG changeset patch # Parent 3eaedf3f30570024bdac00f3b6a784bed52d01f9 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,11 +109,12 @@ INCLUDE_DIRECTORIES( ${EVENT2_INCLUDE_DIR} + ${LIGHTSD_SOURCE_DIR} + ${LIGHTSD_SOURCE_DIR}/compat/generic + ${LIGHTSD_BINARY_DIR} ${LIGHTSD_BINARY_DIR}/compat - ${LIGHTSD_BINARY_DIR}/compat/generic ) -ADD_SUBDIRECTORY(compat) ADD_SUBDIRECTORY(core) ADD_SUBDIRECTORY(lifx) 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/CMakeLists.txt b/compat/CMakeLists.txt deleted file mode 100644 --- a/compat/CMakeLists.txt +++ /dev/null @@ -1,1 +0,0 @@ -ADD_SUBDIRECTORY(generic) diff --git a/compat/Darwin/time_monotonic.c b/compat/Darwin/time_monotonic.c --- a/compat/Darwin/time_monotonic.c +++ b/compat/Darwin/time_monotonic.c @@ -22,9 +22,15 @@ #include <mach/mach_time.h> #include <sys/time.h> #include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> #include <stdint.h> +#include <stdlib.h> +#include <string.h> -#include "time_monotonic.h" +#include "core/time_monotonic.h" +#include "core/lightsd.h" enum { MSECS_IN_NSEC = 1000000 }; @@ -40,3 +46,23 @@ return time * timebase.numer / timebase.denom / MSECS_IN_NSEC; } + +void +lgtd_sleep_monotonic_msecs(int msecs) +{ + assert(msecs >= 0); + + struct timespec remainder = LGTD_MSECS_TO_TIMESPEC(msecs), + request = { 0, 0 }, + *rmtp = &remainder, + *rqtp = &request; + do { + LGTD_SWAP(struct timespec *, rqtp, rmtp); + int err = nanosleep(rqtp, rmtp); + if (err && errno != EINTR) { + const char *reason = strerror(errno); + fprintf(stderr, "lightsd: nanosleep failed: %s.\n", reason); + abort(); + } + } while (remainder.tv_sec > 0 && remainder.tv_nsec > 0); +} 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/CMakeLists.txt b/compat/generic/CMakeLists.txt deleted file mode 100644 --- a/compat/generic/CMakeLists.txt +++ /dev/null @@ -1,1 +0,0 @@ -FILE(COPY sys DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 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,17 @@ // 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 <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> #include <stdint.h> +#include <string.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 +34,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 = { 0, 0 }, + *rmtp = &remainder, + *rqtp = &request; + do { + LGTD_SWAP(struct timespec *, rqtp, rmtp); + int err = nanosleep(rqtp, rmtp); + if (err && errno != EINTR) { + const char *reason = strerror(errno); + fprintf(stderr, "lightsd: nanosleep failed: %s.\n", reason); + abort(); + } + } while (remainder.tv_sec > 0 && remainder.tv_nsec > 0); +} 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/CMakeLists.txt b/core/CMakeLists.txt --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -2,9 +2,7 @@ # I only have lifx bulbs right now and I don't want to do any premature work. INCLUDE_DIRECTORIES( - ${CMAKE_CURRENT_SOURCE_DIR}/../ ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/../ ${CMAKE_CURRENT_BINARY_DIR} ) 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) % 1000) * 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/lifx/CMakeLists.txt b/lifx/CMakeLists.txt --- a/lifx/CMakeLists.txt +++ b/lifx/CMakeLists.txt @@ -1,7 +1,5 @@ INCLUDE_DIRECTORIES( - ${CMAKE_CURRENT_SOURCE_DIR}/../ ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/../ ${CMAKE_CURRENT_BINARY_DIR} ) 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,1 @@ +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", (uintmax_t)elapsed); + return LGTD_ABS(elapsed - 50) > 10; +} diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt --- a/tests/core/CMakeLists.txt +++ b/tests/core/CMakeLists.txt @@ -1,9 +1,7 @@ INCLUDE_DIRECTORIES( - ${LIGHTSD_SOURCE_DIR} ${LIGHTSD_SOURCE_DIR}/core/ ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../lifx - ${LIGHTSD_BINARY_DIR} ${LIGHTSD_BINARY_DIR}/core/ ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/../lifx diff --git a/tests/lifx/CMakeLists.txt b/tests/lifx/CMakeLists.txt --- a/tests/lifx/CMakeLists.txt +++ b/tests/lifx/CMakeLists.txt @@ -1,9 +1,7 @@ INCLUDE_DIRECTORIES( - ${LIGHTSD_SOURCE_DIR} ${LIGHTSD_SOURCE_DIR}/lifx/ ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../core - ${LIGHTSD_BINARY_DIR} ${LIGHTSD_BINARY_DIR}/lifx/ ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/../core