M2
M2 copied to clipboard
Keyword shield doesn't work
The documentation claims:
shield x -- executes the expression x, temporarily ignoring interrupts.
Unless I'm misunderstanding the page, which doesn't include any examples, shield
doesn't seem to be working:
i1 : f = t -> shield sleep t;
i2 : f 10
^Cstdio:2:1:(3): error: interrupted
i3 : f = t -> ( alarm 1; shield sleep t );
i4 : f 5
stdio:4:1:(3): error: alarm occurred
Yup, it seems that that doesn't work. Good catch.
The interrupt mechanism in the interpreter is pretty complicated, so I doubt this will be easy to do for a volunteer. The relevant code is in evaluate.d
and the most recent changes to it are from 13 years ago by you (there are no other contributors).
If this is still available, I'd love to take a swing at it!
I've assigned you, thanks for volunteering!
Of course, thanks so much!
Finally got to figuring out the issue here, my apologies for the delay!
This is what I've been able to surmise is happening during e.g. shield sleep 5
:
-
shieldfun
sets theinterruptShield
flag and executes thesleep 5
expression - the
sleep 5
expression in turn calls sleep(2) which suspends the thread - the SIGINT is received, waking the prompt thread and passing execution into
interrupt_handler
-
interrupt_handler
sees thatinterruptShield
is set, and correspondingly setsinterruptPending
- control then passes immediately back to
sleep(2)
, which passes control flow back toshieldfun
-
shieldfun
turns offinterruptShield
and storesinterruptPending
intointerruptFlag
-
evalraw
seesinterruptFlag
is set and gives the exception
The "core" issue here seems to just be that the sleep concludes immediately when SIGINT is received. There's two possible fixes I thought of--if either of them seem useful, I can write them up real quick and share a PR:
- Make both the
sleep
andnanosleep
keywords both use nanosleep(2) directly, saving the return value (atimespec
with the remaining amount of sleep time before the interrupt) somewhereinterrupt_handler
can access it, and havinginterrupt_handler
resume sleep if it sees that value set. - Change
sleep
andnanosleep
to manually mask signals before execution and unmask signals after.
Do either of these seem like a useful approach I should try implementing?
(Wanted to quickly follow up on this, in case it's still relevant--would either of these solutions help?)
Yes, I think it's definitely still relevant! I'm not sure which approach is better.
Are sleep
and nanosleep
the only things for which shield
isn't working? It seems to be doing the correct thing for engine computations.
I'll make a PR in that case!
I'm not sure if there's any other similar issues with shield
(I haven't seen any), but @mahrud would know better than me.
Change sleep and nanosleep to manually mask signals before execution and unmask signals after.
Wouldn't it be simpler to mask signals when shieldfun starts?
Hopefully this will cover shielding calls to external libraries as well.
That sounds like a better plan--will give that a shot :)