mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-27 07:31:03 +08:00
Problem: sockets can be created after calling zmq_ctx_shutdown
Solution: fix handling of _starting and _terminate flags Add tests for this situation. Clarify documentation of zmq_ctx_shutdown and zmq_socket. Fixes #3792
This commit is contained in:
parent
349e3e21db
commit
36a8df2f8c
@ -19,7 +19,9 @@ The _zmq_ctx_shutdown()_ function shall shutdown the 0MQ context 'context'.
|
||||
Context shutdown will cause any blocking operations currently in progress on
|
||||
sockets open within 'context' to return immediately with an error code of ETERM.
|
||||
With the exception of _zmq_close()_, any further operations on sockets open within
|
||||
'context' shall fail with an error code of ETERM.
|
||||
'context' shall fail with an error code of ETERM. No further sockets can be created
|
||||
using _zmq_socket()_ on a context for which _zmq_ctx_shutdown()_ has been called,
|
||||
it will return and set errno to ETERM.
|
||||
|
||||
This function is optional, client code is still required to call the linkzmq:zmq_ctx_term[3]
|
||||
function to free all resources allocated by zeromq.
|
||||
|
@ -556,7 +556,7 @@ The provided 'context' is invalid.
|
||||
*EMFILE*::
|
||||
The limit on the total number of open 0MQ sockets has been reached.
|
||||
*ETERM*::
|
||||
The context specified was terminated.
|
||||
The context specified was shutdown or terminated.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
|
31
src/ctx.cpp
31
src/ctx.cpp
@ -232,16 +232,18 @@ int zmq::ctx_t::shutdown ()
|
||||
{
|
||||
scoped_lock_t locker (_slot_sync);
|
||||
|
||||
if (!_starting && !_terminating) {
|
||||
if (!_terminating) {
|
||||
_terminating = true;
|
||||
|
||||
// Send stop command to sockets so that any blocking calls
|
||||
// can be interrupted. If there are no sockets we can ask reaper
|
||||
// thread to stop.
|
||||
for (sockets_t::size_type i = 0; i != _sockets.size (); i++)
|
||||
_sockets[i]->stop ();
|
||||
if (_sockets.empty ())
|
||||
_reaper->stop ();
|
||||
if (!_starting) {
|
||||
// Send stop command to sockets so that any blocking calls
|
||||
// can be interrupted. If there are no sockets we can ask reaper
|
||||
// thread to stop.
|
||||
for (sockets_t::size_type i = 0; i != _sockets.size (); i++)
|
||||
_sockets[i]->stop ();
|
||||
if (_sockets.empty ())
|
||||
_reaper->stop ();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -471,17 +473,18 @@ zmq::socket_base_t *zmq::ctx_t::create_socket (int type_)
|
||||
{
|
||||
scoped_lock_t locker (_slot_sync);
|
||||
|
||||
if (unlikely (_starting)) {
|
||||
if (!start ())
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Once zmq_ctx_term() was called, we can't create new sockets.
|
||||
// Once zmq_ctx_term() or zmq_ctx_shutdown() was called, we can't create
|
||||
// new sockets.
|
||||
if (_terminating) {
|
||||
errno = ETERM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (unlikely (_starting)) {
|
||||
if (!start ())
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If max_sockets limit was reached, return error.
|
||||
if (_empty_slots.empty ()) {
|
||||
errno = EMFILE;
|
||||
|
@ -88,7 +88,46 @@ void test_ctx_shutdown ()
|
||||
// Close the socket.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));
|
||||
|
||||
// Destory the context, will now not hang as we have closed the socket.
|
||||
// Destroy the context, will now not hang as we have closed the socket.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));
|
||||
}
|
||||
|
||||
void test_ctx_shutdown_socket_opened_after ()
|
||||
{
|
||||
// Set up our context.
|
||||
void *ctx = zmq_ctx_new ();
|
||||
TEST_ASSERT_NOT_NULL (ctx);
|
||||
|
||||
// Open a socket to start context, and close it immediately again.
|
||||
void *socket = zmq_socket (ctx, ZMQ_PULL);
|
||||
TEST_ASSERT_NOT_NULL (socket);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));
|
||||
|
||||
// Shutdown context.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_shutdown (ctx));
|
||||
|
||||
// Opening socket should now fail.
|
||||
TEST_ASSERT_NULL (zmq_socket (ctx, ZMQ_PULL));
|
||||
TEST_ASSERT_FAILURE_ERRNO (ETERM, -1);
|
||||
|
||||
// Destroy the context.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));
|
||||
}
|
||||
|
||||
void test_ctx_shutdown_only_socket_opened_after ()
|
||||
{
|
||||
// Set up our context.
|
||||
void *ctx = zmq_ctx_new ();
|
||||
TEST_ASSERT_NOT_NULL (ctx);
|
||||
|
||||
// Shutdown context.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_shutdown (ctx));
|
||||
|
||||
// Opening socket should now fail.
|
||||
TEST_ASSERT_NULL (zmq_socket (ctx, ZMQ_PULL));
|
||||
TEST_ASSERT_FAILURE_ERRNO (ETERM, -1);
|
||||
|
||||
// Destroy the context.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));
|
||||
}
|
||||
|
||||
@ -201,6 +240,8 @@ int main (void)
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_ctx_destroy);
|
||||
RUN_TEST (test_ctx_shutdown);
|
||||
RUN_TEST (test_ctx_shutdown_socket_opened_after);
|
||||
RUN_TEST (test_ctx_shutdown_only_socket_opened_after);
|
||||
RUN_TEST (test_zmq_ctx_term_null_fails);
|
||||
RUN_TEST (test_zmq_term_null_fails);
|
||||
RUN_TEST (test_zmq_ctx_shutdown_null_fails);
|
||||
|
Loading…
x
Reference in New Issue
Block a user