18 Feb 2026
timo uhhh I thought there's an ID? 14:01
for breakpoint hit notifications it uses the ID of your breakpoint set request 14:02
StepCompleted behaves similarly 14:03
thread list response should also use the id from the thread list request
patrickb I can correlate the response to the request. 14:04
timo oh, you mean from one response to another things can change, and then after the response things can change further?
you never know when the results from some request get invalidated? 14:05
patrickb Yes. Specifically when I asynchronously receive two responses (e.g. a frame dump and a break point notification also containing a frame dump) and they disagree I can't know which one is fresh. 14:09
If they had an absolute ordering, I could discard any chunk of data for which I already received a state with a higher order no. 14:10
Or is there already an ordering guarantee simply by the order in which I receive the events over the wire? 14:11
(Not entirely sure, but I think I've seen that not be the case. Test scenario was: Suspend_all, set_breakpoint, resume_all, thread_list, breakpoint_hit_response, thread_list_response (this last thread_list_response has the broken thread still as running)) 14:13
timo hm. a thread can only have its stack trace dumped when it's suspended, and access to sending on the socket is mutexed
by broken thread you mean suspended?
patrickb yes
gets suspendend by the breakpoint
timo here's where MDS_PROTOCOL may be actually insightful 14:14
btw do you keep all these tests you do around in a relatively easy-to-reproduce form? would be great to get more tests for the debugserver feature 14:17
patrickb Maybe. But I strongly suspect it's an undefinedness in the protocol itself.
I don't. This is on the go stuff happening while I click around in the UI :-P 14:18
timo aw 14:19
did you see the test cases in the MoarVM::Remote module?
I've built a little "interpreter" for test scenarios 14:20
patrickb I didn't yet. I'll have a look.
Are thread IDs immutable? 14:21
timo I believe we dole them out from a central counter when a thread is created and don't change them afterwards 14:22
patrickb cool
patrickb learned a new word 14:23
timo > child_tc->thread_id = 1 + MVM_incr(&tc->instance->next_user_thread_id);
patrickb probably unrelated, but github.com/MoarVM/MoarVM/blob/main...ver.c#L711 this MVM_cas looks wrongly used (it doesn't compare to the old value) 14:47
timo oh, I think you're right 15:41
patrickb github.com/MoarVM/MoarVM/blob/main...ate.c#L260 <- Is this safe? (it doesn't validate if the swap worked) 15:45
The thread that refuses to step has a gc_status of 15, i.e. 00001111, i.e. SUSPENDED|SUSPEND_REQUEST|STOLEN 15:46
timo > 13 years ago
> full code audit of all atomics usage
stollen! but it's not anywhere near christmas!
patrickb wait, is stolen meant to be a superset of unable? 15:48
timo i'm thinking when a thread suspends it should be clearing its suspend request, but "stolen" is what happens when a thread is blocked when a GC run starts, so it wouldn't have done the state transition itself
patrickb I.e. can STOLEN be treated as UNABLE? 15:49
timo yeah, "mark thread blocked" sets "unable", when a GC run then starts the orchestrator thread will transition it to "stolen"
with just a very quick think, yes 15:50
patrickb Hm. Still fishy. How can it end up with SUSPENDED|SUSPEND_REQUEST? Also why doesn't the STOLEN turn back to UNABLE after the GC finishes? 15:55
It's pretty repeatable btw...
Ow. SUSPEND_REQUEST = 12, SUSPENDED = 4, so SUSPEND_REQUEST is actually a superset of SUSPENDED. 15:57
timo you have to mask it out 15:58
I think the two cas that don't check the result value could very well be the problem, they don't take suspend requesds into account at all 15:59
so if the stolen thread has the request bit set or is even marked suspended, it wouldn't go back to unable, then it can't resume itself properly when mark_thread_unblocked happens
does that sound about right?
patrickb Sounds about right. Is there some reason that code in question can safely assume it can change that field unchecked? 16:05
timo it's the orchestrator thread, all other threads are assumed to not be doing anything at that point
patrickb But the debugger thread still can? 16:06
So got the assumption broken by the introduction of the debugger thread?
timo ah, yeah 16:07
patrickb A first quick change seems to make it work. 16:47