Skip to content

Commit ac18cc9

Browse files
thaystgradical
andauthored
[wasm] [debugger] First version of multithreaded debugging (#74820)
* First version of multithreaded debugging. * Revert package-lock.json * New line at package-lock.json * Fix not used variable. * Fix debugger on firefox. * Rewrite code to avoid duplicated code. * Fix where mono_init_debugger_agent_common is called. * Remove whitespace. * Update src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs Co-authored-by: Ankit Jain <radical@gmail.com> * Update src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs Co-authored-by: Ankit Jain <radical@gmail.com> * Update src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs Co-authored-by: Ankit Jain <radical@gmail.com> * [wasm] Debugger tests: support running with multithreaded runtime * Add runtime-wasm-dbgtests pipeline with debugger tests running on a multi-threaded runtime * Add multi-threaded debugger tests to runtime-wasm * fix yml * Always run the new tests when the pipeline is invoked manually * Pass through extra build args for wasm debugger tests * Addressing @radical comments. * Apply suggestions from code review Co-authored-by: Ankit Jain <radical@gmail.com> * addressing radical comments * Fixing tests failures and adding a schema to run a test that will only run in a multithreaded environment. * Adding support for run debugger-tests in a multithreaded runtime. * Fix running debugger tests for multithreaded runtime, passing sessionId where it's necessary. * Fix CI. * Addressing @radical comments Adding a test case. * Update src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs Co-authored-by: Ankit Jain <radical@gmail.com> * Update src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs Co-authored-by: Ankit Jain <radical@gmail.com> * Update src/mono/wasm/debugger/DebuggerTestSuite/InspectorClient.cs Co-authored-by: Ankit Jain <radical@gmail.com> * Dictionary with the scriptId also uses sessionId. * Addressing @radical review. * Apply suggestions from code review Co-authored-by: Ankit Jain <radical@gmail.com> * Avoiding getting this error: Cannot transition thread 0x2a15360 from STATE_BLOCKING with DO_BLOCKING. In the transport_send we don't save the thread context, we save it before the send function. * Addressing @radical comments. * Using more threads in unit test. * Apply suggestions from code review Co-authored-by: Ankit Jain <radical@gmail.com> * Addressing @radical comments, and trying to fix ci. * Removing unnecessary changes. * Export function used on mini-wasm-debugger. * Fixing line number. * Fix run tests on release. * fix compilation for multithread runtime * trying to fix multithread debugger tests on ci * trying to fix debugger tests on ci * disabling tests on multithreaded runtime * Update eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml Co-authored-by: Ankit Jain <radical@gmail.com> * Throwing an exception if the "what" is not the one that is being get from the nextNotificationQueue. --------- Co-authored-by: Ankit Jain <radical@gmail.com>
1 parent d28e6ce commit ac18cc9

31 files changed

+414
-139
lines changed

eng/pipelines/common/templates/wasm-debugger-tests.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ parameters:
44
isWasmOnlyBuild: false
55
browser: 'chrome'
66
shouldContinueOnError: false
7+
extraBuildArgs: ''
8+
nameSuffix: ''
79
platforms: []
810

911
jobs:
@@ -30,8 +32,11 @@ jobs:
3032
jobParameters:
3133
testGroup: innerloop
3234
isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }}
33-
nameSuffix: Mono_DebuggerTests_${{ parameters.browser }}
34-
buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmDebuggerTests=true /p:TestAssemblies=false /p:BrowserHost=$(_hostedOs) /p:DebuggerHost=${{ parameters.browser }}
35+
${{ if eq(parameters.nameSuffix, '') }}:
36+
nameSuffix: Mono_DebuggerTests_${{ parameters.browser }}
37+
${{ else }}:
38+
nameSuffix: ${{ parameters.nameSuffix }}
39+
buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:TestWasmDebuggerTests=true /p:TestAssemblies=false /p:BrowserHost=$(_hostedOs) /p:DebuggerHost=${{ parameters.browser }} ${{ parameters.extraBuildArgs }}
3540
timeoutInMinutes: 180
3641
# if !alwaysRun, then:
3742
# if this is runtime-wasm (isWasmOnlyBuild):

eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ jobs:
9999
- WasmTestOnBrowser
100100
- WasmTestOnNodeJS
101101

102-
# Library tests with full threading
102+
# Library tests with full threading
103103
- template: /eng/pipelines/common/templates/wasm-library-tests.yml
104104
parameters:
105105
platforms:
@@ -212,6 +212,17 @@ jobs:
212212
# ff tests are unstable currently
213213
shouldContinueOnError: true
214214

215+
- template: /eng/pipelines/common/templates/wasm-debugger-tests.yml
216+
parameters:
217+
platforms:
218+
- Browser_wasm
219+
- Browser_wasm_win
220+
extraBuildArgs: /p:MonoWasmBuildVariant=multithread /p:WasmEnableThreads=true
221+
nameSuffix: DebuggerTests_MultiThreaded
222+
alwaysRun: ${{ parameters.isWasmOnlyBuild }}
223+
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
224+
isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }}
225+
215226
# Disable for now
216227
#- template: /eng/pipelines/coreclr/perf-wasm-jobs.yml
217228
#parameters:
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
trigger: none
2+
3+
variables:
4+
- template: /eng/pipelines/common/variables.yml
5+
6+
jobs:
7+
8+
#
9+
# Evaluate paths
10+
#
11+
- template: /eng/pipelines/common/evaluate-default-paths.yml
12+
13+
# Debugger tests
14+
- template: /eng/pipelines/common/templates/wasm-debugger-tests.yml
15+
parameters:
16+
platforms:
17+
- Browser_wasm
18+
- Browser_wasm_win
19+
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
20+
isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }}
21+
22+
- template: /eng/pipelines/common/templates/wasm-debugger-tests.yml
23+
parameters:
24+
platforms:
25+
- Browser_wasm
26+
- Browser_wasm_win
27+
extraBuildArgs: /p:MonoWasmBuildVariant=multithread /p:WasmEnableThreads=true
28+
nameSuffix: DebuggerTests_MultiThreaded
29+
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
30+
isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }}
31+
32+
- template: /eng/pipelines/common/templates/wasm-debugger-tests.yml
33+
parameters:
34+
platforms:
35+
- Browser_wasm_firefox
36+
browser: firefox
37+
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
38+
isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }}
39+
alwaysRun: ${{ parameters.isWasmOnlyBuild }}
40+
# ff tests are unstable currently
41+
shouldContinueOnError: true

src/mono/mono/component/debugger-agent.c

Lines changed: 45 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,6 @@ typedef struct {
323323
/*
324324
* Globals
325325
*/
326-
#ifdef TARGET_WASM
327-
static DebuggerTlsData debugger_wasm_thread;
328-
#endif
329326
static AgentConfig agent_config;
330327

331328
/*
@@ -414,7 +411,7 @@ static gint32 suspend_count;
414411
/* Whenever to buffer reply messages and send them together */
415412
static gboolean buffer_replies;
416413

417-
#ifndef TARGET_WASM
414+
418415
#define GET_TLS_DATA_FROM_THREAD(thread) \
419416
DebuggerTlsData *tls = NULL; \
420417
mono_loader_lock(); \
@@ -424,15 +421,6 @@ static gboolean buffer_replies;
424421
#define GET_DEBUGGER_TLS() \
425422
DebuggerTlsData *tls; \
426423
tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
427-
#else
428-
/* the thread argument is omitted on wasm, to avoid compiler warning */
429-
#define GET_TLS_DATA_FROM_THREAD(...) \
430-
DebuggerTlsData *tls; \
431-
tls = &debugger_wasm_thread;
432-
#define GET_DEBUGGER_TLS() \
433-
DebuggerTlsData *tls; \
434-
tls = &debugger_wasm_thread;
435-
#endif
436424

437425
#define GET_EXTRA_SPACE_FOR_REF_FIELDS(klass) \
438426
extra_space_size = 0; \
@@ -528,6 +516,8 @@ static void process_profiler_event (EventKind event, gpointer arg);
528516

529517
static void invalidate_frames (DebuggerTlsData *tls);
530518

519+
static void mono_init_debugger_agent_common (MonoProfilerHandle *prof);
520+
531521
/* Callbacks used by debugger-engine */
532522
static MonoContext* tls_get_restore_state (void *the_tls);
533523
static gboolean try_process_suspend (void *tls, MonoContext *ctx, gboolean from_breakpoint);
@@ -814,25 +804,13 @@ mono_debugger_agent_init_internal (void)
814804
mono_profiler_set_domain_loaded_callback (prof, appdomain_load);
815805
mono_profiler_set_domain_unloading_callback (prof, appdomain_start_unload);
816806
mono_profiler_set_domain_unloaded_callback (prof, appdomain_unload);
817-
mono_profiler_set_thread_started_callback (prof, thread_startup);
818-
mono_profiler_set_thread_stopped_callback (prof, thread_end);
819807
mono_profiler_set_assembly_loaded_callback (prof, assembly_load);
820808
mono_profiler_set_assembly_unloading_callback (prof, assembly_unload);
821-
mono_profiler_set_jit_done_callback (prof, jit_done);
822809
mono_profiler_set_jit_failed_callback (prof, jit_failed);
823810
mono_profiler_set_gc_finalizing_callback (prof, gc_finalizing);
824811
mono_profiler_set_gc_finalized_callback (prof, gc_finalized);
825812

826-
mono_native_tls_alloc (&debugger_tls_id, NULL);
827-
828-
/* Needed by the hash_table_new_type () call below */
829-
mono_gc_base_init ();
830-
831-
thread_to_tls = mono_g_hash_table_new_type_internal ((GHashFunc)mono_object_hash_internal, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger TLS Table");
832-
833-
tid_to_thread = mono_g_hash_table_new_type_internal (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Table");
834-
835-
tid_to_thread_obj = mono_g_hash_table_new_type_internal (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Object Table");
813+
mono_init_debugger_agent_common (&prof);
836814

837815
pending_assembly_loads = g_ptr_array_new ();
838816

@@ -852,7 +830,6 @@ mono_debugger_agent_init_internal (void)
852830
}
853831
mono_de_set_log_level (log_level, log_file);
854832

855-
ids_init ();
856833
objrefs_init ();
857834
suspend_init ();
858835

@@ -1636,6 +1613,31 @@ static GHashTable *obj_to_objref;
16361613
/* Protected by the dbg lock */
16371614
static MonoGHashTable *suspended_objs;
16381615

1616+
static void
1617+
mono_init_debugger_agent_common (MonoProfilerHandle *prof)
1618+
{
1619+
ids_init ();
1620+
1621+
event_requests = g_ptr_array_new ();
1622+
1623+
pending_assembly_loads = g_ptr_array_new ();
1624+
1625+
mono_profiler_set_thread_started_callback (*prof, thread_startup);
1626+
mono_profiler_set_thread_stopped_callback (*prof, thread_end);
1627+
mono_profiler_set_jit_done_callback (*prof, jit_done);
1628+
1629+
mono_native_tls_alloc (&debugger_tls_id, NULL);
1630+
1631+
/* Needed by the hash_table_new_type () call below */
1632+
mono_gc_base_init ();
1633+
1634+
thread_to_tls = mono_g_hash_table_new_type_internal ((GHashFunc)mono_object_hash_internal, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger TLS Table");
1635+
1636+
tid_to_thread = mono_g_hash_table_new_type_internal (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Table");
1637+
1638+
tid_to_thread_obj = mono_g_hash_table_new_type_internal (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Object Table");
1639+
}
1640+
16391641
#ifdef TARGET_WASM
16401642
void
16411643
mono_init_debugger_agent_for_wasm (int log_level_parm, MonoProfilerHandle *prof)
@@ -1646,23 +1648,17 @@ mono_init_debugger_agent_for_wasm (int log_level_parm, MonoProfilerHandle *prof)
16461648
int ntransports = 0;
16471649
DebuggerTransport *transports = mono_debugger_agent_get_transports (&ntransports);
16481650

1649-
ids_init();
16501651
objrefs = g_hash_table_new_full (NULL, NULL, NULL, mono_debugger_free_objref);
16511652
obj_to_objref = g_hash_table_new (NULL, NULL);
1652-
pending_assembly_loads = g_ptr_array_new ();
16531653

16541654
log_level = log_level_parm;
1655-
event_requests = g_ptr_array_new ();
1655+
16561656
vm_start_event_sent = TRUE;
16571657
transport = &transports [0];
16581658

1659-
memset(&debugger_wasm_thread, 0, sizeof(DebuggerTlsData));
1660-
mono_native_tls_alloc (&debugger_tls_id, NULL);
1661-
mono_native_tls_set_value (debugger_tls_id, &debugger_wasm_thread);
1662-
16631659
agent_config.enabled = TRUE;
16641660

1665-
mono_profiler_set_jit_done_callback (*prof, jit_done);
1661+
mono_init_debugger_agent_common (prof);
16661662
}
16671663

16681664
void
@@ -2255,14 +2251,17 @@ save_thread_context (MonoContext *ctx)
22552251
void
22562252
mono_wasm_save_thread_context (void)
22572253
{
2258-
debugger_wasm_thread.really_suspended = TRUE;
2259-
mono_thread_state_init_from_current (&debugger_wasm_thread.context);
2254+
DebuggerTlsData* tls = mono_wasm_get_tls ();
2255+
tls->really_suspended = TRUE;
2256+
mono_thread_state_init_from_current (&tls->context);
22602257
}
22612258

22622259
DebuggerTlsData*
22632260
mono_wasm_get_tls (void)
22642261
{
2265-
return &debugger_wasm_thread;
2262+
MonoThread *thread = mono_thread_current ();
2263+
GET_TLS_DATA_FROM_THREAD (thread);
2264+
return tls;
22662265
}
22672266
#endif
22682267

@@ -2855,7 +2854,11 @@ wait_for_suspend (void)
28552854
static gboolean
28562855
is_suspended (void)
28572856
{
2857+
#ifdef HOST_WASM
2858+
return true;
2859+
#else
28582860
return count_threads_to_wait_for () == 0;
2861+
#endif
28592862
}
28602863

28612864
static void
@@ -3762,6 +3765,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx
37623765

37633766
#ifdef TARGET_WASM
37643767
PRINT_DEBUG_MSG (1, "[%p] Sent %d events %s(%d), suspend=%d.\n", (gpointer) (gsize) mono_native_thread_id_get (), nevents, event_to_string (event), ecount, suspend_policy);
3768+
mono_wasm_save_thread_context();
37653769
#endif
37663770

37673771
send_success = send_packet (CMD_SET_EVENT, CMD_COMPOSITE, &buf);
@@ -3910,8 +3914,9 @@ thread_startup (MonoProfiler *prof, uintptr_t tid)
39103914
/*
39113915
* suspend_vm () could have missed this thread, so wait for a resume.
39123916
*/
3913-
3917+
#ifndef HOST_WASM
39143918
suspend_current_func ();
3919+
#endif
39153920
}
39163921

39173922
static void
@@ -9313,7 +9318,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
93139318

93149319
// Wait for suspending if it already started
93159320
// FIXME: Races with suspend_count
9316-
#ifndef HOST_WASI
9321+
#if !defined(HOST_WASI) && !defined(HOST_WASM)
93179322
while (!is_suspended ()) {
93189323
if (suspend_count)
93199324
wait_for_suspend ();
@@ -9498,9 +9503,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
94989503
int objid;
94999504
ErrorCode err;
95009505
MonoThread *thread_obj;
9501-
#ifndef TARGET_WASM
95029506
MonoInternalThread *thread;
9503-
#endif
95049507
int pos, i, len, frame_idx;
95059508
StackFrame *frame;
95069509
MonoDebugMethodJitInfo *jit;
@@ -9514,16 +9517,10 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
95149517
if (err != ERR_NONE)
95159518
return err;
95169519

9517-
#ifndef TARGET_WASM
95189520
thread = THREAD_TO_INTERNAL (thread_obj);
9519-
#endif
95209521
id = decode_id (p, &p, end);
95219522

9522-
#ifndef TARGET_WASM
95239523
GET_TLS_DATA_FROM_THREAD (thread);
9524-
#else
9525-
GET_TLS_DATA_FROM_THREAD ();
9526-
#endif
95279524
g_assert (tls);
95289525

95299526
for (i = 0; i < tls->frame_count; ++i) {

src/mono/mono/component/mini-wasm-debugger.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_send_dbg_command_with_parms (int id, Mdb
4141

4242

4343
//JS functions imported that we use
44-
extern void mono_wasm_fire_debugger_agent_message (void);
44+
extern void mono_wasm_fire_debugger_agent_message_with_data (const char *data, int len);
4545
extern void mono_wasm_asm_loaded (const char *asm_name, const char *assembly_data, guint32 assembly_len, const char *pdb_data, guint32 pdb_len);
4646

4747
G_END_DECLS
@@ -382,7 +382,7 @@ mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, i
382382
goto done;
383383
}
384384
MdbgProtBuffer bufWithParms;
385-
buffer_init (&bufWithParms, 128);
385+
m_dbgprot_buffer_init (&bufWithParms, 128);
386386
m_dbgprot_buffer_add_data (&bufWithParms, data, size);
387387
if (!write_value_to_buffer(&bufWithParms, valtype, newvalue)) {
388388
mono_wasm_add_dbg_command_received(0, id, 0, 0);
@@ -410,11 +410,11 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command,
410410
}
411411
ss_calculate_framecount (NULL, NULL, TRUE, NULL, NULL);
412412
MdbgProtBuffer buf;
413-
buffer_init (&buf, 128);
414413
gboolean no_reply;
415414
MdbgProtErrorCode error = 0;
416415
if (command_set == MDBGPROT_CMD_SET_VM && command == MDBGPROT_CMD_VM_INVOKE_METHOD )
417416
{
417+
m_dbgprot_buffer_init (&buf, 128);
418418
DebuggerTlsData* tls = mono_wasm_get_tls ();
419419
InvokeData invoke_data;
420420
memset (&invoke_data, 0, sizeof (InvokeData));
@@ -426,6 +426,7 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command,
426426
char* assembly_name = m_dbgprot_decode_string (data, &data, data + size);
427427
if (assembly_name == NULL)
428428
{
429+
m_dbgprot_buffer_init (&buf, 128);
429430
m_dbgprot_buffer_add_int (&buf, 0);
430431
m_dbgprot_buffer_add_int (&buf, 0);
431432
}
@@ -435,16 +436,20 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command,
435436
int symfile_size = 0;
436437
const unsigned char* assembly_bytes = mono_wasm_get_assembly_bytes (assembly_name, &assembly_size);
437438
const unsigned char* pdb_bytes = mono_get_symfile_bytes_from_bundle (assembly_name, &symfile_size);
439+
m_dbgprot_buffer_init (&buf, assembly_size + symfile_size);
438440
m_dbgprot_buffer_add_byte_array (&buf, (uint8_t *) assembly_bytes, assembly_size);
439441
m_dbgprot_buffer_add_byte_array (&buf, (uint8_t *) pdb_bytes, symfile_size);
440442
}
441443
}
442444
else
445+
{
446+
m_dbgprot_buffer_init (&buf, 128);
443447
error = mono_process_dbg_packet (id, command_set, command, &no_reply, data, data + size, &buf);
448+
}
444449

445450
mono_wasm_add_dbg_command_received (error == MDBGPROT_ERR_NONE, id, buf.buf, buf.p-buf.buf);
446451

447-
buffer_free (&buf);
452+
m_dbgprot_buffer_free (&buf);
448453
result = TRUE;
449454
done:
450455
MONO_EXIT_GC_UNSAFE;
@@ -454,9 +459,7 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command,
454459
static gboolean
455460
receive_debugger_agent_message (void *data, int len)
456461
{
457-
mono_wasm_add_dbg_command_received(1, 0, data, len);
458-
mono_wasm_save_thread_context();
459-
mono_wasm_fire_debugger_agent_message ();
462+
mono_wasm_fire_debugger_agent_message_with_data ((const char*)data, len);
460463
return FALSE;
461464
}
462465

0 commit comments

Comments
 (0)