Route all module interaction through dispatch
A module is addressed by name and command string, and nothing else. Typed API access handed a caller a pointer into the callee's function table, which meant compiling against that module's struct layout — a build-time dependency between modules that the design does not permit. Removing it also removes the manifest, the table magic constant, and the table size field, which existed only to describe and validate those tables. Load validation is now three steps: reserved contract symbols resolve, the minimum-version handshake passes, and the version and description probes return well-formed values. The contract is four reserved symbols, and a module's interface is the command vocabulary it documents. Documentation is brought in line, and artifacts are named exactly: libdpm-core.so for the library, <dpm/core.h> for the header, the dpm binary for the command-line tool.
This commit is contained in:
@@ -95,37 +95,6 @@ typedef struct dpm_module_info {
|
||||
const char* core_min; /* minimum libdpm-core version it supports */
|
||||
} dpm_module_info;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Module contract structures (layout fixed by the DPM spec) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/** Magic constant opening every module API table. */
|
||||
#define DPM_API_TABLE_MAGIC 0x314D5044u /* "DPM1" */
|
||||
|
||||
/**
|
||||
* Every module API table begins with this header: the magic constant,
|
||||
* then the full size in bytes of the table struct as the exporting
|
||||
* module compiled it (permits tail-extension within a table version).
|
||||
*/
|
||||
typedef struct dpm_api_table_header {
|
||||
uint32_t magic;
|
||||
uint32_t size;
|
||||
} dpm_api_table_header;
|
||||
|
||||
/** One entry of a module's declared functional surface. */
|
||||
typedef struct dpm_manifest_entry {
|
||||
const char* api_name; /* e.g. "raw" */
|
||||
int table_version; /* e.g. 1 */
|
||||
const char* symbol; /* exact exported symbol carrying the
|
||||
table, e.g. "raw_api_v1" */
|
||||
} dpm_manifest_entry;
|
||||
|
||||
/** A module's manifest: its entire declared functional surface. */
|
||||
typedef struct dpm_manifest {
|
||||
uint32_t count;
|
||||
const dpm_manifest_entry* entries;
|
||||
} dpm_manifest;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Context lifecycle */
|
||||
/* ------------------------------------------------------------------ */
|
||||
@@ -199,24 +168,6 @@ DPM_API dpm_module* dpm_require(dpm_ctx* ctx, const char* name);
|
||||
DPM_API int dpm_module_info_of(dpm_ctx* ctx, dpm_module* mod,
|
||||
dpm_module_info* out);
|
||||
|
||||
/**
|
||||
* @brief Returns a module's API table for direct typed calls
|
||||
*
|
||||
* The table was already validated (manifest cross-check, magic,
|
||||
* minimum size) at module load. The caller casts the pointer to the
|
||||
* table struct type for that API and version. The table is valid for
|
||||
* the life of the context.
|
||||
*
|
||||
* @param ctx The libdpm-core context
|
||||
* @param mod A module handle from dpm_require()
|
||||
* @param api_name The API name as declared in the module's manifest
|
||||
* @param table_version The table version to retrieve
|
||||
* @return The table pointer, or NULL if the module does not provide
|
||||
* that api/version pair
|
||||
*/
|
||||
DPM_API const void* dpm_get_api(dpm_ctx* ctx, dpm_module* mod,
|
||||
const char* api_name, int table_version);
|
||||
|
||||
/**
|
||||
* @brief Dispatches a command to a module
|
||||
*
|
||||
@@ -224,6 +175,11 @@ DPM_API const void* dpm_get_api(dpm_ctx* ctx, dpm_module* mod,
|
||||
* command, and the argument vector. argv[0] is the command when
|
||||
* argc > 0; semantics beyond that are the module's to define.
|
||||
*
|
||||
* This is the only path into module code. A caller addresses a module
|
||||
* by name and a capability by command string, so it holds no
|
||||
* compile-time knowledge of the module it is calling — the same call
|
||||
* a module makes to reach a peer.
|
||||
*
|
||||
* @param ctx The libdpm-core context
|
||||
* @param mod A module handle from dpm_require()
|
||||
* @param command The command name; NULL or empty behaves as the
|
||||
@@ -341,12 +297,12 @@ DPM_API const char* dpm_last_error(dpm_ctx* ctx);
|
||||
* const char* dpm_module_version(void);
|
||||
* const char* dpm_module_description(void);
|
||||
* const char* dpm_module_core_min(void);
|
||||
* const dpm_manifest* dpm_module_manifest(void);
|
||||
*
|
||||
* plus one exported table symbol per manifest entry. libdpm-core
|
||||
* refuses to
|
||||
* load any module that does not validate completely (see the DPM
|
||||
* specification: load-time enforcement).
|
||||
* dpm_module_execute is the module's entire functional surface; its
|
||||
* capabilities are addressed by command string, so a module publishes
|
||||
* no headers, struct layouts, or symbols to anything that calls it.
|
||||
* The library refuses to load any module that does not validate
|
||||
* completely (see the DPM specification: load-time enforcement).
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -35,7 +35,6 @@ struct dpm_module {
|
||||
std::string version;
|
||||
std::string description;
|
||||
std::string core_min;
|
||||
const dpm_manifest* manifest = nullptr;
|
||||
int (*execute)(dpm_ctx*, const char*, int, char**) = nullptr;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user