The RIP Data Resource (RDR) API is used to share blocks of data and functional interfaces between the skin and core, or in general, between multiple Providers and Consumers. More...
Files | |
file | apis.h |
This header file defines Types of RDR_CLASS_API, used to identify APIs exposed through the RDR system. | |
file | rdrapi.h |
Header file defining the RIP Data Resource (RDR) System. | |
file | rdrerrors.h |
Header file defining the RIP Data Resource (RDR) System result translation. | |
file | rdrmetrics.h |
This header file defines how metrics are published through RDR. | |
file | event.c |
This file provides the Events system API. | |
file | rdr.c |
This file implements the RIP Data Resource (RDR) System. | |
file | rdrglue.c |
This file provides interfacing between the core RIP Data Resource API and the skin. | |
file | rdrpriv.h |
This file provides definitions for the core RIP Data Resource API. | |
Data Structures | |
struct | sw_rdr_api_20110201 |
The RDR API structure for version 20110201. More... | |
struct | sw_rdr_api_20191120 |
The RDR API structure for version 20191120. More... | |
Macros | |
#define | SwFindRDRs(void) rdr_api->find_all |
Find all RDRs. More... | |
Typedefs | |
typedef HqnIdent | sw_rdr_class |
A type used to store and communicate RDR classes. More... | |
typedef HqnIdent | sw_rdr_type |
RDR Types. More... | |
typedef HqnIdent | sw_rdr_namespace |
A type used to store and communicate RDR Namespaces. More... | |
typedef HqnIdent | sw_rdr_id |
RDR IDs. More... | |
typedef int32 | sw_rdr_priority |
RDR priorities. More... | |
typedef HqnResult | sw_rdr_result |
A type used to communicate return values from RDR API calls. More... | |
typedef struct sw_rdr_iterator | sw_rdr_iterator |
Iterator for finding multiple RDRs. More... | |
Functions | |
int | rdr_start (void) |
Initialise the RDR system. More... | |
void | rdr_end (void) |
Finalise the RDR system. More... | |
HqBool | get_skin_api_ptr (sw_rdr_type apitype, sw_rdr_id id, void *papi) |
Get an API pointer to a specified version of an RDR_CLASS_API resource. More... | |
sw_rdr_result | SwRegisterRDR (sw_rdr_class rdrclass, sw_rdr_type rdrtype, sw_rdr_id rdrid, void *ptr, size_t length, sw_rdr_priority priority) |
Register an RDR. More... | |
sw_rdr_result | SwRegisterRDRandID (sw_rdr_class rdrclass, sw_rdr_type rdrtype, sw_rdr_id *prdrid, void *ptr, size_t length, sw_rdr_priority priority) |
Register an RDR and allocate it a unique ID. More... | |
sw_rdr_result | SwDeregisterRDR (sw_rdr_class rdrclass, sw_rdr_type rdrtype, sw_rdr_id rdrid, void *ptr, size_t length) |
Deregister an RDR. More... | |
sw_rdr_result | SwFindRDR (sw_rdr_class rdrclass, sw_rdr_type rdrtype, sw_rdr_id rdrid, void **pptr, size_t *plength) |
Find an RDR given the Class, Type and ID. More... | |
sw_rdr_iterator * | SwFindRDRbyType (sw_rdr_class rdrclass, sw_rdr_type rdrtype) |
Find all RDRs of a specified Class and Type. More... | |
sw_rdr_iterator * | SwFindRDRbyClass (sw_rdr_class rdrclass) |
Find all RDRs of a specified Class. More... | |
sw_rdr_result | SwNextRDR (sw_rdr_iterator *iterator, sw_rdr_class *pclass, sw_rdr_type *ptype, sw_rdr_id *pid, void **pptr, size_t *plength) |
Find an RDR by iteration. More... | |
sw_rdr_result | SwLockNextRDR (sw_rdr_iterator *iterator, sw_rdr_class *pclass, sw_rdr_type *ptype, sw_rdr_id *pid, void **pptr, size_t *plength) |
Find an RDR by iteration and lock it to prevent deregistration. More... | |
sw_rdr_result | SwRestartFindRDR (sw_rdr_iterator *iterator) |
Restart an RDR iterator. More... | |
sw_rdr_result | SwFoundRDR (sw_rdr_iterator *iterator) |
Destroy an RDR iterator. More... | |
sw_rdr_result | SwRegisterNamedRDR (sw_rdr_namespace rdrspace, const char *name, size_t namelen, sw_rdr_id rdrid, void *ptr, size_t length, sw_rdr_priority priority) |
Register a Named RDR. More... | |
sw_rdr_result | SwRegisterNamedRDRandID (sw_rdr_namespace rdrspace, const char *name, size_t namelen, sw_rdr_id *prdrid, void *ptr, size_t length, sw_rdr_priority priority) |
Register a Named RDR and allocate it a unique ID. More... | |
sw_rdr_result | SwDeregisterNamedRDR (sw_rdr_namespace rdrspace, const char *name, size_t namelen, sw_rdr_id rdrid, void *ptr, size_t length) |
Deregister a Named RDR. More... | |
sw_rdr_result | SwFindNamedRDR (sw_rdr_namespace rdrspace, const char *name, size_t namelen, sw_rdr_id rdrid, void **pptr, size_t *plength) |
Find a named RDR given the Namespace, Name, and ID. More... | |
sw_rdr_iterator * | SwFindNamedRDRbyName (sw_rdr_namespace rdrspace, const char *name, size_t namelen) |
Find all Named RDRs of a specified Namespace and Name. More... | |
static HqnResult | rdr_result_translate (sw_rdr_result result) |
Translate an RDR-specific error code to a generic HqnResult error code. More... | |
The RIP Data Resource (RDR) API is used to share blocks of data and functional interfaces between the skin and core, or in general, between multiple Providers and Consumers.
The RDR system is a thread-safe database for entity publishing and discovery built on the concepts of:
The RDR API allows data to be discovered at run time, rather than being statically linked at build time. This allows complete decoupling of skin-supplied, RIP-consumed data, or vice versa; allows the skin to optionally override RIP-embedded data; and even allows data to be selected contextually.
An RDR is an entity represented by an address and a size. RDRs are identified by Class, Type and ID, or by Namespace, Name and ID. RDRs usually represent a block of data in memory, but the semantic interpretation of the address and size are (with one exception) specific to the Class and Type, or Namespace, of the RDR. The address and/or size could be used to represent, amongst other things:
The interpretation of the address and length is defined by the owner of the RDR Class and Type or Namespace. The only exception is the null case where both address and length are zero, which has a special meaning: If a null RDR is the highest priority registration of a particular Class, Type and ID (or Namespace, Name and ID), it appears to the consumer as though the RDR has not been registered at all. The RDR iteration functions will fail to find anything for that Class, Type and ID (or Namespace, Name and ID). This allows one provider to suppress an RDR registered by another.
A provider can register an entity (for example an API structure pointer or a block of data in memory) as an RDR identified by Class, Type and ID, with a particular priority; or identified by Namespace, Name and ID, with a particular priority. If multiple RDRs are registered with the same Class, Type and ID (or Namespace, Name and ID), only the highest priority is visible. RDRs can be de-registered and re-prioritized at any time, possibly revealing other registrations. Registrations of the same Class, Type, ID and priority, or Namespace, Name, ID and priority, operate a strict chronological ordering, with the last registration being visible.
A consumer can locate a particular RDR by Class, Type and ID, by Namespace, Name, and ID, or iterate through RDRs by Class and Type, or by Namespace and Name.
Names and Namespaces may be more or less convenient than Classes and Types depending on where the RDR is defined and registered, and how the knowledge of the RDR's existence is identified to the RIP. RDRs are either registered, deregistered and found by Class and Type, or by Namespace and Name. There is no mixing of the concepts; RDRs registered by Class and Type cannot be discovered or deregistered by Namespace and Name, and vice-versa.
Pre-defined RDR classes are enumerated in the RDR_CLASSES enumeration. Classes are subdivided into Types. The distinction between Class and Type is usually clear from the context: APIs registered as RDRs might have a Class of RDR_CLASS_API, and a Type indicating the use of the particular API (and hence its member functions). Classes are stored and passed through the interface as values of sw_rdr_class, an alias for the generic integer type HqnIdent.
RDR Types are enumerated elsewhere, as they are unique only within a single Class. For example, the RDR_CLASS_API Class uses the value RDR_API_EVENT (value 2) to indicate the entity is the events API pointer, and RDR_API_PTHREADS (value 3) to indicate the entity is the threading API pointer. Within another Class, Type values of 2 and 3 will have different meanings. Types are stored and passed through the interface as values of sw_rdr_type, an alias for the generic integer type HqnIdent.
Named RDRs are typically used for RDRs where there may be multiple instances of the same type of entity with the same ID that must be selected, e.g., multiple implementation instances of an interface using the same API and version. When using named RDRs, Namespaces are used to separate the domains in which names apply. The same name can be used in multiple namespaces. Pre-defined RDR namespaces are enumerated in the RDR_NAMES enumeration.
An RDR name is used to discriminate between different entity registrations in a Namespace. When using named RDR objects, the name is supplied as a string and length. When searching for RDRs, the name is compared for equality using the length supplied: it need not be zero-terminated, and any zeros included in the length supplied will be included in the name comparison. The calling functions retain ownership over the memory for the name in all cases, the name will be copied by the RDR system if necessary.
Individual RDRs of a particular Class and Type, or Namespace and Name, are discerned by their ID. There can only ever be one RDR with a particular Class, Type, and ID or Namespace, Name, and ID combination. The most recently registered (or highest priority) RDR with that combination is the visible RDR: see Priorities, overriding, hiding, and filtering for prioritisation. IDs are stored and passed through the interface as values of the generic integer type HqnIdent.
The significance of the ID depends on the Class and Type or Namespace and Name. In some combinations the ID is used as a version number for the RDR data; in other combinations the ID is not significant, and may be created automatically on registration by the RDR system.
Previous registrations are remembered in chronological order, and will be restored if the current RDR is deregistered. This allows contextual overriding of a default RDR.
The Class and Namespace identifiers and most Type identifiers follow common conventions in the Harlequin RIP interfaces for the ranges of values that are used:
You may safely define and use RDR classes and namespaces in your own customer range for your own entities.
The RDR API is used by the Harlequin MultiRIP and Harlequin Core to communicate with RIP plugins and skins and across modular boundaries. RDR is implemented in the skin code and is general purpose. It can be used by the customers for their own purposes in addition to existing RIP usage. A client can register and deregister RDRs, iterate through available RDRs, filtered by Class and Type or by Namespace and Name if required, or can directly locate a specific RDR.
Class-based RDRs are registered and deregistered using SwRegisterRDR(), SwRegisterRDRandID(), and SwDeregisterRDR(). They are discovered using SwFindRDR(), and iterated using SwFindRDRbyType() followed by SwNextRDR(), SwLockNextRDR(), and/or SwRestartFindRDR(), and finally SwFoundRDR().
Name-based RDRs are registered and deregistered using SwRegisterNamedRDR(), SwRegisterNamedRDRandID(), and SwDeregisterNamedRDR(). They are discovered using SwFindNamedRDR(), and iterated by using SwFindNamedRDRbyName() followed by SwNextRDR(), SwLockNextRDR(), and/or SwRestartFindRDR(), and finally SwFoundRDR(). When reporting Named RDR iterations through the SwNextRDR() function, the Class will be reported as RDR_CLASS_RDR, and the Type reported will be a synonym for the Namespace. The names in an RDR namespace can be iterated separately from the named RDRs, by calling SwFindRDRbyType() with the Class RDR_CLASS_RDR, and using the Namespace as the Type for the iteration.
The RDR interface is generally thread-safe, however the users of a particular RDR have to agree on the lifetimes of registered objects, so that one client does not deregister and free an object after another client has discovered it, but not finished using it. Using SwLockNextRDR() and paying attention to the SW_RDR_ERROR_IN_USE result value when deregistering RDRs can help clients avoid this problem.
Ideally, where two RDRs of the same Class, Type, and ID (or Namespace, Name and ID) are registered, the first would be the default definition, and the second the overridden version. In practice this chronology may be difficult to ensure, so RDR registration takes a priority parameter. High priority registrations always override lower priority registrations, regardless of registration ordering. Strict chronological ordering is still maintained within any one priority level.
RDR priorities can be used to override registrations, to temporarily hide registrations, and to install API filters. The RDR system provides three suggested priority levels to use for registrations, but you may vary from these:
To temporarily override an RDR, you can register a new entity with the same Class, Type, and ID (or Namespace, Name and ID) but with a higher priority than any expected existing registration, perform an operation, and then deregister the entity. For this to be effective, you have to know that the client will perform a search or iteration over the RDRs during the period your registration is active.
To install API filters, you can use RDR to discover an API structure, retain a pointer or a copy of the API structure, and then install your own definition of the API structure with a higher priority that manipulates data or diverts the function calls, calling the saved API copy as necessary. The RDR examples section contains examples of these use cases.
While RDR provides a great deal of flexibility for developers, you also require equivalent responsibility to both document the expected protocols, and for clients to follow those protocols. Arbitrarily suppressing overriding RDRs may cause incorrect functioning of software that relies on them, including the Harlequin core RIP and SDK.
The main use for RDR by the Harlequin RIP core code is for discovery of externally provided implementation code for APIs. This allows OEMs to share libraries used by a RIP integration; to upgrade libraries provided by Global Graphics; and to provide custom implementations for some functionality.
The RIP also uses RDR so that optional or additional code, such as device type implementations, CMM and screening modules can use data supplied by the RIP skin without requiring a proprietary skin interface and associated build variance. This allows you to supply your own device type implementations, CMM or screening modules, or to omit them entirely, with no other configuration or build changes.
The RIP core uses RDR registered APIs for a number of libraries that it uses internally. Using RDR allows you to intercept and redirect the API calls, so you can upgrade the version of a library that the RIP core uses, or share the library with your own application code, without needing a new RIP core library.
The utility function get_skin_api_ptr() is provided by the Harlequin RIP SDK to assist discovery of API pointers registered in the RDR Class RDR_CLASS_API. The get_skin_api_ptr() function has special logic to allow it to get the Pthreads API even before the SDK is initialized. If this function fails, the application should abort immediately. The Harlequin SDK and RIP will not function without it.
This section describes possible usages of the RDR system in more detail.
To have code access data located elsewhere, a symbol must be exported from the data provider and linked to the consumer. This kind of linkage can cause build difficulties, and is entirely inflexible the data cannot be optional unless the consumer is build-variant, and if there is a variable number of chunks of data, further complexity arises.
Registering data as an RDR, even when the supplier and consumer are within the same file, has many advantages including the ability to have that data overridden by some other system, or for further RDRs of that type to be defined.
For example, a module that displays the authors of all systems and modules in the build might be as simple as this:
Anything that wanted to output such a message would register an RDR of the appropriate type and the RDR system does all the work. Note the usage of SwRegisterRDRandID() to ensure each registration has a unique ID so that all registrations are visible.
It is possible to reveal APIs as RDRs. This allows a module controller to redefine an API implementation, but also allows multiple versions of an API to coexist without confusion.
For example, the sw_data_api implementor could publish its code like this:
Note that sizeof() is not usually important unless the thing pointed to can be different lengths, such as an array or a subclassed (extended) structure. To be generally useful with multiple API versions, versioned API struct definitions are also required, so a registration pointing at a structure of type sw_data_api_20071111
and a registration pointing at a structure of type sw_data_api_20110502
can exist simultaneously, using the same Class and Type but a different ID to discriminate between the different versions.
Anything that requires the data API would find it like this:
Multiple versions of an API can coexist simultaneously without requiring code that uses those APIs to be changed when a newer version is added, and the newer version does not necessarily need to be backwards compatible.
This also allows a module controller to temporarily override an API with its own implementation during its module's initialization. Significantly, if it subsequently becomes necessary to override some other API that module implementation may already be using, no change to the module or the API is required the module controller just overrides that API too. For example:
Note that such a module must find its APIs during its initialization and store them for later use, rather than finding them later.
The OEM can extend or modify a supplied API by finding the original with SwFindRDR(), copy or take a reference to it, then registering a replacement with a higher priority. A cloned API's lifetime would have to match that of the module that may be using it.
In addition to finding an RDR by Class, Type and ID using SwFindRDR() or by Namespace, Name and ID using SwFindNamedRDR() (which may or may not succeed, depending on registrations), a consumer can also search through registered RDRs by Class and Type or by Namespace and Name.
The consumer calls SwFindRDRbyType() or SwFindNamedRDRbyName() to create an Iterator. It then calls SwNextRDR() repeatedly using that Iterator until that fails to return a matching RDR, and finally finishes with the Iterator by calling SwFoundRDR().
If such a search is a common occurrence, the consumer may choose to use a persistent Iterator. SwFindRDRbyType() and SwFindNamedRDRbyName() can be called long in advance of the search to create the Iterator. Once a search has completed you can call SwRestartFindRDR() to return the Iterator to its initialized state ready for another search. Once finished with, SwFoundRDR() must still be called to delete the Iterator.
Care must be taken to handle multi-threading safely when iterating. It is possible for an RDR to be de-registered by some other thread between a call to SwNextRDR() returning that RDR and the consumer using it. Using SwLockNextRDR() instead of SwNextRDR() avoids this possibility by locking the RDR returned to prevent it being deregistered. The RDR remains locked against deregistration until the consumer calls SwLockNextRDR() with the iterator again, or any of SwNextRDR(), SwFoundRDR() or SwRestartFindRDR().
If SwDeregisterRDR() or SwDeregisterNamedRDR() is called on a locked RDR it is deregistered at once to prevent further discovery but is only discarded once fully unlocked. Also note that multiple separate find operations could have locked the RDR many times, and all must unlock before the RDR is finally discarded.
A supplier which calls SwDeregisterRDR() or SwDeregisterNamedRDR() because it intends to discard the entity in question must therefore be prepared for that call to return SW_RDR_ERROR_IN_USE, indicating that the RDR has been locked, and retry the deregistration until that error is no longer returned, indicating the consumers have moved on to other RDRs. Only then is it safe to discard the entity in question.
Suppliers are encouraged to avoid blocking after SW_RDR_ERROR_IN_USE has been returned unless absolutely necessary.
The Event system is tied closely to RDR. The RDR and Event systems can be described using pull and push metaphors; or as passive and active systems.
RDR is a pull mechanism: something requiring an entity can find it (or them) at a certain moment, but the RDR system provides no direct mechanism for managing the lifetime of an individual RDR. It is conceivable that an RDR might be de-registered between something successfully finding it and actually accessing the contents. This must be considered when designing a protocol using RDRs.
The worked examples of publishing RDRs implicitly require that the lifetime of an RDR found by a module will exceed that of the module itself. The RDR system is passive, so there is no automatic usage counting. Entities that can disappear or change asynchronously, or that require lifetime management or long-term locking, should use the Event system or Timelines.
The Event system is a push mechanism: something that knows, has, or is about to remove something, can communicate immediately with interested parties with the possibility of those handlers refusing or modifying the intended behavior.
The RDR system is passive, but the Event system active. Events can also be used to find things, much like the RDR system. The distinction is that handlers are actually called by the Event system. Providers of RDRs are never informed when those RDRs are found, delivered or used.
The RDR system is automatically started when the Harlequin RIP SDK is started. It remains active until the Harlequin RIP SDK is shutdown.
The utility function rdr_result_translate() is provided the translate RDR error codes to generic HqnResult error codes.
sw_rdr_iterator * SwFindRDRs | ( | void | ) | rdr_api->find_all |
Find all RDRs.
This call begins an iteration to find all RDRs.
typedef HqnIdent sw_rdr_class |
A type used to store and communicate RDR classes.
Values of this type will be one of the RDR_CLASSES enumeration values.
RDR IDs.
IDs are unique per Class and Type, and are either predefined elsewhere or allocated on demand by SwRegisterRDRandID().
typedef struct sw_rdr_iterator sw_rdr_iterator |
Iterator for finding multiple RDRs.
These are created by any of the SwFindRDR*() calls, passed to SwNextRDR(), can be restarted by SwRestartFindRDR() and are destroyed by SwFoundRDR().
They are opaque and should not be inspected or altered.
typedef HqnIdent sw_rdr_namespace |
A type used to store and communicate RDR Namespaces.
Values of this type will be one of the RDR_NAMES enumeration values.
typedef int32 sw_rdr_priority |
RDR priorities.
RDRs defined with the same Class:Type:ID or Namespace:Name:ID combination are held in strict chronological order, with the most recent registration being the visible definition. Prioritisation allows this chronology to be overridden, in that low priority RDRs are guaranteed to be superseded by higher priority registrations, regardless of chronology. Strict chronological ordering is maintained for RDRs at the same priority level.
typedef HqnResult sw_rdr_result |
A type used to communicate return values from RDR API calls.
This is a subclass of HqnResult that also supports some specific extra error codes generated by RDR (declared as the RDR_RESULT enumeration). Before assigning to values of HqnResult type or any of its other subclasses, sw_rdr_result values must be converted to change the RDR specific values to HQN_RESULT_SUCCESS or a monitor UID error code greater than MON_CLASS_ERROR. This can be done by including the file rdrerrors.h and calling the function rdr_result_translate().
typedef HqnIdent sw_rdr_type |
RDR Types.
Types are defined on a per-Class basis elsewhere.
anonymous enum |
Enumeration of RDR priorities.
It is defined that the usual case is a priority of zero, so SW_RDR_NORMAL can be replaced with 0
in actual code.
Priority is primarily used to discern default from override definitions, but within any particular Class and Type, prioritisation can be used to implement any weighting, preference or selection process.
Note however that priority is an attribute of the Provider's registration, not of the RDR that is being registered - the priority of the RDR is not revealed to the Consumer.
Enumerator | |
---|---|
SW_RDR_DEFAULT | Known to be a default |
SW_RDR_NORMAL | The usual case |
SW_RDR_OVERRIDE | High priority registration |
enum RDR_APIS |
RDR-discoverable API numbers (RDR Types for RDR_CLASS_API).
API numbering follows the numbering conventions for DEVICETYPE numbers.
These ranges are sub-allocated here and elsewhere.
Enumerator | |
---|---|
RDR_API_RDR | RIP Data Resource (RDR) System gets the pride of place! |
RDR_API_EVENT | |
RDR_API_PTHREADS | |
RDR_API_TIMER | |
RDR_API_HTM | |
RDR_API_TIMELINE | |
RDR_API_DATA | |
RDR_API_JPEG | |
RDR_API_BARCODE | |
RDR_API_ZLIB | |
RDR_API_LIBPNG | |
RDR_API_EXPAT | |
RDR_API_LIBJPEG | |
RDR_API_RASTERSTORE | |
RDR_API_GUISKIN | (HMR only) |
RDR_API_NAMEDCOLOR | (HMR only) |
RDR_API_CDF | (HMR only) |
RDR_API_THROUGHPUT | (HMR only) |
RDR_API_INPUTQ | Input queue and source API (HMR and HHR) |
RDR_API_RASTERMANAGER_OUTPUT | |
RDR_API_COLORLOGIC | (GG internal) |
enum RDR_CLASSES |
RDR Classes.
Classes are defined here and subdivided into Types defined elsewhere.
Class numbering follows the numbering conventions for DEVICETYPE numbers.
Enumerator | |
---|---|
RDR_CLASS_EVENT | Asynchronous Events and Messages for Events system |
RDR_CLASS_RDR | For RDR's internal use |
RDR_CLASS_FONT | Embedded font files |
RDR_CLASS_RESERVE1 | Reserved |
RDR_CLASS_API | Function tables, such as skin-supplied timer API. Type is identifier, ID is version number. Types are defined in apis.h |
RDR_CLASS_TIMELINE | Timeline specific definitions for Timeline API |
RDR_CLASS_LOW_MEM | Low-memory handlers |
RDR_CLASS_SOAR | SOAR NX command-line options (HMR only) |
RDR_CLASS_DEVICETYPE | DEVICETYPE structures provided by skin. |
enum RDR_NAMES |
RDR Namespaces.
Namespace numbering follows the numbering conventions for DEVICETYPE numbers.
These ranges are sub-allocated here and elsewhere.
Names in an RDR Namespace can be iterated by using SwFindRDRbyType(), using Class RDR_CLASS_RDR and the namespace as the iteration Type.
When reporting named RDR iterations through SwNextRDR(), the Class will be RDR_CLASS_RDR and the Type will be a synonym for the namespace, using one of the Namespace values.
Enumerator | |
---|---|
RDR_NAMES_RDR | Reserved for RDR internal use |
RDR_NAMES_TILEAPI | Instances of the Tiling method API |
RDR_NAMES_CMMAPI | Instances of the Color management module interface |
RDR_NAMES_HTMAPI | Instances of the Halftone module interface |
RDR_NAMES_NAMEDCOLOR_DEVICE | Details for named color device instance. |
RDR_NAMES_RASTERAPI | Instances of the Raster backend output API |
enum RDR_RESULT |
Return values from RDR API calls.
HqBool get_skin_api_ptr | ( | sw_rdr_type | apitype, |
sw_rdr_id | id, | ||
void * | papi | ||
) |
Get an API pointer to a specified version of an RDR_CLASS_API resource.
[in] | apitype | The API type to get the pointer for. |
[in] | id | The version number of the API to get the pointer for. |
[out] | papi | A pointer to the API pointer to be updated. A pointer to the API version requested will be stored in this location, if the API version is known and the API is valid. Nothing will be written through this pointer if the API version is not known or it is not yet valid. |
TRUE | if the API pointer requested was stored in papi . |
FALSE | if the API pointer requested was not known or the API was not valid. |
If the RDR API is linked into a dynamic library, applications or libraries linking with it will not have direct access to the storage for the API pointers used to indirect to the API functions. The recommended method of discovering this API is to look it up in RDR. However, the first access will happen before the pointer is accessible to a application. In this case, the API pointer can be discovered through this function.
void rdr_end | ( | void | ) |
Finalise the RDR system.
The control variable and mutex are destroyed, and allocations discarded.
|
inlinestatic |
Translate an RDR-specific error code to a generic HqnResult error code.
[in] | result | One of the RDR_RESULT values, or an error value greater than MON_CLASS_ERROR. |
The header file defining this function should be included explicitly in every C or C++ file that calls it.
int rdr_start | ( | void | ) |
Initialise the RDR system.
The mutex and control variables are created and configured, and the concurrency count zeroed.
sw_rdr_result SwDeregisterNamedRDR | ( | sw_rdr_namespace | rdrspace, |
const char * | name, | ||
size_t | namelen, | ||
sw_rdr_id | rdrid, | ||
void * | ptr, | ||
size_t | length | ||
) |
Deregister a Named RDR.
This call deregisters a Named RDR of a particular Namespace, Name and ID. Any previously registered RDR of that Namespace, Name and ID will reappear.
[in] | rdrspace | The Namespace of the RDR when registered. |
[in] | name | The Name of the RDR within this Namespace. |
[in] | namelen | The length of the RDR name. |
[in] | rdrid | The ID of the Named RDR within this Namespace and Name. If an ID was automatically allocated, it must be supplied to deregister the RDR. |
[in] | ptr | A pointer to the start of the data. This must be the originally registered pointer. |
[in] | length | The length of the data. This must be the originally registered length. |
SW_RDR_SUCCESS | if the RDR was deregistered. |
SW_RDR_ERROR_UNKNOWN | is returned if the RDR could not be found. |
SW_RDR_ERROR_IN_USE | if the RDR is locked. This is informational - the RDR has been deregistered and cannot be found again. It will be discarded only when there are no remaining locks on it. It is not safe to dispose of the RDR contents if this error is returned, see below. |
All parameters MUST match those specified during registration for the RDR to be deregistered.
Note that this prevents (or at least changes) discovery of a particular RDR - it does not withdraw access rights from Consumers that have already found the RDR - that must be achieved by some additional protocol such as an Event or Timeline.
If the RDR has been locked by SwLockNextRDR(), it is deregistered but SW_RDR_ERROR_IN_USE is returned. This call can be repeated and will continue to return SW_RDR_ERROR_IN_USE for as long as the RDR is locked. Once unlocked it will automatically be discarded and this call will return SW_RDR_ERROR_UNKNOWN. See SwLockNextRDR() for more details of RDR locking.
Important: If the RDR refers to something that is to be discarded after deregistration it must NOT be discarded until SwDeregisterNamedRDR() returns something other than SW_RDR_ERROR_IN_USE.
When the last RDR using a particular name is deregistered from a namespace, the name is removed from the iterable names in the namespace.
sw_rdr_result SwDeregisterRDR | ( | sw_rdr_class | rdrclass, |
sw_rdr_type | rdrtype, | ||
sw_rdr_id | rdrid, | ||
void * | ptr, | ||
size_t | length | ||
) |
Deregister an RDR.
This call deregisters an RDR of a particular Class, Type and ID. Any previously registered RDR of that Class, Type and ID will reappear.
[in] | rdrclass | The Class of the RDR when registered. |
[in] | rdrtype | The Type of the RDR when registered. |
[in] | rdrid | The ID of the RDR within this Class and Type. If an ID was automatically allocated, it must be supplied to deregister the RDR. |
[in] | ptr | A pointer to the start of the data. This must be the originally registered pointer. |
[in] | length | The length of the data. This must be the originally registered length. |
SW_RDR_SUCCESS | if the RDR was deregistered. |
SW_RDR_ERROR_UNKNOWN | is returned if the RDR could not be found. |
SW_RDR_ERROR_IN_USE | if the RDR is locked. This is informational - the RDR has been deregistered and cannot be found again. It will be discarded only when there are no remaining locks on it. It is not safe to dispose of the RDR contents if this error is returned, see below. |
All parameters MUST match those specified during registration for the RDR to be deregistered.
Note that this prevents (or at least changes) discovery of a particular RDR - it does not withdraw access rights from Consumers that have already found the RDR - that must be achieved by some additional protocol such as an Event or Timeline.
If the RDR has been locked by SwLockNextRDR(), it is deregistered but SW_RDR_ERROR_IN_USE is returned. This call can be repeated and will continue to return SW_RDR_ERROR_IN_USE for as long as the RDR is locked. Once unlocked it will automatically be discarded and this call will return SW_RDR_ERROR_UNKNOWN. See SwLockNextRDR() for more details of RDR locking.
Important: If the RDR refers to something that is to be discarded after deregistration it must NOT be discarded until SwDeregisterRDR() returns something other than SW_RDR_ERROR_IN_USE.
sw_rdr_result SwFindNamedRDR | ( | sw_rdr_namespace | rdrspace, |
const char * | name, | ||
size_t | namelen, | ||
sw_rdr_id | rdrid, | ||
void ** | pptr, | ||
size_t * | plength | ||
) |
Find a named RDR given the Namespace, Name, and ID.
[in] | rdrspace | The Namespace of the RDR. |
[in] | name | The Name of the RDR within this Namespace. |
[in] | namelen | The length of the RDR name. |
[in] | rdrid | The ID of the RDR. |
[out] | pptr | A pointer to a pointer. If not NULL, this will be filled in with the pointer if the RDR is found. |
[out] | plength | A pointer to a length. If not NULL, this will be filled in with the length if the RDR is found. |
SW_RDR_SUCCESS | if the RDR was found; |
SW_RDR_ERROR_UNKNOWN | is returned if no named RDR with the specified Namespace, Name, and ID was found. |
eg:
sw_rdr_iterator* SwFindNamedRDRbyName | ( | sw_rdr_namespace | rdrspace, |
const char * | name, | ||
size_t | namelen | ||
) |
Find all Named RDRs of a specified Namespace and Name.
This call begins an iteration to find all RDRs of a specific typa and name.
[in] | rdrspace | The Namespace of the RDR. |
[in] | name | The Name of the RDR within this Namespace. |
[in] | namelen | The length of the RDR name. |
It is permissible to create the iterator long in advance of calling SwNextRDR() to avoid the possibility of failing due to insufficient memory. Iterators can be restarted using SwRestartFindRDR() and hence multiple searches can be performed using the same iterator without having to call SwFoundRDR() and SwFindRDRbyName() again. e.g.,
When calling SwNextRDR(), the namespace will be reported through that function's Type output pointer.
sw_rdr_result SwFindRDR | ( | sw_rdr_class | rdrclass, |
sw_rdr_type | rdrtype, | ||
sw_rdr_id | rdrid, | ||
void ** | pptr, | ||
size_t * | plength | ||
) |
Find an RDR given the Class, Type and ID.
This call allows the consumer to find a specific RDR.
[in] | rdrclass | The Class of the RDR. |
[in] | rdrtype | The Type of the RDR. |
[in] | rdrid | The ID of the RDR. |
[out] | pptr | A pointer to a pointer. If not NULL, this will be filled in with the pointer if the RDR is found. |
[out] | plength | A pointer to a length. If not NULL, this will be filled in with the length if the RDR is found. |
SW_RDR_SUCCESS | if the RDR was found; |
SW_RDR_ERROR_UNKNOWN | is returned if no RDR of the specified Class, Type and ID was found. |
eg:
sw_rdr_iterator* SwFindRDRbyClass | ( | sw_rdr_class | rdrclass | ) |
Find all RDRs of a specified Class.
This call begins an iteration to find all RDRs of a specific class.
[in] | rdrclass | The Class of the RDR. |
sw_rdr_iterator* SwFindRDRbyType | ( | sw_rdr_class | rdrclass, |
sw_rdr_type | rdrtype | ||
) |
Find all RDRs of a specified Class and Type.
This call begins an iteration to find all RDRs of a specific type.
[in] | rdrclass | The Class of the RDR. |
[in] | rdrtype | The Type of the RDR. |
It is permissible to create the iterator long in advance of calling SwNextRDR() to avoid the possibility of failing due to insufficient memory. Iterators can be restarted using SwRestartFindRDR() and hence multiple searches can be performed using the same iterator without having to call SwFoundRDR() and SwFindRDRbyType() again. e.g.,
sw_rdr_result SwFoundRDR | ( | sw_rdr_iterator * | iterator | ) |
Destroy an RDR iterator.
This call ends an iteration to find RDRs.
[in] | iterator | The iterator to destroy. Passing in a NULL iterator is pointless but safe. |
SW_RDR_SUCCESS | normally; |
SW_RDR_ERROR_IN_USE | if the iterator cannot be destroyed because it is threaded; |
SW_RDR_ERROR_SYNTAX | if the iterator is not recognised. |
This automatically unlocks the RDR returned by a call to SwLockNextRDR().
sw_rdr_result SwLockNextRDR | ( | sw_rdr_iterator * | iterator, |
sw_rdr_class * | pclass, | ||
sw_rdr_type * | ptype, | ||
sw_rdr_id * | pid, | ||
void ** | pptr, | ||
size_t * | plength | ||
) |
Find an RDR by iteration and lock it to prevent deregistration.
All parameters and behavour as SwNextRDR(), except the returned RDR is locked and can not be deregistered. It is unlocked automatically when the iterator is next passed to SwNextRDR(), SwLockNextRDR(), SwFoundRDR() or SwRestartFindRDR().
If SwDeregisterRDR() or SwDeregisterNamedRDR() are called on a locked RDR it is deregistered at once to prevent further discovery but is only discarded once fully unlocked. Note that multiple seperate find operations could have locked the RDR many times, and all must unlock before the RDR is finally discarded.
Important: If the RDR refers to something that is to be discarded after deregistration it must NOT be discarded until SwDeregisterRDR() or SwDeregisterNamedRDR() returned something other than SW_RDR_ERROR_IN_USE.
sw_rdr_result SwNextRDR | ( | sw_rdr_iterator * | iterator, |
sw_rdr_class * | pclass, | ||
sw_rdr_type * | ptype, | ||
sw_rdr_id * | pid, | ||
void ** | pptr, | ||
size_t * | plength | ||
) |
Find an RDR by iteration.
This call returns an RDR from the given iterator.
[in] | iterator | The sw_rdr_iterator created by SwFindRDR*(). |
[out] | pclass | Optional pointer to an RDR class. If not NULL, this will be filled in with the class of the found RDR. If iterating named RDRs, the class will be RDR_CLASS_RDR. |
[out] | ptype | Optional pointer to an RDR type. If not NULL, this will be filled in with the type of the found RDR. If iterating named RDRs, the namespace will be returned through this pointer. |
[out] | pid | Optional pointer to an RDR id. If not NULL, this will be filled in with the Id of the found RDR. |
[out] | pptr | Pointer to a pointer. If not NULL, this will be filled in with the ptr of the found RDR. |
[out] | plength | Pointer to a length. If not NULL, this will be filled in with the length of the found RDR. |
SW_RDR_SUCCESS | if an RDR was found; |
SW_RDR_ERROR_UNKNOWN | if no further RDRs match; |
SW_RDR_ERROR_SYNTAX | if the iterator is invalid. |
Once the iteration is finished, the iterator must be destroyed by calling SwFoundRDR(), or reset using SwRestartFindRDR() if the iterator is to persist or be reused immediately.
Note that in a multithreaded system it is possible for an RDR to be deregistered after this call has returned but before the caller tries to use it. See SwLockNextRDR().
sw_rdr_result SwRegisterNamedRDR | ( | sw_rdr_namespace | rdrspace, |
const char * | name, | ||
size_t | namelen, | ||
sw_rdr_id | rdrid, | ||
void * | ptr, | ||
size_t | length, | ||
sw_rdr_priority | priority | ||
) |
Register a Named RDR.
This call registers an RDR of a particular Namespace, Name, and ID.
[in] | rdrspace | The Namespace of the Named RDR. Named RDRs are subdivided into Namespaces, which are enumerated elsewhere. |
[in] | name | The Name of the RDR within this Namespace. |
[in] | namelen | The length of the RDR name. |
[in] | rdrid | The ID of the RDR within this Namespace and Name. |
[in] | ptr | A pointer to the start of the data. This pointer can be NULL. See below for special behaviour if length is also zero. |
[in] | length | The length of the data. This length can be zero. If ptr is NOT NULL then this delivers a zero-length RDR. This may still be meaningful to the consumer. If the length is zero AND the ptr is NULL (and this RDR is the highest priority registration), then any existing RDR of this Namespace, Name, and ID is suppressed and therefore appears to the consumer to be unregistered. Deregistering this RDR will cause the previous registration to reappear. |
[in] | priority | The priority of the registration - usually zero. Known defaults can be registered with a negative priority such as SW_RDR_DEFAULT. This ensures they are placed below any existing definition of the same Namespace:Name:ID combination (with a higher priority) - as though the default registration occured first. Similarly, a positive priority such as SW_RDR_OVERRIDE will remain the definitive registration until a registration at the same or higher priority is made. |
Reregistering an existing RDR (with the same parameters including ptr and length) does not produce multiple RDRs - it simply ensures that this RDR definition supersedes any of the same priority.
If there are any named RDRs registered in a namespace, the names in it can be iterated by using SwFindRDRbyType(), using Class RDR_CLASS_RDR and the namespace as the iteration Type.
sw_rdr_result SwRegisterNamedRDRandID | ( | sw_rdr_namespace | rdrspace, |
const char * | name, | ||
size_t | namelen, | ||
sw_rdr_id * | prdrid, | ||
void * | ptr, | ||
size_t | length, | ||
sw_rdr_priority | priority | ||
) |
Register a Named RDR and allocate it a unique ID.
This call registers an RDR as above, but also allocates it a new ID which has not been used within that Namespace and Name.
[in] | rdrspace | The Namespace of the RDR. |
[in] | name | The Name of the RDR within this Namespace. |
[in] | namelen | The length of the RDR name. |
[out] | prdrid | A pointer to an RDR ID, or NULL. An unused ID (within this Namespace and Name) will be allocated and returned if this pointer is not NULL. If no pointer is provided, an ID is still allocated but is not returned to the provider, so the RDR cannot be deregistered. |
[in] | ptr | A pointer to the start of the data. |
[in] | length | The length of the data. |
[in] | priority | The priority of the registration - usually zero. |
SW_RDR_SUCCESS | if the RDR was successfully registered. |
SW_RDR_ERROR | is returned in the unlikely event of every ID already having been allocated. |
sw_rdr_result SwRegisterRDR | ( | sw_rdr_class | rdrclass, |
sw_rdr_type | rdrtype, | ||
sw_rdr_id | rdrid, | ||
void * | ptr, | ||
size_t | length, | ||
sw_rdr_priority | priority | ||
) |
Register an RDR.
This call registers an RDR of a particular Class, Type and ID.
[in] | rdrclass | The Class of the RDR, as enumerated above. |
[in] | rdrtype | The Type of the RDR. RDR Classes are subdivided into Types, which are enumerated elsewhere. |
[in] | rdrid | The ID of the RDR within this Class and Type. |
[in] | ptr | A pointer to the start of the data. This pointer can be NULL. See below for special behaviour if length is also zero. |
[in] | length | The length of the data. This length can be zero. If ptr is NOT NULL then this delivers a zero-length RDR. This may still be meaningful to the consumer. If the length is zero AND the ptr is NULL (and this RDR is the highest priority registration), then any existing RDR of this Class, Type and ID is suppressed and therefore appears to the consumer to be unregistered. Deregistering this RDR will cause the previous registration to reappear. |
[in] | priority | The priority of the registration - usually zero. Known defaults can be registered with a negative priority such as SW_RDR_DEFAULT. This ensures they are placed below any existing definition of the same Class:Type:ID combination (with a higher priority) - as though the default registration occured first. Similarly, a positive priority such as SW_RDR_OVERRIDE will remain the definitive registration until a registration at the same or higher priority is made. |
Reregistering an existing RDR (with the same parameters including ptr and length) does not produce multiple RDRs - it simply ensures that this RDR definition supersedes any of the same priority.
sw_rdr_result SwRegisterRDRandID | ( | sw_rdr_class | rdrclass, |
sw_rdr_type | rdrtype, | ||
sw_rdr_id * | prdrid, | ||
void * | ptr, | ||
size_t | length, | ||
sw_rdr_priority | priority | ||
) |
Register an RDR and allocate it a unique ID.
This call registers an RDR as above, but also allocates it a new ID which has not been used within that Class and Type.
[in] | rdrclass | The Class of the RDR. |
[in] | rdrtype | The Type of the RDR. |
[out] | prdrid | A pointer to an RDR ID, or NULL. An unused ID (within this Class and Type) will be allocated and returned if this pointer is not NULL. If no pointer is provided, an ID is still allocated but is not returned to the provider, so the RDR cannot be deregistered. |
[in] | ptr | A pointer to the start of the data. |
[in] | length | The length of the data. |
[in] | priority | The priority of the registration - usually zero. |
SW_RDR_SUCCESS | if the RDR was successfully registered. |
SW_RDR_ERROR | is returned in the unlikely event of every ID already having been allocated. |
sw_rdr_result SwRestartFindRDR | ( | sw_rdr_iterator * | iterator | ) |
Restart an RDR iterator.
This call restarts the find process by returning the iterator to its initial state. It can be called instead of SwFoundRDR() to reuse a persistent iterator. Note that ultimately it is still necessary to call SwFoundRDR() to destroy the iterator. It can be called before SwNextRDR() has exhausted its results.
[in] | iterator | The iterator to restart. |
SW_RDR_SUCCESS | normally; |
SW_RDR_ERROR_IN_USE | if the iterator cannot be restarted because it is threaded; |
SW_RDR_ERROR_SYNTAX | if the iterator is not recognised. |
This automatically unlocks the RDR returned by a call to SwLockNextRDR().