Skip to content

EebusService shutdown fix - #49

Open
gennadiyvt wants to merge 20 commits into
NIBEGroup:mainfrom
gennadiyvt:feature/eebus-service-shutdown-fix
Open

EebusService shutdown fix#49
gennadiyvt wants to merge 20 commits into
NIBEGroup:mainfrom
gennadiyvt:feature/eebus-service-shutdown-fix

Conversation

@gennadiyvt

Copy link
Copy Markdown
Contributor

No description provided.

…_ctx` before mutex/queue teardown

  `lws_context_destroy() may fire `LWS_CALLBACK_CLOSED` during teardown, which
  reaches callbacks that access the write mutex and queue. Moving the destroy
  before mutex/queue delete ensures those objects are still valid when the final callbacks fire.
  Setting `is_closed` first lets any callback that checks `WEBSOCKET_IS_CLOSED` bail out early.
… reschedule when `websocket` is no longer active

  `lws_sul_schedule() was called unconditionally, keeping the callback firing
  forever even after the websocket was gone. Move it inside the `ws != NULL`
  guard so it only reschedules while there is an active connection.
…et::Close()`

  `WebsocketClose()` can set `ws->wsi = NULL `from a different thread between the
  `NULL` check and `lws_write()`/`lws_callback_on_writable()`. Snapshot `wsi` into a local
  variable once at the start of the callback so all uses see a consistent value.
…n hang

  `HttpServer::ConnectionLoop()` held mutex for the entire `lws_service()`
  call and immediately re-acquired it, starving `HttpServer::UnbindWsi()` in
  `ShipConnection::Loop()` (`ShipConnection::Loop()` calls `HttpServer::UnbindWsi()` from
  `WebsocketServer::Close()`, blocking the connection close indefinitely)
… clear from `HttpServer::OnConnectionClose()`
…sDatagram()` crash

  `DeviceLocal::Stop()` was called after `ShipNodeStop()`, letting `ShipNode` free
  remote-device objects via `ShipNode::OnRemoteSkiDisconnected` while `DeviceLocal`'s loop
  thread was still alive and could dereference them in `DeviceLocal::ProcessDatagram()`.

  Swap to `DeviceLocal::Stop()` → `ShipNode::Stop()` so `DeviceLocal`'s thread is
  joined before ShipNode tears down the remote devices.
…e-initiated close

  `ShipConnection::DataExchangeHandleClose()` called `ShipConnection::HandleConnectionClosed()`
  but did not set `shutdown_once`, so the subsequent `ShipConnection::CloseConnection()`
  from `ShipConnection::Stop()` called it a second time with a dangling `sc` pointer.
  Mirror the `ShipConnection::CloseConnection()` tail: stop timers;
  set `cancel` and `shutdown_once` before `ShipConnection::HandleConnectionClosed()` so
  that the `ShipConnection::Stop()` path becomes a no-op
…leep as a known limitation

  The Announce path sleeps 500ms regardless of whether a Confirm arrives.
  Add a `TODO` noting that the correct fix is to dequeue and wait for
  `kConnectionClosePhaseTypeConfirm` with a 500ms timeout instead
…llbacks

  After `ShipNode::Stop()` sets `sn->cancel` and joins the connection thread,
  a `ShipConnection` close callback can still fire before `ShipNode::Destruct()` completes.
  Return early if `sn->cancel` is true to prevent a stale `ShipConnection`
  from being re-queued into an already-stopped node loop
  `ShipNode::ConnectionLoop()` may exit via `kCancel` before it processes a
  `kShipConnectionClosed` that arrived concurrently (e.g. during the 500 ms
  wait in `ShipConnection::DataExchangeHandleClose()`). Stop, disconnect, and delete the
  connection explicitly after joining the thread so `ShipNode::Destruct()` never encounters
  a live `ship_connection`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant