@@ -124,6 +124,12 @@ buffer_manager_convert_buffer_to_read_only (
124124 EventPipeBufferManager * buffer_manager ,
125125 EventPipeBuffer * new_read_buffer );
126126
127+ static
128+ void
129+ buffer_manager_remove_and_delete_thread_session_state (
130+ EventPipeBufferManager * buffer_manager ,
131+ EventPipeThreadSessionState * thread_session_state );
132+
127133/*
128134 * EventPipeBufferList.
129135 */
@@ -258,6 +264,14 @@ ep_buffer_list_get_and_remove_head (EventPipeBufferList *buffer_list)
258264 return ret_buffer ;
259265}
260266
267+ bool
268+ ep_buffer_list_is_empty (const EventPipeBufferList * buffer_list )
269+ {
270+ EP_ASSERT (buffer_list != NULL );
271+ EP_ASSERT (ep_buffer_list_ensure_consistency ((EventPipeBufferList * )buffer_list ));
272+ return buffer_list -> head_buffer == NULL ;
273+ }
274+
261275bool
262276buffer_manager_try_reserve_buffer (
263277 EventPipeBufferManager * buffer_manager ,
@@ -701,6 +715,17 @@ buffer_manager_advance_to_non_empty_buffer (
701715
702716 // get the next buffer
703717 current_buffer = buffer_list -> head_buffer ;
718+
719+ if (!current_buffer && (ep_rt_volatile_load_uint32_t_without_barrier (ep_thread_get_unregistered_ref (ep_thread_session_state_get_thread (thread_session_state ))) > 0 )) {
720+ if (buffer_manager -> sequence_point_alloc_budget != 0 ) {
721+ // The next sequence point needs to update the sequence number for this thread
722+ // Delay the thread session state removal until the next sequence point is written.
723+ ep_thread_session_state_set_delete_deferred (thread_session_state , true);
724+ } else {
725+ buffer_manager_remove_and_delete_thread_session_state (buffer_manager , thread_session_state );
726+ }
727+ }
728+
704729 if (!current_buffer || ep_buffer_get_creation_timestamp (current_buffer ) >= before_timestamp ) {
705730 // no more buffers in the list before this timestamp, we're done
706731 current_buffer = NULL ;
@@ -1197,19 +1222,8 @@ ep_buffer_manager_write_all_buffers_to_file_v4 (
11971222
11981223 it = dn_list_it_next (it );
11991224
1200- // if a session_state was exhausted during this sequence point, mark it for deletion
1201- if (ep_thread_session_state_get_buffer_list (session_state )-> head_buffer == NULL ) {
1202- // We don't hold the thread lock here, so it technically races with a thread getting unregistered. This is okay,
1203- // because we will either not have passed the above if statement (there were events still in the buffers) or we
1204- // will catch it at the next sequence point.
1205- EventPipeThread * thread = ep_thread_session_state_get_thread (session_state );
1206- EventPipeSession * session = ep_thread_session_state_get_session (session_state );
1207- if (ep_rt_volatile_load_uint32_t_without_barrier (ep_thread_get_unregistered_ref (thread )) > 0 ) {
1208- dn_vector_ptr_push_back (& session_states_to_delete , session_state );
1209- dn_list_remove (buffer_manager -> thread_session_state_list , session_state );
1210- ep_thread_set_session_state (thread , session , NULL );
1211- }
1212- }
1225+ if (ep_thread_session_state_get_delete_deferred (session_state ))
1226+ dn_vector_ptr_push_back (& session_states_to_delete , session_state );
12131227 }
12141228 EP_SPIN_LOCK_EXIT (& buffer_manager -> rt_lock , section2 )
12151229
@@ -1218,35 +1232,12 @@ ep_buffer_manager_write_all_buffers_to_file_v4 (
12181232
12191233 // we are done with the sequence point
12201234 EP_SPIN_LOCK_ENTER (& buffer_manager -> rt_lock , section3 )
1221- buffer_manager_dequeue_sequence_point (buffer_manager );
1222- EP_SPIN_LOCK_EXIT (& buffer_manager -> rt_lock , section3 )
1223- }
1224-
1225- // There are sequence points created during this flush and we've marked session states for deletion.
1226- // We need to remove these from the internal maps of the subsequent Sequence Points
1227- if (dn_vector_ptr_size (& session_states_to_delete ) > 0 ) {
1228- EP_SPIN_LOCK_ENTER (& buffer_manager -> rt_lock , section4 )
1229- if (buffer_manager_try_peek_sequence_point (buffer_manager , & sequence_point )) {
1230- DN_LIST_FOREACH_BEGIN (EventPipeSequencePoint * , current_sequence_point , buffer_manager -> sequence_points ) {
1231- // foreach (session_state in session_states_to_delete)
1232- DN_VECTOR_PTR_FOREACH_BEGIN (EventPipeThreadSessionState * , thread_session_state , & session_states_to_delete ) {
1233- dn_umap_it_t found = dn_umap_ptr_uint32_find (ep_sequence_point_get_thread_sequence_numbers (current_sequence_point ), thread_session_state );
1234- if (!dn_umap_it_end (found )) {
1235- dn_umap_erase (found );
1236- // every entry of this map was holding an extra ref to the thread (see: ep-event-instance.{h|c})
1237- ep_thread_release (ep_thread_session_state_get_thread (thread_session_state ));
1238- }
1239- } DN_VECTOR_PTR_FOREACH_END ;
1240- } DN_LIST_FOREACH_END ;
1241- }
1242-
1243- // foreach (thread_session_state in session_states_to_delete)
12441235 DN_VECTOR_PTR_FOREACH_BEGIN (EventPipeThreadSessionState * , thread_session_state , & session_states_to_delete ) {
1245- EP_ASSERT ( thread_session_state != NULL );
1246- ep_thread_session_state_free ( thread_session_state );
1236+ if ( ep_thread_session_state_get_delete_deferred ( thread_session_state ))
1237+ buffer_manager_remove_and_delete_thread_session_state ( buffer_manager , thread_session_state );
12471238 } DN_VECTOR_PTR_FOREACH_END ;
1248-
1249- EP_SPIN_LOCK_EXIT (& buffer_manager -> rt_lock , section4 )
1239+ buffer_manager_dequeue_sequence_point ( buffer_manager );
1240+ EP_SPIN_LOCK_EXIT (& buffer_manager -> rt_lock , section3 )
12501241 }
12511242
12521243ep_on_exit :
@@ -1330,6 +1321,73 @@ ep_buffer_manager_ensure_consistency (EventPipeBufferManager *buffer_manager)
13301321}
13311322#endif
13321323
1324+ static
1325+ void
1326+ buffer_manager_remove_thread_session_state_from_sequence_points (
1327+ EventPipeBufferManager * buffer_manager ,
1328+ EventPipeThreadSessionState * thread_session_state )
1329+ {
1330+ EP_ASSERT (buffer_manager != NULL );
1331+ EP_ASSERT (thread_session_state != NULL );
1332+
1333+ ep_buffer_manager_requires_lock_held (buffer_manager );
1334+
1335+ DN_LIST_FOREACH_BEGIN (EventPipeSequencePoint * , current_sequence_point , buffer_manager -> sequence_points ) {
1336+ dn_umap_it_t found = dn_umap_ptr_uint32_find (ep_sequence_point_get_thread_sequence_numbers (current_sequence_point ), thread_session_state );
1337+ if (!dn_umap_it_end (found )) {
1338+ dn_umap_erase (found );
1339+ // buffer_manager_init_sequence_point_thread_list - every entry of this map was holding an extra ref to the thread
1340+ ep_thread_release (ep_thread_session_state_get_thread (thread_session_state ));
1341+ }
1342+ } DN_LIST_FOREACH_END ;
1343+ }
1344+
1345+ static
1346+ void
1347+ buffer_manager_remove_and_delete_thread_session_state (
1348+ EventPipeBufferManager * buffer_manager ,
1349+ EventPipeThreadSessionState * thread_session_state )
1350+ {
1351+ EP_ASSERT (buffer_manager != NULL );
1352+ EP_ASSERT (thread_session_state != NULL );
1353+
1354+ ep_buffer_manager_requires_lock_held (buffer_manager );
1355+
1356+ dn_list_remove (buffer_manager -> thread_session_state_list , thread_session_state );
1357+ ep_thread_set_session_state (ep_thread_session_state_get_thread (thread_session_state ), ep_thread_session_state_get_session (thread_session_state ), NULL );
1358+ buffer_manager_remove_thread_session_state_from_sequence_points (buffer_manager , thread_session_state );
1359+ ep_thread_session_state_free (thread_session_state );
1360+ }
1361+
1362+ void
1363+ ep_buffer_manager_remove_and_delete_thread_session_state (
1364+ EventPipeBufferManager * buffer_manager ,
1365+ EventPipeThreadSessionState * thread_session_state )
1366+ {
1367+ EP_ASSERT (buffer_manager != NULL );
1368+ EP_ASSERT (thread_session_state != NULL );
1369+
1370+ ep_buffer_manager_requires_lock_not_held (buffer_manager );
1371+
1372+ EP_SPIN_LOCK_ENTER (& buffer_manager -> rt_lock , section1 )
1373+ buffer_manager_remove_and_delete_thread_session_state (buffer_manager , thread_session_state );
1374+ EP_SPIN_LOCK_EXIT (& buffer_manager -> rt_lock , section1 )
1375+
1376+ ep_on_exit :
1377+ ep_buffer_manager_requires_lock_not_held (buffer_manager );
1378+ return ;
1379+
1380+ ep_on_error :
1381+ ep_exit_error_handler ();
1382+ }
1383+
1384+ bool
1385+ ep_buffer_manager_uses_sequence_points (const EventPipeBufferManager * buffer_manager )
1386+ {
1387+ EP_ASSERT (buffer_manager != NULL );
1388+ return buffer_manager -> sequence_point_alloc_budget != 0 ;
1389+ }
1390+
13331391#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */
13341392#endif /* ENABLE_PERFTRACING */
13351393
0 commit comments