Skip to content

Update PL_main_thread on fork() and add more tests #23422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: blead
Choose a base branch
from

Conversation

tonycoz
Copy link
Contributor

@tonycoz tonycoz commented Jul 10, 2025

Ensure the saved PL_main_thread when the process forks, this ensures we are still forwarding signals received by non-perl threads to the main thread.

This turns out not to be necessary on Linux and FreeBSD as tested, since the main thread id in parent and child processes appear to have the same value (they compare equal with pthread_equal()), but this may not be true for other platforms and may change for Linux or FreeBSD.

Also add extra on-point tests for the original issue from #22487

Not sure if this needs a perldelta.


  • This set of changes requires a perldelta entry, and I need help writing it.

tonycoz added 2 commits July 9, 2025 14:12
85e9706 modified the perl signal handler to forward signals to the
main thread if it received a signal in a non-perl thread, which
required saving the id of the main perl thread.

Unfortunately I forgot to handle a possible change in the main thread
id on a fork, this fixes that by re-saving the new main thread id
immediately after a fork (via pthread_atfork())

On Linux it appears that the main thread id returned by pthread_seld()
is constant between processes, but this may not be true on other
platforms.

Discussed at:

Perl#23326 (comment)
This was fixed by 85e9706 but the test only checked the sanity of the
saved main thread thread id.

Tested locally for failure by disarming the change in
Perl_csighandler3.
make_signal_thread()
CODE:
if (pthread_create(&RETVAL, NULL, signal_thread_start, NULL) != 0)
XSRETURN_EMPTY;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why return empty list instead of &PL_sv_undef or &PL_sv_no or SvPV "" empty str or less perfect, SvIV -1 or SvIV 0? I know pp_entersub will cast empty list to 1 x &PL_sv_undef in G_SCALAR cxt, but why mk `pp_entersub do the cast?

else {
is(waitpid($pid, 0), $pid, "wait child");
# catches the child segfaulting for example
is($?, 0, "child success");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would test.pl/Test2:: sub is() corrupt PP mg var $? between waitpid() ret and sampling of $??

OUTPUT

WPV
sv_setpvn($arg, (const char *)($var), sizeof(WCHAR) * (1+wcslen($var)));

T_THREADID
sv_setpvn($arg, (const char *)&($var), sizeof($var));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see paranoia above with SvPVbyte(), so OUTPUT: also needs paranoia. sv_setpvn() doesn't clear the UTF8 flag if TARG already has UTF8 flag on. Also following paranoia guidelines, you forgot to call a _mg() SV* setter variant. Per rules, remember to clear UTF8 flag before the SMG setter method fires, not after. It should be sv_setpvn(); SvUTF8_off(); SvSETMAGIC(); or better yet SvUTF8_off(); sv_setpvn_mg();.

I am very aware this is code is inside XS-APItest, and not some high river CPAN XS module, so XS code "quality" is a very low priority here, but I saw paranoia INPUT: type entry so I'll keep the paranoia going.

new main thread
*/
PTHREAD_INIT_SELF(PL_main_thread);
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More of a Win32 problem than a Posix Perl problem, but what happens to the entire Perl or 3P embedder process if the 1st Perl thread or 1st process startup thread, exits itself on Unix? Instant Process kill? If not, the TID or pthread_t obj stored in PL_main_thread now points to a zombie TID? Why would a child interp/my_perl on a 2nd pthread rethrow a signal to a gone/finished/dealloced root my_perl and dealloced or zombie TID??

static void
S_init_tls_and_interp(PerlInterpreter *my_perl)
{
    if (!PL_curinterp) {
        PERL_SET_INTERP(my_perl);
#if defined(USE_ITHREADS)
        INIT_THREADS;
        ALLOC_THREAD_KEY;
        PERL_SET_THX(my_perl);
        OP_REFCNT_INIT;
        OP_CHECK_MUTEX_INIT;
        KEYWORD_PLUGIN_MUTEX_INIT;
        HINTS_REFCNT_INIT;
        LOCALE_INIT;
        USER_PROP_MUTEX_INIT;
        ENV_INIT;
        MUTEX_INIT(&PL_dollarzero_mutex);
        MUTEX_INIT(&PL_my_ctx_mutex);
        PTHREAD_INIT_SELF(PL_main_thread);
#  endif
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants