Remote Administration Daemon Developer Guide

Exit Print View

Updated: July 2014
 
 

adr_data_t Type

The most frequently used type defined by rad/adr.h is adr_data_t. An adr_data_t object represents a unit of typed data. It could be of a base type, such as an integer (“1”) or string (“banana”), or of a derived type like a structure or an array. Each adr_data_t maintains a pointer to its adr_type_t.

A few common traits simplify access to adr_data_t objects. The first is that, except for the structure and array derived types (not enumerations), all adr_data_t values are immutable. They are assigned a value when they are created, and may not be changed thereafter.

Another is that all adr_data_t values are reference counted. Sometimes data structures need to be used by multiple consumers simultaneously, or simply retained for subsequent use. Reference counting is a cheap way to cut down on the cost of copying large data structures and the complexity of handling allocation failures. Though the reference counting is thread-safe, there is no other locking, which is not a problem for an immutable adr_data_t. Though the value of a non-immutable adr_data_t may be modified post-creation, the convention used throughout rad and its associated libraries is that once visibility of an adr_data_t has spread past its creator, it may no longer be modified. This eliminates the need for additional synchronization.

adr_data_t *adr_data_ref(adr_data_t *data);
void adr_data_free(adr_data_t *data);

The reference count on the adr_data_t data is incremented with adr_data_ref. For convenience, adr_data_ref returns data. Symmetrically, the reference count on the adr_data_t data is decremented with adr_data_free. As the name implies, this may result in data being freed; after calling adr_data_free the caller must not access data in any way. Neither adr_data_ref nor adr_data_free can fail.

A third trait is that interfaces that accept adr_data_t values take ownership of the caller's reference on the adr_data_t. If the caller needs to refer to the adr_data_t after passing a pointer to it to a libadr interface, it must first secure an additional reference with adr_data_ref. Interfaces that return adr_data_t that are referenced by other adr_data_t do not increase the reference count on the returned adr_data_t. The returned value is guaranteed to persist only as long as the caller retains a reference on the referring adr_data_t, or if the caller uses adr_data_ref to acquire its own reference on the returned adr_data_t. The net result is that in the common case where an adr_data_t does not have multiple simultaneous consumers, libadr consumers need not perform any explicit reference counting at all. They can naively allocate and free adr_data_t values as if they were any other data structure. Therefore the adr_data_t implementation can optimize for the case where the reference count is 1.

Lastly, many adr_data_t management routines rely on dynamic memory allocation, which means that proper error handling is essential. To increase the clarity and maintainability of adr_data_t consumers, and reduce the likelihood of mishandling errors, libadr interfaces explicitly accept NULL adr_data_t inputs and fail in sympathy. This means that a libadr consumer can perform a large number of operations on the instances of adr_data_t, checking only the final result for failure. Additionally, if a libadr routine is going to fail for any reason, references to a non-NULL adr_data_t passed to the routine is released. In other words, no special clean-up is needed when a libadr routine fails.