Merge 7.0 into rtems5
This commit is contained in:
@ -71,6 +71,8 @@ INSTALL_DBD = $(INSTALL_LOCATION)/dbd
|
||||
INSTALL_DB = $(INSTALL_LOCATION)/db
|
||||
INSTALL_CONFIG = $(INSTALL_LOCATION)/configure
|
||||
|
||||
FINAL_LOCATION = $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
|
||||
|
||||
# Directory for OS independant build created files
|
||||
COMMON_DIR = ../O.Common
|
||||
|
||||
|
@ -155,6 +155,14 @@ CROSS_WARN=YES
|
||||
# different location then uncomment and set this.
|
||||
#INSTALL_LOCATION=<fullpathname>
|
||||
|
||||
# The location from which files placed in INSTALL_LOCATION will actually run.
|
||||
# This path is compiled into executables, and so should be an absolute.
|
||||
# May be used to achieve the effect of autotools. eg.
|
||||
# ./configure --prefix=<FINAL_LOCATION>
|
||||
# make DESTDIR=<INSTALL_LOCATION>
|
||||
# Defaults to the absolute expansion of $(INSTALL_LOCATION)
|
||||
#FINAL_LOCATION=
|
||||
|
||||
# Use POSIX thread priority scheduling (if available).
|
||||
# Must be either YES or NO
|
||||
USE_POSIX_THREAD_PRIORITY_SCHEDULING = YES
|
||||
|
@ -17,6 +17,61 @@ should also be read to understand what has changed since earlier releases.
|
||||
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
### epicsEnvShow accepts glob pattern
|
||||
|
||||
The optional argument to epicsEnvShow can now be a glob pattern.
|
||||
|
||||
### New function `epicsStrnGlobMatch()`
|
||||
|
||||
The function `epicsStrnGlobMatch(char* str, size_t len, char* pattern)`
|
||||
works exactly the same as `epicsStrGlobMatch()` but takes an additional
|
||||
length arguments which limits the number of characters of `str` to match.
|
||||
|
||||
### Automatic fallback to thread when unable to exec caRepeater
|
||||
|
||||
A process using libca which does not find an existing caRepeater process
|
||||
will attempt to start one by running the caRepeater executable.
|
||||
This is not always possible, usually when caRepeater is not in `$PATH`.
|
||||
Now, instead of printing a warning, an internal caRepeater thread
|
||||
will be started (as is done be RTEMS and vxWorks targets).
|
||||
|
||||
If this fallback occurs, the lifetime of the caRepeater thread
|
||||
may be shorter than the lifetime of a separate caRepeater process
|
||||
would have been.
|
||||
|
||||
It remains the recommended practice to explicitly start a caRepeater
|
||||
instance. Examples of both systemd (`caRepeater.service`) and sysv
|
||||
(`S99caRepeater`) scripts may be found under `bin/`.
|
||||
|
||||
### Glob pattern allowed in `var` command
|
||||
|
||||
When used with one argument, the `var` command can be used with a glob pattern
|
||||
for printing matching variables.
|
||||
|
||||
### Formalize/fix `FINAL_LOCATION`
|
||||
|
||||
The `FINAL_LOCATION` make variable has for some time been an undocumented
|
||||
means of performing a staged build. This is a build which "installs" to
|
||||
a temporary location, which will later be moved to a final location.
|
||||
|
||||
This has now been added to `configure/CONFIG_SITE`.
|
||||
|
||||
Usage analogous to the autotools recipe
|
||||
|
||||
```sh
|
||||
./configure --prefix=/usr/lib/epics
|
||||
make install DESTDIR=/tmp/build
|
||||
```
|
||||
|
||||
would be
|
||||
|
||||
```sh
|
||||
make INSTALL_LOCATION=/tmp/build FINAL_LOCATION=/usr/lib/epics
|
||||
```
|
||||
|
||||
`FINAL_LOCATION` is now correctly used in systemd and sysv init scripts
|
||||
`caRepeater.service`, `S99caRepeater`, and `S99logServer`.
|
||||
|
||||
### IOCsh sets `${PWD}`
|
||||
|
||||
IOC shell will now ensure `${PWD}` is set on startup,
|
||||
|
@ -113,7 +113,7 @@ SCRIPTS_Linux = caRepeater.service
|
||||
|
||||
EXPAND += S99caRepeater@
|
||||
EXPAND += caRepeater.service@
|
||||
EXPAND_VARS = INSTALL_BIN=$(abspath $(INSTALL_BIN))
|
||||
EXPAND_VARS = INSTALL_BIN=$(FINAL_LOCATION)/bin/$(T_A)
|
||||
|
||||
SRC_DIRS += $(CURDIR)/test
|
||||
PROD_HOST += ca_test
|
||||
|
@ -629,8 +629,8 @@ void epicsStdCall caStartRepeaterIfNotInstalled ( unsigned repeaterPort )
|
||||
* repeater's port)
|
||||
*/
|
||||
osiSpawnDetachedProcessReturn osptr =
|
||||
osiSpawnDetachedProcess ( "CA Repeater", "caRepeater" );
|
||||
if ( osptr == osiSpawnDetachedProcessNoSupport ) {
|
||||
osiSpawnDetachedProcess ( "!CA Repeater", "caRepeater" );
|
||||
if ( osptr != osiSpawnDetachedProcessSuccess ) {
|
||||
epicsThreadId tid;
|
||||
|
||||
tid = epicsThreadCreate ( "CAC-repeater", epicsThreadPriorityLow,
|
||||
@ -639,9 +639,6 @@ void epicsStdCall caStartRepeaterIfNotInstalled ( unsigned repeaterPort )
|
||||
fprintf ( stderr, "caStartRepeaterIfNotInstalled : unable to create CA repeater daemon thread\n" );
|
||||
}
|
||||
}
|
||||
else if ( osptr == osiSpawnDetachedProcessFail ) {
|
||||
fprintf ( stderr, "caStartRepeaterIfNotInstalled (): unable to start CA repeater daemon detached process\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,5 @@ softIoc_LIBS = $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
DB += softIocExit.db
|
||||
|
||||
FINAL_LOCATION ?= $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
|
||||
|
||||
CLEANS += epicsInstallDir.h
|
||||
|
||||
|
@ -249,7 +249,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
} else {
|
||||
if (loadedDb || ranScript) {
|
||||
epicsThreadExitMain();
|
||||
// non-interactive IOC. spin forever
|
||||
while(true) {
|
||||
epicsThreadSleep(1000.0);
|
||||
}
|
||||
|
||||
} else {
|
||||
usage(argv[0], dbd_file);
|
||||
|
@ -40,7 +40,6 @@ HTMLS += dbdToHtml.html
|
||||
|
||||
# Build Package Config Files
|
||||
|
||||
FINAL_LOCATION ?= $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
|
||||
C_CFLAGS += $(filter-out -g,$(filter-out -O%,$(filter-out -W%,$(CPPFLAGS))))
|
||||
C_CFLAGS += $(filter-out -g,$(filter-out -O%,$(filter-out -W%,$(CFLAGS))))
|
||||
PKGVARS += FINAL_LOCATION OS_CLASS CMPLR_CLASS C_CFLAGS LDFLAGS LDLIBS
|
||||
|
@ -12,9 +12,11 @@
|
||||
#include <testMain.h>
|
||||
#include <dbAccess.h>
|
||||
#include <epicsTime.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
#include <errlog.h>
|
||||
#include <alarm.h>
|
||||
#include <callback.h>
|
||||
|
||||
#include "recSup.h"
|
||||
#include "aiRecord.h"
|
||||
@ -414,6 +416,15 @@ void testSiolWrite(const char *name,
|
||||
* Asynchronous processing using simm:DELAY
|
||||
*/
|
||||
|
||||
static void
|
||||
ping(CALLBACK *pcb)
|
||||
{
|
||||
epicsEventId ev;
|
||||
callbackGetUser(ev, pcb);
|
||||
|
||||
epicsEventMustTrigger(ev);
|
||||
}
|
||||
|
||||
static
|
||||
void testSimmDelay(const char *name,
|
||||
epicsFloat64 *psdly,
|
||||
@ -422,6 +433,14 @@ void testSimmDelay(const char *name,
|
||||
epicsTimeStamp now;
|
||||
const double delay = 0.01; /* 10 ms */
|
||||
double diff;
|
||||
epicsEventId poked;
|
||||
CALLBACK cb;
|
||||
|
||||
memset(&cb, 0, sizeof(CALLBACK));
|
||||
poked = epicsEventMustCreate(epicsEventEmpty);
|
||||
callbackSetCallback(ping, &cb);
|
||||
callbackSetPriority(priorityLow, &cb);
|
||||
callbackSetUser(poked, &cb);
|
||||
|
||||
testDiag("## Asynchronous processing with simm:DELAY ##");
|
||||
|
||||
@ -443,14 +462,11 @@ void testSimmDelay(const char *name,
|
||||
testdbPutFieldOk(namePROC, DBR_LONG, 0);
|
||||
testdbGetFieldEqual(namePACT, DBR_USHORT, 1);
|
||||
epicsTimeGetCurrent(&now);
|
||||
epicsThreadSleep(1.75*delay);
|
||||
if(testImpreciseTiming())
|
||||
testTodoBegin("imprecise");
|
||||
callbackRequestDelayed(&cb, 1.5 * delay);
|
||||
epicsEventWait(poked);
|
||||
testdbGetFieldEqual(namePACT, DBR_USHORT, 0);
|
||||
diff = epicsTimeDiffInSeconds(mytime, &now);
|
||||
testOk(diff >= 0.0, "time stamp is recent (%.9f sec)", diff);
|
||||
if(testImpreciseTiming())
|
||||
testTodoEnd();
|
||||
|
||||
/* Reset delay */
|
||||
*psdly = -1.;
|
||||
|
@ -1126,17 +1126,26 @@ static void varHandler(const iocshVarDef *v, const char *setString)
|
||||
static void varCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
struct iocshVariable *v;
|
||||
if(args[0].sval == NULL) {
|
||||
const char *name = args[0].sval;
|
||||
const char *value = args[1].sval;
|
||||
|
||||
if (!value) {
|
||||
int found = 0;
|
||||
for (v = iocshVariableHead ; v != NULL ; v = v->next)
|
||||
varHandler(v->pVarDef, args[1].sval);
|
||||
if (!name || epicsStrGlobMatch(v->pVarDef->name, name) != 0) {
|
||||
varHandler(v->pVarDef, NULL);
|
||||
found = 1;
|
||||
}
|
||||
if (!found && name != NULL)
|
||||
fprintf(epicsGetStderr(), "No var matching %s found.\n", name);
|
||||
}
|
||||
else {
|
||||
v = (iocshVariable *)registryFind(iocshVarID, args[0].sval);
|
||||
if (v == NULL) {
|
||||
fprintf(epicsGetStderr(), "Var %s not found.\n", args[0].sval);
|
||||
fprintf(epicsGetStderr(), "Var %s not found.\n", name);
|
||||
}
|
||||
else {
|
||||
varHandler(v->pVarDef, args[1].sval);
|
||||
varHandler(v->pVarDef, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,5 +24,5 @@ iocLogServer_SYS_LIBS_WIN32 += user32 ws2_32 dbghelp
|
||||
SCRIPTS_HOST = S99logServer
|
||||
|
||||
EXPAND += S99logServer@
|
||||
EXPAND_VARS = INSTALL_BIN=$(abspath $(INSTALL_BIN))
|
||||
EXPAND_VARS = INSTALL_BIN=$(FINAL_LOCATION)/bin/$(T_A)
|
||||
|
||||
|
@ -23,6 +23,15 @@
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef vxWorks
|
||||
#include <stdint.h>
|
||||
#else
|
||||
/* VxWorks automaticaly includes stdint.h defining SIZE_MAX in 6.9 but not earlier */
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX (size_t)-1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "cantProceed.h"
|
||||
@ -259,30 +268,31 @@ size_t epicsStrnLen(const char *s, size_t maxlen)
|
||||
return i;
|
||||
}
|
||||
|
||||
int epicsStrGlobMatch(const char *str, const char *pattern)
|
||||
int epicsStrnGlobMatch(const char *str, size_t len, const char *pattern)
|
||||
{
|
||||
const char *cp = NULL, *mp = NULL;
|
||||
const char *mp = NULL;
|
||||
size_t cp = 0, i = 0;
|
||||
|
||||
while ((*str) && (*pattern != '*')) {
|
||||
if ((*pattern != *str) && (*pattern != '?'))
|
||||
while ((i < len) && (str[i]) && (*pattern != '*')) {
|
||||
if ((*pattern != str[i]) && (*pattern != '?'))
|
||||
return 0;
|
||||
pattern++;
|
||||
str++;
|
||||
i++;
|
||||
}
|
||||
while (*str) {
|
||||
while ((i < len) && str[i]) {
|
||||
if (*pattern == '*') {
|
||||
if (!*++pattern)
|
||||
return 1;
|
||||
mp = pattern;
|
||||
cp = str+1;
|
||||
cp = i+1;
|
||||
}
|
||||
else if ((*pattern == *str) || (*pattern == '?')) {
|
||||
else if ((*pattern == str[i]) || (*pattern == '?')) {
|
||||
pattern++;
|
||||
str++;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
pattern = mp;
|
||||
str = cp++;
|
||||
i = cp++;
|
||||
}
|
||||
}
|
||||
while (*pattern == '*')
|
||||
@ -290,6 +300,10 @@ int epicsStrGlobMatch(const char *str, const char *pattern)
|
||||
return !*pattern;
|
||||
}
|
||||
|
||||
int epicsStrGlobMatch(const char *str, const char *pattern) {
|
||||
return epicsStrnGlobMatch(str, SIZE_MAX, pattern);
|
||||
}
|
||||
|
||||
char * epicsStrtok_r(char *s, const char *delim, char **lasts)
|
||||
{
|
||||
const char *spanp;
|
||||
|
@ -36,7 +36,30 @@ LIBCOM_API char * epicsStrnDup(const char *s, size_t len);
|
||||
LIBCOM_API int epicsStrPrintEscaped(FILE *fp, const char *s, size_t n);
|
||||
#define epicsStrSnPrintEscaped epicsStrnEscapedFromRaw
|
||||
LIBCOM_API size_t epicsStrnLen(const char *s, size_t maxlen);
|
||||
|
||||
/** Matches a string against a pattern.
|
||||
*
|
||||
* Checks if str matches the glob style pattern, which may contain ? or * wildcards.
|
||||
* A ? matches any single character.
|
||||
* A * matched any sub-string.
|
||||
*
|
||||
* @returns 1 if str matches the pattern, 0 if not.
|
||||
*
|
||||
* @since EPICS 3.14.7
|
||||
*/
|
||||
LIBCOM_API int epicsStrGlobMatch(const char *str, const char *pattern);
|
||||
|
||||
/** Matches a string against a pattern.
|
||||
*
|
||||
* Like epicsStrGlobMatch but with limited string length.
|
||||
* If the length of str is less than len, the full string is matched.
|
||||
*
|
||||
* @returns 1 if the first len characters of str match the pattern, 0 if not.
|
||||
*
|
||||
* @since UNRELEASED
|
||||
*/
|
||||
LIBCOM_API int epicsStrnGlobMatch(const char *str, size_t len, const char *pattern);
|
||||
|
||||
LIBCOM_API char * epicsStrtok_r(char *s, const char *delim, char **lasts);
|
||||
LIBCOM_API unsigned int epicsStrHash(const char *str, unsigned int seed);
|
||||
LIBCOM_API unsigned int epicsMemHash(const char *str, size_t length,
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "libComAPI.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -142,8 +143,12 @@ LIBCOM_API void epicsThreadRealtimeLock(void);
|
||||
* call this routine. This should be the last call in main, except the
|
||||
* final return. On most systems epicsThreadExitMain never returns.This
|
||||
* must only be called by the main thread.
|
||||
*
|
||||
* @deprecated Deprecated for lack of use. Please report any usage.
|
||||
* Recommended replacement is loop + epicsThreadSleep(),
|
||||
* epicsEventMustWait(), or similar.
|
||||
**/
|
||||
LIBCOM_API void epicsStdCall epicsThreadExitMain(void);
|
||||
LIBCOM_API void epicsStdCall epicsThreadExitMain(void) EPICS_DEPRECATED;
|
||||
|
||||
/** For use with epicsThreadCreateOpt() */
|
||||
typedef struct epicsThreadOpts {
|
||||
|
@ -219,6 +219,8 @@ threadWrapper (rtems_task_argument arg)
|
||||
*/
|
||||
void epicsThreadExitMain (void)
|
||||
{
|
||||
cantProceed("epicsThreadExitMain() has been deprecated for lack of usage."
|
||||
" Please report if you see this message.");
|
||||
}
|
||||
|
||||
static rtems_status_code
|
||||
|
@ -15,11 +15,11 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsString.h"
|
||||
#include "errlog.h"
|
||||
#include "envDefs.h"
|
||||
#include "osiUnistd.h"
|
||||
@ -61,18 +61,10 @@ LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
|
||||
{
|
||||
if (name == NULL) {
|
||||
extern char **environ;
|
||||
char **sp;
|
||||
char **sp;
|
||||
|
||||
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++)
|
||||
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) {
|
||||
if (!name || epicsStrnGlobMatch(*sp, strchr(*sp, '=') - *sp, name))
|
||||
printf ("%s\n", *sp);
|
||||
}
|
||||
else {
|
||||
const char *cp = getenv (name);
|
||||
if (cp == NULL)
|
||||
printf ("%s is not an environment variable.\n", name);
|
||||
else
|
||||
printf ("%s=%s\n", name, cp);
|
||||
}
|
||||
}
|
||||
|
@ -92,17 +92,27 @@ LIBCOM_API epicsEventStatus epicsEventWait ( epicsEventId pSem )
|
||||
LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout (
|
||||
epicsEventId pSem, double timeOut )
|
||||
{
|
||||
static const unsigned nSec100PerSec = 10000000u;
|
||||
/* waitable timers use 100 nanosecond intervals, like FILETIME */
|
||||
static const unsigned ivalPerSec = 10000000u; /* number of 100ns intervals per second */
|
||||
static const unsigned mSecPerSec = 1000u; /* milliseconds per second */
|
||||
HANDLE handles[2];
|
||||
DWORD status;
|
||||
LARGE_INTEGER tmo;
|
||||
HANDLE timer;
|
||||
LONGLONG nIvals; /* number of intervals */
|
||||
|
||||
if ( timeOut <= 0.0 ) {
|
||||
tmo.QuadPart = 0u;
|
||||
}
|
||||
else if ( timeOut >= INFINITE / mSecPerSec ) {
|
||||
/* we need to apply a maximum wait time to stop an overflow. We choose (INFINITE - 1) milliseconds,
|
||||
to be compatible with previous WaitForSingleObject() implementation */
|
||||
nIvals = (LONGLONG)(INFINITE - 1) * (ivalPerSec / mSecPerSec);
|
||||
tmo.QuadPart = -nIvals; /* negative value means a relative time offset for timer */
|
||||
}
|
||||
else {
|
||||
tmo.QuadPart = -((LONGLONG)(timeOut * nSec100PerSec + 0.5));
|
||||
nIvals = (LONGLONG)(timeOut * ivalPerSec + 0.999999);
|
||||
tmo.QuadPart = -nIvals;
|
||||
}
|
||||
|
||||
if (tmo.QuadPart < 0) {
|
||||
|
@ -50,10 +50,14 @@ LIBCOM_API osiGetUserNameReturn epicsStdCall osiGetUserName (char *pBuf, unsigne
|
||||
LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
|
||||
( const char *pProcessName, const char *pBaseExecutableName )
|
||||
{
|
||||
BOOL silent = pProcessName && pProcessName[0]=='!';
|
||||
BOOL status;
|
||||
STARTUPINFO startupInfo;
|
||||
PROCESS_INFORMATION processInfo;
|
||||
|
||||
if(silent)
|
||||
pProcessName++; /* skip '!' */
|
||||
|
||||
GetStartupInfo ( &startupInfo );
|
||||
startupInfo.lpReserved = NULL;
|
||||
startupInfo.lpTitle = (char *) pProcessName;
|
||||
@ -115,7 +119,7 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
|
||||
/* Free the buffer. */
|
||||
LocalFree (errStrMsgBuf);
|
||||
}
|
||||
else {
|
||||
else if(!silent) {
|
||||
fprintf (stderr, "!!WARNING!!\n");
|
||||
fprintf (stderr, "Unable to locate executable \"%s\".\n", pBaseExecutableName);
|
||||
fprintf (stderr, "You may need to modify your \"path\" environment variable.\n");
|
||||
|
@ -260,7 +260,8 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm )
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall epicsThreadExitMain ( void )
|
||||
{
|
||||
_endthread ();
|
||||
cantProceed("epicsThreadExitMain() has been deprecated for lack of usage."
|
||||
" Please report if you see this message.");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -818,15 +819,25 @@ HANDLE osdThreadGetTimer()
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall epicsThreadSleep ( double seconds )
|
||||
{
|
||||
static const unsigned nSec100PerSec = 10000000u;
|
||||
/* waitable timers use 100 nanosecond intervals, like FILETIME */
|
||||
static const unsigned ivalPerSec = 10000000u; /* number of 100ns intervals per second */
|
||||
static const unsigned mSecPerSec = 1000u; /* milliseconds per second */
|
||||
LARGE_INTEGER tmo;
|
||||
HANDLE timer;
|
||||
LONGLONG nIvals; /* number of intervals */
|
||||
|
||||
if ( seconds <= 0.0 ) {
|
||||
tmo.QuadPart = 0u;
|
||||
}
|
||||
else if ( seconds >= INFINITE / mSecPerSec ) {
|
||||
/* we need to apply a maximum wait time to stop an overflow. We choose (INFINITE - 1) milliseconds,
|
||||
to be compatible with previous WaitForSingleObject() implementation */
|
||||
nIvals = (LONGLONG)(INFINITE - 1) * (ivalPerSec / mSecPerSec);
|
||||
tmo.QuadPart = -nIvals; /* negative value means a relative time offset for timer */
|
||||
}
|
||||
else {
|
||||
tmo.QuadPart = -((LONGLONG)(seconds * nSec100PerSec + 0.5));
|
||||
nIvals = (LONGLONG)(seconds * ivalPerSec + 0.999999);
|
||||
tmo.QuadPart = -nIvals;
|
||||
}
|
||||
|
||||
if (tmo.QuadPart == 0) {
|
||||
|
@ -15,11 +15,11 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsVersion.h"
|
||||
#include "errlog.h"
|
||||
#include "envDefs.h"
|
||||
@ -68,18 +68,11 @@ LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
|
||||
{
|
||||
if (name == NULL) {
|
||||
extern char **environ;
|
||||
char **sp;
|
||||
extern char **environ;
|
||||
char **sp;
|
||||
|
||||
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++)
|
||||
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) {
|
||||
if (!name || epicsStrnGlobMatch(*sp, strchr(*sp, '=') - *sp, name))
|
||||
printf ("%s\n", *sp);
|
||||
}
|
||||
else {
|
||||
const char *cp = getenv (name);
|
||||
if (cp == NULL)
|
||||
printf ("%s is not an environment variable.\n", name);
|
||||
else
|
||||
printf ("%s=%s\n", name, cp);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,9 @@
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <pwd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "osiProcess.h"
|
||||
#include "errlog.h"
|
||||
@ -61,12 +63,22 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
|
||||
(const char *pProcessName, const char *pBaseExecutableName)
|
||||
{
|
||||
int status;
|
||||
int silent = pProcessName && pProcessName[0]=='!';
|
||||
int fds[2]; /* [reader, writer] */
|
||||
|
||||
if(silent)
|
||||
pProcessName++; /* skip '!' */
|
||||
|
||||
if(pipe(fds))
|
||||
return osiSpawnDetachedProcessFail;
|
||||
|
||||
/*
|
||||
* create a duplicate process
|
||||
*/
|
||||
status = fork ();
|
||||
if (status < 0) {
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return osiSpawnDetachedProcessFail;
|
||||
}
|
||||
|
||||
@ -75,11 +87,29 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
|
||||
* in the initiating (parent) process
|
||||
*/
|
||||
if (status) {
|
||||
return osiSpawnDetachedProcessSuccess;
|
||||
}
|
||||
osiSpawnDetachedProcessReturn ret = osiSpawnDetachedProcessSuccess;
|
||||
char buf;
|
||||
ssize_t n;
|
||||
close(fds[1]);
|
||||
|
||||
/*
|
||||
* This is executed only by the new child process.
|
||||
n = read(fds[0], &buf, 1);
|
||||
/* Success if child exec'd without sending a '!'.
|
||||
* Of course child may crash soon after, but can't
|
||||
* wait around for this to happen.
|
||||
*/
|
||||
if(n!=0) {
|
||||
ret = osiSpawnDetachedProcessFail;
|
||||
}
|
||||
|
||||
close(fds[0]);
|
||||
return ret;
|
||||
}
|
||||
close(fds[0]);
|
||||
(void)fcntl ( fds[1], F_SETFD, FD_CLOEXEC );
|
||||
|
||||
/* This is executed only by the new child process.
|
||||
* Since we may be called from a library, we don't assume that
|
||||
* all other code has set properly set FD_CLOEXEC.
|
||||
* Close all open files except for STDIO, so they will not
|
||||
* be inherited by the new program.
|
||||
*/
|
||||
@ -89,6 +119,8 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
|
||||
if (fd==STDIN_FILENO) continue;
|
||||
if (fd==STDOUT_FILENO) continue;
|
||||
if (fd==STDERR_FILENO) continue;
|
||||
/* pipe to our parent will be closed automatically via FD_CLOEXEC */
|
||||
if (fd==fds[1]) continue;
|
||||
close (fd);
|
||||
}
|
||||
}
|
||||
@ -109,12 +141,16 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
|
||||
* Run the specified executable
|
||||
*/
|
||||
status = execlp (pBaseExecutableName, pBaseExecutableName, (char *)NULL);
|
||||
if ( status < 0 ) {
|
||||
if ( status < 0 && !silent ) {
|
||||
fprintf ( stderr, "**** The executable \"%s\" couldn't be located\n", pBaseExecutableName );
|
||||
fprintf ( stderr, "**** because of errno = \"%s\".\n", strerror (errno) );
|
||||
fprintf ( stderr, "**** You may need to modify your PATH environment variable.\n" );
|
||||
fprintf ( stderr, "**** Unable to start \"%s\" process.\n", pProcessName);
|
||||
}
|
||||
/* signal error to parent */
|
||||
ssize_t ret = write(fds[1], "!", 1);
|
||||
(void)ret; /* not much we could do about this */
|
||||
close(fds[1]);
|
||||
/* Don't run our parent's atexit() handlers */
|
||||
_exit ( -1 );
|
||||
}
|
||||
|
@ -690,6 +690,10 @@ LIBCOM_API void epicsStdCall epicsThreadExitMain(void)
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
epicsThreadInit();
|
||||
|
||||
cantProceed("epicsThreadExitMain() has been deprecated for lack of usage."
|
||||
" Please report if you see this message.");
|
||||
|
||||
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
|
||||
if(pthreadInfo==NULL)
|
||||
pthreadInfo = createImplicit();
|
||||
|
@ -16,17 +16,18 @@
|
||||
/* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */
|
||||
#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <envLib.h>
|
||||
|
||||
#include "epicsFindSymbol.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsString.h"
|
||||
#include "errlog.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
|
||||
/*
|
||||
* Set the value of an environment variable
|
||||
* Leaks memory, but the assumption is that this routine won't be
|
||||
@ -86,14 +87,12 @@ LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
|
||||
*/
|
||||
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
|
||||
{
|
||||
if (name == NULL) {
|
||||
envShow (0);
|
||||
}
|
||||
else {
|
||||
const char *cp = getenv (name);
|
||||
if (cp == NULL)
|
||||
printf ("%s is not an environment variable.\n", name);
|
||||
else
|
||||
printf ("%s=%s\n", name, cp);
|
||||
extern char **ppGlobalEnviron; /* Used in 'environ' macro but not declared in envLib.h */
|
||||
char **sp;
|
||||
|
||||
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) {
|
||||
if (!**sp) continue; /* skip unset environment variables */
|
||||
if (!name || epicsStrnGlobMatch(*sp, strchr(*sp, '=') - *sp, name))
|
||||
printf ("%s\n", *sp);
|
||||
}
|
||||
}
|
||||
|
@ -353,7 +353,8 @@ void epicsThreadResume(epicsThreadId id)
|
||||
|
||||
void epicsThreadExitMain(void)
|
||||
{
|
||||
errlogPrintf("epicsThreadExitMain was called for vxWorks. Why?\n");
|
||||
cantProceed("epicsThreadExitMain() has been deprecated for lack of usage."
|
||||
" Please report if you see this message.");
|
||||
}
|
||||
|
||||
unsigned int epicsThreadGetPriority(epicsThreadId id)
|
||||
|
@ -73,6 +73,43 @@ void testGlob(void) {
|
||||
testOk1(epicsStrGlobMatch("hello","he*"));
|
||||
testOk1(epicsStrGlobMatch("hello","*lo"));
|
||||
testOk1(epicsStrGlobMatch("hello","*"));
|
||||
|
||||
/* epicsStrnGlobMatch */
|
||||
|
||||
testOk1(epicsStrnGlobMatch("xyzq",3,"xyz"));
|
||||
testOk1(!epicsStrnGlobMatch("xyzq",3,"xyzm"));
|
||||
testOk1(!epicsStrnGlobMatch("xyzm",3,"xyzm"));
|
||||
testOk1(!epicsStrnGlobMatch("xyzm",0,"xyzm"));
|
||||
testOk1(!epicsStrnGlobMatch("xyzq",3,""));
|
||||
testOk1(epicsStrnGlobMatch("xyz",0,""));
|
||||
|
||||
testOk1(epicsStrnGlobMatch("xyz",0,"*"));
|
||||
testOk1(!epicsStrnGlobMatch("xyz",0,"?"));
|
||||
testOk1(!epicsStrnGlobMatch("xyz",0,"?*"));
|
||||
|
||||
testOk1(epicsStrnGlobMatch("hello!",5,"h*o"));
|
||||
testOk1(!epicsStrnGlobMatch("hello!",5,"h*x"));
|
||||
testOk1(!epicsStrnGlobMatch("hellxo",5,"h*o"));
|
||||
|
||||
testOk1(epicsStrnGlobMatch("hello!",5,"he?lo"));
|
||||
testOk1(!epicsStrnGlobMatch("hello!",5,"he?xo"));
|
||||
testOk1(epicsStrnGlobMatch("hello!",5,"he??o"));
|
||||
testOk1(!epicsStrnGlobMatch("helllo!",5,"he?lo"));
|
||||
|
||||
testOk1(!epicsStrnGlobMatch("hello world!",10,"he*o w*d"));
|
||||
testOk1(epicsStrnGlobMatch("hello world!",11,"he*o w*d"));
|
||||
testOk1(!epicsStrnGlobMatch("hello world!",12,"he*o w*d"));
|
||||
testOk1(!epicsStrnGlobMatch("hello_world!",11,"he*o w*d"));
|
||||
testOk1(epicsStrnGlobMatch("hello world!",11,"he**d"));
|
||||
|
||||
testOk1(epicsStrnGlobMatch("hello hello world!!!!!!!!!!!!!!!!!!!!",17,"he*o w*d"));
|
||||
|
||||
testOk1(!epicsStrnGlobMatch("hello hello world",15,"he*o w*d"));
|
||||
|
||||
testOk1(epicsStrnGlobMatch("hello!!",5,"he*"));
|
||||
testOk1(epicsStrnGlobMatch("hello!!",5,"*lo"));
|
||||
testOk1(epicsStrnGlobMatch("hello!!",5,"*"));
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
@ -118,7 +155,7 @@ MAIN(epicsStringTest)
|
||||
char *s;
|
||||
int status;
|
||||
|
||||
testPlan(401);
|
||||
testPlan(427);
|
||||
|
||||
testChars();
|
||||
|
||||
|
@ -8,9 +8,19 @@ RULES = $(EPICS_BASE)
|
||||
# RELEASE files point to other application tops
|
||||
include $(TOP)/configure/RELEASE
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
|
||||
ifdef T_A
|
||||
-include $(TOP)/configure/RELEASE.Common.$(T_A)
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
-include $(TOP)/configure/RELEASE.Common.$(T_A)
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
||||
|
||||
# Check EPICS_BASE is set properly
|
||||
ifneq (file,$(origin EPICS_BASE))
|
||||
$(error EPICS_BASE must be set in a configure/RELEASE file)
|
||||
else
|
||||
ifeq ($(wildcard $(EPICS_BASE)/configure/CONFIG_BASE),)
|
||||
$(error EPICS_BASE does not point to an EPICS installation)
|
||||
endif
|
||||
endif
|
||||
|
||||
CONFIG = $(RULES)/configure
|
||||
@ -19,11 +29,17 @@ include $(CONFIG)/CONFIG
|
||||
# Override the Base definition:
|
||||
INSTALL_LOCATION = $(TOP)
|
||||
|
||||
# CONFIG_SITE files contain other build configuration settings
|
||||
# CONFIG_SITE files contain local build configuration settings
|
||||
include $(TOP)/configure/CONFIG_SITE
|
||||
|
||||
# Host-arch specific settings
|
||||
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
|
||||
|
||||
ifdef T_A
|
||||
# Target-arch specific settings
|
||||
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
|
||||
|
||||
# Host & target specific settings
|
||||
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
# CONFIG - Load build configuration data
|
||||
#
|
||||
# Do not make changes in this file, any site-specific
|
||||
# overrides should be given in a CONFIG_SITE file.
|
||||
# Do not make changes to this file!
|
||||
|
||||
# Where the build rules come from
|
||||
# Allow user to override where the build rules come from
|
||||
RULES = $(EPICS_BASE)
|
||||
|
||||
INSTALL_IDLFILE = $(INSTALL)
|
||||
|
||||
# RELEASE files point to other application tops
|
||||
include $(TOP)/configure/RELEASE
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH)
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
@ -17,27 +15,38 @@ ifdef T_A
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
||||
|
||||
# Check EPICS_BASE is set properly
|
||||
ifneq (file,$(origin EPICS_BASE))
|
||||
$(error EPICS_BASE must be set in a configure/RELEASE file)
|
||||
else
|
||||
ifeq ($(wildcard $(EPICS_BASE)/configure/CONFIG_BASE),)
|
||||
$(error EPICS_BASE does not point to an EPICS installation)
|
||||
endif
|
||||
endif
|
||||
|
||||
CONFIG = $(RULES)/configure
|
||||
include $(CONFIG)/CONFIG
|
||||
|
||||
# Override some Base definitions
|
||||
# Override the Base definition:
|
||||
INSTALL_LOCATION = $(TOP)
|
||||
|
||||
# CONFIG_SITE files contain build configuration overrides
|
||||
# CONFIG_SITE files contain local build configuration settings
|
||||
include $(TOP)/configure/CONFIG_SITE
|
||||
|
||||
# Host-arch specific settings
|
||||
# Host-arch specific settings for extensions are in configure/os
|
||||
-include $(TOP)/configure/os/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
|
||||
|
||||
ifdef T_A
|
||||
# Target-arch specific settings for extensions are in configure/os
|
||||
-include $(TOP)/configure/os/CONFIG_SITE.Common.$(T_A)
|
||||
|
||||
# Host & target specific settings for extensions are in configure/os
|
||||
-include $(TOP)/configure/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
||||
|
||||
# Additional settings for extensions
|
||||
INSTALL_IDLFILE = $(INSTALL)
|
||||
|
||||
ifdef INSTALL_LOCATION_EXTENSIONS
|
||||
INSTALL_LOCATION = $(INSTALL_LOCATION_EXTENSIONS)
|
||||
endif
|
||||
|
||||
ifdef T_A
|
||||
# Target-arch specific settings
|
||||
-include $(TOP)/configure/os/CONFIG_SITE.Common.$(T_A)
|
||||
|
||||
# Host & target specific combination settings
|
||||
-include $(TOP)/configure/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
||||
|
||||
|
@ -227,6 +227,12 @@ sub envPaths {
|
||||
# Check RELEASE file consistency with support modules
|
||||
#
|
||||
sub checkRelease {
|
||||
die "\nEPICS_BASE must be set in a configure/RELEASE file.\n\n"
|
||||
unless grep(m/^(EPICS_BASE)$/, @apps) &&
|
||||
exists $macros{EPICS_BASE} &&
|
||||
$macros{EPICS_BASE} ne '' &&
|
||||
-f "$macros{EPICS_BASE}/configure/CONFIG_BASE";
|
||||
|
||||
my $status = 0;
|
||||
delete $macros{RULES};
|
||||
delete $macros{TOP};
|
||||
|
Reference in New Issue
Block a user