(v13) Asynchronous actions
This page applies to Harlequin v13.1r0 and later; and to Harlequin Core but not Harlequin MultiRIP
All platforms that the Harlequin Core runs on now support multi-tasking.
By using threads, the Harlequin Core no longer has to simulate a multi-tasking system. The use of threads allows you to have your own code running whenever you want, but more thought must be given to overall system configuration, both in terms of hardware capabilities and RIP thread configuration, for optimum RIP performance.
The Harlequin Core will no longer call a device's “tickle function” but it is still possible to interrupt a job or have a piece of asynchronous PostScript language code run. In addition to dropping support for device tickle functions the SwTimer
“clock” is also dropped and should no longer be relied upon. The Harlequin Core now provides a timer API that can be used to set up regular calling of your specific code. For more information see the API Reference Manual
.
An interrupt or timeout interrupt is signaled by sending the appropriate event. For example, to raise an interrupt you would use something like the following code (the job timeline reference would be picked up from a timeline handler that looks for the start of a job):
{
SWMSG_INTERRUPT irq;
...
irq.timeline = job_tl_ref; (void)SwEvent(SWEVT_INTERRUPT_USER, &irq, sizeof(irq));
...
}
For more information see the file timelineapi.h, and the API Reference Manual .
NOTE:
The return value from the call to
SwEvent()
can be ignored since it will be acted upon in a normal system. This is also true for all the sample code in this section.
A timeout interrupt is raised with very similar code:
{
SWMSG_INTERRUPT timeout;
...
timeout.timeline = job_tl_ref; (void)SwEvent(SWEVT_INTERRUPT_TIMEOUT, &timeout, sizeof(timeout));
...
}
While interrupts are now signaled using events, your code should not register event handlers to detect when an interrupt has been signaled and abort their processing. The Harlequin Core does not always immediately process an interrupt and requires PostScript language devices to continue working normally until it handles the interrupt. If a device function takes a while to do some processing, it should periodically check to see if the Harlequin Core has been interrupted. This is done by calling the Harlequin Core function SwOften()
. This function normally returns 0
and nothing needs to be done, but if this function returns -1
the device routine should abort and should return DeviceInterrupted
on the next call to the device's last_error()
function. It is expected that existing code that calls SwOften()
should not need to be changed to support this method of handling interrupts.
For example, if a device routine needs to write a large amount of data, it should not be written in one operation, but should use code something like this:
{
int32 bytes_written = 0; while (len > 0)
{
int32 this_size; int32 result;
this_size = (len > CHUNK) ? CHUNK : len;
result = underlying_write(desc, buff, this_size); bytes_written += result;
buff += result; len -= result;
if (SwOften() == -1)
{
error = Device Interrupted; return -1;
}
}
return bytes_written;
}
In this code listing any error handling has been omitted for clarity.
Asynchronous PostScript language actions are also done with events. The asynchronous PostScript language action event message specifies the number of the PostScript language procedure in the serviceinterrupt
dictionary, defined in execdict
, to be run. The number must be in the range 0
to 31
. An asynchronous PostScript language action can be requested with the following code:
{
SWMSG_ASYNC_PS async_ps;
...
async_ps.id = ps_action;
(void)SwEvent(SWEVT_ASYNC_PS, &async_ps, sizeof(async_ps));
...
}
Asynchronous PostScript language actions are run in the order they are requested. Multiple requests to run an asynchronous PostScript language action that occur before it can be run are treated as a single request the asynchronous PostScript language action will not be run multiple times. Requests to run an asynchronous PostScript language action with an id greater than 31
will be ignored.
The entries in the serviceinterrupt
dictionary are defined by a startup file. The content of the serviceinterrupt
dictionary is different for each skin type (Harlequin Core, or Harlequin MultiRIP). The values (procedure actions) are highly dependent on the skin, and best determined by you. However, asynchronous PS id of 31 is normally initialized to an action that will quit the RIP cleanly, and should not usually be changed.