RAD APIs in C
This section describes the APIs that are available for C language.
Entry Points in C
All entry points take a pointer to the object instance and a pointer to the
internal structure for the method or attribute. The object instance pointer is
essential for distinguishing different objects that implement the same interface.
The internal structure pointer is theoretically useful for sharing the same
implementation across multiple methods or attributes, but isn't used and may be
removed.
Additionally, all entry points return a conerr_t. If the access is
successful, they should return CE_OK.
If the access fails due to a system error or a module defined error, they should return
the respective error codes. For more information about the error codes, see Error Codes in C.
If an expected error occurs and an error payload is defined, it may be set in *error. The caller will unref the error object when it is done
with it.
-
A method entry point has the type meth_invoke_f:
typedef conerr_t (meth_invoke_f)(rad_instance_t *inst, adr_method_t *meth,
adr_data_t **result, adr_data_t **args, int count, adr_data_t **error);
args is an array of count
arguments.
Upon successful return, *result
should contain the return value of the method, if any.
The entry point for a method named METHOD in interface
INTERFACE is named
interface_INTERFACE_invoke_METHOD.
-
An attribute read entry point has the type
attr_read_f:
typedef conerr_t (attr_read_f)(rad_instance_t *inst, adr_attribute_t *attr,
adr_data_t **value, adr_data_t **error);
Upon successful return, *value
should contain the value of the attribute, if any.
The read entry point for an attribute named ATTR in interface
INTERFACE is named
interface_INTERFACE_read_ATTR.
-
An attribute write entry point has the type
attr_write_f:
typedef conerr_t (attr_write_f)(rad_instance_t *inst, adr_attribute_t *attr,
adr_data_t *newvalue, adr_data_t **error);
newvalue points to the new value.
If the attribute is nullable, newvalue can be NULL.
The write entry point for an attribute named ATTR in
interface INTERFACE is named
interface_INTERFACE_write_ATTR.
rad explicitly checks the types of all arguments passed to
methods and all values written to attributes. Stub implementations can assume that
all data provided is of the correct type. Stub implementations are responsible for
returning valid data. Returning invalid data results in an undefined
behavior.
Error Codes in C
RAD distinguishes errors as system errors and module defined errors.
System Errors
If the access fails due to a system error, the entry points should return one of the
following error codes:
-
CE_SYSTEM - An operation fails due to a system error. This
error code should not have payload.
-
CE_NOTFOUND - The retrieve operation fails because the object
does not exist. This error code should not have payload.
-
CE_EXISTS - The create operation fails because the object
already exists. This error code should not have payload.
-
CE_PRIV - An operation fails due to insufficient privileges.
This error code should not have payload.
-
CE_NOMEM - An operation fails due to insufficient memory.
This error code should not have payload.
Module Defined Errors
If the access fails due to an expected error as described in the API definition, the
entry points should return CE_OBJECT. If an expected error occurs and
an error payload is defined, it may be set in *error.
Note -
Do not use the CE_MISMATCH and the
CE_ILLEGAL error codes. If there is any data type mismatch error or
an illegal access error, return the CE_OBJECT error code with a
payload describing the illegal arguments.
Global Variables in C
|
|
boolean_t
rad_isproxy
|
A flag to determine if code is executing in the main or proxy
rad daemon. Only special system modules,
which are integral to the operation of RAD, may use this
variable.
|
rad_container_t
*rad_container
|
The rad container that contains the object
instance.
|
|
RAD Module Registration in C
|
|
int _rad_init(void *handle);
|
A module must provide a _rad_init. This is
called by the RAD daemon when the module is loaded and is a
convenient point for module initialization including
registration. Return 0 to indicate that the
module successfully initialized.
|
int rad_module_register(void *handle, int version, rad_modinfo_t *modinfo);
|
rad_module_register provides a handle,
which is the handle provided to the module in the call to
_rad_init. This handle is used by the RAD
daemon to maintain the private list of loaded modules. The
version indicates which version of the rad
module interface the module is using. modinfo
contains information used to identify the module.
|
|
RAD Instance Management in C
|
|
rad_instance_t *rad_instance_create(rad_object_type *type, void *data, void (*)(void *)freef);
|
rad_instance_create uses the supplied
parameters to create a new instance of an object of type.
data is the user data to store with the
instance and the freef function is a callback which will be
called with the user data when the instance is removed. If the
function fails, it returns NULL. Otherwise, a
valid instance reference is returned.
|
void * rad_instance_getdata(rad_instance_t *instance);
|
rad_instance_getdata returns the user data
(supplied in rad_instance_create) of the RAD
instance.
|
void rad_instance_notify (rad_instance_t *instance, const char *event, long sequence, adr_data_t *data);
|
rad_instance_notify generates an event on
the supplied instance. The
sequence is supplied in the event as the
sequence number and the payload of the event is provided in
data.
|
|
RAD Container Interactions in C
|
|
conerr_t rad_cont_insert(rad_container_t *container, adr_name_t *name, rad_instance_t *instance);
|
Create a RAD instance, rad_instance_t,
using the supplied name and object and then insert into
container. If the operation succeeds, CE_OK
is returned.
|
conerr_t rad_cont_insert_singleton(rad_container_t *container, adr_name_t *name, rad_object_t *object);
|
void rad_cont_remove(rad_container_t *container, adr_name_t *name);
|
Remove the instance from the
container.
|
conerr_t rad_cont_register_dynamic(rad_container_t *container, adr_name_t *name, rad_modinfo_t *modinfo, rad_dyn_list_t listf, rad_dyn_lookup_t lookupf, void *arg);
|
Register a dynamic container instance manager. The container
defines the container in which the instances will be managed.
The name defines the name filter for which
this instance manager is responsible. A typical name would
define the type of the instance which are managed. For example,
zname = adr_name_vcreate (MOD_DOMAIN, 1, "type",
"Zone") would be responsible for managing all
instances with a type of "Zone". listf is a
user-supplied function which is invoked when objects with the
matching pattern are listed. lookupf is a
user-supplied function which is invoked when objects with the
matching name are looked up. arg is stored and provided in the
callback to the user functions.
|
conerr_t (*rad_dyn_list_t)(adr_pattern_t *pattern, adr_data_t **data, void *arg);
|
conerr_t (*rad_dyn_lookup_t)(adr_name_t **name, rad_instance_t **inst, void *arg);
|
|
RAD Logging in C
|
|
void rad_log(rad_logtype_t type,
const char * format, ...);
|
Log a message with type and format to the
rad log. If the type is a lower level
than the rad logging level, then the message
is discarded.
|
void rad_log_alloc()
|
Log a memory allocation failure with log level
RL_FATAL.
|
rad_logtype_t rad_get_loglevel()
|
Return the logging level.
|
|
Using Threads in RAD in C
|
|
void *rad_thread_arg(rad_thread_t *tp);
|
Return the arg referenced by the thread
tp.
|
void rad_thread_ack(rad_thread_t *tp,
rad_moderr_t error);
|
This function is intended to be used from a user function
previously supplied as an argument to
rad_thread_create. It should not be used
in any other context.
Acknowledge the thread referenced by tp.
This process enables the controlling thread, from which a new
thread was created using rad_thread_create,
to make progress. The error is used to update the return value
from rad_thread_create and is set to
RM_OK for success.
|
rad_moderr_t rad_thread_create(rad_threadfp_t fp,
void *arg);
|
Create a thread to run fp. This function
will not return until the user function (fp)
calls rad_thread_ack. arg is stored and
passed into fp as a member of the
rad_thread_t data. It can be accessed
using rad_thread_arg.
|
rad_moderr_t rad_thread_create_async(
rad_thread_asyncfp_t fp, void *arg);
|
Create a thread to run fp. arg is stored
and passed into fp.
|
|
RAD Synchronization Functions in C
|
|
void rad_mutex_init(pthread_mutex_t *mutex);
|
Initialize a mutex.abort() on failure.
|
void rad_mutex_enter(pthread_mutex_t *mutex);
|
Lock a mutex. abort() on failure.
|
void rad_mutex_exit(pthread_mutex_t *mutex);
|
Unlock a mutex. abort() on failure.
|
void rad_cond_init(pthread_cond_t *cond);
|
Initialize a condition variable, cond.
abort(), on failure.
|
|
RAD Subprocess Functions in C
|
|
exec_params_t *rad_exec_params_alloc
|
Allocate a control structure for executing a
subprocess.
|
void rad_exec_params_free(exec_params_t *params);
|
Free a subprocess control structure, params.
|
void rad_exec_params_set_cwd(exec_params_t *params,
const char *cwd);
|
Set the current working directory, cwd, in
a subprocess control structure,
params.
|
void rad_exec_params_set_env(exec_params_t *params,
const char **envp);
|
Set the environment, envp, in a subprocess
control structure, params.
|
void rad_exec_params_set_loglevel(
exec_params_t *params, rad_logtype_t loglevel);
|
Set the RAD log level, loglevel, in a
subprocess control structure, params.
|
int rad_exec_params_set_stdin(exec_params_t *params,
int fd);
|
Set the stdin file descriptor, fd, in a
subprocess control structure, params.
|
int rad_exec_params_set_stdout(exec_params_t *params,
int fd);
|
Set the stdout file descriptor, fd, in a
subprocess control structure, params.
|
int rad_exec_params_set_stderr(exec_params_t *params,
int fd);
|
Set the stderr file descriptor, fd, in a
subprocess control structure, params.
|
int rad_forkexec(exec_params_t *params,
const char **argv, exec_result_t *result);
|
Use the supplied subprocess control structure,
params, to fork and execute
(execv) the supplied args,
argv. If result is not
NULL, it is updated with the subprocess
pid and file descriptor details.
|
int rad_forkexec_wait(exec_params_t *params,
const char **argv, int *status);
|
Use the supplied subprocess control structure,
params, to fork and execute
(execv) the supplied args,
argv. If status is not
NULL, it is updated with the exit status
of the subprocess. This function will wait for the subprocess to
terminate before returning.
|
int rad_wait(exec_params_t *params,
exec_result_t *result, int *status);
|
Use the supplied subprocess control structure, params, to wait
for a previous invocation of rad_forkexe to
complete. If result is not NULL, it is
updated with the subprocess pid and file descriptor details. If
status is not NULL, it is updated with the
exit status of the subprocess. This function will wait for the
subprocess to terminate before returning.
|
|
RAD Utility Functions in C
|
|
void *rad_zalloc(size_t size);
|
Return a pointer to a zero-allocated block of size
bytes.
|
char *rad_strndup(char *string, size_t length);
|
Create and return a duplicate of string that is of size,
length bytes.
|
int rad_strccmp(const char * zstring, const char * cstring, size_t length);
|
Compare two strings, up to a maximum size of length
bytes.
|
int rad_openf(const char *format, int oflag, mode_tmode, ...);
|
Open a file with access mode, oflag, and mode, mode, whose
path is specified by calling sprintf() on
format.
|
FILE *rad_fopenf(const char *format, const char *mode, ...);
|
Open a file with mode, whose path is specified by calling
sprintf() on format.
|
|
RAD Locale Functions in C
|
|
int rad_locale_parse(const char *locale,
rad_locale_t **rad_locale);
|
Update rad_locale with locale details based
on locale. If locale is NULL, then attempt to
retrieve a locale based on the locale of the RAD connection.
Returns 0 on success.
|
void rad_locale_free(rad_locale_t *rad_locale);
|
Free a locale, rad_locale, previously
obtained with rad_locale_parse.
|
|
Transactional Processing in RAD Modules in C
Transactional processing has no direct support within a module. If a
transactional model is desirable, the module
creator must provide the required building blocks, start_transaction, commit,
rollback, and other related processes.
Asynchronous Methods and Progress Reporting in RAD in C
Asynchronous methods and progress reporting is achieved using threads and events.
The pattern is to return a token from a synchronous method invocation which spawns a
thread to do work asynchronously. This worker thread is then responsible for
providing notifications to interested parties events.
For example, an interface has a method which returns a Task object. The method is
called installpkg and takes one argument, the name of the package
to install.
Task installpkg(string pkgname);
The Task instance returned by the method, contains enough information to identify
a task. Prior to invoking installpkg, the client subscribes to a
task-update event. The worker thread is responsible for issuing events about the
progress of the work. These events contain information about the progress of the
task.
In a minimal implementation, the worker thread would issue one event to notify the
client that the task was complete and what the outcome of the task was. A more
complex implementation would provide multiple events documenting progress and
possibly also provide an additional method that a client could invoke to interrogate
the server for a progress report.