Front page | perl.perl5.porters |
Postings from October 2014
[perl #81074] Perl reports SIGINT handler "IGNORE" not defined in multi-threaded apps
Thread Previous
|
Thread Next
From:
bulk88 via RT
Date:
October 4, 2014 08:42
Subject:
[perl #81074] Perl reports SIGINT handler "IGNORE" not defined in multi-threaded apps
Message ID:
rt-4.0.18-14279-1412412116-1557.81074-15-0@perl.org
On Fri Oct 03 17:29:52 2014, LeonT wrote:
> On Mon, Jul 28, 2014 at 6:15 AM, Tony Cook via RT <perlbug-followup@perl.org
> > wrote:
>
> > --- a/mg.c
> > +++ b/mg.c
> > @@ -1353,6 +1353,15 @@ Perl_csighandler(int sig)
> > PERL_UNUSED_ARG(sip);
> > PERL_UNUSED_ARG(uap);
> > #endif
> > +#ifdef USE_ITHREADS
> > + /* handle a signal received in a non-perl thread, eg. a thread
> > + created by a framework */
> > + if (!my_perl) {
> > + my_perl = PL_curinterp;
> > + PERL_SET_THX(my_perl);
> > + }
> > +#endif
> > +
> > #ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS
> > (void) rsignal(sig, PL_csighandlerp);
> > if (PL_sig_ignoring[sig]) return;
> >
>
> You're peeking and poking into an interpreter owned by another thread. This
> is suffering from a race condition. If possible, a pthread_kill to the main
> thread would be preferable I guess.
If you grep / and /win32 for "curinterp" you will see that is already done in win32.c . I am not saying it is right or wrong. On win32 Perl there is a race condition that nobody ever solved regarding the Ctrl-C signal on Win32. Win32 API will always call the Ctrl-C function from a fresh thread. If perl is at 100% cpu in runloop without being stuck in kernel mode, and Ctrl-C is pressed, there is a race between my_exit() and the code executing in runloop. Usually the OP * is freed while the PP func is running and somehow usually a NULL is returned and the runloop quickly exits if the sign handler thread doesn't reach C lib exit() first. Maybe this code is needed for Win32 too.
>
>
> > @@ -1384,16 +1393,33 @@ Perl_csighandler(int sig)
> > (*PL_sighandlerp)(sig);
> > #endif
> > else {
> > + int pending;
> > if (!PL_psig_pend) return;
> > /* Set a flag to say this signal is pending, that is awaiting
> > delivery after
> > * the current Perl opcode completes */
> > - PL_psig_pend[sig]++;
> > +#ifdef USE_ITHREADS
> > + /* Only deliver to the current thread if it has a non-default
> > + signal handler set */
> > + if (PL_sighand_set && PL_sighand_set[sig]) {
> > + PL_psig_pend[sig]++;
> > + pending = ++PL_sig_pending;
> > + }
> > + else {
> > + /* no handler specific to thread, deliver to the main thread
> > */
> > + dTHXa(PL_curinterp);
> > + PL_psig_pend[sig]++;
> > + pending = ++PL_sig_pending;
> > + }
> >
>
> The else block is racy too, though over a smaller scope than the previous
> one.
C doesn't require that PL_psig_pend[sig]++; be atomic, but if the type is 8/16/32 bits and it is on x86 single core, it is atomic since a HW interupt or kernel preemption can't cause half a machine instruction ("inc *(reg+constant)" is an x86 op) to execute. For safety on x86 multicore, you must the correct atomic APIs http://preshing.com/20130618/atomic-vs-non-atomic-operations/ .
>
> Also, it should be noted that your additions feature is enabled on
> USE_ITHREADS, even though your solution is multiplicity based and the
> problem is also a multiplicity issue. Then again, the solution I suggested
> for your race condition is assuming ithreads. I'm not sure how to deal with
> that, possibly by not caring.
I agree. AFAIK MULTIPLICITY is dead but the token remains for backcompat since 5.005 threads are gone. PERL_IMPLICIT_CONTEXT is what you probably want. PERL_IMPLICIT_CONTEXT *without* USE_ITHREADS means you want multiple perl threads/interps in 1 process for embedding reasons, but you do not want the ithreads module. So what happens if the signal is delivered to a 3rd party GUI or IO OS thread while the OS thread with Perl is blocked?
-----------------------------------------
@@ -1573,9 +1599,17 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
PL_psig_ptr[i] = NULL;
}
}
+#ifdef USE_ITHREADS
+ if (!PL_sighand_set) {
+ Newxz(PL_sighand_set, SIG_SIZE, int);
+ }
-----------------------------------------
Can PL_sighand_set be an inline array in interp struct? Im not sure of details since this is unix, but I'm afraid this array will wind up always getting allocated in every run of the interp, and therefore malloc overhead for something that will be unconditionally allocated if an interp struct was allocated. Also if the malloc design stays. Dont let Newxz use PL_sighand_set, instead let it use a C auto void pointer, then assign the C auto to PL_sighand_set, that way the sig handler func wont see half zero-ed data where PL_sighand_set was set, but memset hasnt been called yet, or memset is half way done zeroing the block. I didn't trace exactly how the Newxz macros work but assume Newxz can cause half zeroed data.
--
bulk88 ~ bulk88 at hotmail.com
---
via perlbug: queue: perl5 status: open
https://rt.perl.org/Ticket/Display.html?id=81074
Thread Previous
|
Thread Next