@@ -542,21 +542,59 @@ using ConnThread = ConnThreads::iterator;
542542// inserted bool.
543543std::tuple<ConnThread, bool > SetThread (ConnThreads& threads, std::mutex& mutex, Connection* connection, const std::function<Thread::Client()>& make_thread);
544544
545+ // ! The thread_local ThreadContext g_thread_context struct provides information
546+ // ! about individual threads and a way of communicating between them. Because
547+ // ! it's a thread local struct, each ThreadContext instance is initialized by
548+ // ! the thread that owns it.
549+ // !
550+ // ! ThreadContext is used for any client threads created externally which make
551+ // ! IPC calls, and for server threads created by
552+ // ! ProxyServer<ThreadMap>::makeThread() which execute IPC calls for clients.
553+ // !
554+ // ! In both cases, the struct holds information like the thread name, and a
555+ // ! Waiter object where the EventLoop can post incoming IPC requests to execute
556+ // ! on the thread. The struct also holds ConnThread maps associating the thread
557+ // ! with local and remote ProxyClient<Thread> objects.
545558struct ThreadContext
546559{
547560 // ! Identifying string for debug.
548561 std::string thread_name;
549562
550- // ! Waiter object used to allow client threads blocked waiting for a server
551- // ! response to execute callbacks made from the client's corresponding
552- // ! server thread.
563+ // ! Waiter object used to allow remote clients to execute code on this
564+ // ! thread. If this is a server thread created by
565+ // ! ProxyServer<ThreadMap>::makeThread(), it is initialized by that
566+ // ! function. Otherwise if this is a thread that was created externally,
567+ // ! this is just initialized the first time the thread tries to make an IPC
568+ // ! call. Having a waiter is necessary for threads making IPC calls in case
569+ // ! a server they are calling expects them to execute a callback during the
570+ // ! call, before it sends a response.
571+ // !
572+ // ! For IPC client threads, the Waiter pointer is never cleared and the Waiter
573+ // ! just gets destroyed when the thread does. For server threads created by
574+ // ! makeThread(), this pointer is set to null in the ~ProxyServer<Thread> as
575+ // ! a signal for the thread to exit and destroy itself. In both cases, the
576+ // ! same Waiter object is used across different calls and only created and
577+ // ! destroyed once for the lifetime of the thread.
553578 std::unique_ptr<Waiter> waiter = nullptr ;
554579
555580 // ! When client is making a request to a server, this is the
556581 // ! `callbackThread` argument it passes in the request, used by the server
557582 // ! in case it needs to make callbacks into the client that need to execute
558583 // ! while the client is waiting. This will be set to a local thread object.
559- ConnThreads callback_threads;
584+ // !
585+ // ! Synchronization note: The callback_thread and request_thread maps are
586+ // ! only ever accessed internally by this thread's destructor and externally
587+ // ! by Cap'n Proto event loop threads. Since it's possible for IPC client
588+ // ! threads to make calls over different connections that could have
589+ // ! different event loops, these maps are guarded by Waiter::m_mutex in case
590+ // ! different event loop threads add or remove map entries simultaneously.
591+ // ! However, individual ProxyClient<Thread> objects in the maps will only be
592+ // ! associated with one event loop and guarded by EventLoop::m_mutex. So
593+ // ! Waiter::m_mutex does not need to be held while accessing individual
594+ // ! ProxyClient<Thread> instances, and may even need to be released to
595+ // ! respect lock order and avoid locking Waiter::mutex before
596+ // ! EventLoop::mutex.
597+ ConnThreads callback_threads MP_GUARDED_BY (waiter->m_mutex);
560598
561599 // ! When client is making a request to a server, this is the `thread`
562600 // ! argument it passes in the request, used to control which thread on
@@ -565,6 +603,8 @@ struct ThreadContext
565603 // ! by makeThread. If a client call is being made from a thread currently
566604 // ! handling a server request, this will be set to the `callbackThread`
567605 // ! request thread argument passed in that request.
606+ // !
607+ // ! Synchronization note: \ref callback_threads note applies here as well.
568608 ConnThreads request_threads;
569609
570610 // ! Whether this thread is a capnp event loop thread. Not really used except
0 commit comments