Skip to content

Commit 4b9892e

Browse files
Guard against a deadlock with an assertion
1 parent 486bb7f commit 4b9892e

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

src/common/common-thread-private.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ BSON_BEGIN_DECLS
3737
#define BSON_ONCE_INIT PTHREAD_ONCE_INIT
3838
#define bson_once pthread_once
3939
#define bson_once_t pthread_once_t
40-
#define bson_thread_t pthread_t
4140
#define BSON_THREAD_FUN(_function_name, _arg_name) \
4241
void *(_function_name) (void *(_arg_name))
4342
#define BSON_THREAD_FUN_TYPE(_function_name) void *(*(_function_name)) (void *)
@@ -57,6 +56,24 @@ BSON_BEGIN_DECLS
5756
#define bson_mutex_t pthread_mutex_t
5857
#define bson_mutex_unlock pthread_mutex_unlock
5958

59+
#ifdef _WIN32
60+
typedef DWORD bson_thread_t;
61+
#elif defined(BSON_OS_UNIX)
62+
typedef pthread_t bson_thread_t;
63+
#else
64+
typedef void bson_thread_t;
65+
#endif
66+
67+
/**
68+
* @brief Get the numeric ID of the calling thread
69+
*/
70+
static BSON_INLINE bson_thread_t
71+
bson_current_thread_id ()
72+
{
73+
BSON_IF_POSIX (return pthread_self ();)
74+
BSON_IF_WINDOWS (return GetCurrentThreadId ();)
75+
}
76+
6077
#else
6178
typedef struct {
6279
pthread_t lock_owner;
@@ -105,9 +122,9 @@ typedef struct {
105122
#define bson_once_t INIT_ONCE
106123
#define bson_thread_t HANDLE
107124
#define BSON_THREAD_FUN(_function_name, _arg_name) \
108-
unsigned(__stdcall _function_name) (void *(_arg_name))
125+
unsigned (__stdcall _function_name) (void *(_arg_name))
109126
#define BSON_THREAD_FUN_TYPE(_function_name) \
110-
unsigned(__stdcall * _function_name) (void *)
127+
unsigned (__stdcall * _function_name) (void *)
111128
#define BSON_THREAD_RETURN return
112129
#endif
113130

src/libmongoc/src/mongoc/mongoc-topology-private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ typedef struct _mongoc_topology_t {
180180
* topology. This could occur if the URI is invalid.
181181
* An invalid topology does not monitor servers. */
182182
bool valid;
183+
184+
/* Track the thread with a pending topology description modification */
185+
int _current_modifying_thread;
183186
} mongoc_topology_t;
184187

185188
mongoc_topology_t *

src/libmongoc/src/mongoc/mongoc-topology.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ mongoc_topology_new (const mongoc_uri_t *uri, bool single_threaded)
346346
topology->server_selection_try_once = false;
347347
}
348348

349+
topology->_current_modifying_thread = -1;
350+
349351
topology->server_selection_timeout_msec = mongoc_uri_get_option_as_int32 (
350352
topology->uri,
351353
MONGOC_URI_SERVERSELECTIONTIMEOUTMS,
@@ -1969,7 +1971,19 @@ mc_tpld_modify_begin (mongoc_topology_t *tpl)
19691971
{
19701972
mc_shared_tpld prev_td;
19711973
mongoc_topology_description_t *new_td;
1974+
int modifier_thread = bson_atomic_int_fetch (&tpl->_current_modifying_thread,
1975+
bson_memory_order_relaxed);
1976+
int cur_thread = (int) bson_current_thread_id ();
1977+
/* If the same thread attempts to perform a modification while a modification
1978+
* is already in progress on the same thread, that would deadlock and is an
1979+
* inherent bug */
1980+
BSON_ASSERT (
1981+
modifier_thread != cur_thread &&
1982+
"Attempted to begin recursive modification of topology description");
19721983
bson_mutex_lock (&tpl->tpld_modification_mtx);
1984+
bson_atomic_int_exchange (&tpl->_current_modifying_thread,
1985+
(int) bson_current_thread_id (),
1986+
bson_memory_order_relaxed);
19731987
prev_td = mc_tpld_take_ref (tpl);
19741988
new_td = mongoc_topology_description_new_copy (prev_td.ptr),
19751989
mc_tpld_drop_ref (&prev_td);
@@ -1986,13 +2000,17 @@ mc_tpld_modify_commit (mc_tpld_modification mod)
19862000
mongoc_shared_ptr_create (mod.new_td, _topo_descr_destroy_and_free);
19872001
mongoc_atomic_shared_ptr_store (&mod.topology->_shared_descr_._sptr_,
19882002
new_sptr);
2003+
bson_atomic_int_exchange (
2004+
&mod.topology->_current_modifying_thread, -1, bson_memory_order_relaxed);
19892005
bson_mutex_unlock (&mod.topology->tpld_modification_mtx);
19902006
mongoc_shared_ptr_reset_null (&new_sptr);
19912007
}
19922008

19932009
void
19942010
mc_tpld_modify_drop (mc_tpld_modification mod)
19952011
{
2012+
bson_atomic_int_exchange (
2013+
&mod.topology->_current_modifying_thread, -1, bson_memory_order_relaxed);
19962014
bson_mutex_unlock (&mod.topology->tpld_modification_mtx);
19972015
mongoc_topology_description_destroy (mod.new_td);
19982016
}

0 commit comments

Comments
 (0)