Move operating system abstractions from DDSI to abstraction layer

Signed-off-by: Jeroen Koekkoek <jeroen@koekkoek.nl>
This commit is contained in:
Jeroen Koekkoek 2019-01-07 15:35:40 +01:00
parent 9475024a5f
commit c86bda7aa4
60 changed files with 540 additions and 602 deletions

View file

@ -27,7 +27,8 @@ set(sources
src/os_iter.c
src/os_strlcpy.c
src/os_dns.c
src/os_process.c)
src/os_process.c
src/os_random.c)
string(TOLOWER ${CMAKE_SYSTEM_NAME} system_name)
set(system_sources
@ -39,7 +40,8 @@ set(system_sources
os_platform_sync.c
os_platform_thread.c
os_platform_time.c
os_platform_init.c)
os_platform_init.c
os_platform_rusage.c)
foreach(source ${system_sources})
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/${system_name}/${source}")

View file

@ -29,6 +29,7 @@ extern "C" {
#endif
#define OS_DARWIN 1
#define OS_HAVE_GETRUSAGE 1
typedef double os_timeReal;
typedef int os_timeSec;

View file

@ -29,6 +29,7 @@ extern "C" {
#endif
#define OS_LINUX 1
#define OS_HAVE_GETRUSAGE 1
typedef double os_timeReal;
typedef int os_timeSec;

View file

@ -44,5 +44,7 @@
#include "os_iter.h"
#include "os_log.h"
#include "os_strlcpy.h"
#include "os_random.h"
#include "os_rusage.h"
#endif

View file

@ -157,10 +157,24 @@ OSAPI_EXPORT int os_atomic_cas64 (volatile os_atomic_uint64_t *x, uint64_t exp,
#endif
OSAPI_EXPORT int os_atomic_casptr (volatile os_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des);
OSAPI_EXPORT int os_atomic_casvoidp (volatile os_atomic_voidp_t *x, void *exp, void *des);
#if OS_ATOMIC_LIFO_SUPPORT
OSAPI_EXPORT int os_atomic_casvoidp2 (volatile os_atomic_uintptr2_t *x, uintptr_t a0, uintptr_t b0, uintptr_t a1, uintptr_t b1);
#endif
/* FENCES */
OSAPI_EXPORT void os_atomic_fence (void);
OSAPI_EXPORT void os_atomic_fence_acq (void);
OSAPI_EXPORT void os_atomic_fence_rel (void);
/* LIFO */
#if OS_ATOMIC_LIFO_SUPPORT
typedef struct os_atomic_lifo {
os_atomic_uintptr2_t aba_head;
} os_atomic_lifo_t;
OSAPI_EXPORT void os_atomic_lifo_init (os_atomic_lifo_t *head);
OSAPI_EXPORT void os_atomic_lifo_push (os_atomic_lifo_t *head, void *elem, size_t linkoff);
OSAPI_EXPORT void *os_atomic_lifo_pop (os_atomic_lifo_t *head, size_t linkoff);
OSAPI_EXPORT void os_atomic_lifo_pushmany (os_atomic_lifo_t *head, void *first, void *last, size_t linkoff);
#endif /* OS_ATOMIC_LIFO_SUPPORT */
#endif /* OS_HAVE_INLINE */

View file

@ -25,6 +25,18 @@
#endif
#endif
#if ( OS_ATOMIC64_SUPPORT && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) || \
(!OS_ATOMIC64_SUPPORT && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
#define OS_ATOMIC_LIFO_SUPPORT 1
#if OS_ATOMIC64_SUPPORT
typedef union { __int128 x; struct { uintptr_t a, b; } s; } os_atomic_uintptr2_t;
#else
typedef union { uint64_t x; struct { uintptr_t a, b; } s; } os_atomic_uintptr2_t;
#endif
#endif
#if ! OS_ATOMICS_OMIT_FUNCTIONS
/* Eliminate C warnings */
@ -73,6 +85,9 @@ OS_INLINE uintptr_t os_atomic_orptr_nv (volatile os_atomic_uintptr_t *x, uintptr
OS_INLINE int os_atomic_cas32 (volatile os_atomic_uint32_t *x, uint32_t exp, uint32_t des);
OS_INLINE int os_atomic_casptr (volatile os_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des);
OS_INLINE int os_atomic_casvoidp (volatile os_atomic_voidp_t *x, void *exp, void *des);
#if OS_ATOMIC_LIFO_SUPPORT
OS_INLINE int os_atomic_casvoidp2 (volatile os_atomic_uintptr2_t *x, uintptr_t a0, uintptr_t b0, uintptr_t a1, uintptr_t b1);
#endif
OS_INLINE void os_atomic_fence (void);
OS_INLINE void os_atomic_fence_acq (void);
OS_INLINE void os_atomic_fence_rel (void);
@ -325,6 +340,14 @@ OS_INLINE int os_atomic_casptr (volatile os_atomic_uintptr_t *x, uintptr_t exp,
OS_INLINE int os_atomic_casvoidp (volatile os_atomic_voidp_t *x, void *exp, void *des) {
return os_atomic_casptr (x, (uintptr_t) exp, (uintptr_t) des);
}
#if OS_ATOMIC_LIFO_SUPPORT
OS_INLINE int os_atomic_casvoidp2 (volatile os_atomic_uintptr2_t *x, uintptr_t a0, uintptr_t b0, uintptr_t a1, uintptr_t b1) {
os_atomic_uintptr2_t o, n;
o.s.a = a0; o.s.b = b0;
n.s.a = a1; n.s.b = b1;
return __sync_bool_compare_and_swap (&x->x, o.x, n.x);
}
#endif /* OS_ATOMIC_LIFO_SUPPORT */
/* FENCES */

View file

@ -0,0 +1,27 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_RANDOM_H
#define OS_RANDOM_H
#include "os/os_defs.h"
#if defined (__cplusplus)
extern "C" {
#endif
OSAPI_EXPORT long os_random(void);
#if defined (__cplusplus)
}
#endif
#endif /* OS_RANDOM_H */

View file

@ -0,0 +1,35 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef OS_RUSAGE_H
#define OS_RUSAGE_H
#include "os/os_defs.h"
typedef struct {
os_time utime; /* User CPU time used. */
os_time stime; /* System CPU time used. */
size_t maxrss; /* Maximum resident set size in bytes. */
size_t idrss; /* Integral unshared data size. Not maintained on (at least)
Linux and Windows. */
size_t nvcsw; /* Voluntary context switches. Not maintained on Windows. */
size_t nivcsw; /* Involuntary context switches. Not maintained on Windows. */
} os_rusage_t;
#define OS_RUSAGE_SELF 0
#define OS_RUSAGE_THREAD 1
_Pre_satisfies_((who == OS_RUSAGE_SELF) || \
(who == OS_RUSAGE_THREAD))
_Success_(return == 0)
int os_getrusage(_In_ int who, _Out_ os_rusage_t *usage);
#endif /* OS_GETRUSAGE_H */

View file

@ -36,6 +36,7 @@ extern "C" {
* @addtogroup OS_NET
* @{
*/
#define OS_VALID_SOCKET(s) ((s) != OS_INVALID_SOCKET)
/**
* Socket handle type. SOCKET on windows, int otherwise.
@ -235,7 +236,7 @@ extern "C" {
*/
OSAPI_EXPORT int
os_sockaddr_is_unspecified(
const os_sockaddr *const sa) __nonnull_all__;
_In_ const os_sockaddr *__restrict sa) __nonnull_all__;
/**
* Check this address to see if it represents loopback.

View file

@ -127,6 +127,8 @@ extern "C" {
OSAPI_EXPORT os_threadId
os_threadIdSelf(void);
int os_threadEqual (os_threadId a, os_threadId b);
/** \brief Wait for the termination of the identified thread
*
* If the identified thread is still running, wait for its termination

View file

@ -68,9 +68,24 @@ extern "C" {
typedef int os_socket; /* signed */
#define PRIsock "d"
#define OS_SOCKET_INVALID (-1)
#define OS_INVALID_SOCKET (-1)
typedef struct iovec os_iovec_t;
typedef size_t os_iov_len_t;
#if defined(__sun) && !defined(_XPG4_2)
#define msg_accrights msg_control
#define msg_accrightslen msg_controllen
#define OS_MSGHDR_FLAGS 0
#else
#define OS_MSGHDR_FLAGS 1
#endif
#if defined(__linux)
typedef size_t os_msg_iovlen_t;
#else /* POSIX says int (which macOS, FreeBSD, Solaris do) */
typedef int os_msg_iovlen_t;
#endif
#if defined (__cplusplus)
}

View file

@ -29,6 +29,7 @@ extern "C" {
#endif
#define OS_SOLARIS 1
#define OS_HAVE_GETRUSAGE 1
typedef double os_timeReal;
typedef int os_timeSec;

View file

@ -98,6 +98,7 @@ extern "C" {
#endif
#define OS_VXWORKS 1
#define OS_HAVE_GETRUSAGE 0
typedef double os_timeReal;
typedef int os_timeSec;

View file

@ -34,6 +34,7 @@ extern "C" {
#endif
#define OS_WIN32 1
#define OS_HAVE_GETRUSAGE 1
typedef double os_timeReal;
typedef int os_timeSec;

View file

@ -43,7 +43,7 @@ extern "C" {
#define os_sockENOMEM WSABASEERR
#define os_sockENOSR WSABASEERR
#define os_sockENOENT WSABASEERR
#define os_sockEPERM WSABASEERR
#define os_sockEPERM WSAEACCES
#define os_sockEINTR WSAEINTR
#define os_sockEBADF WSAEBADF
#define os_sockEACCES WSAEACCES
@ -61,7 +61,36 @@ extern "C" {
typedef SOCKET os_socket;
#define PRIsock PRIuPTR
#define OS_SOCKET_INVALID (-1)
#define OS_INVALID_SOCKET (INVALID_SOCKET)
typedef unsigned os_iov_len_t;
typedef struct os_iovec {
os_iov_len_t iov_len;
void *iov_base;
} os_iovec_t;
typedef DWORD os_msg_iovlen_t;
struct msghdr {
void *msg_name;
socklen_t msg_namelen;
os_iovec_t *msg_iov;
os_msg_iovlen_t msg_iovlen;
void *msg_control;
size_t msg_controllen;
int msg_flags;
};
#define OS_MSGHDR_FLAGS 1
/* Only implements iovec of length 1, no control */
ssize_t recvmsg (os_socket fd, struct msghdr *message, int flags);
ssize_t sendmsg (os_socket fd, const struct msghdr *message, int flags);
#ifndef MSG_TRUNC
#define MSG_TRUNC 1
#endif
void os_socketModuleInit(void);
void os_socketModuleExit(void);

View file

@ -14,3 +14,40 @@
#define OS_ATOMICS_OMIT_FUNCTIONS 0 /* force inclusion of functions defs */
#include "os/os.h"
#if OS_ATOMIC_LIFO_SUPPORT
void os_atomic_lifo_init (os_atomic_lifo_t *head)
{
head->aba_head.s.a = head->aba_head.s.b = 0;
}
void os_atomic_lifo_push (os_atomic_lifo_t *head, void *elem, size_t linkoff)
{
uintptr_t a0, b0;
do {
a0 = *((volatile uintptr_t *) &head->aba_head.s.a);
b0 = *((volatile uintptr_t *) &head->aba_head.s.b);
*((volatile uintptr_t *) ((char *) elem + linkoff)) = b0;
} while (!os_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, (uintptr_t)elem));
}
void *os_atomic_lifo_pop (os_atomic_lifo_t *head, size_t linkoff) {
uintptr_t a0, b0, b1;
do {
a0 = *((volatile uintptr_t *) &head->aba_head.s.a);
b0 = *((volatile uintptr_t *) &head->aba_head.s.b);
if (b0 == 0) {
return NULL;
}
b1 = (*((volatile uintptr_t *) ((char *) b0 + linkoff)));
} while (!os_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, b1));
return (void *) b0;
}
void os_atomic_lifo_pushmany (os_atomic_lifo_t *head, void *first, void *last, size_t linkoff)
{
uintptr_t a0, b0;
do {
a0 = *((volatile uintptr_t *) &head->aba_head.s.a);
b0 = *((volatile uintptr_t *) &head->aba_head.s.b);
*((volatile uintptr_t *) ((char *) last + linkoff)) = b0;
} while (!os_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, (uintptr_t)first));
}
#endif

42
src/os/src/os_random.c Normal file
View file

@ -0,0 +1,42 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <stdlib.h>
#if WIN32
#define _CRT_RAND_S
#include <errno.h>
long random (void)
{
/* rand() is a really terribly bad PRNG */
/* FIXME: Indeed (especially if not seeded), use rand_s instead. */
union { long x; unsigned char c[4]; } t;
int i;
for (i = 0; i < 4; i++)
t.c[i] = (unsigned char) ((rand () >> 4) & 0xff);
#if RAND_MAX == INT32_MAX || RAND_MAX == 0x7fff
t.x &= RAND_MAX;
#elif RAND_MAX <= 0x7ffffffe
t.x %= (RAND_MAX+1);
#else
#error "RAND_MAX out of range"
#endif
return t.x;
}
#endif
long os_random(void)
{
/* FIXME: Not MT-safe, should use random_r (or a real PRNG) instead. */
return random();
}

View file

@ -124,7 +124,7 @@ os_sockaddr_is_loopback(
#if OS_SOCKET_HAS_IPV6
case AF_INET6:
return IN6_IS_ADDR_LOOPBACK(
((const os_sockaddr_in6 *)sa)->sin6_addr);
&((const os_sockaddr_in6 *)sa)->sin6_addr);
#endif /* OS_SOCKET_HAS_IPV6 */
case AF_INET:
return (((const os_sockaddr_in *)sa)->sin_addr.s_addr

View file

@ -37,3 +37,9 @@ os_threadAttrInit (
threadAttr->schedPriority = 0;
threadAttr->stackSize = 0;
}
int os_threadEqual (os_threadId a, os_threadId b)
{
/* on pthreads boxes, pthread_equal (a, b); as a workaround: */
return os_threadIdToInteger (a) == os_threadIdToInteger (b);
}

View file

@ -0,0 +1,93 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#define _GNU_SOURCE /* Required for RUSAGE_THREAD. */
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/resource.h>
#if defined(__APPLE__)
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/thread_act.h>
#endif
#include "os/os.h"
_Pre_satisfies_((who == OS_RUSAGE_SELF) || \
(who == OS_RUSAGE_THREAD))
_Success_(return == 0)
int os_getrusage(_In_ int who, _Out_ os_rusage_t *usage)
{
int err = 0;
struct rusage buf;
assert(who == OS_RUSAGE_SELF || who == OS_RUSAGE_THREAD);
assert(usage != NULL);
memset(&buf, 0, sizeof(buf));
#if defined(__linux)
if (getrusage(who, &buf) == -1) {
err = errno;
} else {
buf.ru_maxrss *= 1024;
}
#else
if (getrusage(RUSAGE_SELF, &buf) == -1) {
err = errno;
} else if (who == OS_RUSAGE_THREAD) {
memset(&buf.ru_utime, 0, sizeof(buf.ru_utime));
memset(&buf.ru_stime, 0, sizeof(buf.ru_stime));
buf.ru_nvcsw = 0;
buf.ru_nivcsw = 0;
#if defined(__APPLE__)
kern_return_t ret;
mach_port_t thr;
mach_msg_type_number_t cnt;
thread_basic_info_data_t info;
thr = mach_thread_self();
assert(thr != MACH_PORT_DEAD);
if (thr == MACH_PORT_NULL) {
/* Resource shortage prevented reception of send right. */
err = ENOMEM;
} else {
cnt = THREAD_BASIC_INFO_COUNT;
ret = thread_info(
thr, THREAD_BASIC_INFO, (thread_info_t)&info, &cnt);
assert(ret != KERN_INVALID_ARGUMENT);
/* Assume MIG_ARRAY_TOO_LARGE will not happen. */
buf.ru_utime.tv_sec = info.user_time.seconds;
buf.ru_utime.tv_usec = info.user_time.microseconds;
buf.ru_stime.tv_sec = info.system_time.seconds;
buf.ru_stime.tv_usec = info.system_time.microseconds;
mach_port_deallocate(mach_task_self(), thr);
}
#endif /* __APPLE__ */
}
#endif /* __linux */
if (err == 0) {
usage->utime.tv_sec = (os_timeSec)buf.ru_utime.tv_sec;
usage->utime.tv_nsec = (int32_t)buf.ru_utime.tv_usec * 1000;
usage->stime.tv_sec = (os_timeSec)buf.ru_stime.tv_sec;
usage->stime.tv_nsec = (int32_t)buf.ru_stime.tv_usec * 1000;
usage->maxrss = (size_t)buf.ru_maxrss;
usage->idrss = (size_t)buf.ru_idrss;
usage->nvcsw = (size_t)buf.ru_nvcsw;
usage->nivcsw = (size_t)buf.ru_nivcsw;
}
return err;
}

View file

@ -0,0 +1,56 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <stdint.h>
#include "os/os.h"
#include <psapi.h>
static void
filetime_to_time(_In_ const FILETIME *ft, _Out_ os_time *t)
{
/* FILETIME structures express times in 100-nanosecond time units. */
uint64_t ns = ((ft->dwHighDateTime << 31) + (ft->dwLowDateTime));
t->tv_sec = (os_timeSec)(ns / (1000 * 1000 * 10));
t->tv_nsec = (int32_t)(ns % (1000 * 1000 * 10)) * 100;
}
_Pre_satisfies_((who == OS_RUSAGE_SELF) || \
(who == OS_RUSAGE_THREAD))
_Success_(return == 0)
int os_getrusage(_In_ int who, _Out_ os_rusage_t *usage)
{
FILETIME stime, utime, ctime, etime;
PROCESS_MEMORY_COUNTERS pmctrs;
assert(who == OS_RUSAGE_SELF || who == OS_RUSAGE_THREAD);
assert(usage != NULL);
/* Memory counters are per process, but populate them if thread resource
usage is requested to keep in sync with Linux. */
if ((!GetProcessMemoryInfo(GetCurrentProcess(), &pmctrs, sizeof(pmctrs)))
|| (who == OS_RUSAGE_SELF &&
!GetProcessTimes(GetCurrentProcess(), &ctime, &etime, &stime, &utime))
|| (who == OS_RUSAGE_THREAD &&
!GetThreadTimes(GetCurrentThread(), &ctime, &etime, &stime, &utime)))
{
return GetLastError();
}
memset(usage, 0, sizeof(*usage));
filetime_to_time(&stime, &usage->stime);
filetime_to_time(&utime, &usage->utime);
usage->maxrss = pmctrs.PeakWorkingSetSize;
return 0;
}

View file

@ -548,3 +548,52 @@ os__sockSelect(
return r;
}
ssize_t recvmsg (os_socket fd, struct msghdr *message, int flags)
{
ssize_t ret;
assert (message->msg_iovlen == 1);
assert (message->msg_controllen == 0);
message->msg_flags = 0;
ret = recvfrom (fd, message->msg_iov[0].iov_base, (int)message->msg_iov[0].iov_len, flags,
message->msg_name, &message->msg_namelen); /* To fix the warning of conversion from 'size_t' to 'int', which may cause possible loss of data, type casting is done*/
/* Windows returns an error for too-large messages, Unix expects
original size and the MSG_TRUNC flag. MSDN says it is truncated,
which presumably means it returned as much of the message as it
could - so we return that the message was 1 byte larger than the
available space, and set MSG_TRUNC if we can. */
if (ret == -1 && GetLastError () == WSAEMSGSIZE) {
ret = message->msg_iov[0].iov_len + 1;
message->msg_flags |= MSG_TRUNC;
}
return ret;
}
#define ASSERT_IOVEC_MATCHES_WSABUF do { \
struct iovec_matches_WSABUF { \
char sizeof_matches[sizeof(struct os_iovec) == sizeof(WSABUF) ? 1 : -1]; \
char base_off_matches[offsetof(struct os_iovec, iov_base) == offsetof(WSABUF, buf) ? 1 : -1]; \
char base_size_matches[sizeof(((struct os_iovec *)8)->iov_base) == sizeof(((WSABUF *)8)->buf) ? 1 : -1]; \
char len_off_matches[offsetof(struct os_iovec, iov_len) == offsetof(WSABUF, len) ? 1 : -1]; \
char len_size_matches[sizeof(((struct os_iovec *)8)->iov_len) == sizeof(((WSABUF *)8)->len) ? 1 : -1]; \
}; } while (0)
ssize_t sendmsg (os_socket fd, const struct msghdr *message, int flags)
{
DWORD sent;
ssize_t ret;
ASSERT_IOVEC_MATCHES_WSABUF;
assert(message->msg_controllen == 0);
if (WSASendTo (fd, (WSABUF *) message->msg_iov, (DWORD)message->msg_iovlen, &sent, flags, (SOCKADDR *) message->msg_name, message->msg_namelen, NULL, NULL) == 0)
ret = (ssize_t) sent;
else
ret = -1;
return ret;
}

View file

@ -74,9 +74,9 @@ CU_Test(os_getifaddrs, ipv4)
CU_ASSERT_EQUAL(ifa->addr->sa_family, AF_INET);
if (ifa->addr->sa_family == AF_INET) {
if (ifa->flags & IFF_LOOPBACK) {
CU_ASSERT(os_sockaddrIsLoopback(ifa->addr));
CU_ASSERT(os_sockaddr_is_loopback(ifa->addr));
} else {
CU_ASSERT(!os_sockaddrIsLoopback(ifa->addr));
CU_ASSERT(!os_sockaddr_is_loopback(ifa->addr));
}
seen = 1;
}