int nn_close (int s) { int rc; NN_BASIC_CHECKS; /* TODO: nn_sock_term can take a long time to accomplish. It should not be performed under global critical section. */ nn_glock_lock (); /* Deallocate the socket object. */ rc = nn_sock_term (self.socks [s]); if (nn_slow (rc == -EINTR)) { errno = EINTR; return -1; } /* Remove the socket from the socket table, add it to unused socket table. */ nn_free (self.socks [s]); self.socks [s] = NULL; self.unused [NN_MAX_SOCKETS - self.nsocks] = s; --self.nsocks; /* Destroy the global context if there's no socket remaining. */ nn_global_term (); nn_glock_unlock (); return 0; }
int nn_close (int s) { int rc; struct nn_sock *sock; nn_glock_lock (); rc = nn_global_hold_socket_locked (&sock, s); if (nn_slow (rc < 0)) { nn_glock_unlock (); errno = -rc; return -1; } /* Start the shutdown process on the socket. This will cause all other socket users, as well as endpoints, to begin cleaning up. This is done with the glock held to ensure that two instances of nn_close can't access the same socket. */ nn_sock_stop (sock); /* We have to drop both the hold we just acquired, as well as the original hold, in order for nn_sock_term to complete. */ nn_sock_rele (sock); nn_sock_rele (sock); nn_glock_unlock (); /* Now clean up. The termination routine below will block until all other consumers of the socket have dropped their holds, and all endpoints have cleanly exited. */ rc = nn_sock_term (sock); if (nn_slow (rc == -EINTR)) { nn_global_rele_socket (sock); errno = EINTR; return -1; } /* Remove the socket from the socket table, add it to unused socket table. */ nn_glock_lock (); self.socks [s] = NULL; self.unused [NN_MAX_SOCKETS - self.nsocks] = s; --self.nsocks; nn_free (sock); /* Destroy the global context if there's no socket remaining. */ nn_global_term (); nn_glock_unlock (); return 0; }