Plugins and Asynchronous actions
This page applies to Harlequin v13.1r0 and later; and to Harlequin MultiRIP but not Harlequin Core
Asynchronous actions are specialized, usually small, PostScript language jobs which are executed at unpredictable times, often while another job is running. This means that the set of PostScript language operators they can execute is very restricted. If it were not, the asynchronous job might interfere with the job in progress. Also, the memory available to an asynchronous action is limited, because another job in progress may already be using most of the available memory. A small amount of memory is reserved by the RIP for asynchronous actions.
The asynchronous action mechanism is provided so that two classes of tasks can be done while the RIP is busy:
- Answering queries. For example, providing a list of the fonts currently installed. In such a case, you would need to take care not to include transient fonts introduced by the job in progress.
- Filing operations. For example, installing a new file on the disk, perhaps to add a pagebuffer to the Output Controller.
The general mechanism of asynchronous actions requires a “trigger” to activate and identify the action, and a PostScript language procedure to define it. When implemented as an input plugin, the trigger is the raising of the dataAvailable
flag in the plugin, and the procedure is predefined to exe‐ cute the PostScript language provided by the plugin. The PostScript language fragments executed are almost never from ordinary jobs often they are constructed explicitly in the plugin. The plugin is usually written in such a way that it responds to an external trigger which it can define for example the plugin might respond to the presence of a particular file.
A channel identifies itself as a source of asynchronous actions by setting the CCF_ASYNCHRONOUS_ACTION
channel class flag, which changes the interpretation of data available. (A channel class cannot support both asynchronous actions and ordinary jobs.)
Unlike ordinary channels, channels opened for asynchronous actions are opened for reading only
. The PostScript language fragment it supplies can open the channel for writing if necessary (so that text output from the job can be written back to the plugin). The print
operator will send its output to either the place the current job has declared as its standard output, or to the RIP monitor.
The following restrictions apply to asynchronous actions:
- The job must make no assumptions about its environment.
For example, the top dictionary on the dictionary stack will probably not be userdict
, so any necessary def
operations must be performed with an appropriate begin
.
- The job must not change the environment of any other running job, in any way.
Changes are side effects, such as modifications to files on disk. The easiest way to ensure this doesn't happen is to wrap save
and restore
around the whole action. The action must also leave the operand and dictionary stacks as they were on entry.
- All errors must be caught, using
stopped
, so that they do not interfere with the correct operation of any other job in progress. - The job must not perform any graphics operations,
setpagedevice
,showpage
, or any other operations that affect the page in progress. - The action must not consume arbitrarily large amounts of PostScript language Virtual Memory.
The amount of memory required for the job should be minimized. A minimal amount of VM can be reserved for asynchronous actions with the AsyncMemorySize
system parameter.
For example, to reserve 25KB:
<< /AsyncMemorySize 25 1024 mul /Password 0 >> setsystemparams
Note: When designing and implementing an asynchronous action, it is important to make sure it will not disturb any job in progress. It is a good idea to keep each action simple so that its effects are easily understood.