From 953ca274ae57f8edd12536a3dd15d134aa6e5576 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Fri, 6 Jul 2018 14:42:53 -0700 Subject: fixes #568 Want a single reader/write lock on socket child objects fixes #170 Make more use of reaper This is a complete restructure/rethink of how child objects interact with the socket. (This also backs out #576 as it turns out not to be needed.) While 568 says reader/writer lock, for now we have settled for a single writer lock. Its likely that this is sufficient. Essentially we use the single socket lock to guard lists of the socket children. We also use deferred deletion in the idhash to facilitate teardown, which means endpoint closes are no longer synchronous. We use the reaper to clean up objects when the reference count drops to zero. We make a special exception for pipes, since they really are not reference counted by their parents, and they are leaf objects anyway. We believe this addresses the main outstanding race conditions in a much more correct and holistic way. Note that endpoint shutdown is a little tricky, as it makes use of atomic flags to guard against double entry, and against recursive lock entry. This is something that would be nice to make a bit more obvious, but what we have is safe, and the complexity is at least confined to one place. --- src/core/pipe.h | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) (limited to 'src/core/pipe.h') diff --git a/src/core/pipe.h b/src/core/pipe.h index 5c505514..1d73ce51 100644 --- a/src/core/pipe.h +++ b/src/core/pipe.h @@ -29,38 +29,11 @@ extern void nni_pipe_send(nni_pipe *, nni_aio *); // Pipe operations that protocols use. extern uint32_t nni_pipe_id(nni_pipe *); -// nni_pipe_destroy destroys a pipe -- there must not be any other -// references to it; this is used only during creation failures. -extern void nni_pipe_destroy(nni_pipe *); - // nni_pipe_close closes the underlying transport for the pipe. Further -// operations against will return NNG_ECLOSED. +// operations against will return NNG_ECLOSED. This is idempotent. The +// actual pipe will be reaped asynchronously. extern void nni_pipe_close(nni_pipe *); -// nni_pipe_stop is called to begin the process of tearing down the socket. -// This function runs asynchronously, and takes care to ensure that no -// other consumers are referencing the pipe. We assume that either the -// socket (protocol code) or endpoint may have references to the pipe -// when this function is called. The pipe cleanup is asynchronous and -// make take a while depending on scheduling, etc. The pipe lock itself -// may not be held during this, but any other locks may be. -extern void nni_pipe_stop(nni_pipe *); - -// nni_pipe_create is used only by endpoints - as we don't wish to expose the -// details of the pipe structure outside of pipe.c. This function must be -// called without any locks held, as it will call back up into the socket and -// endpoint, grabbing each of those locks. The function takes ownership of -// the transport specific pipe (3rd argument), regardless of whether it -// succeeds or not. The endpoint should be held when calling this. -extern int nni_pipe_create2(nni_pipe **, nni_sock *, nni_tran *, void *); -extern void nni_pipe_set_dialer(nni_pipe *, nni_dialer *); -extern void nni_pipe_set_listener(nni_pipe *, nni_listener *); - -// nni_pipe_start is called by the socket to begin any startup activities -// on the pipe before making it ready for use by protocols. For example, -// TCP and IPC initial handshaking is performed this way. -extern void nni_pipe_start(nni_pipe *); - extern uint16_t nni_pipe_proto(nni_pipe *); extern uint16_t nni_pipe_peer(nni_pipe *); @@ -73,14 +46,6 @@ extern int nni_pipe_getopt( // nni_pipe_set_proto_data function. No locking is performed. extern void *nni_pipe_get_proto_data(nni_pipe *); -// nni_pipe_sock_list_init initializes a list of pipes, to be used by -// a per-socket list. -extern void nni_pipe_sock_list_init(nni_list *); - -// nni_pipe_ep_list_init initializes a list of pipes, to be used by -// a per-endpoint list. -extern void nni_pipe_ep_list_init(nni_list *); - // nni_pipe_find finds a pipe given its ID. It places a hold on the // pipe, which must be released by the caller when it is done. extern int nni_pipe_find(nni_pipe **, uint32_t); -- cgit v1.2.3-70-g09d2