Hi all,
attached is a test program that can reproduce the problem. Since it uses sysClkRateGet(), it compiles only on vxWorks.
It calls pasynOctet->readRaw() once with pasynUser->timeout=1.1/sysClkRateGet() and once with pasynUser->timeout=1.0/sysClkRateGet().
In the first case, readRaw() returns asynTimeout, as expected. In the second case, readRaw() does not return.
I print the thread ID before calling readRaw(). When I do 'tt' on the thread ID, readRaw() suddenly returns asynTimeout. Very strange.
A Makefile is also attached. No records are required. Just set up a TCP server somewhere, call drvAsynIPPortConfigure and run:
readTimeoutTest "portname".
BTW: As long as readRaw() hangs, I could not open a channel access connection to records on that IOC and the dbior command hangs when trying to report drvAsyn.
I use asynDriver version 4-5, EPICS base R3.14.8, vxWorks 5.5 on MVME2300 (ppc604).
Dirk
Dirk Zimoch wrote:
Hi Marty, Jeff et al
When asynOctet->read() (or at least readRaw() of the TCP port driver) is called on vxWorks with pasynUser->timeout < 1/sysClkRateGet() [normally about 16 ms], the read call hangs and does never time out.
I think it is actually a problem with epicsTimer, which never expires for timeouts < 1/sysClkRateGet(). But I have not tested this.
I think, a timer should wait at least the specified amount of time, thus always round up to at least one tick.
Dirk
--
Dr. Dirk Zimoch
Swiss Light Source
Paul Scherrer Institut
Computing and Controls
phone +41 56 310 5182
fax +41 56 310 4413
#include <asynDriver.h>
#include <asynOctet.h>
#include <epicsThread.h>
#include <sysLib.h>
static char* asynStatusStr[] = {"Success", "Timeout", "Overflow", "Error"};
void readTimeoutTestHandleRequest(asynUser* pasynUser)
{
asynInterface* pasynInterface;
asynOctet* pasynOctet;
void* pvtOctet;
char buffer[1];
asynStatus status;
size_t received;
int eomReason;
printf ("readTimeoutTestHandleRequest, thread = %s %p\n",
epicsThreadGetNameSelf(), epicsThreadGetIdSelf());
pasynInterface = pasynUser->userPvt;
pasynOctet = pasynInterface->pinterface;
pvtOctet = pasynInterface->drvPvt;
pasynUser->timeout = 1.1 / sysClkRateGet();
printf ("calling pasynOctet->readRaw() with %g seconds timeout\n",
pasynUser->timeout);
status = pasynOctet->readRaw(pvtOctet, pasynUser, buffer, 1,
&received, &eomReason);
printf ("pasynOctet->readRaw() returned status %s\n",
asynStatusStr[status]);
pasynUser->timeout = 1.0 / sysClkRateGet();
printf ("calling pasynOctet->readRaw() with %g seconds timeout\n",
pasynUser->timeout);
status = pasynOctet->readRaw(pvtOctet, pasynUser, buffer, 1,
&received, &eomReason);
printf ("pasynOctet->readRaw() returned status %s\n",
asynStatusStr[status]);
}
void readTimeoutTestTimeout(asynUser* pasynUser)
{
printf ("pasynManager->queueRequest() timed out\n");
}
int readTimeoutTest(char * port, int addr)
{
asynStatus status;
asynUser* pasynUser;
asynInterface* pasynInterface;
pasynUser = pasynManager->createAsynUser(readTimeoutTestHandleRequest,
readTimeoutTestTimeout);
if (pasynManager->connectDevice(pasynUser, port, addr) !=
asynSuccess)
{
printf ("No such device: %s,%d\n", port, addr);
return ERROR;
}
pasynInterface = pasynManager->findInterface(pasynUser,
asynOctetType, TRUE);
if (!pasynInterface)
{
printf ("No asynOctet interface: %s,%d\n", port, addr);
return ERROR;
}
pasynUser->userPvt = pasynInterface;
status = pasynManager->queueRequest(pasynUser,
asynQueuePriorityHigh, 10.0);
if (status != asynSuccess)
{
printf ("pasynManager->queueRequest() failed: %s\n",
pasynUser->errorMessage);
return ERROR;
}
return OK;
}
TOP=../..
include $(TOP)/configure/CONFIG
HOST_OPT = NO
PROD_vxWorks = asynApp
DBD = asynApp.dbd
asynApp_DBD += base.dbd
PROD_SRCS += asynApp_registerRecordDeviceDriver.cpp
PROD_SRCS += readTimeoutTest.c
asynApp_DBD += drvAsynIPPort.dbd
PROD_LIBS += asyn
PROD_LIBS += $(EPICS_BASE_IOC_LIBS)
include $(TOP)/configure/RULES