Skip to content

Commit

Permalink
lightsd: get the build system and time_monotonic to work on Windows
Browse files Browse the repository at this point in the history
This is the first step towards Windows portability.
  • Loading branch information
lopter committed May 18, 2017
1 parent 4de0c8d commit 9f976a6
Show file tree
Hide file tree
Showing 23 changed files with 325 additions and 60 deletions.
32 changes: 21 additions & 11 deletions CMakeLists.txt
Expand Up @@ -19,6 +19,12 @@ OPTION(BUILD_SLIDES "Build slides using LaTeX")

### 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)
Expand All @@ -37,28 +43,24 @@ IF (WITH_SLIDES)
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)
INCLUDE(AddTestFromSources)

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")
Expand All @@ -74,6 +76,13 @@ IF (APPLE)
ADD_DEFINITIONS("-D_DARWIN_C_SOURCE=1")
ENDIF ()

IF (MSVC)
ADD_DEFINITIONS(
"-D_CRT_SECURE_NO_WARNINGS"
"-DNOMINMAX"
)
ENDIF ()

ADD_DEFINITIONS(
"-DLGTD_BIG_ENDIAN_SYSTEM=${BIG_ENDIAN_SYSTEM}"
"-DLGTD_SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P}"
Expand All @@ -99,11 +108,12 @@ MESSAGE(STATUS "lightsd runtime directory: ${LGTD_RUNTIME_DIRECTORY}")

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)

Expand Down
8 changes: 6 additions & 2 deletions CMakeScripts/AddAllSubdirectories.cmake
@@ -1,8 +1,12 @@
FUNCTION(ADD_ALL_SUBDIRECTORIES)
FILE(GLOB SUBDIRECTORIES "*")
FOREACH (ENTRY ${SUBDIRECTORIES})
IF (IS_DIRECTORY ${ENTRY} AND EXISTS "${ENTRY}/CMakeLists.txt")
ADD_SUBDIRECTORY(${ENTRY})
IF (
IS_DIRECTORY "${ENTRY}" AND
NOT IS_SYMLINK "${ENTRY}" AND
EXISTS "${ENTRY}/CMakeLists.txt"
)
ADD_SUBDIRECTORY("${ENTRY}")
ENDIF ()
ENDFOREACH ()
ENDFUNCTION()
38 changes: 32 additions & 6 deletions CMakeScripts/CompatTimeMonotonic.cmake
@@ -1,8 +1,6 @@
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")

IF (APPLE)
Expand All @@ -18,6 +16,7 @@ IF (NOT TIME_MONOTONIC_LIBRARY)
ENDIF ()

SET(CMAKE_REQUIRED_QUIET TRUE)

MESSAGE(STATUS "Looking for clock_gettime")
CHECK_FUNCTION_EXISTS("clock_gettime" HAVE_CLOCK_GETTIME)
IF (NOT HAVE_CLOCK_GETTIME)
Expand All @@ -32,29 +31,56 @@ IF (NOT TIME_MONOTONIC_LIBRARY)
UNSET(TIME_MONOTONIC_LIBRARY_DEP CACHE)
ENDIF ()
ENDIF ()
UNSET(CMAKE_REQUIRED_QUIET)

UNSET(CMAKE_REQUIRED_FLAGS)

IF (HAVE_CLOCK_GETTIME)
MESSAGE(STATUS "Looking for clock_gettime - found")
FILE(COPY "${GENERIC_TIME_MONOTONIC_H}" DESTINATION "${LIGHTSD_BINARY_DIR}/core/")
SET(
TIME_MONOTONIC_IMPL ${GENERIC_TIME_MONOTONIC_IMPL}
CACHE INTERNAL "lgtd_time_monotonic (POSIX generic source)"
)
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/")
SET(
TIME_MONOTONIC_IMPL "${COMPAT_TIME_MONOTONIC_IMPL}"
CACHE INTERNAL "lgtd_time_monotonic (${CMAKE_SYSTEM_NAME} specific source)"
)
ELSE ()
MESSAGE(SEND_ERROR "Looking for clock_gettime - not found")
ENDIF ()

SET(COMPAT_SLEEP_MONOTONIC_IMPL "${LIGHTSD_SOURCE_DIR}/compat/${CMAKE_SYSTEM_NAME}/sleep_monotonic.c")
SET(GENERIC_SLEEP_MONOTONIC_IMPL "${LIGHTSD_SOURCE_DIR}/compat/generic/sleep_monotonic.c")

MESSAGE(STATUS "Looking for nanosleep")
CHECK_FUNCTION_EXISTS("nanosleep" HAVE_NANOSLEEP)
IF (HAVE_NANOSLEEP)
MESSAGE(STATUS "Looking for nanosleep - found")
SET(
SLEEP_MONOTONIC_IMPL "${GENERIC_SLEEP_MONOTONIC_IMPL}"
CACHE INTERNAL "lgtd_sleep_monotonic (POSIX generic source)"
)
ELSEIF (EXISTS "${COMPAT_SLEEP_MONOTONIC_IMPL}")
MESSAGE(STATUS "Looking for nanosleep - not found, using built-in compatibilty file")
SET(
SLEEP_MONOTONIC_IMPL "${COMPAT_SLEEP_MONOTONIC_IMPL}"
CACHE INTERNAL "lgtd_sleep_monotonic (${CMAKE_SYSTEM_NAME} specific source)"
)
IF (WIN32)
SET(TIME_MONOTONIC_LIBRARY_DEP Winmm CACHE INTERNAL "dependency for lgtd_sleep_monotonic")
ENDIF ()
ENDIF ()

UNSET(CMAKE_REQUIRED_QUIET)
ENDIF ()

ADD_LIBRARY(${TIME_MONOTONIC_LIBRARY} STATIC "${TIME_MONOTONIC_IMPL}")
ADD_LIBRARY(
${TIME_MONOTONIC_LIBRARY}
STATIC
"${TIME_MONOTONIC_IMPL}"
"${SLEEP_MONOTONIC_IMPL}"
)

IF (TIME_MONOTONIC_LIBRARY_DEP)
TARGET_LINK_LIBRARIES(${TIME_MONOTONIC_LIBRARY} ${TIME_MONOTONIC_LIBRARY_DEP})
Expand Down
11 changes: 8 additions & 3 deletions CMakeScripts/FindEndian.cmake
Expand Up @@ -12,10 +12,15 @@ IF (NOT ENDIAN_H_PATH)
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 ()
Expand Down
13 changes: 10 additions & 3 deletions 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)
Expand Down
1 change: 0 additions & 1 deletion compat/CMakeLists.txt

This file was deleted.

2 changes: 1 addition & 1 deletion compat/Darwin/time_monotonic.c
Expand Up @@ -24,7 +24,7 @@
#include <assert.h>
#include <stdint.h>

#include "time_monotonic.h"
#include "core/time_monotonic.h"

enum { MSECS_IN_NSEC = 1000000 };

Expand Down
35 changes: 35 additions & 0 deletions 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
63 changes: 63 additions & 0 deletions compat/Windows/sleep_monotonic.c
@@ -0,0 +1,63 @@
// 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/>.

// See:
//
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686298(v=vs.85).aspx
// https://msdn.microsoft.com/en-us/library/dd743626(v=vs.85).aspx

#include <Windows.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

#include "core/time_monotonic.h"
#include "core/lightsd.h"

enum { TIMER_RESOLUTION_MS = 1 };

static UINT
_lgtd_set_timer_resolution(UINT resolution_ms)
{
TIMECAPS tc;
if (timeGetDevCaps(&tc, sizeof(tc)) != TIMERR_NOERROR) {
fprintf(stderr, "lightsd: multimedia timers unavailable.");
exit(1);
}

UINT resolution = LGTD_MAX(tc.wPeriodMin, resolution_ms);
resolution = LGTD_MIN(resolution, tc.wPeriodMax);
timeBeginPeriod(resolution);
return resolution;
}

static void
_lgtd_reset_timer_resolution(UINT resolution_ms)
{
if (timeEndPeriod(resolution_ms) != TIMERR_NOERROR) {
fprintf(stderr, "lightsd: can't reset timer resolution.");
}
}

void
lgtd_sleep_monotonic_msecs(int msecs)
{
UINT actual = _lgtd_set_timer_resolution(TIMER_RESOLUTION_MS);
Sleep(msecs);
_lgtd_reset_timer_resolution(actual);
}
67 changes: 67 additions & 0 deletions compat/Windows/time_monotonic.c
@@ -0,0 +1,67 @@
// 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/>.

// This is pretty much "Using QPC in native code" from:
//
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx

#include <Windows.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>

#include "core/time_monotonic.h"

lgtd_time_mono_t
lgtd_time_monotonic_msecs(void)
{
static LARGE_INTEGER frequency = { .QuadPart = 0 }; // ticks per second
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);
// Multiply the number of ticks by 1000 first to get a final value in ms:
time.QuadPart *= 1000;
// Then (the order is important to avoid loosing precision) divide by the
// number of ticks per second:
time.QuadPart /= frequency.QuadPart;
return time.QuadPart;
}
1 change: 0 additions & 1 deletion compat/generic/CMakeLists.txt

This file was deleted.

0 comments on commit 9f976a6

Please sign in to comment.