ish-app / ish

Linux shell for iOS
https://ish.app
Other
16.8k stars 881 forks source link

Signal seem not processed until a syscall occurs #1510

Open francoisvignon opened 3 years ago

francoisvignon commented 3 years ago

Hello.

It seem no signal will be processed when running code not calling some syscall. as example, the following code C:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>

void DoSig(int sig)
{
  printf("Sig %d\n", sig);
  exit(0);
}

int main(int co, char **va)
{
        int x;
        signal(SIGALRM, DoSig);
        alarm(1);
        x = 0;
        for(x = 0 ; x<200000000 ; x++) // value sufficient to use more one second to run without printf
        {
                x ++;
                printf("x=%d\n",x);
        }
        printf("Done\n");
        return(0);
}

work fine and show "Sig 14" more or less 1 second after starting, and the code can be interrupted by a ^C, normal life...

but if you comment the inner printf(), like // printf(...), no signal will be processed (nore signal nor interrupt) until the sycall made at the end of the loop by printf and Done was output: at this time, the signal 14 is well processed.

maybe is a "normal way" of work by the iSh cpu emulator, maybe not ... if normal, ok, I will live with that ;-)

test.c.txt

saagarjha commented 3 years ago

Yes, this is a somewhat unfortunate limitation of the iSH interpreter loop. Here's the relevant code:

https://github.com/ish-app/ish/blob/5b5c4e9a7d72f3e6ef6dab66c2ea13102a5947ae/jit/jit.c#L231

As an optimization, we decode "blocks" of x86 code at once and direct thread them through our gadgets, during which time we will continue execution until a synchronous interrupt occurs-a system call, or memory access violation, for example. When this happens we hand back control to the interpreter loop for it to handle as necessary. One side effect of this is that we have removed our updates of the cycle counter from each individual instruction, and instead we only increment it whenever the threaded code exits to the interpreter. For most applications this is fine because they will eventually perform a system call and allow us to update their timer, but for hot loops like the one you've constructed there isn't a chance to do this. This causes a variety of subtle problems in corner cases such as the one you've described and it's certainly something we would like to fix, but it would require some rethinking of the emulator. We believe that it's something we'll get around to at some point, but can't commit to a timeline unfortunately.

francoisvignon commented 3 years ago

Many thanks for you answer. So, maybe, as a short fix, I can call a "don’t take too many time" syscall … like syscall(20), (getpid, seem fine) and call it sometime in my loop. if you have a better idea, your are welcome

Le 30 juil. 2021 à 12:09, Saagar Jha @.***> a écrit :

Yes, this is a somewhat unfortunate limitation of the iSH interpreter loop. Here's the relevant code:

https://github.com/ish-app/ish/blob/5b5c4e9a7d72f3e6ef6dab66c2ea13102a5947ae/jit/jit.c#L231 https://github.com/ish-app/ish/blob/5b5c4e9a7d72f3e6ef6dab66c2ea13102a5947ae/jit/jit.c#L231 As an optimization, we decode "blocks" of x86 code at once and direct thread them through our gadgets, during which time we will continue execution until a synchronous interrupt occurs-a system call, or memory access violation, for example. When this happens we hand back control to the interpreter loop for it to handle as necessary. One side effect of this is that we have removed our updates of the cycle counter from each individual instruction, and instead we only increment it whenever the threaded code exits to the interpreter. For most applications this is fine because they will eventually perform a system call and allow us to update their timer, but for hot loops like the one you've constructed there isn't a chance to do this. This causes a variety of subtle problems in corner cases such as the one you've described and it's certainly something we would like to fix, but it would require some rethinking of the emulator. We believe that it's something we'll get around to at some point, but can't commit to a timeline unfortunately.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ish-app/ish/issues/1510#issuecomment-889788906, or unsubscribe https://github.com/notifications/unsubscribe-auth/AK466USZQKFS76RXIAATXVLT2J26DANCNFSM5BIGIXXA.

francoisvignon commented 3 years ago

I close it ... any better idea than mine will be appreciate :-)

saagarjha commented 3 years ago

Yeah, that should hopefully be a functional workaround for now. You can keep this open if you'd like since the issue isn't actually fixed.

francoisvignon commented 3 years ago

ok ... I let it open ;-) thanks

allengrr commented 3 years ago

Envoyé de mon iPhone

Le 30 juil. 2021 à 05:53, francoisvignon @.***> a écrit :

Hello.

It seem no signal will be processed when running code not calling some syscall. as example, the following code C:

include

include

include

include

include

void DoSig(int sig) { printf("Sig %d\n", sig); exit(0); }

int main(int co, char **va) { int x; signal(SIGALRM, DoSig); alarm(1); x = 0; for(x = 0 ; x<200000000 ; x++) // value sufficient to use more one second to run without printf { x ++; printf("x=%d\n",x); } printf("Done\n"); return(0); } work fine and show "Sig 14" more or less 1 second after starting, and the code can be interrupted by a ^C, normal life...

but if you comment the inner printf(), like // printf(...), no signal will be processed (nore signal nor interrupt) until the sycall made at the end of the loop by printf and Done was output: at this time, the signal 14 is well processed.

maybe is a "normal way" of work by the iSh cpu emulator, maybe not ... if normal, ok, I will live with that ;-)

test.c.txt

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe.