Dynamic Interface Infrastructure

Name

gg_api, gg_stem, ggInitAPI, ggExitAPI, ggNewStem, ggDelStem, ggAttach, ggDetach, ggGetAPIByName : Dynamic Interface Infrastructure

Synopsis

#include <ggi/gg-api.h>

struct gg_api_ops;
struct gg_api_state;

struct gg_version {
      uint32_t major;
      uint32_t minor;
};

struct gg_api {
      int id;
      const char *name;
      struct gg_version version;
      struct gg_channel *channel;
      /* end of read-only public members */
      struct gg_api_ops *ops;
      uint32_t debug;
      struct gg_config *config;
      /* the following is for libgg internals */
      struct gg_api_state *state;
};

struct gg_stem;

int ggInitAPI(struct gg_api *);

int ggExitAPI(struct gg_api *);

struct gg_api* ggGetAPIByName(const char *);

struct gg_stem* ggNewStem(struct gg_api *, ...);

void ggDelStem(struct gg_stem *);

int  ggAttach(struct gg_api *, struct gg_stem *);

int  ggDetach(struct gg_api *, struct gg_stem *);

Overview

These structures and functions provide a framework for managing dynamic interfaces, or capacities attached to or revoked from objects at runtime. There are two primary structures involved: gg_api and gg_stem. A gg_stem is a void object. As the name suggests, it is an object that has no application-specific behavior when created, but that can be blessed with various capabilities at runtime, by attaching an interface to it. Once an interface is attached to a stem, the stem provides this interface (meaning that interface-specific functions can be used with this item) until the interface is detached. Each interface that can be attached dynamically to a stem is described by a gg_api structure. To be usable, an interface must first be initialzed (registered to libgg).

Note that the framework is very generic and does not impose any restriction on interfaces which can be attached to stems, providing them with orthogonal capabilities. The only requirements is that each API must have a unique name. The point is to allow possible (but not mandatory) cooperations between interfaces installed on the same stem. Using simple message passing features offered by the observer implementation, interfaces can be notified of each other's presence and activity on the same stem, without depending on one another at build time.

Description

ggInitAPI registers an interface and initializes it if needed. api must be a pointer to a valid structure describing the interface. This function will count the number of time an interface is initialized. Code that successfully calls ggInitAPI is responsible for calling ggExitAPI symetrically later. Technically ggInitAPI grabs a reference to the api, so it must release it later.

ggExitAPI is used to bring an interface down when not needed any more, freeing all resources it holds. If the interface is still in used (ggInitAPI has been called more than once), it simply decrements the use count,thus releasing a refernce.

ggGetAPIByName is used to retrieve an installed interface by its well-known name. The name is supposed to be unique by design.

ggNewStem is used to create new stem objects. When created, a stem does not provide any functionality (besides the ones defined in this framework) until one or more APIs are attached on it. As a shortcut, this function takes a NULL-terminated list of APIs that should be attached to this stem when it is created. These APIs will be automatically be initialized and attached on the new stem. If any of the above step fails for any reason the stem creation is completly aborted. If fine-grained control and error reporting is needed, the user must explicitely initialize and attach the requested APIs via ggInitAPI and ggAttach functions.

ggDelStem frees a stem previously allocated with ggNewStem. Upon deletion, all interfaces still attached on it will be cleanly detached.

ggAttach and ggDetach are used to attach and detach an interface on a stem respectively. An attachment count is kept internally, so initialization/finalization will only occur if necessary (on first attachment or when the counter is down to 0).

Return value

ggInitAPI returns the number of time this interface is already registered (0 means first time) or a negative error code:

  • GGI_EBUSY if this interface is already installed on another relam, or if an interface with the same name is already installed.
  • GGI_EUNKNOWN if the interface was installed for the first time, but the interface-specific initialization failed, or if libgg could be initialized.

ggExitAPI returns the number of time this interface is still installed (0 means not anymore) or a negatice error code:

  • GGI_ENOTALLOC if the interface is not currently installed.
  • GGI_EBUSY if the usage count for this interface is 0 but it is still attached on a stem.

ggGetAPIByName returns the given interface structure or 'NULL' if not found.

ggNewStem returns a newly allocated stem or 'NULL'.

ggAttach returns the number of time this interface is already attached on the stem (0 means first time) or a negative error code:

  • GGI_ENOMATCH if the interface and the stem do not belong to the same realm.
  • GGI_ENOMEM if the stem object could not be expanded to hold this new attachment.
  • GGI_UNKNOWN if the library-specific attachement code failed.

ggDetach returns the number of time this interface is still attached on the stem (0 means the interface is revoked) or a negative error code:

  • GGI_ENOMATCH if the interface and the stem do not belong to the same realm.
  • GGI_ENOTALLOC if the interface is not attached on that stem.

Standard channels

The API framework relies on the channel infrastucture as a generic message passing mechanism between various elements that must communicate at runtime, without knowing each other at compile time. A default channel is defined for gg_stem and gg_api.

The channel installed on every stem has the following observable events:

GG_MESSAGE_STEM_ATTACH, GG_MESSAGE_STEM_DETACH

These events will be triggered respectively when a API is successfully attached on that stem for the first time, and before it is detached completely. The data structure is:

struct gg_message_api_stem {
    struct gg_api  *api;
    struct gg_stem *stem;
};

GG_MESSAGE_STEM_DELETE

This message will be triggered before the stem is deleted. This allow third-party code to know when they need to drop a weak reference they hold on this stem.

The message data is the stem itself.

Currently, there is no control defined on this channel.

The channel installed on the gg_api has the following messages:

GG_MESSAGE_API_ATTACH, GG_MESSAGE_API_DETACH

These events will be triggered respectively when a API is successfully attached on a stem for the first time, and before it is detached completely. The data structure is:

struct gg_message_api_stem {
    struct gg_api  *api;
    struct gg_stem *stem;
};

GG_MESSAGE_API_EXIT

This message is sent when the API is really exiting (init count goes down to 0). The parameter is the API pointer.

See also