fix: join the RNS loop thread before exit and keep the response slot per-request
This commit is contained in:
parent
39c4c4d6a5
commit
234b75651f
17 changed files with 84 additions and 11 deletions
|
|
@ -41,6 +41,10 @@ static RNS::Link active_link({RNS::Type::NONE});
|
|||
static microStore::FileSystem filesystem{microStore::Adapters::UniversalFileSystem()};
|
||||
|
||||
static volatile bool running = false;
|
||||
// Joinable, never detached: the loop thread must be joined by
|
||||
// smolmail_rns_stop before the process tears down statics, or it keeps
|
||||
// calling reticulum.loop() while their destructors run.
|
||||
static std::thread loop_thread;
|
||||
|
||||
// The single response slot (plan: one request in flight at a time).
|
||||
static std::mutex slot_mutex;
|
||||
|
|
@ -94,9 +98,11 @@ static void on_failed(const RNS::RequestReceipt& receipt) {
|
|||
slot_cv.notify_all();
|
||||
}
|
||||
|
||||
// The unwrapped large-response payload, filled in by smolmail_rns_request.
|
||||
static RNS::Bytes unwrapped;
|
||||
|
||||
// The unwrapped large-response payload, filled in per request below. It is
|
||||
// deliberately local: a static here kept the last resource-path response
|
||||
// alive past its request, so every later bare response -- an empty fetch
|
||||
// page, an ack -- was misread as that stale page and the client looped
|
||||
// FETCH/DELETE pairs forever.
|
||||
static void loop_thread_main() {
|
||||
while (running) {
|
||||
reticulum.loop();
|
||||
|
|
@ -139,7 +145,7 @@ extern "C" int smolmail_rns_start(const char* storage_dir,
|
|||
reticulum.start();
|
||||
|
||||
running = true;
|
||||
std::thread(loop_thread_main).detach();
|
||||
loop_thread = std::thread(loop_thread_main);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -256,6 +262,7 @@ extern "C" int smolmail_rns_request(const uint8_t* request, size_t request_len,
|
|||
// raw remainder to handle_response on that path). The wrapper is
|
||||
// unambiguous: a smolmail status is a single byte below 16, and the
|
||||
// msgpack bin headers are 0xC4..0xC6, so only those are unwrapped.
|
||||
RNS::Bytes unwrapped;
|
||||
const RNS::Bytes& payload = [&]() -> const RNS::Bytes& {
|
||||
if (slot_response.size() > 0 && slot_response.data()[0] >= 0xC4
|
||||
&& slot_response.data()[0] <= 0xC6) {
|
||||
|
|
@ -286,3 +293,23 @@ extern "C" void smolmail_rns_close(void) {
|
|||
active_link = RNS::Link({RNS::Type::NONE});
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void smolmail_rns_stop(void) {
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
// Order matters: halt and join the loop thread first, so nothing is
|
||||
// inside Reticulum, Transport or the filesystem while they are torn
|
||||
// down; only then take the link, the interface and the instance apart.
|
||||
running = false;
|
||||
if (loop_thread.joinable()) {
|
||||
loop_thread.join();
|
||||
}
|
||||
if (active_link) {
|
||||
active_link.teardown();
|
||||
active_link = RNS::Link({RNS::Type::NONE});
|
||||
}
|
||||
RNS::Transport::deregister_interface(udp_interface);
|
||||
udp_interface.stop();
|
||||
reticulum = RNS::Reticulum({RNS::Type::NONE});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,14 @@ int smolmail_rns_request(const uint8_t *request, size_t request_len,
|
|||
* minutes (upstream spec sec 13.10). */
|
||||
void smolmail_rns_close(void);
|
||||
|
||||
/* Stops the Reticulum stack: halts and joins the loop thread, tears the link
|
||||
* down, deregisters and stops the UDP interface, and releases the
|
||||
* Reticulum instance. The loop thread must be joined before the process (or
|
||||
* embedding host) tears down statics, or it keeps calling into Reticulum
|
||||
* while their destructors run. A no-op when the stack is not running.
|
||||
* The stack can be started again afterwards. */
|
||||
void smolmail_rns_stop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue