Skip to content

Commit

Permalink
Merge 6177939 into 7eb7988
Browse files Browse the repository at this point in the history
  • Loading branch information
mark0n committed Mar 18, 2021
2 parents 7eb7988 + 6177939 commit 6b5be60
Show file tree
Hide file tree
Showing 12 changed files with 330 additions and 35 deletions.
4 changes: 3 additions & 1 deletion configure/os/CONFIG.win32-x86.win32-x86
Expand Up @@ -188,7 +188,9 @@ RES=.res

# MS Visual C++ doesn't recognize *.cc as a C++ source file,
# so C++ compiles get the flag -TP
COMPILER_CXXFLAGS = -TP
# We want MSVC to report a reasonable C++ version in the __cplusplus macro so
# we need to set -Zc:__cplusplus (this is at least required for MSVC 19.xx).
COMPILER_CXXFLAGS = -TP -Zc:__cplusplus

# Operating system flags
OP_SYS_CFLAGS =
Expand Down
1 change: 1 addition & 0 deletions modules/libcom/src/osi/Makefile
Expand Up @@ -39,6 +39,7 @@ INC += epicsGeneralTime.h
INC += osdTime.h
INC += generalTimeSup.h
INC += osiClockTime.h
INC += osdTimer.h
INC += epicsSignal.h
INC += osiProcess.h
INC += osiUnistd.h
Expand Down
14 changes: 14 additions & 0 deletions modules/libcom/src/osi/os/Linux/osdTimer.h
@@ -0,0 +1,14 @@
/*************************************************************************\
* Copyright (c) 2021 Facility for Rare Isotope Beams
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/

#ifndef osdTimerh
#define osdTimerh

/* Linux supports high-precision timers (in contrast to quantized timers which
* only support sleeping for a multiple of the quantum). */
#define HAS_HIGH_PREC_TIMERS

#endif /* osdTimerh */
34 changes: 23 additions & 11 deletions modules/libcom/src/osi/os/WIN32/osdEvent.c
Expand Up @@ -26,6 +26,8 @@
#include "libComAPI.h"
#include "epicsEvent.h"

#include "osdThreadPvt.h"

typedef struct epicsEventOSD {
HANDLE handle;
} epicsEventOSD;
Expand Down Expand Up @@ -90,27 +92,37 @@ LIBCOM_API epicsEventStatus epicsEventWait ( epicsEventId pSem )
LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout (
epicsEventId pSem, double timeOut )
{
static const unsigned mSecPerSec = 1000;
static const unsigned nSec100PerSec = 10000000u;
HANDLE handles[2];
DWORD status;
DWORD tmo;
LARGE_INTEGER tmo;
HANDLE timer;

if ( timeOut <= 0.0 ) {
tmo = 0u;
}
else if ( timeOut >= INFINITE / mSecPerSec ) {
tmo = INFINITE - 1;
tmo.QuadPart = 0u;
}
else {
tmo = ( DWORD ) ( ( timeOut * mSecPerSec ) + 0.5 );
if ( tmo == 0 ) {
tmo = 1;
tmo.QuadPart = -((LONGLONG)(timeOut * nSec100PerSec + 0.5));
}

if (tmo.QuadPart < 0) {
timer = osdThreadGetTimer();
if (!SetWaitableTimer(timer, &tmo, 0, NULL, NULL, 0)) {
return epicsEventError;
}
handles[0] = pSem->handle;
handles[1] = timer;
status = WaitForMultipleObjects (2, handles, FALSE, INFINITE);
}
else {
status = WaitForSingleObject(pSem->handle, 0);
}
status = WaitForSingleObject ( pSem->handle, tmo );
if ( status == WAIT_OBJECT_0 ) {
return epicsEventOK;
}
else if ( status == WAIT_TIMEOUT ) {
else if ( status == WAIT_OBJECT_0 + 1 || status == WAIT_TIMEOUT ) {
/* WaitForMultipleObjects will trigger WAIT_OBJECT_0 + 1,
WaitForSingleObject will trigger WAIT_TIMEOUT */
return epicsEventWaitTimeout;
}
else {
Expand Down
89 changes: 69 additions & 20 deletions modules/libcom/src/osi/os/WIN32/osdThread.c
Expand Up @@ -19,9 +19,6 @@

#define VC_EXTRALEAN
#define STRICT
#ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x400 /* No support for W95 */
#endif
#include <windows.h>
#include <process.h> /* for _endthread() etc */

Expand All @@ -34,6 +31,8 @@
#include "epicsExit.h"
#include "epicsAtomic.h"

#include "osdThreadPvt.h"

LIBCOM_API void osdThreadHooksRun(epicsThreadId id);

void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName );
Expand All @@ -55,6 +54,7 @@ typedef struct epicsThreadOSD {
unsigned epicsPriority;
char isSuspended;
int joinable;
HANDLE timer; /* waitable timer */
} win32ThreadParam;

typedef struct epicsThreadPrivateOSD {
Expand Down Expand Up @@ -221,6 +221,19 @@ static win32ThreadGlobal * fetchWin32ThreadGlobal ( void )
return pWin32ThreadGlobal;
}

static void epicsParmCleanupDataWIN32 ( win32ThreadParam * pParm )
{
if ( pParm ) {
if ( pParm->handle ) {
CloseHandle ( pParm->handle );
}
if ( pParm->timer ) {
CloseHandle ( pParm->timer );
}
free ( pParm );
}
}

static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm )
{
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
Expand All @@ -239,8 +252,8 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm )
ellDelete ( & pGbl->threadList, & pParm->node );
LeaveCriticalSection ( & pGbl->mutex );

CloseHandle ( pParm->handle );
free ( pParm );
epicsParmCleanupDataWIN32 ( pParm );

}
}

Expand Down Expand Up @@ -493,6 +506,16 @@ static win32ThreadParam * epicsThreadParmCreate ( const char *pName )
strcpy ( pParmWIN32->pName, pName );
pParmWIN32->isSuspended = 0;
epicsAtomicIncrIntT(&pParmWIN32->refcnt);
#ifdef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
pParmWIN32->timer = CreateWaitableTimerEx(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
#endif
if (pParmWIN32->timer == NULL) {
pParmWIN32->timer = CreateWaitableTimer(NULL, 0, NULL);
}
if (pParmWIN32->timer == NULL) {
free(pParmWIN32);
return NULL;
}
}
return pParmWIN32;
}
Expand Down Expand Up @@ -590,7 +613,7 @@ epicsThreadId epicsThreadCreateOpt (
CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION,
& threadId );
if ( pParmWIN32->handle == 0 ) {
free ( pParmWIN32 );
epicsParmCleanupDataWIN32 ( pParmWIN32 );
return NULL;
}
/* weird win32 interface threadId parameter inconsistency */
Expand All @@ -600,8 +623,7 @@ epicsThreadId epicsThreadCreateOpt (
osdPriority = epicsThreadGetOsdPriorityValue (opts->priority);
bstat = SetThreadPriority ( pParmWIN32->handle, osdPriority );
if (!bstat) {
CloseHandle ( pParmWIN32->handle );
free ( pParmWIN32 );
epicsParmCleanupDataWIN32 ( pParmWIN32 );
return NULL;
}

Expand All @@ -614,8 +636,7 @@ epicsThreadId epicsThreadCreateOpt (
EnterCriticalSection ( & pGbl->mutex );
ellDelete ( & pGbl->threadList, & pParmWIN32->node );
LeaveCriticalSection ( & pGbl->mutex );
CloseHandle ( pParmWIN32->handle );
free ( pParmWIN32 );
epicsParmCleanupDataWIN32 ( pParmWIN32 );
return NULL;
}

Expand Down Expand Up @@ -777,24 +798,52 @@ LIBCOM_API int epicsStdCall epicsThreadIsSuspended ( epicsThreadId id )
}
}

/**
* osdThreadGetTimer ()
* return stored waitable timer object for thread
*/
HANDLE osdThreadGetTimer()
{
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;

assert ( pGbl );

pParm = ( win32ThreadParam * )
TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS );

return pParm->timer;
}

/*
* epicsThreadSleep ()
*/
LIBCOM_API void epicsStdCall epicsThreadSleep ( double seconds )
{
static const unsigned mSecPerSec = 1000;
DWORD milliSecDelay;
static const unsigned nSec100PerSec = 10000000u;
LARGE_INTEGER tmo;
HANDLE timer;

if ( seconds <= 0.0 ) {
tmo.QuadPart = 0u;
}
else {
tmo.QuadPart = -((LONGLONG)(seconds * nSec100PerSec + 0.5));
}

if ( seconds > 0.0 ) {
seconds *= mSecPerSec;
seconds += 0.99999999; /* 8 9s here is optimal */
milliSecDelay = ( seconds >= INFINITE ) ?
INFINITE - 1 : ( DWORD ) seconds;
if (tmo.QuadPart == 0) {
Sleep ( 0 );
}
else { /* seconds <= 0 or NAN */
milliSecDelay = 0u;
else {
timer = osdThreadGetTimer();
if (!SetWaitableTimer(timer, &tmo, 0, NULL, NULL, 0)) {
fprintf ( stderr, "epicsThreadSleep: SetWaitableTimer failed %lu\n", GetLastError() );
return;
}
if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) {
fprintf ( stderr, "epicsThreadSleep: WaitForSingleObject failed %lu\n", GetLastError() );
}
}
Sleep ( milliSecDelay );
}

/*
Expand Down
14 changes: 14 additions & 0 deletions modules/libcom/src/osi/os/WIN32/osdTimer.h
@@ -0,0 +1,14 @@
/*************************************************************************\
* Copyright (c) 2021 Facility for Rare Isotope Beams
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/

#ifndef osdTimerh
#define osdTimerh

/* Windows supports high-precision timers (in contrast to quantized timers
* which only support sleeping for a multiple of the quantum). */
#define HAS_HIGH_PREC_TIMERS

#endif /* osdTimerh */
14 changes: 14 additions & 0 deletions modules/libcom/src/osi/os/default/osdThreadPvt.h
@@ -0,0 +1,14 @@
#ifndef osdThreadPvth
#define osdThreadPvth

#ifdef __cplusplus
extern "C" {
#endif

extern HANDLE osdThreadGetTimer(void);

#ifdef __cplusplus
}
#endif

#endif /* osdThreadPvth */
12 changes: 12 additions & 0 deletions modules/libcom/src/osi/os/default/osdTimer.h
@@ -0,0 +1,12 @@
/*************************************************************************\
* Copyright (c) 2021 Facility for Rare Isotope Beams
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/

#ifndef osdTimerh
#define osdTimerh

/* For systems other than Linux we do not define HAS_HIGH_PREC_TIMERS. */

#endif /* osdTimerh */
1 change: 1 addition & 0 deletions modules/libcom/src/timer/epicsTimer.h
Expand Up @@ -19,6 +19,7 @@
#include "libComAPI.h"
#include "epicsTime.h"
#include "epicsThread.h"
#include "osdTimer.h"

#ifdef __cplusplus

Expand Down
5 changes: 5 additions & 0 deletions modules/libcom/src/timer/timer.cpp
Expand Up @@ -20,6 +20,7 @@
#include <stdio.h>

#include "epicsGuard.h"
#include "osdTimer.h"
#include "timerPrivate.h"
#include "errlog.h"

Expand Down Expand Up @@ -65,7 +66,11 @@ void timer::start ( epicsTimerNotify & notify, const epicsTime & expire )
void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire )
{
this->pNotify = & notify;
#ifdef HAS_HIGH_PREC_TIMERS
this->exp = expire;
#else
this->exp = expire - ( this->queue.notify.quantum () / 2.0 );
# endif

bool reschedualNeeded = false;
if ( this->curState == stateActive ) {
Expand Down
4 changes: 2 additions & 2 deletions modules/libcom/test/epicsEventTest.cpp
Expand Up @@ -172,7 +172,7 @@ static double eventWaitCheckDelayError( const epicsEventId &id, const double & d
#define WAITCOUNT 21
static void eventWaitTest()
{
#if defined(_WIN32) || defined(__rtems__) || defined(vxWorks)
#if defined(__rtems__) || defined(vxWorks)
testTodoBegin("Known issue with delay calculation");
#endif

Expand All @@ -184,7 +184,7 @@ static void eventWaitTest()
errorSum += eventWaitCheckDelayError ( event, delay );
}
double meanError = errorSum / WAITCOUNT;
testOk(meanError < 0.05, "Mean delay error was %.6f sec", meanError);
testOk(testImpreciseTiming() || meanError < 0.05, "Mean delay error was %.6f sec", meanError);

testTodoEnd();

Expand Down

0 comments on commit 6b5be60

Please sign in to comment.