From: Jorge on 8 Feb 2010 10:48 Hello, I have a forked process that enters a loop like this: while (RUN) { //do nothing but burn the CPU } it also has a handler set for SIGALRM that just flips RUN to 0. Later on the parent sends it a kill(child, SIGALRM), and, the problem is that the sent SIGALRM signal is never handled -I don't know why- unless I put a sleep(0); inside the above loop. Why is this so ? Thanks in advance, -- Jorge.
From: Rainer Weikusat on 8 Feb 2010 10:55 Jorge <jorge(a)jorgechamorro.com> writes: > I have a forked process that enters a loop like this: > > while (RUN) { > //do nothing but burn the CPU > } > > it also has a handler set for SIGALRM that just flips RUN to 0. > > Later on the parent sends it a kill(child, SIGALRM), and, the problem > is that the sent SIGALRM signal is never handled -I don't know why- > unless I put a sleep(0); inside the above loop. > > Why is this so ? In absence of the code, one has to rely on guesswork and my guess would be 'the code in the loop doesn't touch RUN' and you haven't declared to be volatile, hence, the compiler transformed the actually executed code into something working like the pseudo-code below: if (RUN) while (1) burn_cpu();
From: Jorge on 8 Feb 2010 11:21 On Feb 8, 4:55 pm, Rainer Weikusat <rweiku...(a)mssgmbh.com> wrote: > Jorge <jo...(a)jorgechamorro.com> writes: > > I have a forked process that enters a loop like this: > > > while (RUN) { > > //do nothing but burn the CPU > > } > > > it also has a handler set for SIGALRM that just flips RUN to 0. > > > Later on the parent sends it a kill(child, SIGALRM), and, the problem > > is that the sent SIGALRM signal is never handled -I don't know why- > > unless I put a sleep(0); inside the above loop. > > > Why is this so ? > > In absence of the code, one has to rely on guesswork and my guess > would be 'the code in the loop doesn't touch RUN' and you haven't > declared to be volatile, hence, the compiler transformed the actually > executed code into something working like the pseudo-code below: > > if (RUN) while (1) burn_cpu(); Thanks. Here's the source. Removing the sleep(0) makes the loop an infinite loop... What do you think ? #define kMaxProcesos 8 int signalCtr= 0; int RUN= 1; pid_t children[kMaxProcesos]; void signalHandler (int status) { signalCtr++; } void alarmHandler (int status) { RUN= 0; } extern int main (int argc, char* argv[]) { long processNr= 0; int parentProc= getpid(); signal(SIGCHLD, signalHandler); signal(SIGALRM, alarmHandler); while (processNr < kMaxProcesos) { if(children[processNr] = fork()) { //parent processNr++; } else if (parentProc != getpid()) { //child fprintf(stdout, "PID (%i) %i: Hola !\r\n", processNr, getpid()); while (RUN) { sleep(0); //****** COMENTAR ESTA LINEA } fprintf(stdout, "PID (%i) %i: Adiós !\r\n", processNr, getpid()); return 0; } else { fprintf(stdout, "Pasa algo muy muy raro(%i)\r\n", processNr); } } int n; processNr= kMaxProcesos; while (processNr--) { n= signalCtr; kill(children[processNr], SIGALRM); while (n == signalCtr) { sleep(0); //****** COMENTAR ESTA LINEA } } fprintf(stdout, "BYE: %i fork()s, %i signals\r\n", kMaxProcesos, signalCtr); return 0; } Thanks in advance, -- Jorge.
From: Rainer Weikusat on 8 Feb 2010 12:58 Jorge <jorge(a)jorgechamorro.com> writes: > On Feb 8, 4:55�pm, Rainer Weikusat <rweiku...(a)mssgmbh.com> wrote: >> Jorge <jo...(a)jorgechamorro.com> writes: >> > I have a forked process that enters a loop like this: >> >> > while (RUN) { >> > � //do nothing but burn the CPU >> > } >> >> > it also has a handler set for SIGALRM that just flips RUN to 0. >> >> > Later on the parent sends it a kill(child, SIGALRM), and, the problem >> > is that the sent SIGALRM signal is never handled -I don't know why- >> > unless I put a sleep(0); inside the above loop. >> >> > Why is this so ? >> >> In absence of the code, one has to rely on guesswork and my guess >> would be 'the code in the loop doesn't touch RUN' and you haven't >> declared to be volatile, hence, the compiler transformed the actually >> executed code into something working like the pseudo-code below: >> >> � � � � if (RUN) while (1) burn_cpu(); > > Thanks. Here's the source. Removing the sleep(0) makes the loop an > infinite loop... What do you think ? [please see original for code] Exactly what I originally wrote. Accessing an object (as in while (RUN);) is considered to be free of side effects in the C-norm and because of this, a compiler may generate code with fewer accesses (that is, load operations) than what would be needed for a 'naive' translation if it can 'prove' that the value cannot have changed. Your code with the sleep commented out (I am only going to show this for the first loop) looks like this: ------------------ if(children[processNr] = fork()) { //parent processNr++; } else if (parentProc != getpid()) { //child fprintf(stdout, "PID (%i) %i: Hola !\r\n", processNr, getpid()); while (RUN); fprintf(stdout, "PID (%i) %i: Adi�s !\r\n", processNr, getpid()); return 0; ------------------ And when optimizing, gcc translates this to (x86) --------------------- 8048510: e8 ab fe ff ff call 80483c0 <fork(a)plt> 8048515: 85 c0 test %eax,%eax 8048517: 89 04 9d a0 98 04 08 mov %eax,0x80498a0(,%ebx,4) 804851e: 75 e8 jne 8048508 <main+0x48> ---------------------- fork, store the pid in the processNr array, compare fork return value with zero, jump to 8048508 when not zero ----------------------- 8048520: e8 4b fe ff ff call 8048370 <getpid(a)plt> 8048525: 39 c6 cmp %eax,%esi 8048527: 0f 85 8b 00 00 00 jne 80485b8 <main+0xf8> ---------------------- That's the (mostly redundant) parentProc check. If running in the child, jump to 80485b8: ---------------------- 80485b8: e8 b3 fd ff ff call 8048370 <getpid(a)plt> 80485bd: 89 5c 24 08 mov %ebx,0x8(%esp) 80485c1: c7 44 24 04 e0 86 04 movl $0x80486e0,0x4(%esp) 80485c8: 08 80485c9: 89 44 24 0c mov %eax,0xc(%esp) 80485cd: a1 80 98 04 08 mov 0x8049880,%eax 80485d2: 89 04 24 mov %eax,(%esp) 80485d5: e8 d6 fd ff ff call 80483b0 <fprintf(a)plt> ----------------------- That's the 'Hola!'-fprintf in the child. ----------------------- 80485da: a1 64 98 04 08 mov 0x8049864,%eax 80485df: 85 c0 test %eax,%eax 80485e1: 75 2f jne 8048612 <main+0x152> ----------------------- Load value of RUN into eax, jmp to 8048612 if not zero. ----------------------- 8048612: eb fe jmp 8048612 <main+0x152> ---------------------- For obvious reasons, this instruction will execute forever :-). As I already wrote: you need to declare both signalCtr and RUN to be volatile to inform the compiler that it must reload the value because loading it is supposed to be a necessary side effect. Assuming that RUN has been declared as volatile int RUN = 1; the loop is translated as ------------------------ 80485e0: a1 64 98 04 08 mov 0x8049864,%eax 80485e5: 85 c0 test %eax,%eax 80485e7: 75 f7 jne 80485e0 <main+0x120> ------------------------ Load value, test if non-zero, if non-zero, jump to load The reason the loop works with the sleep(0) is presumably because whatever code gets executed because of the call might have changed the value of RUN and hence, the compiler generates code to check this.
From: Jorge on 8 Feb 2010 13:21
On Feb 8, 6:58 pm, Rainer Weikusat <rweiku...(a)mssgmbh.com> wrote: > (...) > Load value of RUN into eax, jmp to 8048612 if not zero. > > ----------------------- > 8048612: eb fe jmp 8048612 <main+0x152> > ---------------------- > > For obvious reasons, this instruction will execute forever :-). > > As I already wrote: you need to declare both signalCtr and RUN to be > volatile to inform the compiler that it must reload the value because > loading it is supposed to be a necessary side effect. Assuming that > RUN has been declared as > > volatile int RUN = 1; > > the loop is translated as > > ------------------------ > 80485e0: a1 64 98 04 08 mov 0x8049864,%eax > 80485e5: 85 c0 test %eax,%eax > 80485e7: 75 f7 jne 80485e0 <main+0x120> > ------------------------ > > Load value, test if non-zero, if non-zero, jump to load > > The reason the loop works with the sleep(0) is presumably because > whatever code gets executed because of the call might have changed the > value of RUN and hence, the compiler generates code to check this. Hmm, yes, I see. This is of great help. Thank you very very much ! Bye, -- Jorge. |