Merged Jeff's 3.15_libcom_from_cvs_trunk branch.
This commit is contained in:
@@ -211,9 +211,10 @@ void casPVI::updateEnumStringTableAsyncCompletion ( const gdd & resp )
|
||||
}
|
||||
}
|
||||
else {
|
||||
errMessage ( S_cas_badType,
|
||||
errPrintf ( S_cas_badType, __FILE__, __LINE__,
|
||||
"application type \"enums\" string conversion"
|
||||
" table for enumerated PV isnt a string type?" );
|
||||
" table for enumerated PV \"%s\" isnt a string type?",
|
||||
getName() );
|
||||
}
|
||||
}
|
||||
else if ( resp.dimension() == 1 ) {
|
||||
|
||||
@@ -144,7 +144,7 @@ static ITEM **bucketStringCompare (ITEM **ppi, const void *pId)
|
||||
*/
|
||||
static BUCKETID bucketUnsignedHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
const unsigned *pUId = pId;
|
||||
const unsigned *pUId = (const unsigned *) pId;
|
||||
unsigned src;
|
||||
BUCKETID hashid;
|
||||
|
||||
@@ -194,7 +194,7 @@ static BUCKETID bucketPointerHash (BUCKET *pb, const void *pId)
|
||||
*/
|
||||
static BUCKETID bucketStringHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
const char *pStr = pId;
|
||||
const char *pStr = (const char *) pId;
|
||||
BUCKETID hashid;
|
||||
unsigned i;
|
||||
|
||||
|
||||
@@ -30,28 +30,6 @@ class "T" (the type stored in the hash table) must derive
|
||||
from class "ID" (the hash table key type) and also derive from
|
||||
tsSLNode<T>.
|
||||
|
||||
So far, the only confusion I have run into with templates has been:
|
||||
|
||||
1) strange compiler messages - unrelated to cause of course -
|
||||
when I get the class declaration order wrong (so that the
|
||||
compiler has trouble instantiating the template).
|
||||
|
||||
2) sun pro/dec/att compilers use a template database and
|
||||
gnu/msvc++ compilers use explicit template instantiation.
|
||||
Therefore blocks of code of this sort are required:
|
||||
|
||||
#include "resourceLib.h" // template def
|
||||
#include "resourceLib.cc" // template functions (that are not inline)
|
||||
#if defined (EXPL_TEMPL)
|
||||
//
|
||||
// From Stroustrups's "The C++ Programming Language"
|
||||
// Appendix A: r.14.9
|
||||
//
|
||||
// This explicitly instantiates the template class's member
|
||||
// functions into "templInst.o"
|
||||
//
|
||||
template class resTable<fred,uintId>;
|
||||
template class resTable<jane,stringId>;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,20 +21,17 @@
|
||||
// 1) This library is not thread safe
|
||||
//
|
||||
|
||||
//
|
||||
// ANSI C
|
||||
//
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
#define instantiateRecourceLib
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsThread.h"
|
||||
#include "tsMinMax.h"
|
||||
#include "fdManager.h"
|
||||
#include "locationException.h"
|
||||
|
||||
using std :: max;
|
||||
|
||||
epicsShareDef fdManager fileDescriptorManager;
|
||||
|
||||
const unsigned mSecPerSec = 1000u;
|
||||
@@ -261,9 +258,9 @@ void fdRegId::show ( unsigned level ) const
|
||||
//
|
||||
// fdManager::installReg ()
|
||||
//
|
||||
epicsShareFunc void fdManager::installReg (fdReg ®)
|
||||
void fdManager::installReg (fdReg ®)
|
||||
{
|
||||
this->maxFD = tsMax ( this->maxFD, reg.getFD()+1 );
|
||||
this->maxFD = max ( this->maxFD, reg.getFD()+1 );
|
||||
// Most applications will find that its important to push here to
|
||||
// the front of the list so that transient writes get executed
|
||||
// first allowing incoming read protocol to find that outgoing
|
||||
|
||||
@@ -104,8 +104,8 @@ private:
|
||||
fdReg * pCBReg;
|
||||
void reschedule ();
|
||||
double quantum ();
|
||||
epicsShareFunc void installReg (fdReg ®);
|
||||
epicsShareFunc void removeReg (fdReg ®);
|
||||
void installReg (fdReg ®);
|
||||
void removeReg (fdReg ®);
|
||||
void lazyInitTimerQueue ();
|
||||
fdManager ( const fdManager & );
|
||||
fdManager & operator = ( const fdManager & );
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2013 LANS LLC, as Operator of
|
||||
* Los Alamos National Laboratory.
|
||||
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
@@ -15,21 +15,52 @@
|
||||
#include <string.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsTypes.h"
|
||||
#include "osiSock.h"
|
||||
#include "epicsStdlib.h"
|
||||
|
||||
#ifndef NELEMENTS
|
||||
#define NELEMENTS(A) (sizeof(A)/sizeof(A[0]))
|
||||
#endif /*NELEMENTS*/
|
||||
|
||||
/*
|
||||
* addrArrayToUL ()
|
||||
*/
|
||||
static int addrArrayToUL ( const unsigned *pAddr,
|
||||
unsigned nElements, struct in_addr *pIpAddr )
|
||||
{
|
||||
unsigned i;
|
||||
epicsUInt32 addr = 0ul;
|
||||
|
||||
for ( i=0u; i < nElements; i++ ) {
|
||||
if ( pAddr[i] > 0xff ) {
|
||||
return -1;
|
||||
}
|
||||
addr <<= 8;
|
||||
addr |= ( epicsUInt32 ) pAddr[i];
|
||||
}
|
||||
pIpAddr->s_addr = htonl ( addr );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initIPAddr()
|
||||
* !! ipAddr should be passed in in network byte order !!
|
||||
* !! port is passed in in host byte order !!
|
||||
*/
|
||||
static int initIPAddr (struct in_addr ipAddr, unsigned short port,
|
||||
struct sockaddr_in *pIP)
|
||||
static int initIPAddr ( struct in_addr ipAddr, unsigned port,
|
||||
struct sockaddr_in *pIP )
|
||||
{
|
||||
memset(pIP, '\0', sizeof(*pIP));
|
||||
pIP->sin_family = AF_INET;
|
||||
pIP->sin_port = htons(port);
|
||||
pIP->sin_addr = ipAddr;
|
||||
if ( port > 0xffff ) {
|
||||
return -1;
|
||||
}
|
||||
{
|
||||
epicsUInt16 port_16 = (epicsUInt16) port;
|
||||
memset (pIP, '\0', sizeof(*pIP));
|
||||
pIP->sin_family = AF_INET;
|
||||
pIP->sin_port = htons(port_16);
|
||||
pIP->sin_addr = ipAddr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -42,47 +73,121 @@ static int initIPAddr (struct in_addr ipAddr, unsigned short port,
|
||||
*
|
||||
* Sets the port number to "defaultPort" only if
|
||||
* "pAddrString" does not contain an address of the form
|
||||
* "n.n.n.n:p"
|
||||
* "n.n.n.n:p or host:p"
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI
|
||||
aToIPAddr(const char *pAddrString, unsigned short defaultPort,
|
||||
struct sockaddr_in *pIP)
|
||||
epicsShareFunc int epicsShareAPI
|
||||
aToIPAddr( const char *pAddrString, unsigned short defaultPort,
|
||||
struct sockaddr_in *pIP )
|
||||
{
|
||||
int status;
|
||||
char hostName[512]; /* !! change n elements here requires change in format below !! */
|
||||
unsigned int port;
|
||||
unsigned long numaddr;
|
||||
unsigned addr[4];
|
||||
unsigned long rawAddr;
|
||||
/*
|
||||
* !! change n elements here requires change in format below !!
|
||||
*/
|
||||
char hostName[512];
|
||||
char dummy[8];
|
||||
unsigned port;
|
||||
struct in_addr ina;
|
||||
|
||||
/*
|
||||
* Scan for a port number
|
||||
* dotted ip addresses
|
||||
*/
|
||||
status = sscanf( pAddrString, " %511[^:]:%u", hostName, &port );
|
||||
if ( status == 0 ) {
|
||||
return -1;
|
||||
status = sscanf ( pAddrString, " %u . %u . %u . %u %7s ",
|
||||
addr, addr+1u, addr+2u, addr+3u, dummy );
|
||||
if ( status == 4 ) {
|
||||
if ( addrArrayToUL ( addr, NELEMENTS ( addr ), & ina ) < 0 ) {
|
||||
return -1;
|
||||
}
|
||||
port = defaultPort;
|
||||
return initIPAddr ( ina, port, pIP );
|
||||
}
|
||||
|
||||
/*
|
||||
* dotted ip addresses and port
|
||||
*/
|
||||
status = sscanf ( pAddrString, " %u . %u . %u . %u : %u %7s",
|
||||
addr, addr+1u, addr+2u, addr+3u, &port, dummy );
|
||||
if ( status >= 5 ) {
|
||||
if ( status > 5 ) {
|
||||
/*
|
||||
* valid at the start but detritus on the end
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
if ( addrArrayToUL ( addr, NELEMENTS ( addr ), &ina ) < 0 ) {
|
||||
return -1;
|
||||
}
|
||||
return initIPAddr ( ina, port, pIP );
|
||||
}
|
||||
|
||||
/*
|
||||
* IP address as a raw number
|
||||
*/
|
||||
status = sscanf ( pAddrString, " %lu %7s ", &rawAddr, dummy );
|
||||
if ( status == 1 ) {
|
||||
if ( rawAddr > 0xffffffff ) {
|
||||
return -1;
|
||||
}
|
||||
port = defaultPort;
|
||||
{
|
||||
epicsUInt32 rawAddr_32 = ( epicsUInt32 ) rawAddr;
|
||||
ina.s_addr = htonl ( rawAddr_32 );
|
||||
return initIPAddr ( ina, port, pIP );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* IP address as a raw number, and port
|
||||
*/
|
||||
status = sscanf ( pAddrString, " %lu : %u %7s ", &rawAddr, &port, dummy );
|
||||
if ( status >= 2 ) {
|
||||
if ( status > 2 ) {
|
||||
/*
|
||||
* valid at the start but detritus on the end
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
if ( rawAddr > 0xffffffff ) {
|
||||
return -1;
|
||||
}
|
||||
{
|
||||
epicsUInt32 rawAddr_32 = ( epicsUInt32 ) rawAddr;
|
||||
ina.s_addr = htonl ( rawAddr_32 );
|
||||
return initIPAddr ( ina, port, pIP );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* host name string
|
||||
*/
|
||||
status = sscanf ( pAddrString, " %511[^:] %s ", hostName, dummy );
|
||||
if ( status == 1 ) {
|
||||
port = defaultPort;
|
||||
status = hostToIPAddr ( hostName, &ina );
|
||||
if ( status == 0 ) {
|
||||
return initIPAddr ( ina, port, pIP );
|
||||
}
|
||||
}
|
||||
else if (status == 2 && port > 65535) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Look for a valid host name or dotted quad
|
||||
* host name string, and port
|
||||
*/
|
||||
status = hostToIPAddr( hostName, &ina );
|
||||
if ( status == 0 ) {
|
||||
return initIPAddr( ina, port, pIP );
|
||||
status = sscanf ( pAddrString, " %511[^:] : %u %s ", hostName,
|
||||
&port, dummy );
|
||||
if ( status >= 2 ) {
|
||||
if ( status > 2 ) {
|
||||
/*
|
||||
* valid at the start but detritus on the end
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
status = hostToIPAddr ( hostName, &ina );
|
||||
if ( status == 0 ) {
|
||||
return initIPAddr ( ina, port, pIP );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try the IP address as a decimal integer
|
||||
*/
|
||||
if ( epicsParseULong( hostName, &numaddr, 10, NULL ) ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ina.s_addr = htonl( numaddr );
|
||||
return initIPAddr( ina, port, pIP );
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <string>
|
||||
#include <climits>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "ipAddrToAsciiAsynchronous.h"
|
||||
@@ -206,7 +206,7 @@ ipAddrToAsciiEnginePrivate::~ipAddrToAsciiEnginePrivate ()
|
||||
this->thread.exitWait ();
|
||||
}
|
||||
|
||||
// for now its probably sufficent to allocate one
|
||||
// for now its probably sufficient to allocate one
|
||||
// DNS transaction thread for all codes sharing
|
||||
// the same process that need DNS services but we
|
||||
// leave our options open for the future
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2011 LANS LLC, as Operator of
|
||||
* Los Alamos National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
@@ -58,8 +60,12 @@ static const unsigned long NTP_TIME_AT_EPICS_EPOCH =
|
||||
//
|
||||
// epicsTime (const unsigned long secIn, const unsigned long nSecIn)
|
||||
//
|
||||
inline epicsTime::epicsTime (const unsigned long secIn, const unsigned long nSecIn) :
|
||||
secPastEpoch ( nSecIn / nSecPerSec + secIn ), nSec ( nSecIn % nSecPerSec ) {}
|
||||
inline epicsTime::epicsTime (const unsigned long secIn,
|
||||
const unsigned long nSecIn) :
|
||||
secPastEpoch ( nSecIn / nSecPerSec + secIn ),
|
||||
nSec ( nSecIn % nSecPerSec )
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// epicsTimeLoadTimeInit
|
||||
@@ -109,51 +115,45 @@ epicsTimeLoadTimeInit::epicsTimeLoadTimeInit ()
|
||||
//
|
||||
// epicsTime::addNanoSec ()
|
||||
//
|
||||
// many of the UNIX timestamp formats have nano sec stored as a long
|
||||
// The nano-second field of several of the the UNIX time stamp formats
|
||||
// field is stored in the C type "long".
|
||||
//
|
||||
void epicsTime::addNanoSec (long nSecAdj)
|
||||
void epicsTime :: addNanoSec ( long nSecAdj )
|
||||
{
|
||||
// After optimizing this function we now have a larger
|
||||
// code which uses only unsigned integer arithmetic.
|
||||
// This is for the benefit of embedded cpu's lacking
|
||||
// a hardware floating point coprocessor at the
|
||||
// expense of some additional code to maintain.
|
||||
// joh 14-11-2012
|
||||
//
|
||||
// After optimizing this function we now have a larger code which
|
||||
// uses only unsigned integer, and not floating point, arithmetic.
|
||||
// This change benefits embedded CPU's lacking a floating point
|
||||
// co-processor at the expense of some additional code to maintain.
|
||||
//
|
||||
// We hope that all CPU's we run on provide at least an integer
|
||||
// divide instruction which should enable this implementation
|
||||
// to be more efficient than implementations based on branching;
|
||||
// this is presuming that we will run on pipelined architectures.
|
||||
//
|
||||
// Overflow and underflow is expected; in the future we might
|
||||
// operate close to, the modulo of, the EPICS epic.
|
||||
//
|
||||
// We are depending on the normalize operation in the private
|
||||
// constructor used below.
|
||||
//
|
||||
// joh 11-04-2012
|
||||
//
|
||||
if ( nSecAdj >= 0 ) {
|
||||
unsigned long nSecOffsetLong =
|
||||
static_cast < unsigned long > ( nSecAdj );
|
||||
while ( nSecOffsetLong >= nSecPerSec ) {
|
||||
this->secPastEpoch++; // overflow expected
|
||||
nSecOffsetLong -= nSecPerSec;
|
||||
}
|
||||
const epicsUInt32 nSecOffset =
|
||||
static_cast < epicsUInt32 > ( nSecOffsetLong );
|
||||
epicsUInt32 nSecPerSecRemaining = nSecPerSec - nSecOffset;
|
||||
if ( this->nSec >= nSecPerSecRemaining ) {
|
||||
this->secPastEpoch++; // overflow expected
|
||||
this->nSec -= nSecPerSecRemaining;
|
||||
}
|
||||
else {
|
||||
this->nSec += nSecOffset;
|
||||
}
|
||||
const unsigned long nSecPlus =
|
||||
static_cast <unsigned long> ( nSecAdj );
|
||||
const unsigned long nSecPlusAdj = nSecPlus % nSecPerSec;
|
||||
const unsigned long secPlusAdj = nSecPlus / nSecPerSec;
|
||||
*this = epicsTime ( this->secPastEpoch+secPlusAdj,
|
||||
this->nSec+nSecPlusAdj );
|
||||
}
|
||||
else {
|
||||
unsigned long nSecOffsetLong =
|
||||
static_cast <unsigned long> ( -nSecAdj );
|
||||
while ( nSecOffsetLong >= nSecPerSec ) {
|
||||
this->secPastEpoch--; // underflow expected
|
||||
nSecOffsetLong -= nSecPerSec;
|
||||
}
|
||||
const epicsUInt32 nSecOffset =
|
||||
static_cast < epicsUInt32 > ( nSecOffsetLong );
|
||||
if ( this->nSec >= nSecOffset ) {
|
||||
this->nSec -= nSecOffset;
|
||||
}
|
||||
else {
|
||||
// borrow
|
||||
this->secPastEpoch--; // underflow expected
|
||||
this->nSec += nSecPerSec - nSecOffset;
|
||||
}
|
||||
const unsigned long nSecMinus =
|
||||
static_cast <unsigned long> ( -nSecAdj );
|
||||
const unsigned long nSecMinusAdj = nSecMinus % nSecPerSec;
|
||||
const unsigned long secMinusAdj = nSecMinus / nSecPerSec;
|
||||
*this = epicsTime ( this->secPastEpoch - secMinusAdj - 1u,
|
||||
this->nSec + nSecPerSec - nSecMinusAdj );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,8 +368,8 @@ epicsTime::operator struct timeval () const
|
||||
time_t_wrapper ansiTimeTicks;
|
||||
|
||||
ansiTimeTicks = *this;
|
||||
// On Posix systems timeval :: tv_sec is a time_t so this can be
|
||||
// a direct assignement. On other systems I dont know that we can
|
||||
// On Posix systems timeval :: tv_sec is a time_t so this can be
|
||||
// a direct assignment. On other systems I dont know that we can
|
||||
// guarantee that time_t and timeval :: tv_sec will have the
|
||||
// same epoch or have the same scaling factor to discrete seconds.
|
||||
// For example, on windows time_t changed recently to a 64 bit
|
||||
@@ -387,8 +387,8 @@ epicsTime::operator struct timeval () const
|
||||
epicsTime::epicsTime (const struct timeval &ts)
|
||||
{
|
||||
time_t_wrapper ansiTimeTicks;
|
||||
// On Posix systems timeval :: tv_sec is a time_t so this can be
|
||||
// a direct assignement. On other systems I dont know that we can
|
||||
// On Posix systems timeval :: tv_sec is a time_t so this can be
|
||||
// a direct assignment. On other systems I dont know that we can
|
||||
// guarantee that time_t and timeval :: tv_sec will have the
|
||||
// same epoch or have the same scaling factor to discrete seconds.
|
||||
// For example, on windows time_t changed recently to a 64 bit
|
||||
@@ -438,11 +438,11 @@ epicsTime::operator epicsTimeStamp () const
|
||||
}
|
||||
epicsTimeStamp ts;
|
||||
//
|
||||
// trucation by design
|
||||
// truncation by design
|
||||
// -------------------
|
||||
// epicsTime::secPastEpoch is based on ulong and has much greater range
|
||||
// on 64 bit hosts than the orginal epicsTimeStamp::secPastEpoch. The
|
||||
// epicsTimeStamp::secPastEpoch is based on epicsUInt32 so that it will
|
||||
// epicsTime::secPastEpoch is based on ulong and has much greater range
|
||||
// on 64 bit hosts than the original epicsTimeStamp::secPastEpoch. The
|
||||
// epicsTimeStamp::secPastEpoch is based on epicsUInt32 so that it will
|
||||
// match the original network protocol. Of course one can anticipate
|
||||
// that eventually, a epicsUInt64 based network time stamp will be
|
||||
// introduced when 64 bit architectures are more ubiquitous.
|
||||
@@ -655,7 +655,7 @@ void epicsTime::show ( unsigned level ) const
|
||||
}
|
||||
|
||||
if ( level > 1 ) {
|
||||
// this also supresses the "defined, but not used"
|
||||
// this also suppresses the "defined, but not used"
|
||||
// warning message
|
||||
printf ( "epicsTime: revision \"%s\"\n",
|
||||
pEpicsTimeVersion );
|
||||
|
||||
@@ -64,90 +64,76 @@ epicsShareFunc osiSpawnDetachedProcessReturn epicsShareAPI osiSpawnDetachedProce
|
||||
startupInfo.wShowWindow = SW_SHOWMINNOACTIVE;
|
||||
|
||||
status = CreateProcess (
|
||||
NULL, /* pointer to name of executable module (not required if command line is specified) */
|
||||
(char *) pBaseExecutableName, /* pointer to command line string */
|
||||
NULL, /* pointer to process security attributes */
|
||||
NULL, /* pointer to thread security attributes */
|
||||
FALSE, /* handle inheritance flag */
|
||||
CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, /* creation flags */
|
||||
NULL, /* pointer to new environment block (defaults to caller's environement) */
|
||||
NULL, /* pointer to current directory name (defaults to caller's current directory) */
|
||||
&startupInfo, /* pointer to STARTUPINFO */
|
||||
&processInfo /* pointer to PROCESS_INFORMATION */
|
||||
);
|
||||
if ( status == 0 ) {
|
||||
DWORD W32status;
|
||||
LPVOID errStrMsgBuf;
|
||||
LPVOID complteMsgBuf;
|
||||
NULL, /* pointer to name of executable module (not required if command line is specified) */
|
||||
(char *) pBaseExecutableName, /* pointer to command line string */
|
||||
NULL, /* pointer to process security attributes */
|
||||
NULL, /* pointer to thread security attributes */
|
||||
FALSE, /* handle inheritance flag */
|
||||
CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, /* creation flags */
|
||||
NULL, /* pointer to new environment block (defaults to caller's environement) */
|
||||
NULL, /* pointer to current directory name (defaults to caller's current directory) */
|
||||
&startupInfo, /* pointer to STARTUPINFO */
|
||||
&processInfo /* pointer to PROCESS_INFORMATION */
|
||||
);
|
||||
if ( status == 0 ) {
|
||||
DWORD W32status;
|
||||
LPVOID errStrMsgBuf;
|
||||
LPVOID complteMsgBuf;
|
||||
|
||||
W32status = FormatMessage (
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
GetLastError (),
|
||||
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
||||
(LPTSTR) &errStrMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
W32status = FormatMessage (
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
GetLastError (),
|
||||
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
||||
(LPTSTR) &errStrMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( W32status ) {
|
||||
char *pFmtArgs[6];
|
||||
if ( W32status ) {
|
||||
char *pFmtArgs[6];
|
||||
pFmtArgs[0] = "Failed to start executable -";
|
||||
pFmtArgs[1] = (char *) pBaseExecutableName;
|
||||
pFmtArgs[2] = errStrMsgBuf;
|
||||
pFmtArgs[3] = "Changes may be required in your \"path\" environment variable.";
|
||||
pFmtArgs[4] = "PATH = ";
|
||||
pFmtArgs[5] = getenv ("path");
|
||||
if ( pFmtArgs[5] == NULL ) {
|
||||
pFmtArgs[5] = "<empty string>";
|
||||
}
|
||||
|
||||
W32status = FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING |
|
||||
FORMAT_MESSAGE_ARGUMENT_ARRAY | 80,
|
||||
"%1 \"%2\". %3 %4 %5 \"%6\"",
|
||||
0,
|
||||
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
||||
(LPTSTR) &complteMsgBuf,
|
||||
0,
|
||||
pFmtArgs
|
||||
);
|
||||
if (W32status) {
|
||||
/* Display the string. */
|
||||
MessageBox (NULL, complteMsgBuf, "Configuration Problem",
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
LocalFree (complteMsgBuf);
|
||||
}
|
||||
else {
|
||||
/* Display the string. */
|
||||
MessageBox (NULL, errStrMsgBuf, "Failed to start executable",
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
|
||||
/* Free the buffer. */
|
||||
LocalFree (errStrMsgBuf);
|
||||
}
|
||||
else {
|
||||
errlogPrintf ("!!WARNING!!\n");
|
||||
errlogPrintf ("Unable to locate executable \"%s\".\n", pBaseExecutableName);
|
||||
errlogPrintf ("You may need to modify your environment.\n");
|
||||
}
|
||||
if ( pFmtArgs[5] == NULL ) {
|
||||
pFmtArgs[5] = "<empty string>";
|
||||
}
|
||||
|
||||
W32status = FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING |
|
||||
FORMAT_MESSAGE_ARGUMENT_ARRAY | 80,
|
||||
"%1 \"%2\". %3 %4 %5 \"%6\"",
|
||||
0,
|
||||
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
||||
(LPTSTR) &complteMsgBuf,
|
||||
0,
|
||||
pFmtArgs
|
||||
);
|
||||
if (W32status) {
|
||||
/* Display the string. */
|
||||
MessageBox (NULL, complteMsgBuf, "Configuration Problem",
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
LocalFree (complteMsgBuf);
|
||||
}
|
||||
else {
|
||||
/* Display the string. */
|
||||
MessageBox (NULL, errStrMsgBuf, "Failed to start executable",
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
|
||||
/* Free the buffer. */
|
||||
LocalFree (errStrMsgBuf);
|
||||
}
|
||||
else {
|
||||
errlogPrintf ("!!WARNING!!\n");
|
||||
errlogPrintf ("Unable to locate executable \"%s\".\n", pBaseExecutableName);
|
||||
errlogPrintf ("You may need to modify your \"path\" environment variable.\n");
|
||||
}
|
||||
return osiSpawnDetachedProcessFail;
|
||||
}
|
||||
}
|
||||
|
||||
return osiSpawnDetachedProcessSuccess;
|
||||
|
||||
/*
|
||||
use of spawn here causes problems when the ca repeater
|
||||
inherits open files (and sockets) from the spawning
|
||||
process
|
||||
|
||||
status = _spawnlp (_P_DETACH, pBaseExecutableName, pBaseExecutableName, NULL);
|
||||
if (status<0) {
|
||||
errlogPrintf ("!!WARNING!!\n");
|
||||
errlogPrintf ("Unable to locate the EPICS executable \"%s\".\n",
|
||||
pBaseExecutableName);
|
||||
errlogPrintf ("You may need to modify your environment.\n");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
//
|
||||
// ANSI C
|
||||
//
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
|
||||
//
|
||||
// WIN32
|
||||
@@ -28,6 +28,7 @@
|
||||
#define VC_EXTRALEAN
|
||||
#define STRICT
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
|
||||
//
|
||||
// EPICS
|
||||
@@ -46,19 +47,26 @@
|
||||
# define debugPrintf(argsInParen)
|
||||
#endif
|
||||
|
||||
extern "C" void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName );
|
||||
|
||||
static int osdTimeGetCurrent ( epicsTimeStamp *pDest );
|
||||
|
||||
// for mingw
|
||||
#if !defined ( MAXLONGLONG )
|
||||
#define MAXLONGLONG 0x7fffffffffffffffLL
|
||||
# define MAXLONGLONG 0x7fffffffffffffffLL
|
||||
#endif
|
||||
#if !defined ( MINLONGLONG )
|
||||
#define MINLONGLONG (~0x7fffffffffffffffLL)
|
||||
# define MINLONGLONG ~0x7fffffffffffffffLL
|
||||
#endif
|
||||
#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
|
||||
# define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
|
||||
#endif
|
||||
|
||||
static const LONGLONG epicsEpochInFileTime = 0x01b41e2a18d64000LL;
|
||||
|
||||
class currentTime : public epicsTimerNotify {
|
||||
static unsigned __stdcall _pllThreadEntry ( void * pCurrentTimeIn );
|
||||
|
||||
class currentTime {
|
||||
public:
|
||||
currentTime ();
|
||||
~currentTime ();
|
||||
@@ -72,20 +80,24 @@ private:
|
||||
LONGLONG perfCounterFreqPLL;
|
||||
LONGLONG lastPerfCounterPLL;
|
||||
LONGLONG lastFileTimePLL;
|
||||
epicsTimerQueueActive * pTimerQueue;
|
||||
epicsTimer * pTimer;
|
||||
HANDLE threadHandle;
|
||||
unsigned threadId;
|
||||
bool perfCtrPresent;
|
||||
bool threadShutdownCmd;
|
||||
bool threadHasExited;
|
||||
void updatePLL ();
|
||||
static const int pllDelay; /* integer seconds */
|
||||
epicsTimerNotify::expireStatus expire ( const epicsTime & );
|
||||
// cant be static because of diff btw __stdcall and __cdecl
|
||||
friend unsigned __stdcall _pllThreadEntry ( void * pCurrentTimeIn );
|
||||
};
|
||||
|
||||
const int currentTime :: pllDelay = 5;
|
||||
|
||||
static currentTime * pCurrentTime = 0;
|
||||
static const LONGLONG FILE_TIME_TICKS_PER_SEC = 10000000;
|
||||
static const LONGLONG EPICS_TIME_TICKS_PER_SEC = 1000000000;
|
||||
static const LONGLONG ET_TICKS_PER_FT_TICK =
|
||||
EPICS_TIME_TICKS_PER_SEC / FILE_TIME_TICKS_PER_SEC;
|
||||
|
||||
const int currentTime :: pllDelay = 5;
|
||||
|
||||
//
|
||||
// Start and register time provider
|
||||
@@ -185,8 +197,8 @@ int epicsShareAPI epicsTime_localtime (
|
||||
}
|
||||
|
||||
//
|
||||
// There are remarkable weaknessess in the FileTimeToLocalFileTime
|
||||
// interface so we dont use it here. Unfortunately, there is no
|
||||
// There are remarkable weaknesses in the FileTimeToLocalFileTime
|
||||
// interface so we don't use it here. Unfortunately, there is no
|
||||
// corresponding function that works on file time.
|
||||
//
|
||||
SYSTEMTIME st;
|
||||
@@ -263,9 +275,11 @@ currentTime::currentTime () :
|
||||
perfCounterFreqPLL ( 0 ),
|
||||
lastPerfCounterPLL ( 0 ),
|
||||
lastFileTimePLL ( 0 ),
|
||||
pTimerQueue ( 0 ),
|
||||
pTimer ( 0 ),
|
||||
perfCtrPresent ( false )
|
||||
threadHandle ( 0 ),
|
||||
threadId ( 0 ),
|
||||
perfCtrPresent ( false ),
|
||||
threadShutdownCmd ( false ),
|
||||
threadHasExited ( false )
|
||||
{
|
||||
InitializeCriticalSection ( & this->mutex );
|
||||
|
||||
@@ -308,15 +322,34 @@ currentTime::currentTime () :
|
||||
this->lastFileTimePLL = liFileTime.QuadPart;
|
||||
}
|
||||
|
||||
void currentTime :: startPLL ()
|
||||
{
|
||||
// create frequency estimation thread when needed
|
||||
if ( this->perfCtrPresent && ! this->threadHandle ) {
|
||||
this->threadHandle = (HANDLE)
|
||||
_beginthreadex ( 0, 4096, _pllThreadEntry, this,
|
||||
CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION,
|
||||
& this->threadId );
|
||||
assert ( this->threadHandle );
|
||||
BOOL bstat = SetThreadPriority (
|
||||
this->threadHandle, THREAD_PRIORITY_HIGHEST );
|
||||
assert ( bstat );
|
||||
DWORD wstat = ResumeThread ( this->threadHandle );
|
||||
assert ( wstat != 0xFFFFFFFF );
|
||||
}
|
||||
}
|
||||
|
||||
currentTime::~currentTime ()
|
||||
{
|
||||
EnterCriticalSection ( & this->mutex );
|
||||
this->threadShutdownCmd = true;
|
||||
while ( ! this->threadHasExited ) {
|
||||
LeaveCriticalSection ( & this->mutex );
|
||||
Sleep ( 250 /* mS */ );
|
||||
EnterCriticalSection ( & this->mutex );
|
||||
}
|
||||
LeaveCriticalSection ( & this->mutex );
|
||||
DeleteCriticalSection ( & this->mutex );
|
||||
if ( this->pTimer ) {
|
||||
this->pTimer->destroy ();
|
||||
}
|
||||
if ( this->pTimerQueue ) {
|
||||
this->pTimerQueue->release ();
|
||||
}
|
||||
}
|
||||
|
||||
void currentTime::getCurrentTime ( epicsTimeStamp & dest )
|
||||
@@ -386,7 +419,7 @@ void currentTime::getCurrentTime ( epicsTimeStamp & dest )
|
||||
// Maintain corrected version of the performance counter's frequency using
|
||||
// a phase locked loop. This approach is similar to NTP's.
|
||||
//
|
||||
epicsTimerNotify::expireStatus currentTime::expire ( const epicsTime & )
|
||||
void currentTime :: updatePLL ()
|
||||
{
|
||||
EnterCriticalSection ( & this->mutex );
|
||||
|
||||
@@ -431,7 +464,7 @@ epicsTimerNotify::expireStatus currentTime::expire ( const epicsTime & )
|
||||
if ( fileTimeDiff <= 0 ) {
|
||||
LeaveCriticalSection( & this->mutex );
|
||||
debugPrintf ( ( "currentTime: file time difference in PLL was less than zero\n" ) );
|
||||
return expireStatus ( restart, pllDelay /* sec */ );
|
||||
return;
|
||||
}
|
||||
|
||||
LONGLONG freq = ( FILE_TIME_TICKS_PER_SEC * perfCounterDiff ) / fileTimeDiff;
|
||||
@@ -445,7 +478,7 @@ epicsTimerNotify::expireStatus currentTime::expire ( const epicsTime & )
|
||||
static_cast < int > ( -bound ),
|
||||
static_cast < int > ( delta ),
|
||||
static_cast < int > ( bound ) ) );
|
||||
return expireStatus ( restart, pllDelay /* sec */ );
|
||||
return;
|
||||
}
|
||||
|
||||
// update feedback loop estimating the performance counter's frequency
|
||||
@@ -482,7 +515,7 @@ epicsTimerNotify::expireStatus currentTime::expire ( const epicsTime & )
|
||||
debugPrintf ( ( "perf ctr measured delay out of bounds m=%d max=%d\n",
|
||||
static_cast < int > ( perfCounterDiffSinceLastFetch ),
|
||||
static_cast < int > ( expectedDly + bnd ) ) );
|
||||
return expireStatus ( restart, pllDelay /* sec */ );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,9 +554,9 @@ epicsTimerNotify::expireStatus currentTime::expire ( const epicsTime & )
|
||||
|
||||
delta = epicsTimeFromCurrentFileTime - this->epicsTimeLast;
|
||||
if ( delta > EPICS_TIME_TICKS_PER_SEC || delta < -EPICS_TIME_TICKS_PER_SEC ) {
|
||||
// When there is an abrupt shift in the current computed time vs
|
||||
// the time derived from the current file time then someone has
|
||||
// probabably adjusted the real time clock and the best reaction
|
||||
// When there is an abrupt shift in the current computed time vs
|
||||
// the time derived from the current file time then someone has
|
||||
// probably adjusted the real time clock and the best reaction
|
||||
// is to just assume the new time base
|
||||
this->epicsTimeLast = epicsTimeFromCurrentFileTime;
|
||||
this->perfCounterFreq = this->perfCounterFreqPLL;
|
||||
@@ -563,24 +596,31 @@ epicsTimerNotify::expireStatus currentTime::expire ( const epicsTime & )
|
||||
( this->perfCounterFreqPLL - sysFreq.QuadPart );
|
||||
freqEstDiff /= sysFreq.QuadPart;
|
||||
freqEstDiff *= 100.0;
|
||||
debugPrintf ( ( "currentTime: freq delta %f %% freq est delta %f %% time delta %f sec\n",
|
||||
freqDiff, freqEstDiff, static_cast < double > ( delta ) / EPICS_TIME_TICKS_PER_SEC ) );
|
||||
debugPrintf ( ( "currentTime: freq delta %f %% freq est "
|
||||
"delta %f %% time delta %f sec\n",
|
||||
freqDiff,
|
||||
freqEstDiff,
|
||||
static_cast < double > ( delta ) /
|
||||
EPICS_TIME_TICKS_PER_SEC ) );
|
||||
# endif
|
||||
}
|
||||
|
||||
LeaveCriticalSection ( & this->mutex );
|
||||
|
||||
return expireStatus ( restart, pllDelay /* sec */ );
|
||||
}
|
||||
|
||||
void currentTime::startPLL ()
|
||||
static unsigned __stdcall _pllThreadEntry ( void * pCurrentTimeIn )
|
||||
{
|
||||
// create frequency estimation timer when needed
|
||||
if ( this->perfCtrPresent && ! this->pTimerQueue ) {
|
||||
this->pTimerQueue = & epicsTimerQueueActive::allocate ( true );
|
||||
this->pTimer = & this->pTimerQueue->createTimer ();
|
||||
this->pTimer->start ( *this, pllDelay );
|
||||
currentTime * pCT =
|
||||
reinterpret_cast < currentTime * > ( pCurrentTimeIn );
|
||||
setThreadName ( pCT->threadId, "EPICS Time PLL" );
|
||||
while ( ! pCT->threadShutdownCmd ) {
|
||||
Sleep ( currentTime :: pllDelay * 1000 /* mS */ );
|
||||
pCT->updatePLL ();
|
||||
}
|
||||
EnterCriticalSection ( & pCT->mutex );
|
||||
pCT->threadHasExited = true;
|
||||
LeaveCriticalSection ( & pCT->mutex );
|
||||
return 1;
|
||||
}
|
||||
|
||||
epicsTime::operator FILETIME () const
|
||||
|
||||
@@ -115,18 +115,11 @@ epicsShareFunc unsigned epicsShareAPI ipAddrToHostName
|
||||
epicsShareFunc int epicsShareAPI
|
||||
hostToIPAddr(const char *pHostName, struct in_addr *pIPA)
|
||||
{
|
||||
int addr;
|
||||
|
||||
addr = hostGetByName((char *)pHostName);
|
||||
if (addr != ERROR) {
|
||||
pIPA->s_addr = (unsigned long) addr;
|
||||
}
|
||||
else if (inet_aton((char *)pHostName, pIPA) == ERROR) {
|
||||
/*
|
||||
* return indicating an error
|
||||
*/
|
||||
int addr = hostGetByName ( (char *) pHostName );
|
||||
if ( addr == ERROR ) {
|
||||
return -1;
|
||||
}
|
||||
pIPA->s_addr = (unsigned long) addr;
|
||||
|
||||
/*
|
||||
* success
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsTypes.h"
|
||||
|
||||
@@ -56,11 +56,13 @@ private:
|
||||
|
||||
class server {
|
||||
public:
|
||||
server ( address & );
|
||||
server ( const address & );
|
||||
void start ();
|
||||
void daemon ();
|
||||
void stop ();
|
||||
address addr () const;
|
||||
protected:
|
||||
address srvaddr;
|
||||
SOCKET sock;
|
||||
epicsThreadId id;
|
||||
bool exit;
|
||||
@@ -155,20 +157,20 @@ extern "C" void serverDaemon ( void * pParam ) {
|
||||
pSrv->daemon ();
|
||||
}
|
||||
|
||||
server::server ( address & addrIn ) :
|
||||
server::server ( const address & addrIn ) :
|
||||
srvaddr ( addrIn ),
|
||||
sock ( epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ),
|
||||
id ( 0 ), exit ( false )
|
||||
{
|
||||
testOk ( this->sock != INVALID_SOCKET, "Server socket valid" );
|
||||
|
||||
// setup server side
|
||||
int status = bind ( this->sock,
|
||||
& addrIn.sa, sizeof ( addrIn ) );
|
||||
osiSocklen_t slen = sizeof ( this->srvaddr );
|
||||
int status = bind ( this->sock, & this->srvaddr.sa, slen );
|
||||
if ( status ) {
|
||||
testDiag ( "bind to server socket failed, status = %d", status );
|
||||
}
|
||||
osiSocklen_t slen = sizeof ( addrIn );
|
||||
if ( getsockname(this->sock, &addrIn.sa, &slen) != 0 ) {
|
||||
if ( getsockname(this->sock, & this->srvaddr.sa, & slen) != 0 ) {
|
||||
testAbort ( "Failed to read socket address" );
|
||||
}
|
||||
status = listen ( this->sock, 10 );
|
||||
@@ -184,7 +186,7 @@ void server::start ()
|
||||
testOk ( this->id != 0, "Server thread created" );
|
||||
}
|
||||
|
||||
void server::daemon ()
|
||||
void server::daemon ()
|
||||
{
|
||||
while ( ! this->exit ) {
|
||||
// accept client side
|
||||
@@ -206,13 +208,18 @@ void server::stop ()
|
||||
epicsSocketDestroy ( this->sock );
|
||||
}
|
||||
|
||||
address server::addr () const
|
||||
{
|
||||
return this->srvaddr;
|
||||
}
|
||||
|
||||
serverCircuit::serverCircuit ( SOCKET sockIn ) :
|
||||
circuit ( sockIn )
|
||||
{
|
||||
circuit * pCir = this;
|
||||
epicsThreadId threadId = epicsThreadCreate (
|
||||
"server circuit", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
epicsThreadId threadId = epicsThreadCreate (
|
||||
"server circuit", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
socketRecvTest, pCir );
|
||||
testOk ( threadId != 0, "Server circuit thread created" );
|
||||
}
|
||||
@@ -233,7 +240,7 @@ static const char *mechName(int mech)
|
||||
{esscimqi_socketBothShutdownRequired, "esscimqi_socketBothShutdownRequired" },
|
||||
{esscimqi_socketSigAlarmRequired, "esscimqi_socketSigAlarmRequired" }
|
||||
};
|
||||
|
||||
|
||||
for (unsigned i=0; i < (sizeof(mechs) / sizeof(mechs[0])); ++i) {
|
||||
if (mech == mechs[i].mech)
|
||||
return mechs[i].name;
|
||||
@@ -254,6 +261,7 @@ MAIN(blockingSockTest)
|
||||
|
||||
server srv ( addr );
|
||||
srv.start ();
|
||||
addr = srv.addr ();
|
||||
clientCircuit client ( addr );
|
||||
|
||||
epicsThreadSleep ( 1.0 );
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
/*
|
||||
* Authors: Jeff Hill, Marty Kraimer and Andrew Johnson
|
||||
*/
|
||||
|
||||
#ifdef __SUNPRO_CC
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
|
||||
Reference in New Issue
Block a user