@@ -460,6 +460,53 @@ int pqipersongrp::removePeer(const RsPeerId& id)
460460 return 1 ;
461461}
462462
463+ int pqipersongrp::fullstopAllThreads ()
464+ {
465+ /* Stop every peer's network I/O threads at shutdown. Unlike removePeer() this
466+ * does NOT delete the persons, it only makes sure no pqithreadstreamer is left
467+ * running once RetroShare tears down its static objects (otherwise those
468+ * detached threads keep deserialising incoming packets and crash/flood the log
469+ * when the static SmallObject allocator and its mutex get destroyed).
470+ *
471+ * Two phases on purpose:
472+ * 1) while holding coreMtx, signal every peer to stop and close its sockets.
473+ * reset() calls askForStop() on the connection threads and closes the
474+ * sockets; both are non-blocking, so holding coreMtx here is safe (same as
475+ * removePeer()).
476+ * 2) release coreMtx, THEN wait for the threads to really stop.
477+ * We must NOT hold coreMtx while waiting: a peer thread that is delivering a
478+ * received item may still need coreMtx to queue a reply
479+ * (pqihandler::queueOutRsItem), so it would never finish and we would wait for
480+ * it forever -> deadlock. */
481+
482+ std::list<pqiperson *> persons;
483+
484+ {
485+ RsStackMutex stack (coreMtx); /* *************** LOCKED MUTEX ****************/
486+
487+ for (std::map<RsPeerId, SearchModule *>::iterator it = mods.begin (); it != mods.end (); ++it)
488+ {
489+ // mods also holds non-pqiperson interfaces (e.g. the pqiloopback for
490+ // our own node) which have no network I/O threads. Only pqiperson has
491+ // connection threads to stop, so skip anything that is not one -- a
492+ // blind cast would crash on the loopback.
493+ pqiperson *p = dynamic_cast <pqiperson *>(it->second ->pqi );
494+ if (!p)
495+ continue ;
496+ p -> stoplistening ();
497+ p -> reset (); // askForStop() the threads + close the sockets (non-blocking)
498+ persons.push_back (p);
499+ }
500+ }
501+
502+ // coreMtx released: peer threads that still need it can now make progress and
503+ // notice the stop request. Only now do we wait for them to actually stop.
504+ for (std::list<pqiperson *>::iterator it = persons.begin (); it != persons.end (); ++it)
505+ (*it) -> fullstopthreads (); // WAIT FOR THREADS TO STOP.
506+
507+ return 1 ;
508+ }
509+
463510int pqipersongrp::tagHeartbeatRecvd (const RsPeerId& id)
464511{
465512 std::map<RsPeerId, SearchModule *>::iterator it;
0 commit comments