sp_close waits for endpoints termination

Signed-off-by: Martin Sustrik <sustrik@250bpm.com>
diff --git a/src/core/ctx.c b/src/core/ctx.c
index 46e9f8f..259963f 100644
--- a/src/core/ctx.c
+++ b/src/core/ctx.c
@@ -335,21 +335,16 @@
 {
     SP_BASIC_CHECKS;
 
-    sp_mutex_lock (&self.sync);
-
     /*  Deallocate the socket object. */
-    sp_sock_close (self.socks [s]);
-
-    /*  sp_sock_close may actually deallocate the socket. Do not use the
-        pointer anymore. */
-    self.socks [s] = NULL;
+    sp_sock_term (self.socks [s]);
 
     /*  If there's sp_term() waiting for all sockets being closed and this is
         the last open socket let library termination proceed. */
+    sp_mutex_lock (&self.sync);
+    self.socks [s] = NULL;
     --self.nsocks;
     if (self.zombie && self.nsocks == 0)
         sp_cond_post (&self.termcond);
-
     sp_mutex_unlock (&self.sync);
 
     return 0;
diff --git a/src/core/sock.c b/src/core/sock.c
index 507c46e..498629d 100644
--- a/src/core/sock.c
+++ b/src/core/sock.c
@@ -32,9 +32,6 @@
 #define SP_SOCK_EVENT_IN 1
 #define SP_SOCK_EVENT_OUT 2
 
-/*  Private functions. */
-static void sp_sockbase_destroy (struct sp_sockbase *self);
-
 void sp_sockbase_init (struct sp_sockbase *self,
     const struct sp_sockbase_vfptr *vfptr, int fd)
 {
@@ -67,15 +64,18 @@
     sp_cp_unlock (&sockbase->cp);
 }
 
-void sp_sock_close (struct sp_sock *self)
+void sp_sock_term (struct sp_sock *self)
 {
+    int rc;
     struct sp_sockbase *sockbase;
     struct sp_list_item *it;
     struct sp_epbase *ep;
 
     sockbase = (struct sp_sockbase*) self;
 
-    /*  Ask all the associated endpoints to terminate. Call to close(ep) can
+    sp_cp_lock (&sockbase->cp);
+
+    /*  Ask all the associated endpoints to terminate. Call to sp_ep_close can
         actually deallocate the endpoint, so take care to get pointer to the
         next endpoint before the call. */
     it = sp_list_begin (&sockbase->eps);
@@ -85,27 +85,30 @@
         sp_ep_close ((void*) ep);       
     }
 
-    /*  If there are no active endpoints we can deallocate the socket
-        straight away. */
-    if (sp_list_empty (&sockbase->eps)) {
-        sp_sockbase_destroy (sockbase);
-        return;
+    while (1) {
+
+        /*  If there are no active endpoints we can deallocate the socket
+            straight away. */
+        if (sp_list_empty (&sockbase->eps)) {
+
+            /*  Terminate the sp_sockbase itself. */
+            sp_cp_unlock (&sockbase->cp);
+            sp_list_term (&sockbase->eps);
+            sp_clock_term (&sockbase->clock);
+            sp_cond_term (&sockbase->cond);
+            sp_cp_term (&sockbase->cp);
+
+            /*  Deallocate the derived class. */
+            sockbase->vfptr->destroy (sockbase);
+
+            return;
+        }
+
+        /*  Wait till all the endpoints are closed. */
+        sp_cond_set_timeout (&sockbase->cond, -1);
+        rc = sp_cond_wait (&sockbase->cond, &sockbase->cp.sync);
+        errnum_assert (rc == 0, rc);
     }
-
-    /*  Mark the socket as in process of terminating. */
-    sockbase->flags |= SP_SOCK_FLAG_CLOSED;
-}
-
-static void sp_sockbase_destroy (struct sp_sockbase *self)
-{
-    /*  Terminate the sp_sockbase itself. */
-    sp_list_term (&self->eps);
-    sp_clock_term (&self->clock);
-    sp_cond_term (&self->cond);
-    sp_cp_term (&self->cp);
-
-    /*  Deallocate the derived class. */
-    self->vfptr->destroy (self);
 }
 
 void sp_sockbase_unblock_recv (struct sp_sockbase *self)
@@ -350,10 +353,10 @@
     /*  Remove the endpoint from the list of active endpoints. */
     sp_list_erase (&sockbase->eps, &ep->item);
 
-    /*  When last endpoint terminates, socket can be deallocated as well. */
-    if ((sockbase->flags & SP_SOCK_FLAG_CLOSED) &&
-          sp_list_empty (&sockbase->eps))
-        sp_sockbase_destroy (sockbase);
+    /*  sp_close() may be waiting for termination of this endpoint.
+        Send it a signal. */
+    if (sp_list_empty (&sockbase->eps))
+        sp_cond_post (&sockbase->cond);
 }
 
 int sp_sock_send (struct sp_sock *self, const void *buf, size_t len, int flags)
diff --git a/src/core/sock.h b/src/core/sock.h
index e17d6a2..ac93159 100644
--- a/src/core/sock.h
+++ b/src/core/sock.h
@@ -31,7 +31,7 @@
 void sp_sock_zombify (struct sp_sock *self);
 
 /*  Called by sp_close(). */
-void sp_sock_close (struct sp_sock *self);
+void sp_sock_term (struct sp_sock *self);
 
 /*  Returns default completion port associated with the socket. */
 struct sp_cp *sp_sock_getcp (struct sp_sock *self);
diff --git a/src/protocol.h b/src/protocol.h
index b6a3aa3..e84d8ff 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -66,7 +66,6 @@
 };
 
 #define SP_SOCK_FLAG_ZOMBIE 1
-#define SP_SOCK_FLAG_CLOSED 2
 
 struct sp_sockbase
 {