Dispatch returns a result envelope
dpm_execute fills a dpm_result on every call: status and error_code from the module's return value, and a payload the module hands back through dpm_set_result. The payload's layout belongs to the module and is documented per command; its release function is carried in the envelope and invoked by dpm_result_release. The context keeps a stack of the envelopes in progress, so a module calling a peer receives the peer's payload in its own envelope and its caller sees only what the module sets itself. The good fixture returns a payload and counts its releases, and the modules test covers the envelope fields, the payload round trip, single release, discard on a NULL envelope, and a payload set outside any dispatch. The prose documents describe the envelope and the payload header a module ships.
This commit is contained in:
@@ -60,9 +60,11 @@ The context owns everything it hands out. Every string a caller receives stays v
|
||||
|
||||
**Calling into a module.** `dpm_execute` passes a command name and an argument vector to the module's entry point and returns its result. This is the only path into module code, and it is the same one the `dpm` binary takes.
|
||||
|
||||
**Reading what a module returns.** Every dispatch fills a `dpm_result`: a status and error code the library writes from the module's return value, and a payload the module hands back through `dpm_set_result`. The payload's layout is defined and documented by the module, per command, and shipped as a header from the module's repository; the caller that asked for the command reads it as that layout and releases it with `dpm_result_release`.
|
||||
|
||||
**Enumerating.** `dpm_list_modules` yields a cursor over every valid module, which is what backs the listing the `dpm` binary prints.
|
||||
|
||||
**Services.** A module reaches the library through the context that dispatched the call: `dpm_log` to write a message, `dpm_config_get` to read a value from its own configuration namespace, `dpm_get_resolved_module_path` to learn where modules live, `dpm_core_version` to learn the library's version, `dpm_set_last_error` to record why it failed. A module needs no file handling and no logging machinery of its own.
|
||||
**Services.** A module reaches the library through the context that dispatched the call: `dpm_log` to write a message, `dpm_config_get` to read a value from its own configuration namespace, `dpm_get_resolved_module_path` to learn where modules live, `dpm_core_version` to learn the library's version, `dpm_set_last_error` to record why it failed, `dpm_set_result` to return data to its caller. A module needs no file handling and no logging machinery of its own.
|
||||
|
||||
## How a Module Reaches Another Module
|
||||
|
||||
@@ -76,13 +78,16 @@ int dpm_module_execute(dpm_ctx* ctx, const char* command, int argc, char** argv)
|
||||
dpm_log(ctx, DPM_LOG_ERROR, dpm_get_last_error(ctx));
|
||||
return 1;
|
||||
}
|
||||
return dpm_execute(ctx, peer, "somecommand", argc, argv);
|
||||
dpm_result result;
|
||||
int rc = dpm_execute(ctx, peer, "somecommand", argc, argv, &result);
|
||||
dpm_result_release(&result);
|
||||
return rc;
|
||||
}
|
||||
```
|
||||
|
||||
The `ctx` a module needs is the one handed to it in its own entry point, so it requires nothing else to reach the library.
|
||||
|
||||
**A module never links, includes, or hardcodes anything belonging to another module.** No peer headers, no shared struct layouts, no peer symbols. The only build dependency a module has is libdpm-core.so, and the only knowledge it holds about a peer is the peer's name and the command it wants to run. That is what allows every module to live in its own repository and be built with no peer present anywhere on the machine.
|
||||
**A module never links or hardcodes anything belonging to another module.** No peer symbols, no peer internals. The only build dependency a module has is libdpm-core.so. The knowledge it holds about a peer is the peer's name, the command it wants to run, and the layout of the payload that command returns, which the peer publishes as a header from its own repository. That is what allows every module to live in its own repository and be built with no peer present anywhere on the machine.
|
||||
|
||||
## What DPM Reads and Writes on Disk
|
||||
|
||||
@@ -113,7 +118,7 @@ The `ctx` a module needs is the one handed to it in its own entry point, so it r
|
||||
|
||||
A module is one `.so` in the module directory exporting four reserved symbols: a command entry point, its own version, a one-line description, and the alternate names it answers to. It includes `<dpm/core.h>` for those declarations and links `-ldpm-core`, and that is its entire build dependency.
|
||||
|
||||
The entry point receives the context that dispatched the call, the command name, and an argument vector, and returns an int. Everything a module offers the rest of the system is reachable through that one function, addressed by command name — which is what keeps a caller free of any compile-time knowledge of the module it is calling.
|
||||
The entry point receives the context that dispatched the call, the command name, and an argument vector, and returns an int. Data for the caller is handed to `dpm_set_result` before returning, in a layout the module documents for that command. Everything a module offers the rest of the system is reachable through that one function, addressed by command name.
|
||||
|
||||
A module is built against the system-installed `libdpm-core.so` and is responsible for being correct against it. Where it needs to know what it is running on, `dpm_core_version()` reports the running version and the module acts on that itself.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user