I am sort of new to Perl. Using SWIG and with some XS code I am trying to accomplish event-driven callback into Perl from my library (written in C/C++ for windows platform). Callback is fired from different thread context.
The implementation is when Perl registers for callback, Perl's subroutine reference is stored in a global SV pointer and instead a wrapper function is actually registered to the library API. When library fires the callback, the wrapper function calls into perl and puts function arguments into Perl stack.
This approach is working fine for most part. However, it is observed that 1/5 times this implementation runs into race condition and Perl throws strange errors which I don't understand.
1. Somewhere in between processing of callback wrapper function, Perl control seems to be lost (it never returns to main. Perl dies gracefully and no error is reported).
2. panic: pp_iter at F:\TEST\SWIG_API\Debug\run_cb.pl line 22. (Points to Win32::Sleep(int(rand(100))); in main thread).
3. Crash somewhere in perl interpreter (Stack trace shows only perl512.dll calls. Haven't tried debug build).
4. Some other "panic: " errors.
The details part is as below. Please help me understand why this might be happening.
During the callback Registration I'm storing the Perl subroutine reference and Perl context in global pointers.use strict; use warnings; use MyLibSWIG; use Win32; my $cnt_cback = \&my_connect_cb; for(1..100){ print("\n\n ########## TEST ITERATE : $_ ########## \n"); MyTest(); } sub MyTest { MyLibSWIG::MyRegister($cnt_cback); #Test: engage interpreter here while callback is being processed for (1..10){ print(sprintf("[%d] PRL: Doing something %d\n",Win32::GetCurre +ntThreadId(),$_)); Win32::Sleep(int(rand(100))); } MyLibSWIG::MyDeregister(); } sub my_connect_cb { print(sprintf("[%d] PRL: my_connect_cb called bConn = %d\n",Win32: +:GetCurrentThreadId(), $_[0])); }
SV* MyConnectCbPerl = NULL; void* pMyConnectCbPerlCTX = NULL; extern void wrap_connect_cback_handler(BOOL bConnected); XS(_wrap_MyRegister) { { PFN_CONNECT_CALLBACK arg1 = (PFN_CONNECT_CALLBACK) 0 ; int argvi = 0; DWORD result; dXSARGS; if ((items < 1) || (items > 1)) { SWIG_croak("Usage: MyRegister(pfnConnectCallback);"); } { int status = IsValidCBRef(ST(0)); if (status == 0) { MyConnectCbPerl = (SV *)ST(0); //Save reg +istered sub refrence pMyConnectCbPerlCTX = Perl_get_context(); //Save +Perl Context arg1 = wrap_connect_cback_handler; //Register a + wrapper function. When fired, the wrapper function invokes the perl +subroutine. } } result = (DWORD)MyRegister(arg1); ST(argvi) = SWIG_From_unsigned_SS_long SWIG_PERL_CALL_ARGS_1((uns +igned long)(result)); argvi++ ; XSRETURN(argvi); fail: SWIG_croak_null(); } }
When Wrapper callback function is invoked, call perl subroutine :
void wrap_connect_cback_handler(BOOL bConnected) { PERL_SET_CONTEXT(pMyConnectCbPerlCTX); SV * sv = NULL; sv = MyConnectCbPerl; if (sv == (SV*)NULL) croak("Internal error...MyConnectCbPerl not registered\n") +; //Sleep(50); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSViv(bConnected))); PUTBACK; /* Call the Perl sub */ call_sv(sv, G_DISCARD); //PERL_SET_CONTEXT(pMyConnectCbPerlCTX); SPAGAIN; PUTBACK; FREETMPS; LEAVE; }
When issue occurs output looks like this (note below: there was no race condition problem iteration run 1 to 5 )-
Should you want to take a look at the library code -########## TEST ITERATE : 6 ########## [5528] LIB: MyRegister pfnConnectCallback = 54E310A5 [5528] PRL: Doing something 1 [6116] LIB: CallbackWorker firing ConnectCallback(0) [6116] PRL: my_connect_cb called bConn = 1 [5528] PRL: Doing something 2 [6116] LIB: CallbackWorker firing ConnectCallback(1) [6116] PRL: my_connect_cb called bConn = 0 [6116] LIB: CallbackWorker firing ConnectCallback(2) [6116] PRL: my_connect_cb called bConn = 1 [5528] PRL: Doing something 3 [6116] LIB: CallbackWorker firing ConnectCallback(3) [6116] PRL: my_connect_cb called bConn = 0 [5528] PRL: Doing something 4 [6116] LIB: CallbackWorker firing ConnectCallback(4) [6116] PRL: my_connect_cb called bConn = 0 [6116] PRL: my_connect_cb called bConn = 0 panic: pp_iter at F:\TEST\SWIG_API\Debug\run_cb.pl line 22. panic: pp_iter at F:\TEST\SWIG_API\Debug\run_cb.pl line 22.
Thanks.
In reply to Perl interpreter throws strange errors for event-driven callback processing under race conditions by Cotton4Lunch
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |