Table of Contents
Chapter 4: Database Locking, Scanning, And Processing
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, database 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: constant, database link, channel access link, or a reference to a hardware signal.
- INLINK: Input link, used to fetch data.
- OUTLINK: Output link, used to write data.
NOTE: If a forward link is not a database link it is just ignored.
- FWDLINK: A forward link refers to a record that should be processed whenever the record containing the forward link completes processing.
This chapter only discusses database links. Links are defined in file link.h.
Database links are referenced by calling one of the following routines:
A forward link only makes sense if it refers to a passive record that the application developer wants processed after the record containing the link. For input and output links, however, two other attributes can be specified by the application developer, process passive and maximize severity.
- dbGetLink: The value of the field referenced by the input link retrieved.
- dbPutLink: The value of the field referenced by the output link is changed.
- dbScanPassive: The record referred to by the forward link is processed if it is passive.
Process passive (PP or NPP), is either TRUE or FALSE. 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, via a call to dbProcess, only if the record is a passive record and process_passive is TRUE.
Maximize severity (MS or NMS), is TRUE or FALSE. It determines if alarm severity is propagated across links. 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. In either case, if the severity is changed, the alarm status is set to LINK_ALARM.
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 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.
The basic idea is to call dbScanLock before performing any operations that can modify database records and calling dbScanUnlock after the modifications are complete. Because of database links (Input, Output, and Forward) a modification to one record can cause modification to other records. All records linked together, except possibly for input links declared NPP and NMS, 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:
All records linked via OUTLINKs and FWDLINKs are placed in the same lock set. Records linked via INLINKs with process_passive or maximize_severity TRUE are also forced to be in the same lock set. The lock sets are determined during IOC initialization.
- The periodic, I/O event, and event tasks lock before and unlock after processing:
- dbPutField locks before modifying a record and unlocks afterwards.
- dbGetField locks before reading and unlocks afterwards.
- Any asynchronous record support completion routine must lock before modifying a record and unlock afterwards.
Database scanning is the mechanism that requests a database record be processed. Four types of scanning are possible:
A dbScanPassive request results from a task calling one of the following routines:
- Periodic - Records are scanned at regular intervals.
- I/O event - A record is scanned as the result of an I/O interrupt.
- Event - A record is scanned as the result of any task issuing a post_event request.
- Passive - A record is scanned as a result of a call to dbScanPassive. dbScanPassive will issue a record processing request if and only if the record is passive and is not already being processed.
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.
- dbScanPassive: Only record processing routines, dbGetLink, dbPutLink, and dbPutField call dbScanPassive. Record processing routines call it for each forward link in the record.
- dbPutField: This routine changes the specified field and then, if the field has been declared process_passive, calls dbScanPassive. Each field of each record type has the attribute process_passive declared TRUE or FALSE in the ASCII definition file. This attribute is a global property, i.e. the application developer has no control of it. This use of process_passive is used only by dbPutField. 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, when the current processing completes.
- dbGetLink: If the link specifies process passive, this routine calls dbScanPassive. Whether or not dbScanPassive is called, it then obtains the specified value.
- dbPutLink: This routine changes the specified field. Then, if the link specifies process passive, it calls dbScanPassive. dbPutLink is only called from record processing routines. Note that this usage of process_passive is under the control of the application developer. 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, when the current processing completes.
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 "Record And Device Support" on page 65.
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 (Figure 4-1):
Figure 4-1: Example of Database Links
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:
This brief example demonstrates that database links needs more discussion.
- A begins processing. While processing a request is made to process B.
- B starts processing. While processing a request is made to process C.
- C starts processing. One of the first steps is to get a value from A via the input link.
- At this point a question occurs. Note that the input link specifies process passive (signified by the 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.
- C obtains the value from A and completes its processing. Control returns to B.
- B completes returning control to A
- A completes processing.
Rules Relating to Database Links
The processing order is guaranteed to follow the following rules:
- Forward links are processed in order from left to right and top to bottom. For example the following records are processed in the order FLNK1, FLNK2, FLKN3, FLNK4 (Figure 4-2).
Figure 4-2: Processing Order
- If a record has multiple input links (calculation and select records) the input is obtained in the natural order. For example if the fields are named INPA, INPB, ..., INPL, then the links are read in the order A then B then C, etc. Thus if obtaining an input results in a record being processed, the processing order is guaranteed.
- All input and output links are processed before the forward link.
All records, except possibly for NPP & NMS input links, 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.
PACT - processing active
Each 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. In particular no links are processed with pact FALSE. This prevents infinite processing loops. The example given at the beginning of this chapter gives an example. It will be seen in Section 7 on page 32 and Section 8 on page 33 that pact has other uses.
Process Passive: Link option
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 (Figure 4-3):
Figure 4-3: Incorrect Link Definition
Assume that all records except fanout are passive. When the fanout record is processed the following sequence of events occur:
Note that A got processed twice. This is unnecessary. If the input link to C is declared no process passive then A will only be processed once. Thus we should have (Figure 4-4).
- Fanout starts processing and asks that B be processed.
- B begins processing. It calls dbGetLink to obtain data from A.
- Because the input link has process passive true, a request is made to process A.
- A is processed, the data value fetched, and control is returned to B
- B completes processing and control is returned to fanout. Fanout asks that C be processed.
- C begins processing. It calls dbGetLink to obtain data from A.
- Because the input link has process passive TRUE, a request is made to process A.
- A is processed, the data value fetched, and control is returned to C.
- C completes processing and returns to fanout
- The fanout completes
Figure 4-4: Correct Link definition
Process Passive: Field attribute
Each field of each database record type has an attribute called process_passive. This attribute is specified in the ASCII record definition file. It is not under the control of the application developer. This attribute is used only by dbPutField. It determines if a passive record will be processed after dbPutField changes a field in the record. Consult the record specific information in the record reference manual for the setting of individual fields.
Maximize Severity: Link option
Input and output links have an option called maximize severity. For each such link the application developer can specify maximize severity TRUE (MS) or maximize severity FALSE (NMS).
When database input or output links are defined via DCT, the application developer can specify if alarm severities should be propagated across links. For input links the severity is propagated from the record referred to by the link to the record containing the link. For output links the severity of the record containing the link is propagated to the record referenced by the link. The alarm severity is transferred only if the new severity will be greater than the current severity. If the severity is propagated the alarm status is set equal to LINK_ALARM. See `Maximize Severity" on page 28 for details.
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.
Lets review the methods available to the application programmer for deciding when to process a record and for enforcing the order of record processing.
The previous discussion does not allow for asynchronous records. An example is 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. Lets state a few attributes of asynchronous record processing.
- A record can be scanned periodically (at one of several rates), via I/O event, or via Event.
- For each periodic group and for each Event group the phase field can be used to specify processing order.
- The application programmer has no control over the record processing order of records in different groups.
- The disable fields (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.
- A record (periodic or other) can be the root of a set of passive records that will all be processed whenever the root record is processed. The set is formed by input, output, and forward links.
- The process_passive option specified for each field of each record determines if a passive record is 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 if dbPutFields are directed to fields that have process_passive TRUE.
- The process_passive option for input and output links provides the application developer control over how a set of records are scanned.
- General link structures can be defined. The application programmer should be wary, however, of defining arbitrary structures without carefully analyzing the processing order.
During the initial processing for all asynchronous records the following is done:
The asynchronous completion routine performs the following algorithm:
- pact is set TRUE
- Data is obtained for all input links
- Record processing is started
- The record processing routine returns
Lets note a few attributes of the above rules:
- Record processing continues
- Record specific alarm conditions are checked
- Monitors are raised
- Forward links are processed
- pact is set FALSE.
With these rules the following works just fine:
- Asynchronous record processing does not delay the scanners.
- Between the time record processing begins and the asynchronous completion routine completes, no attempt will be made to again process the record. This is because 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.
- Forward and output links are triggered only when the asynchronous completion routine completes record processing.
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.
Thus an infinite loop of record processing has been set up. It is up to the application developer to prevent such loops.
- A starts record processing and returns leaving pact TRUE.
- Sometime later the record completion for A occurs. During record completion a request is made to process B. B starts processing and control returns to A which completes leaving its pact field TRUE.
- Sometime later the record completion for B occurs. During record completion a request is made to process A. A starts processing and control returns to B which completes leaving its pact field TRUE.
Obtain Old Data
A dbGetLink to a passive asynchronous record can get old data.
If A is a passive asynchronous record then the dbGetLink request forces dbProcess to be called for A. dbProcess starts the processing and returns. dbGetLink then reads the desired 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.
If the processing task aborts and the watch dog task cleans up before the asynchronous processing routine completes what happens? If the asynchronous routine completes before the watch dog task runs everything is okay. If it doesn't? This is a more general question of the consequences of having the watchdog timer restart a scan task. EPICS currently does not allow scanners to be automatically restarted.
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. Note that it could already be active because it appears twice in a chain of record processing. In this case 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.
Table of Contents