[Python-Dev] Signals, threads, blocking C functions (original) (raw)
Gustavo Carneiro gjcarneiro at gmail.com
Wed Sep 13 15:17:03 CEST 2006
- Previous message: [Python-Dev] Signals, threads, blocking C functions
- Next message: [Python-Dev] Signals, threads, blocking C functions
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On 9/12/06, Adam Olsen <rhamph at gmail.com> wrote:
On 9/12/06, Gustavo Carneiro <gjcarneiro at gmail.com> wrote: > On 9/12/06, Adam Olsen <rhamph at gmail.com> wrote: > > My previous mention of using a single flag may survive corruption > > simply because we can tolerate false positives. Signal handlers would > > write 0xFFFFFFFF, the poll loop would check if any bit is set. If > > so, write 0x0, read off the fd, then loop around and check it again. > > If the start of the read() acts as a write-barrier it SHOULD guarantee > > we don't miss any positive writes. > > Why write 0xFFFFFFFF? Why can't the variable be of a "volatile > char" type? Assuming sizeof(char) == 1, please don't tell me > architecture XPTO will write the value 4 bits at a time! :P
Nope. It'll write 32 bits, then break that up into 8 bits :) Although, at the moment I can't fathom what harm that would cause...
Hmm... it means that to write those 8 bits the processor / compiler may need to 1. read 32 bits from memory to a register, 2. modify 8 bits of the register, 3. write back those 32 bits. Shouldn't affect our case, but maybe it's better to use sig_atomic_t in any case.
For the record, all volatile does is prevent compiler reordering across sequence points.
It makes the compiler aware the value may change any time, outside the current context/function, so it doesn't assume a constant value and always re-reads it from memory instead of assuming a value from a register is correct.
> static volatile char signalflag; > static int signalpiper, signalpipew; > > PyErrCheckSignals() > { > if (signalflag) { > char signum; > signalflag = 0; > while (read(signalpiper, &signum, 1) == 1) > processsignal(signum); > } > }
I'd prefer this to be a "while (signalflag)" instead, although it should technically work either way.
I guess we can use while instead of if.
> static void > signalhandler(int signum) > { > char signumc = signum; > signalflag = 1; > write(signalpipew, &signumc, 1); > } This is wrong. PyErrCheckSignals could check and clear signalflag before you reach the write() call. "signalflag = 1" should come after.
Yes, good catch.
I don't understand the memory barrier concern in your other email. I know little on the subject, but from what I could find out memory barriers are used to avoid reordering of multiple read and write operations. However, in this case we have a single value at stake, there's nothing to reorder.
Except perhaps that "signal_flag = 0" could be delayed... If it is delayed until after the while (read (...)...) loop below we could get in trouble. I see your point now... :|
But I think that a system call has to act as memory barrier, forcefully, because the CPU has to jump into kernelspace, a completely different context, it has to flush pending memory operations sooner or later.
Round two:
static volatile sig_atomic_t signal_flag; static int signal_pipe_r, signal_pipe_w;
PyErr_CheckSignals() { while (signal_flag) { char signum; signal_flag = 0; while (read(signal_pipe_r, &signum, 1) == 1) process_signal(signum); } }
static void signal_handler(int signum) { char signum_c = signum; write(signal_pipe_w, &signum_c, 1); signal_flag = 1; }
-- Gustavo J. A. M. Carneiro "The universe is always one step beyond logic."
- Previous message: [Python-Dev] Signals, threads, blocking C functions
- Next message: [Python-Dev] Signals, threads, blocking C functions
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]