Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018 
<== Date ==> <== Thread ==>

Subject: asyn R4-14-RC1
From: "Mark Rivers" <>
To: <>, "Beamline Controls and Data Acquisition" <>, <>
Date: Thu, 17 Jun 2010 15:52:26 -0500



I would like to release asyn R4-14.  Before making an official release I have tagged a pre-release version for testing, R4-14-RC1.  The new release has significant improvements in handling initial connections to drivers, and in the implementation of the pasynManager->lockPort() function, which is used by all of the asynXXXSyncIO functions.


The new implementation of lockPort() has one functional difference from previous versions: it will fail if the port is not connected.  Is anyone using lockPort() in a manner such that this change will break anything?


Please read the notes below concerning the timing of the callbacks to pasynCommon->connect() in drivers.  The timing will be different now, and drivers need to be sufficiently initialized to handle the callbacks to pasynCommon->connect() before they register the asynCommon interface.  This is not a change in the API, only in the details of the implementation within the published API.


The new version can be obtained here:


I would appreciate all testing that can be done in the next 10 days or so before I plan to make the official release.


These are the release notes:


Release 4-14

June XXX, 2010


Fixed bugs in connection management. Releases 4-11 through 4-13 had the following problems:

  • If a port was multi-device and auto-connect, and was only accessed using SyncIO calls, then asynManager would never connect to the devices. If regular queued requests were used, which happens if an asyn record is connected to that port and device, then it would connect once the first queue request was done.
  • For all auto-connect ports there was a race condition, such that the port might or might not be connected when the first queued request or SyncIO call was done on that port. This arose because when the port registered its asynCommon interface, asynManager queued a connection request on that port. But if that connection request callback, which executes in the portThread, had not yet occurred when a queue request or SyncIO call was made, then those operations would be rejected because the port was not yet connected.

These problems were fixed by doing the following:

  • When the port registers its asynCommon interface and asynManager queues the connection request, it now waits for a short time for the connection callback to complete. The default time is 0.5 seconds, but this time can be changed with a call to the new function pasynManager->setAutoConnectTimeout(double timeout). This function can be accessed from the iocsh shell with the new asynSetAutoConnectTimeout(double timeout) command. This short timeout is designed to allow devices to time to connect if they are available, but not to excessively slow down booting of the IOC by waiting, for example, for the system timeout on TCP connections. Note that this change means that it is now very likely that the pasynCommon->connect() call will occur as soon as the asynCommon interface is registered. As noted in the R4-12 release notes, this means that the driver must have already done all initialization required for the asynCommon->connect() callback before it registers the asynCommon interface!
  • There is an additional new function, pasynManager->waitConnect(asynUser *pasynUser, double timeout), which will wait for the for the port to connect, up to the specified timeout. This function can be called from the iocsh with the new command asynWaitConnect(const char *portName, double timeout). This function makes it possible to wait longer for a port to connect then the current value of the global autoconnect timeout described above.

Fixed problems with the SyncIO calls, which were caused by the implementation of pasynManager->lockPort():

  • The SyncIO calls (e.g. asynOctetSyncIO) are implemented by calling pasynManager->lockPort(), executing the I/O in the current thread, and then calling pasynManager->unlockPort(). These SyncIO functions are designed to be called from threads that are allowed to block, such as SNL programs, or other drivers. The problem with the previous implementation was that pasynManager->lockPort() immediately took the port mutex when it was available, rather than queueing a request to take the mutex. This could lead to one thread effectively getting exclusive access to the port, even if other threads had queued requests or tried to do SyncIO calls themselves. For example, if a device could send unsolicited input, then one might create a thread that simply called pasynOctetSyncIO->read() with a short timeout in a tight loop. The problem with this was that as soon as that thread released the port mutex when the read timed out, it would take the mutex again, blocking other threads that were trying to access the port.  Previously the only solution to this problem was to add a short epicsThreadSleep() in the read loop.
  • This problem has been fixed by reimplementing pasynManager->lockPort(), which now queues a request to access the port and then blocks until the queue request callback runs in the portThread. When the queue request runs, the thread that called pasynManager->lockPort() executes, and the portThread blocks, until pasynManager->unlockPort() is called.
  • Note that this change to lockPort() does change its functionality in one respect: previously it was OK to call lockPort() on a port that was not connected. This is no longer possible, because the queueRequest call in lockPort will now return an error if the port is not connected.
  • The change to lockPort did not require any changes to the asynXXXSyncIO functions except asynCommonSyncIO. The asynCommonSyncIO->connectDevice and asynCommonSyncIO->connectDevice calls cannot use lockPort() any more, because as noted above it does not work with disconnected ports. Rather, these functions now directly queue a connection request with a private callback function to connect or disconnect the port.


Fixed a bug in driver initialization. The driver had not completed all required initialization before it called pasynGpib->registerPort. Because pasynGpib->registerPort register the asynCommon interface, that now normally triggers an immediate callback to vxiConnect, and the driver was not yet properly initialized to handle that callback.


Changed ipEchoServer2.c to eliminate the epicsThreadSleep(0.01) in the listener thread. This sleep is no longer necessary because of the change to lockPort described above, so the example program was changed to test and demonstrate this.

Added an additional example driver, asynPortTest, that uses asynPortDriver. It implements the asynInt32, asynFloat64, and asynOctet interfaces to communicate with the echo server using asynOctetSyncIO calls. This tests nested SyncIO calls. Added a new startup script, database and medm screen for testing this new driver.






Navigate by Date:
Prev: Re: using hex numbers in calc records Andrew Johnson
Next: Problem building epics base under cygwin Michael D. Westfall
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018 
Navigate by Thread:
Prev: Re: Channel Access Writes Failed on Asyn Record Writable Fields William Lu
Next: Problem building epics base under cygwin Michael D. Westfall
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018 
ANJ, 02 Sep 2010 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·