carb::Framework

Defined in carb/Framework.h

struct carb::Framework

Defines the framework for creating Carbonite applications and plugins.

See Framework Overview for high-level documentation on core concepts, using Framework, and creating plugins.

Plugins are shared libraries with a .plugin.dll/.so suffix. The plugins are named with the .plugin suffix to support plugin discovery and support cohabitation with other supporting .dll/.so libraries in the same folder. It is a recommended naming pattern, but not mandatory.

Plugin library file format:

  • Windows: <plugin-name>.plugin.dll

  • Linux: lib<plugin-name>.plugin.so

A plugin implements one or many interfaces and has a name which uniquely identifies it to the framework. The plugin’s name usually matches the filename, but it is not mandatory, the actual plugin name is provided by the plugin via carb::OnPluginRegisterFn.

“Static” plugin can also be registered with Framework::registerPlugin() function, thus no shared library will be involved.

Framework comes with 3 static plugins:

These plugins are used by Framework itself. Without carb::logging::ILogging, Framework won’t be able to log messages. Without carb::filesystem::IFileSystem, Framework won’t be able to load any “dynamic” plugins. Without carb::assert::IAssert, assertion failures will simply write a message to stderr and abort.

It’s up to the application to register these needed plugins. OMNI_CORE_INIT() performs this registration on the user’s behalf.

The term “client” is often used across the Framework API. Client is either:

Clients are uniquely identified by their name. Many functions accept client name as an argument. This allows Framework to create a dependency tree amonst clients. This dependency tree allows the safe unloading of plugins.

Thread Safety

Unless otherwise noted, Framework functions are thread-safe and may be called from multiple threads simultaneously.

Public Functions

inline void loadPlugins(const PluginLoadingDesc &desc = PluginLoadingDesc::getDefault())

Load and register plugins from shared libraries.

template<typename T>
T *acquireInterface(const char *pluginName = nullptr)

Acquires the typed plugin interface from the given pluginName.

If nullptr is passed as pluginName this method selects the default plugin for the given interface type. Default plugin selection happens on the first such acquire call for a particular interface name and locked until after this interface is released. By default the interface with highest version is selected.

Framework::setDefaultPluginEx can be used to explicitly set which plugin to set as default, but it should be called before the first acquire call.

If acquire fails, nullptr is returned and an error is logged.

See

See tryAcquireInterface(const char*) for a version of this method that does not log errors.

Parameters

pluginName – The option to specify a plugin (implementation) that you specifically want. Pass nullptr to search for all plugins.

Returns

The requested plugin interface or nullptr.

template<typename T>
T *tryAcquireInterface(const char *pluginName = nullptr)

Try to acquire the typed plugin interface from the given pluginName.

This function works exactly as Framework::acquireInterface(const char*), except if acquire fails it returns nullptr and doesn’t log an error.

template<typename T>
T *acquireInterface(const void *pluginInterface)

Acquires the typed plugin interface from the same plugin as the provided interface.

Example:

Foo* foo = framework->acquireInterface<Foo>();

// the returned 'bar' interface is from the same plugin as 'foo'.
Bar* bar = framework->acquireInterface<Bar>(foo);

If foo and bar are not nullptr, they are guaranteed to be on the same plugin.

See

See tryAcquireInterface(const void*) for a version of this method that does not log errors.

Parameters

pluginInterface – The interface that was returned from acquireInterface. It will be used to select a plugin with requested interface.

Returns

The typed plugin interface that is returned and will be started.

template<typename T>
T *tryAcquireInterface(const void *pluginInterface)

Tries to acquires the typed plugin interface from the same plugin as the provided interface.

This function works exactly as Framework::acquireInterface(const void*), except if acquire fails it returns nullptr and doesn’t log an error.

template<typename T>
T *acquireInterfaceFromLibrary(const char *libraryPath)

Acquires to the typed plugin interface from the given file.

See

See Framework::acquireInterfaceFromLibraryWithClient for more details.

See

See tryAcquireInterfaceFromLibrary(const char*) for a version of this method that does not log errors.

Parameters

libraryPath – The library path to acquire interface from. Can be absolute or relative path to actual .dll/.so Carbonite plugin. Path is relative to the current working directory.

Returns

The typed plugin interface or nullptr. If nullptr is returned, an error is logged.

template<typename T>
T *tryAcquireInterfaceFromLibrary(const char *libraryPath)

Try to acquire the typed plugin interface from the given file.

This function works exactly as Framework::acquireInterfaceFromLibrary(const char*), except if acquire fails it returns nullptr and doesn’t log an error.

template<typename T>
uint32_t getInterfacesCount()

Gets the number of plugins with the specified interface.

Returns

The number of plugins with the specified interface.

template<typename T>
void acquireInterfaces(T **interfaces, uint32_t interfacesSize)

Acquires all interfaces of the given type.

The given output array must be preallocated. interfacesSize tells this method the size of the array.

If interfaces is to small, the array is filled as much as possible and an error is logged.

If interfaces is to big, entries past the required size will not be written.

Upon output, nullptr may randomly appear in interfaces. This represents failed internal calls to tryAcquireInterface. No error is logged in this case.

Warning

Carefully read this method’s documentation, as it has a slew of design issues. It’s use is not recommended.

Parameters
  • interfaces – Preallocated array that will hold the acquired interfaces. Values in this array must be preset to nullptr in order to determine which entires in the array are valid upon output.

  • interfacesSize – Number of preallocated array elements. See Framework::getInterfacesCount.

template<typename T>
void releaseInterface(T *pluginInterface)

Releases the use of an interface that is no longer needed.

Correct plugin interface type is expected, compile-time check is performed.

Parameters

pluginInterface – The interface that was returned from acquireInterface

template<typename T>
T *verifyInterface(T *interfaceCandidate)

Checks if the provided plugin interface matches the requirements.

Parameters

interfaceCandidate – The interface that was provided by the user.

Returns

If the interface candidate matches template interface requirements, returns interfaceCandidate. Otherwise, returns nullptr.

inline void *allocate(size_t size, size_t align = 0)

Allocates a block of memory.

Note

Any plugin (or the executable) may allocate the memory and a different plugin (or the executable) may free or reallocate it.

Warning

It is undefined behavior to use memory allocated with this function or reallocate() after the Carbonite framework has been shut down.

Parameters
  • size – The size of the memory block requested, in bytes. Specifying ‘0’ will return a valid pointer that can be passed to free but cannot be used to store any information.

  • align – The minimum alignment (in bytes) of the memory block requested. Must be a power of two. Values less than sizeof(size_t) are ignored. 0 indicates to use default system alignment (typically 2 * sizeof(void*)).

Returns

A non-nullptr memory block of size bytes with minimum alignment align. If an error occurred, or memory could not be allocated, nullptr is returned. The memory is not initialized.

inline void free(void *p)

Frees a block of memory previously allocated with allocate().

Note

Any plugin (or the exescutable) may allocate the memory and a different plugin (or the executable) may free it.

Parameters

p – The block of memory previously returned from allocate() or reallocate(), or nullptr.

inline void *reallocate(void *p, size_t size, size_t align = 0)

Reallocates a block of memory previously allocated with allocate().

This function changes the size of the memory block pointed to by p to size bytes with align alignment. The contents are unchanged from the start of the memory block up to the minimum of the old size and size. If size is larger than the old size, the added memory is not initialized. If p is nullptr, the call is equivalent to allocate(size, align); if size is 0 and p is not nullptr, the call is equivalent to free(p). Unless p is nullptr, it must have been retrieved by an earlier call to allocate() or reallocate(). If the memory region was moved in order to resize it, p will be freed as with free(p).

Note

Any plugin (or the executable) may allocate the memory and a different plugin (or the executable) may reallocate it.

Warning

It is undefined behavior to use memory allocated with this function or allocate() after the Carbonite framework has been shut down.

Parameters
  • p – The block of memory previously returned from allocate() or reallocate() if resizing is resizing is desired. If nullptr is passed as this parameter, the call behaves as if allocate(size, align) was called.

  • size – The size of the memory block requested, in bytes. See above for further explanation.

  • align – The minimum alignment (in bytes) of the memory block requested. Must be a power of two. Values less than sizeof(size_t) are ignored. Changing the alignment from a previous allocation is undefined behavior. 0 indicates to use default system alignment (typically 2 * sizeof(void*)).

Returns

A pointer to a block of memory of size bytes with minimum alignment align, unless an error occurs in which case nullptr is returned. If p is nullptr and size is 0 then nullptr is also returned.

template<class T>
LoadHookHandle addLoadHook(const char *pluginName, LoadHookFn func, void *userData)

Adds a load hook that is called when an interface becomes available.

No attempt is made to load the plugin. This can be used as a notification mechanism when a plugin cannot be loaded immediately (due to circular dependencies for instance) but may be loaded later. To remove the load hook, use removeLoadHook(). It is possible to register multiple load hooks with the same parameters, but this is not recommended and will cause the function to be called multiple times with the same parameters.

Template Parameters

T – The interface type

Parameters
  • pluginName – the name of the specific plugin desired that exposes T, or nullptr for any plugin.

  • func – the function to call when the given interface becomes available. This function may be called multiple times if multiple plugins that expose interface T are loaded.

  • userData – application-specific data that is supplied to func when it is called.

Returns

A LoadHookHandle uniquely identifying this load hook; kInvalidLoadHook if an error occurs. When finished with the load hook, call removeLoadHook().

Public Members

void (*loadPluginsEx)(const PluginLoadingDesc &desc)

Load and register plugins from shared libraries.

Prefer using loadPlugins.

void (*unloadAllPlugins)()

Unloads all plugins, including registered “static” plugins (see Framework::registerPlugin).

void *(*acquireInterfaceWithClient)(const char *clientName, InterfaceDesc desc, const char *pluginName)

Acquires the plugin interface pointer from an interface description.

Do not directly use this method. Instead use Framework::acquireInterface(const char*).

See

See tryAcquireInterfaceWithClient for a version of this method that does not log errors.

Parameters
  • clientName – The client requesting the plugin. This is used to form a dependency graph between clients. Must not be nullptr.

  • desc – The plugin interface description

  • pluginName – The plugin that you specifically want. If nullptr, the interface’s “default” plugin is used.

Returns

The returned function pointer for the interface being queried and started. If nullptr is returned, an error is logged.

void *(*tryAcquireInterfaceWithClient)(const char *clientName, InterfaceDesc desc, const char *pluginName)

Tries to acquires the plugin interface pointer from an interface description.

This method has the same contract as Framework::acquireInterfaceWithClient except an error is not logged if the interface could not be acquired.

Do not directly use this method. Instead use Framework::tryAcquireInterface(const char*).

void *(*acquireInterfaceFromInterfaceWithClient)(const char *clientName, InterfaceDesc desc, const void *pluginInterface)

Acquires the typed plugin interface from the same plugin as the provided interface.

Do not directly use this method. Instead use Framework::acquireInterface(const void*).

See

See tryAcquireInterfaceFromInterfaceWithClient for a version of this method that does not log errors.

Parameters
  • clientName – The client requesting the plugin. This is used to form a dependency graph between clients. Must not be nullptr.

  • desc – The plugin interface description.

  • pluginInterface – The interface that was returned from acquireInterface. It will be used to select a plugin with requested interface.

Returns

The returned function pointer for the interface being queried and started. If nullptr is returned, an error is logged.

void *(*tryAcquireInterfaceFromInterfaceWithClient)(const char *clientName, InterfaceDesc desc, const void *pluginInterface)

Tries to acquires the typed plugin interface from the same plugin as the provided interface.

This method has the same contract as Framework::acquireInterfaceFromInterfaceWithClient except an error is not logged if the interface could not be acquired.

Do not directly use this method. Instead use Framework::tryAcquireInterface(const void*).

void *(*acquireInterfaceFromLibraryWithClient)(const char *clientName, InterfaceDesc desc, const char *libraryPath)

Acquires the plugin interface pointer from an interface description and a filename.

If library with a path specified was already registered before it will be used to acquire the interface. Otherwise Framework attempts first to load specified library as a plugin.

This function guarantess in case of success to return an interface implementation from specified library.

Do not directly use this method. Instead use Framework::acquireInterfaceFromLibrary(const char*).

See

See tryAcquireInterfaceFromLibraryWithClient for a version of this method that does not log errors.

Parameters
  • clientName – The client requesting the plugin. This is used to form a dependency graph between clients. Must not be nullptr.

  • desc – The plugin interface description

  • libraryPath – The filename to acquire the interface from. Can be absolute or relative path to actual .dll/.so Carbonite plugin. Path is relative to the current working directory. Must not be nullptr.

Returns

The returned function pointer for the interface being queried and started. If nullptr is returned, an error is logged.

void *(*tryAcquireInterfaceFromLibraryWithClient)(const char *clientName, InterfaceDesc desc, const char *libraryPath)

Tries to acquire the plugin interface pointer from an interface description and a filename.

This method has the same contract as Framework::acquireInterfaceFromLibraryWithClient except an error is not logged if the interface could not be acquired.

Do not directly use this method. Instead use Framework::tryAcquireInterfaceFromLibrary(const char*).

uint32_t (*getInterfacesCountEx)(InterfaceDesc interfaceDesc)

Gets the number of plugins with the specified interface descriptor.

Parameters

interfaceDesc – The interface descriptor to get the plugin count.

Returns

The number of plugins with the specified interface descriptor.

void (*acquireInterfacesWithClient)(const char *clientName, InterfaceDesc interfaceDesc, void **interfaces, uint32_t interfacesSize)

Acquires all interfaces of the given type.

The given output array must be preallocated. interfacesSize tells this method the size of the array.

If interfaces is to small, the array is filled as much as possible and an error is logged.

If interfaces is to big, entries past the required size will not be written.

Upon output, nullptr may randomly appear in interfaces. This represents failed internal calls to tryAcquireInterface. No error is logged in this case.

Do not directly use this method. Instead use Framework::acquireInterfaces.

Warning

Carefully read this method’s documentation, as it has a slew of design issues. It’s use is not recommended.

Parameters
  • clientName – The client requesting the plugin. This is used to form a dependency graph between clients. Must not be nullptr.

  • desc – The plugin interface description

  • interfaces – Preallocated array that will hold the acquired interfaces. Values in this array must be preset to nullptr in order to determine which entires in the array are valid upon output.

  • interfacesSize – Number of preallocated array elements. See Framework::getInterfacesCount.

void (*releaseInterfaceWithClient)(const char *clientName, void *pluginInterface)

Releases the use of an interface that is no longer needed.

Do not directly use this method. Instead use Framework::releaseInterface.

Parameters
  • clientName – The client requesting the plugin. This is used to form a dependency graph between clients. Must not be nullptr.

  • pluginInterface – The interface that was returned from Framework::acquireInterface.

const PluginDesc &(*getPluginDesc)(const char *pluginName)

Gets the plugin descriptor for a specified plugin.

Parameters

pluginName – The plugin that you specifically want to get the descriptor for. Must not be nullptr.

Returns

The PluginDesc, it will be filled with zeros if the plugin doesn’t exist. The returned memory will be valid as long as the plugin is loaded.

const PluginDesc &(*getInterfacePluginDesc)(void *pluginInterface)

Gets the plugin descriptor for an interface returned from Framework::acquireInterface.

Parameters

pluginInterface – The interface that was returned from acquireInterface

Returns

The PluginDesc, it will be filled with zeros if wrong interface pointer is provided.

void (*getCompatiblePlugins)(InterfaceDesc interfaceDesc, PluginDesc *outPlugins)

Gets the plugins with the specified interface descriptor.

Danger

Do not use this method. The caller will be unable to correctly size outPlugins. The size of the number of loaded plugins matching interfaceDesc may change between the call to carb::Framework::getInterfacesCountEx and this method.

Parameters
  • interfaceDesc – The interface descriptor to get the plugins for.

  • outPlugins – The array to be populated with the plugins of size Framework::getInterfacesCountEx(). This array must be set to all zeros before given to this function in order to be able to tell the number of entries written.

size_t (*getPluginCount)()

Gets the number of registered plugins.

Returns

The number of registered plugins.

void (*getPlugins)(PluginDesc *outPlugins)

Gets all registered plugins.

Danger

Do not use this method. The caller will be unable to correctly size outPlugins. The number of plugins may change between the call to carb::Framework::getPluginCount and this method.

Parameters

outPlugins – The array to be populated with plugin descriptors of size Framework::getPluginCount().

void (*tryReloadPlugins)()

Attempts to reload all plugins that are currently loaded.

bool (*registerPlugin)(const char *clientName, const PluginRegistrationDesc &desc)

Register a “static” plugin.

While typical plugins are “dynamic” and loaded from shared libraries (see Framework::loadPlugins), a “static” plugin can be added by calling this function from an application or another plugin. The contract is exactly the same: you provide a set of functions (some of which are optional), which usually are looked for in a shared library by the framework. It can be useful in some special scenarios where you want to hijack particular interfaces or limited in your ability to produce new shared libraries.

It is important that the plugin name provided by PluginRegistrationDesc::onPluginRegisterFn function is unique, registration will fail otherwise.

Parameters
  • clientName – The client registering the plugin. This is used to form a dependency graph between clients. Must not be nullptr.

  • desc – The plugin registration description.

Returns

If registration was successful.

bool (*unregisterPlugin)(const char *pluginName)

Try to unregister a plugin.

If plugin is in use, which means one if its interfaces was acquired by someone and not yet released, the unregister will fail. Both “dynamic” (shared libraries) and “static” (see Framework::registerPlugin) plugins can be unregistered.

Parameters

pluginName – The plugin to be unregistered.

Returns

If unregistration was successful.

const PluginRegistrationDesc &(*getBuiltinLoggingDesc)()

The descriptor for registering builtin carb::logging::ILogging interface implementation.

const PluginRegistrationDesc &(*getBuiltinFileSystemDesc)()

The descriptor for registering builtin carb::filesystem::IFileSystem interface implementation.

void (*setDefaultPluginEx)(const char *clientName, InterfaceDesc desc, const char *pluginName)

Sets the default plugin to be used when the given interface is acquired.

The mechanism of default interfaces allows Framework to guarantee that every call to acquireInterface<Foo>() will return the same Foo interface pointer for everyone. The only way to bypass it is by explicitly passing the pluginName of the interface you want to acquire.

It is important to note that if the interface was previously already acquired, the effect of this function won’t take place until it is released by all holders. So it is recommended to set defaults as early as possible.

Parameters
  • clientName – The client registering the plugin. This is used to form a dependency graph between clients. Must not be nullptr.

  • desc – The plugin interface description.

  • pluginName – The plugin that will be set as default.

void (*setReloadableTempPath)(const char *tempPath)

Sets the temporary path where the framework will store data for reloadable plugins.

This function must be called before loading any reloadable plugins. By default Framework creates a temporary folder in the executable’s folder.

Parameters

tempPath – Temporary folder path.

const char *(*getReloadableTempPath)()

Returns temporary path where the framework will store data for reloadable plugins.

Returns

Temporary path for reloadable data. The returned memory is valid until the Framework::setReloadableTempPath is called or the Framework is destroyed.

const char *(*getBuildInfo)()

Returns Carbonite version and build information.

The format is: v{major}.{minor} [{shortgithash} {gitbranch} {isdirty}] where:

  • major - kFrameworkVersion.major

  • minor - kFrameworkVersion.minor

  • shortgithash - output of git rev-parse --short HEAD

  • gitbranch - output of git rev-parse --abbrev-ref HEAD

  • isdirty - DIRTY if git status --porcelain is not empty

Examples:

  • v1.0 [56ab220c master]

  • v0.2 [f2fc1ba1 dev/mfornander/harden DIRTY]

void *(*verifyInterfaceEx)(InterfaceDesc desc, void *interfaceCandidate)

Checks if provided plugin interface matches the requirements.

Do not directly use this method. Instead, use Framework::verifyInterface.

Parameters
  • desc – The interface description that sets the compatibility requirements.

  • interfaceCandidate – The interface that was provided by the user.

Returns

if the interface candidate matches desc, returns interfaceCandidate. Otherwise, returns nullptr.

const PluginRegistrationDesc &(*getBuiltinAssertDesc)()

The descriptor for registering builtin carb::assert::IAssert interface implementation.

const PluginRegistrationDesc &(*getBuiltinThreadUtilDesc)()

The descriptor for registering builtin carb::thread::IThreadUtil interface implementation.

LoadPluginResult (*loadPlugin)(const char *libraryPath, bool reloadable, bool unload)

Load and register a plugin from the given filename.

Call unloadPlugin() to unload the plugin at libraryPath.

Parameters
  • libraryPath – Name of the shared library. Must not be nullptr.

  • reloadable – Treat the plugin as reloadable.

  • unload – Grab the list of interfaces from the plugin and then unload it. If the user tries to acquire one of the retrieved interfaces, the plugin will be lazily reloaded.

Returns

Returns a non-negative value on success, negative value otherwise.

bool (*unloadPlugin)(const char *libraryPath)

Unloads the plugin at the given shared library path.

Parameters

Path – to shared library. Must not be nullptr.

Returns

Returns true if a plugin was loaded at the given path and successfully unloaded. false otherwise.

bool (*addReleaseHook)(void *iface, ReleaseHookFn fn, void *user)

Adds a release hook for either the framework or a specific interface.

A release hook can be added multiple times with the same or different user data, in which case it will be called multiple times. It is up to the caller to ensure uniqueness if uniqueness is desired. To remove a release hook, call carb::Framework::removeReleaseHook() with the same parameters.

Danger

It is expressly forbidden to call back into carb::Framework in any way during the carb::ReleaseHookFn callback. Doing so results in undefined behavior. The only exception to this rule is calling removeReleaseHook().

Parameters
  • iface – The interface (returned by carb::Framework::acquireInterface()) to monitor for release. If nullptr is specified, the release hook will be called when the carb::Framework itself is unloaded.

  • fn – The release hook callback function that will be called. Must not be nullptr.

  • user – Data to be passed to the release hook function. May be nullptr.

Returns

Returns true if the inteface was found and the release hook was added successfully; false otherwise.

bool (*removeReleaseHook)(void *iface, ReleaseHookFn fn, void *user)

Removes a release hook previously registered with carb::Framework::addReleaseHook().

The same parameters supplied to carb::Framework::addReleaseHook() must be provided in order to identify the correct release hook to remove. It is safe to call this function from within the release hook callback.

Danger

It is expressly forbidden to call back into carb::Framework in any way during the carb::ReleaseHookFn callback. Doing so results in undefined behavior. The only exception to this rule is calling removeReleaseHook().

Parameters
Returns

Returns true if the release hook was found and removed. If it was not found, false is returned.

const char *(*getSdkVersion)()

Retrieves the Carbonite SDK version string,.

Note

This version is intended for use in plugins. Since Carbonite plugins aren’t directly linked to the carb library, access to carbGetSdkVersion() isn’t as easy as calling a library function. This version just provides access to the same result from a location that is better guaranteed accessible to plugins.

Returns

A string describing the current Carbonite SDK version. This will be the same value as the CARB_SDK_VERSION value that was set when the SDK was built.

bool (*removeLoadHook)(LoadHookHandle handle)

Removes a previously-registered load hook.

It is safe to remove the load hook from within the load hook callback.

Parameters

handle – The LoadHookHandle returned from addLoadHook().

Returns

Returns true if the load hook was found and removed. If it was not found, false is returned.