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.
53 lines
1.6 KiB
C++
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
|