Harlequin RIP SDK
Processing jobs

Once the Harlequin RIP SDK is started, jobs can be submitted though the inputs api from a number of different sources. These jobs will be processed after the RIP is started, by running the job processing loop.

The recommended method to run the job processing loop is to call the SwLeDo() function with the SW_LE_DO_PROCESS_QUEUE operation. The job processing loop may also be run using the low-level SwLeProcessJobs() function, or you may construct your own job processing loop using the low-level SwLeProcessInputQueue() function. Legacy integrations and special cases may send job data directly to the RIP, but Global Graphics strongly recommends you do not use this method.

Processing jobs using SwLeDo()

The SwLeDo() function can be used with the SW_LE_DO_PROCESS_QUEUE operation to process all jobs in the input queue. Global Graphics recommends this method of running the job processing loop, because it performs state checking, and can also start the RIP if it is not already started.

Calling SwLeDo() with the SW_LE_DO_PROCESS_QUEUE operation will call SwLeProcessJobs() to perform the actual processing of the jobs. The SwLeDoParams pointer passed to SwLeDo() will be passed to SwLeProcessJobs(), and so will affect the error and input queue processing. When operating as a server process, it is normal to set both the SwLeDoParams::fContinueAfterError and SwLeDoParams::fProcessQueueWait fields in that structure to TRUE. The return value from SwLeProcessJobs() is left in the SwLeDoParams::queuestate field, so you can determine if the jobs were all processed, or if there was an error.

The SW_LE_DO_PROCESS_QUEUE operation must be explicitly requested to process jobs. Even if the RIP is started, SwLeDo() will not run any jobs currently on the input queue if it is requested to stop or shutdown.

Processing jobs using SwLeProcessJobs()

The low-level function SwLeProcessJobs() is normally called from SwLeDo(). It will repeatedly take a job from the input queue, submit the job to the RIP, and wait for the RIP to complete the job. Two fields from the SwLeDoParams parameter affect this function's operation:

  • SwLeDoParams::fContinueAfterError determines whether SwLeProcessJobs() will continue to process more jobs after an error terminates a job. If this field is FALSE, this function will return SW_LE_QUEUE_JOB_ERROR if an error terminates a job, and the caller must determine the next action to take. If this field is TRUE, then the next job will be taken from the input queue and processed. If an error terminates a job, the status and error information will be available through several other channels (monitor events, the SWEVT_INTERPRET_ERROR or SWEVT_RENDER_ERROR events, and also the job timeline aborted event), so it is usually not necessary to stop processing on job failures.
  • SwLeDoParams::fProcessQueueWait determines what SwLeProcessJobs() does when the input queue is empty. If this field is FALSE, this function will return SW_LE_QUEUE_EMPTY and the caller must determine the next action to take. If this field is TRUE, this function will block if there are any sources of input data registered that may submit more jobs. If you are running the application as a single thread and calling the RIP to process batches of jobs, then this field may be FALSE. If you are running multiple threads in the application, it may be simpler to set this field TRUE to block and wait for more input, and have another thread deregister the input sources (which will make the blocking call to SwLeProcessJobs() return) or stop the RIP.

The SwLeProcessJobs() function may also return SW_LE_QUEUE_NO_RIP if the RIP exits of its own accord. This can happen if one of the jobs on the queue invokes the special stop job PostScript.

Processing jobs using SwLeProcessInputQueue()

The SwLeProcessJobs() function calls the low-level function SwLeProcessInputQueue() repeatedly to take a single job off the input queue, submit it to the RIP, and wait for the job to complete. If you have requirements that are not fulfilled by setting the parameters to SwLeProcessJobs(), you may construct your own job processing loop using SwLeProcessInputQueue().

SwLeProcessInputQueue() will immediately return SW_LE_QUEUE_NO_RIP if the RIP has exited already.

SwLeProcessInputQueue() will immediately return SW_LE_QUEUE_EMPTY if there are no jobs on the input queue.

If the RIP and job are present, SwLeProcessInputQueue() will construct a configuration for the job from the input queue entry, and will submit the job to the RIP. It will wait for the job to be completed by the RIP, and either return SW_LE_QUEUE_JOB_OK or SW_LE_QUEUE_JOB_ERROR.

If you need to construct your own job processing loop, use SwLeProcessInputQueue() to process jobs. Global Graphics does not support any other method of sending job data to the RIP.

Using SwLeProcessInputQueue() does not restrict how you provide configuration or job data to the RIP. This function detects and accepts PostScript device names or device-relative filenames in the configuration name and job name of the input queue entry, so you can use devices to programmatically construct or stream configuration and/or job data directly from memory or a database without touching disk.

Sending job data directly to the RIP

This method of submitting job data to the RIP is not recommended or supported by Global Graphics. Legacy integrations may use this method to send job data to the RIP. Global Graphics recommends converting such integrations to use the input queue for jobs instead. The only utility this description has is explaining how the base RIP configuration is set. This method should not be used for job data.

Configuration data and job data can be injected directly into the RIP, instead of processing a job from the input queue. This is performed by calling the low-level functions SwLeJobStart(); one or more calls to SwLePs(); and then SwLeJobEnd() to notify the RIP thread of the end of the job data.

The low-level functions SwLeSetJobNumber() and SwLeSetJobName() may be called if required before SwLeJobStart() is called. When setting the base RIP configuration, do not call either of these functions.

The low-level function SwLeJobStart() starts a job, providing a buffer of PostScript configuration data. For configuration-only jobs, the configuration PostScript should leave false on the PostScript stack. If submitting a job, the configuration PostScript should leave an open standard input file object and an open standard output file object on the PostScript stack, followed by true.

If submitting a job, the call to SwLeJobStart() may be followed by one or more calls to the low-level function SwLePs(). This provides additional buffers of PostScript job data. This call will return when the data has been accepted by the RIP. This may be before the any of the job data is rendered.

If the call to SwLeJobStart() succeeded, then the low-level SwLeJobEnd() function must be called, even if any intervening SwLePs() call failed. This call waits for the RIP to complete all rendering and interpretation on the buffers of data submitted by SwLeJobStart() and SwLePs().

The caller of these low-level functions is responsible for ensuring that the job is run at the job save level, and not the server loop save level, and for avoiding PostScript VM memory leaks. Getting these details right is tricky, which is one reason why Global Graphics does not recommend directly injecting jobs.

Interrupting the RIP

The RIP may be interrupted while it is processing a job. Another thread in your application can use the event API provided by the SDK to issue a SWEVT_INTERRUPT_USER or SWEVT_INTERRUPT_TIMEOUT event. The event call will return immediately, and at some point soon afterwards, RIP will notice the interrupt and process it. How the RIP processes interrupts depends on how the PostScript error handler in the RIP has been configured. The normal action on processing an interrupt is to terminate interpretation and rendering of a job and issue an error message.

The RIP may be processing several jobs on the input queue, and may be using Harlequin Parallel Pages to render pages on separate threads from the page it is interpreting, so it is possible that by the time your application notices a problem and sends the interrupt, the job will have been completed and another job started. To avoid interrupting the wrong job, you can use timeline references.

The SWEVT_INTERRUPT_USER and SWEVT_INTERRUPT_TIMEOUT events are issued with a SWMSG_INTERRUPT message attached to the event. This message has a SWMSG_INTERRUPT::timeline field defining which job to interrupt. If this is set to SW_TL_REF_INVALID (value zero), then all jobs being processed will be interrupted. If this is non-zero, then only the job referenced by the timeline will be interrupted. The timeline referenced in the interrupt message may be the SWTLT_JOB_STREAM timeline, or any descendent timeline of it. Many callbacks from the RIP include a timeline reference which you can use in the SWMSG_INTERRUPT message. If you do not have access to a suitable timeline reference in the thread or call where wish to interrupt the RIP, you can set up an event to capture the EVENT_TIMELINE_START event, look for the SWTLT_JOB_STREAM timeline type, and save the job's timeline reference. This is explained in more detail in Capturing timeline references.