lsuchocki has asked for the wisdom of the Perl Monks concerning the following question:
Oh Perl Monks, I plead for your insight..
My app uses WWW::Curl::Multi (libcurl) to perform web tasks which are handled, among many other things, in a super loop. I've recently added a piece of code which fork()s to perform an occasional long-running task, which I do not want to block my main loop with.
Works great. On Linux.
Upon testing the same code under Windows (Strawberry Perl) with the newly added code which forks, perl crashes. Debugging shows me if I don't fork(), it doesn't crash, and if I don't "WWW::Curl::Multi->new();" it doesn't crash.
Knowing that Windows emulates fork() with interpreter threads, I'm guessing the WWW::Curl library is not thread safe.
This was confirmed with the following bare-minimum test cases:
Windows (wine):
use WWW::Curl::Multi; my $x = WWW::Curl::Multi->new(); if (fork == 0) { #Do stuff NOT related to WWW::Curl here.. print STDERR "thread sleeping\n"; sleep 1; print STDERR "thread exiting\n"; exit; } print STDERR "main sleeping\n"; sleep 3; print STDERR "main exiting\n"; exit 0;
main sleeping thread sleeping thread exiting Free to wrong pool 249ea0 not 241ba8 at testcrash.pl line 9. wine: Unhandled page fault on write access to 0x00000000 at address 0x +713c9106 (thread 0031), starting debugger...
And under Linux:
use threads; use WWW::Curl::Easy; my $x = WWW::Curl::Easy->new(); my $t = threads->create(sub{ print STDERR "thread sleeping\n"; #Do stuff NOT related to WWW::Curl sleep 1; print STDERR "thread exiting\n"; }); print STDERR "main sleeping\n"; sleep 3; $t->join(); print STDERR "main exiting\n"; exit 0;
Which yields (under GDB):
[New Thread 0x7ffff1689700 (LWP 12664)] main sleeping thread sleeping thread exiting [Thread 0x7ffff1689700 (LWP 12664) exited] main exiting Program received signal SIGSEGV, Segmentation fault. 0x0000003f3fe39d63 in Curl_splay () from /lib64/libcurl.so.4
Now, I don't need any curl resources within my child/thread, it's only used in the main program (technically another .pm), but the object created is globally scoped and has a member with a WWW::Curl object. So I don't think I can keep it hidden from my child/thread. Curl itself is supposed to be thread-safe, with the exception of the curl_global_init. I'm pretty sure that's not the issue though, since the child does not call it. Unless it's being automatically called a second time by the BOOT: XS syntax on the thread creation?
I believe that when I fork under Win32/thread under Linux, my object may be free()d by the DESTORY XS methods when I exit/join the thread? And I probably need to prevent curl_global_cleanup() from being called when the thread exits in the .pm END{} block... ??
So... this is where it gets fuzzy for me. I'm a strong C programmer, but there's a learning curve with perl's XS. Are there any other modules out there which properly deal with these sort of situations which I may learn / copy from? I've spent all day reading perlthrtut, perlguts, perlmod, Example::CLONE and others and ended up with a nasty headache..
Most humbly,
--Luke
Is the solution simply to (in reference to the above examples):
use threads; use threads::shared; ... share($x);
This seems to prevent perl from crashing, and the double DESTROY, however, with the fork() example under windows, the END{} curl_global_cleanup() is called twice, in the thread and in the parent, where in the thread->create()->join() it is only called once.....
Is this a safe workaround to what I'm seeing?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: WWW::Curl and making it thread safe
by marioroy (Prior) on Feb 18, 2016 at 11:36 UTC | |
|
Re: WWW::Curl and making it thread safe
by Anonymous Monk on Feb 18, 2016 at 03:28 UTC | |
by lsuchocki (Novice) on Feb 18, 2016 at 03:49 UTC | |
by Tanktalus (Canon) on Feb 18, 2016 at 04:10 UTC | |
by Anonymous Monk on Feb 18, 2016 at 04:12 UTC |