@@ -122,47 +122,28 @@ static void dist_connection_dtor(ErlNifEnv *caller_env, void *obj)
122122 enif_demonitor_process (caller_env , conn_obj , & conn_obj -> connection_process_monitor );
123123 }
124124
125- // Collect monitors to demonitor outside the lock to avoid holding lock
126- // across potentially blocking enif_demonitor_process calls
127- struct ListHead monitors_to_free ;
128- list_init (& monitors_to_free );
129-
125+ // Must hold lock while calling enif_demonitor_process to prevent race
126+ // with dist_connection_down callback
130127 struct ListHead * remote_monitors = synclist_wrlock (& conn_obj -> remote_monitors );
131128 struct ListHead * item ;
132129 struct ListHead * tmp ;
133130 MUTABLE_LIST_FOR_EACH (item , tmp , remote_monitors ) {
134- list_remove (item );
135- list_append (& monitors_to_free , item );
136- }
137- synclist_unlock (& conn_obj -> remote_monitors );
138- synclist_destroy (& conn_obj -> remote_monitors );
139-
140- // Now demonitor and free outside the lock
141- MUTABLE_LIST_FOR_EACH (item , tmp , & monitors_to_free ) {
142131 struct RemoteMonitor * remote_monitor = GET_LIST_ENTRY (item , struct RemoteMonitor , head );
143132 enif_demonitor_process (caller_env , conn_obj , & remote_monitor -> process_monitor );
144133 list_remove (item );
145134 free (remote_monitor );
146135 }
147-
148- // Collect packets to free outside the lock
149- struct ListHead packets_to_free ;
150- list_init (& packets_to_free );
136+ synclist_unlock (& conn_obj -> remote_monitors );
137+ synclist_destroy (& conn_obj -> remote_monitors );
151138
152139 struct ListHead * pending_packets = synclist_wrlock (& conn_obj -> pending_packets );
153140 MUTABLE_LIST_FOR_EACH (item , tmp , pending_packets ) {
154- list_remove (item );
155- list_append (& packets_to_free , item );
156- }
157- synclist_unlock (& conn_obj -> pending_packets );
158- synclist_destroy (& conn_obj -> pending_packets );
159-
160- // Free packets outside the lock
161- MUTABLE_LIST_FOR_EACH (item , tmp , & packets_to_free ) {
162141 struct DistributionPacket * packet = GET_LIST_ENTRY (item , struct DistributionPacket , head );
163142 list_remove (item );
164143 free (packet );
165144 }
145+ synclist_unlock (& conn_obj -> pending_packets );
146+ synclist_destroy (& conn_obj -> pending_packets );
166147}
167148
168149static void dist_enqueue_message (term control_message , term payload , struct DistConnection * connection , GlobalContext * global )
0 commit comments