Files
pip/utils/cloud_dispatcher/dispatcherserver.h
andrey cc8e8644f1 fix(picloud-dispatcher): do not close/delete clients under map_mutex — deadlock
cleanClients() (timer thread) called close()/stopAndWait() and
disconnectClient() (read thread) did the same while holding
map_mutex, while client read threads wait for the same lock in
registerServer/registerClient/disconnectClient — a guaranteed
deadlock (the -w watchdog aborts exactly this). disconnectClient
could also wait for its own read thread (self-wait in
waitThreadedReadFinished) and the destructor never stopped the timer
or drained the clients, leaving dangling lambda captures of this.

Restructure around a single drainer (the timer thread):
- cleanClients: under map_mutex only mark (move rmrf_* out, mark
  ping-timeout/orphaned clients); after the unlock close
  (stopAndWait) and delete the connections, then delete the servers
- disconnectClient: only mark under the lock, then request a
  non-blocking stop() on the affected connections; the drainer waits
  and deletes (no self-wait, nothing blocks while holding the lock)
- newConnection: start the read thread after releasing the lock
- ~DispatcherServer: stop watchdog/timer first, then close and delete
  all clients before the servers (raw-pointer order) and eth

The watchdog is now a PIThread member so the destructor can stop it;
setMaxConnections takes map_mutex like its readers.
2026-08-23 17:18:03 +03:00

53 lines
1.6 KiB
C++

#ifndef DISPATCHERSERVER_H
#define DISPATCHERSERVER_H
#include "cloudserver.h"
#include "pithread.h"
#include "pitimer.h"
class TileList;
class DispatcherServer: public PIObject {
PIOBJECT(DispatcherServer)
public:
DispatcherServer(PINetworkAddress addr);
~DispatcherServer();
void start();
void updateConnectionsTile(TileList * tl);
void updateServersTile(TileList * tl, PISet<const DispatcherClient *> servers = PISet<const DispatcherClient *>());
void updateClientsTile(TileList * tl, PISet<const DispatcherClient *> servers = PISet<const DispatcherClient *>());
const DispatcherClient * getConnection(int index);
const DispatcherClient * getServer(int index);
PISet<const DispatcherClient *> getServers(PISet<int> ids);
void setMaxConnections(uint max_count);
uint maxConnections() const { return max_connections; }
EVENT_HANDLER0(void, picoutStatus);
void startWatchdog();
private:
EVENT_HANDLER1(void, newConnection, PIEthernet *, cl);
EVENT_HANDLER1(void, disconnectClient, DispatcherClient *, client);
EVENT_HANDLER0(void, cleanClients);
PIEthernet eth;
PIVector<DispatcherClient *> clients;
PIMap<PIByteArray, CloudServer *> c_servers;
PIMap<const DispatcherClient *, CloudServer *> index_c_servers;
PIMap<const DispatcherClient *, CloudServer *> index_c_clients;
PISet<DispatcherClient *> rm_clients;
PISet<DispatcherClient *> rmrf_clients;
PIVector<CloudServer *> rmrf_servers;
PITimer timeout_timer;
PIMutex map_mutex;
std::atomic_int wd_cnt = {0};
PIThread watchdog;
uint client_gid;
uint max_connections;
};
#endif // DISPATCHERSERVER_H