Before describing particular components of the IOC software, it is helpful to give an overview of three closely related topics: Database locking, scanning, and processing. Locking is done to prevent two different tasks from simultaneously modifying related database records. Database scanning is the mechanism for deciding when records should be processed. The basics of record processing involves obtaining the current value of input fields and outputting the current value of output fields. As records become more complex so does the record processing.
One powerful feature of the DATABASE is that records can contain links to other records. This feature also causes considerable complication. Thus, before discussing locking, scanning, and processing, record links are described.
A database record may contain links to other records. Each link is one of the following types:
INLINKs and OUTLINKs can be one of the following:
Not discussed in this chapter
A link to another record in the same IOC.
A link to a record in another IOC. It is accessed via a special IOC client task. It is also possible to force a link to be a channel access link even it references a record in the same IOC.
Not discussed in this chapter
A forward link refers to a record that should be processed whenever the record containing the forward link is processed. The following types are supported:
Ignored.
A link to another record in the same IOC.
A link to a record in another IOC or a link forced to be a channel access link. Unless the link references the PROC field it is ignored. If it does reference the PROC field a channel access put with a value of 1 is issued.
Links are defined in file link.h
.
NOTE: This chapter discusses mainly database links.
Database links are referenced by calling one of the following routines:
A forward link only points to a (normally passive) record that should be processed after the record that contains the link.
For input and output links, two additional attributes can be specified by the application developer: process passive, and maximize severity.
The Process Passive attribute takes the value NPP
(Non-Process Passive) or PP
(Process Passive).
It determines if the linked record should be processed before getting a value from an input link or after writing a value to an output link.
The linked record will be processed only if link's Process Passive attribute is PP
and the target record's SCAN
field is Passive.
NOTE: Three other options may also be specified: CA, CP, and CPP. These options force the link to be handled like a Channel Access Link. See last section of this chapter for details.
The Maximize Severity attribute is one of NMS
(Non-Maximize Severity), MS
(Maximize Severity),
MSS
(Maximize Status and Severity) or MSI
(Maximize Severity if Invalid).
It determines whether alarm severity is propagated across links.
If the attribute is MSI
only a severity of INVALID_ALARM
is propagated; settings of MS
or MSS
propagate all alarms that are more severe than the record's current severity.
For input links the alarm severity of the record referred to by the link is propagated to the record containing the link.
For output links the alarm severity of the record containing the link is propagated to the record referred to by the link.
If the severity is changed the associated alarm status is set to LINK_ALARM
, except if the attribute is MSS
when the alarm status will be copied along with the severity.
The method of determining if the alarm status and severity should be changed is called ``maximize severity".
In addition to its actual status and severity, each record also has a new status and severity.
The new status and severity are initially 0, which means NO_ALARM
.
Every time a software component wants to modify the status and severity, it first checks the new severity and only makes a
change if the severity it wants to set is greater than the current new severity.
If it does make a change, it changes the new status and new severity, not the current status and severity.
When database monitors are checked, which is normally done by a record processing routine, the current status and severity
are set equal to the new values and the new values reset to zero.
The end result is that the current alarm status and severity reflect the highest severity outstanding alarm.
If multiple alarms of the same severity are present the alarm status reflects the first one detected.
The purpose of database locking is to prevent a record from being processed simultaneously by two different tasks. In addition, it prevents ``outside" tasks from changing any field while the record is being processed.
The following routines are provided for database locking.
dbScanLock(precord); dbScanUnlock(precord);
The basic idea is to call dbScanLock
before accessing database records and calling dbScanUnlock
afterwords.
Because of database links (Input, Output, and Forward) a modification to one record can cause modification to other records.
Records linked together with database links are placed in the same lock set.
dbScanLock
locks the entire lock set, not just the record requested.
dbScanUnlock
unlocks the entire set.
The following rules determine when the lock routines must be called:
dbPutField
locks before modifying a record and unlocks afterwards.
dbGetField
locks before reading and unlocks afterwards.
All records connected by any kind of database link are placed in the same lock set. Versions of EPICS Base prior to R3.14 allowed an NPP NMS input link to span two different lock sets, but this was not safe where the read and write operations on the field value were not atomic in nature and is no longer available to break a lockset.
Database scanning refers to requests that database records be processed. Four types of scanning are possible:
post_event
request.
dbScanPassive
.
dbScanPassive
will issue a record processing request if and only if the record is passive and is not already being processed.
A dbScanPassive
request results from a task calling one of the following routines:
dbGetLink
, dbPutLink
, and dbPutField
call the dbScanPassive
routine.
Record processing routines call it for each forward link in the record.
pp(TRUE)
it calls dbScanPassive
.
Each field of each record type has an attribute pp
declared as either TRUE
or FALSE
in the record definition file.
The attribute is a global property which is set by the record type.
This use of pp
only affects calls to the dbPutField
routine.
If dbPutField
finds the record already active (this can happen to asynchronous records) and it is supposed to cause it to process, it arranges for it to be processed again once the current processing completes.
PP
this routine first calls dbScanPassive
to process the target record.
Whether or not dbScanPassive
was called, it then obtains the value from the target field.
PP
it calls dbScanPassive
to process the target record.
dbPutLink
is only called from record processing routines.
If dbPutLink
finds the record already active because of a dbPutField
directed to this record then it arranges for the record to be processed again later, once the current processing completes.
All non-record processing tasks (Channel Access, Sequence Programs, etc.) call dbGetField
to obtain database values.
dbGetField
just reads values without asking that a record be processed.
A record is processed as a result of a call to dbProcess
.
Each record support module must supply a routine process
.
This routine does most of the work related to record processing.
Since the details of record processing are record type specific this topic is discussed in greater detail in the Chapter ``Record Support".
The ability to link records together is an extremely powerful feature of the IOC software. In order to use links properly it is important that the Application Developer understand how they are processed. As an introduction consider the following example:
Assume that A, B, and C are all passive records. The notation states that A has a forward link to B and B to C. C has an input link obtaining a value from A. Assume, for some reason, A gets processed. The following sequence of events occurs:
PP
after InLink
).
But process passive states that A should be processed before the value is retrieved.
Are we in an infinite loop?
The answer is no.
Every record contains a field PACT
(processing active), which is set TRUE
when record processing begins and is not set FALSE
until all processing completes.
When C is processed A still has PACT
TRUE
and will not be processed again.
This brief example demonstrates that database links need more discussion.
The processing order follows the following rules:
FLNK1
, FLNK2
, FLNK3
, FLNK4
.
INPA
, INPB
, ..., INPL
, the links would be read in the order A, B, C etc.
Thus if obtaining an input results in a record being processed, the processing order is guaranteed.
Some record types may not follow this rule however.
All records, except for the conditions listed in the next paragraph, linked together directly or indirectly are placed in the
same lock set.
When dbScanLock
is called the entire set, not just the specified record, is locked.
This prevents two different tasks from simultaneously modifying records in the same lock set.
Every record contains a field PACT
.
This field is set TRUE
at the beginning of record processing and is not set FALSE
until the record is completely processed.
To prevent infinite processing loops, whenever a record gets processed through a forward link, or a database link with the PP
link option, the linking record's PACT
field is saved and set to TRUE
, then restored again afterwards.
The example given at the beginning of this section gives an example.
It will be seen in the next two sections that PACT
has other uses.
Input and output links have an option called process passive.
For each such link the application developer can specify process passive TRUE
(PP
) or process passive FALSE
(NPP
).
Consider the following example:
Assume that all records except fanout are passive. When the fanout record is processed the following sequence of events occur:
dbGetLink
to obtain data from A.
dbGetLink
to obtain data from A.
TRUE
, a request is made to process A.
Note that A was processed twice. This is unnecessary. If the input link to C were declared No Process Passive then A would only be processed once. Thus a better solution would be:
All record type field definitions have an attribute called process_passive
which is specified in the record definition file.
It cannot be changed by an IOC application developer.
This attribute is used only by dbPutField
.
It determines if a passive record will be processed after dbPutField
sets a field in the record.
Consult the record specific information in the record reference manual for the setting of individual fields.
Input and output links have an option called maximize severity.
For each such link the application developer can specify the option as MS
(Maximize Severity), NMS
(Non-Maximize Severity), MSS
(Maximize Status and Severity) or MSI
(Maximize Severity if Invalid).
When database input or output links are defined, the application developer can use this option to specify whether and how alarm severities should be propagated across links with the data.
The alarm severity is transferred only if the new severity will be greater than the current severity of the destination record.
If the severity is propagated the alarm status is set equal to LINK_ALARM
(unless the link option is MSS
when the alarm status will also be copied from the source record).
A synchronous record is a record that can be completely processed without waiting. Thus the application developer never needs to consider the possibility of delays when he defines a set of related records. The only consideration is deciding when records should be processed and in what order a set of records should be processed.
The following reviews the methods available to the application programmer for deciding when to process a record and for enforcing the order of record processing.
PHAS
field can be used to specify processing order.
SDIS
, DISA
, and DISV
) can be used to disable records from being processed.
By letting the SDIS
field of an entire set of records refer to the same input record, the entire set can be enabled or disabled simultaneously.
See the Record Reference Manual for details.
process_passive
attribute of each record field determines if a passive record will be processed when a dbPutField
is directed to the field.
The application developer must be aware of the possibility of record processing being triggered by external sources using this mechanism.
process_passive
option for input and output links provides the application developer control over how a set of records are scanned.
The previous discussion does not cover asynchronous device support. An example might be a GPIB input record. When the record is processed the GPIB request is started and the processing routine returns. Processing, however, is not really complete until the GPIB request completes. This is handled via an asynchronous completion routine. Let's state a few attributes of asynchronous record processing.
During the initial processing for all asynchronous records the following is done:
PACT
is set TRUE
The asynchronous completion routine performs the following algorithm:
PACT
is set FALSE
.
A few attributes of the above rules are:
PACT
is TRUE
.
The routine dbProcess
checks PACT
and does not call the record processing routine if it is TRUE
.
Note, however, that if dbProcess
finds the record active 10 times in succession, it raises a SCAN_ALARM
.
With these rules the following works just fine:
When dbProcess
is called for record ASYN, processing will be started but dbScanPassive
will not be called.
Until the asynchronous completion routine executes any additional attempts to process ASYN are ignored.
When the asynchronous callback is invoked the dbScanPassive
is performed.
Problems still remain. A few examples are:
Infinite processing loops are possible.
Assume both A and B are asynchronous passive records and a request is made to process A. The following sequence of events occur.
PACT
TRUE
.
PACT
field FALSE
.
PACT
field FALSE
.
Thus an infinite loop of record processing has been set up. It is up to the application developer to prevent such loops.
A dbGetLink
to a passive asynchronous record can get old data.
If A is a passive asynchronous record then record B's dbGetLink
request forces dbProcess
to be called for record A.
dbProcess
starts the processing but returns immediately, before the operation has finished.
dbGetLink
then reads the field value which is still old because processing will only be completed at a later time.
Consider the following:
The second ASYN record will not begin processing until the first completes, etc. This is not really a problem except that the application developer must be aware of delays caused by asynchronous records. Again, note that scanners are not delayed, only records downstream of asynchronous records.
The rules followed by dbPutLink
and dbPutField
provide for ``cached" puts.
This is necessary because of asynchronous records.
Two cases arise.
The first results from a dbPutField
, which is a put coming from outside the database, i.e. Channel Access puts.
If this is directed to a record that already has PACT
TRUE
because the record started processing but asynchronous completion has not yet occurred, then a value is written to the record but nothing will be done with the value until the record is again
processed.
In order to make this happen dbPutField
arranges to have the record reprocessed when the record finally completes processing.
The second case results from dbPutLink
finding a record already active because of a dbPutField
directed to the record.
In this case dbPutLink
arranges to have the record reprocessed when the record finally completes processing.
If the record is already active because it appears twice in a chain of record processing, it is not reprocessed because the chain of record processing would constitute an infinite loop.
Note that the term caching not queuing is used. If multiple requests are directed to a record while it is active, each new value is placed in the record but it will still only be processed once, i.e. last value wins.
dbProcessNotify
is used when a Channel Access client calls ca_put_callback
and makes a request to notify the caller when all
records processed as a result of this put are complete.
Because of asynchronous records and conditional use of database links between records this can be complicated and the set of records that are processed because of a put cannot be determined in advance.
The processNotify system is described in section 15.4.3.3 on page .
The result of a dbProcessNotify
with type putProcessRequest
is the same as a dbPutField
except for the following:
dbProcessNotify
requests are queued rather than cached.
Thus when additional requests are directed to a record that already has an active dbProcessNotify
, they are queued.
As each one finishes it releases the next one in the queue.
dbProcessNotify
links to a record that is not active but has a dbProcessNotify
attached to it, no attempt is made to process the record.
A channel access link is:
A channel access client task (dbCa) handles all I/O for channel access links. It does the following:
ca_put
.
Even if a link references a record in the same IOC it can be useful to force it to act like a channel access link. In particular the records will not be forced to be in the same lock set. As an example consider a scan record that links to a set of unrelated records, each of which can cause a lot of records to be processed. It is often NOT desirable to force all these records into the same lock set. Forcing the links to be handled as channel access links solves the problem.
CA links which connect between IOCs incur the extra overhead associated with message passing protocols, operating system calls, and network activity.
In contrast, CA links which connect records in the same IOC are executed more efficiently by directly calling database access functions such as dbPutField
and dbGetField
, or by receiving callbacks directly from a database monitor subscription event queue.
Because channel access links interact with the database only via dbPutField
, dbGetField
and use a database monitor subscription event queue, their interaction with the database is fundamentally different from database links which are tightly integrated within the code that executes database records.
For this reason and because channel access does not support the passing of a process passive flag, the semantics of channel access links are not the same as database links.
Let's discuss the channel access semantics of INLINK, OUTLINK, and FWDLINK separately.
The options for process passive are:
Maximize Severity is honored.
The options for process passive are:
Maximize Severity is not honored.
A channel access forward link is honored only if it references the PROC
field of a record.
In that case a ca_put
with a value of 1 is performed each time a forward link request is issued.
Because of this implementation, the requirement that a forward link can only point to a passive record does not apply to channel access forward links;
the target record will be processed irrespective of the value of its SSCAN
field.
The available options are:
Maximize Severity is not honored.