http://qs321.pair.com?node_id=1064759


in reply to ActivePerl Gtk2::Helper Hangs

Running your first script, the perl process hung/blocked on a syncronous read to the NPFS Win32 Named Pipe that is the cmd.exe process std handles.
ntdll.dll!_KiFastSystemCallRet@0() ntdll.dll!_NtReadFile@36() + 0xc kernel32.dll!_ReadFile@20() + 0x67 > msvcr71.dll!_read_lk(int fh=0x00000005, void * buf=0x01ab870c, un +signed int cnt=0x00000001) Line 154 + 0x15 C msvcr71.dll!_read(int fh=0x00000005, void * buf=0x01ab870c, unsig +ned int cnt=0x00000001) Line 75 + 0xc C perl512.dll!win32_read(int fd=0x00000005, void * buf=0x01ab870c, +unsigned int cnt=0x00000001) Line 3746 + 0x12 C perl512.dll!PerlLIORead(IPerlLIO * piPerl=0x00285774, int handle= +0x00000005, void * buffer=0x01ab870c, unsigned int count=0x00000001) + Line 1049 + 0x11 C++ perl512.dll!Perl_pp_sysread(interpreter * my_perl=0x00393f04) Li +ne 1711 + 0x34 C perl512.dll!Perl_runops_debug(interpreter * my_perl=0x00393f04) +Line 2049 + 0xd C perl512.dll!Perl_call_sv(interpreter * my_perl=0x00393f04, sv * s +v=0x00829f74, volatile long flags=0x0000000a) Line 2605 + 0x36 C Glib.dll!gperl_closure_marshal(_GClosure * closure=0x00e025d0, _G +Value * return_value=0x0006f888, unsigned int n_param_values=0x000000 +02, const _GValue * param_values=0x0006f8a8, void * invocation_hint=0 +x00000000, void * marshal_data=0x00393f04) Line 105 + 0x96 C libgobject-2.0-0.dll!g_closure_invoke(_GClosure * closure=0x00e02 +5d0, _GValue * return_value=0x0006f888, unsigned int n_param_values=0 +x00000002, const _GValue * param_values=0x0006f8a8, void * invocation +_hint=0x00000000) Line 771 + 0x1b libgobject-2.0-0.dll!io_watch_closure_callback(_GIOChannel * chan +nel=0x00dcecf0, GIOCondition condition=G_IO_IN, void * data=0x00e025d +0) Line 94 + 0x15 libglib-2.0-0.dll!g_io_win32_dispatch(_GSource * source=0x00e0258 +0, int (void *)* callback=0x00b3c1c0, void * user_data=0x00e025d0) L +ine 979 + 0x1f libglib-2.0-0.dll!g_main_dispatch(_GMainContext * context=0x00dc9 +698) Line 2442 + 0xf libglib-2.0-0.dll!g_main_context_dispatch(_GMainContext * context +=0x00dc9698) Line 3013 + 0x9 libglib-2.0-0.dll!g_main_context_iterate(_GMainContext * context= +0x00dc9698, int block=0x00000001, int dispatch=0x00000001, _GThread * + self=0x00dc2ad8) Line 3091 + 0x9 libglib-2.0-0.dll!g_main_loop_run(_GMainLoop * loop=0x00e3c2c8) +Line 3299 + 0x13 libgtk-win32-2.0-0.dll!gtk_main() Line 1244 + 0x9 Gtk2.dll!XS_Gtk2_main(interpreter * my_perl=0x00393f04, cv * cv=0 +x0098af94) Line 523 C perl512.dll!Perl_pp_entersub(interpreter * my_perl=0x00393f04) L +ine 2882 + 0x10 C perl512.dll!Perl_runops_debug(interpreter * my_perl=0x00393f04) +Line 2049 + 0xd C perl512.dll!S_run_body(interpreter * my_perl=0x00393f04, long old +scope=0x00000001) Line 2308 + 0xd C perl512.dll!perl_run(interpreter * my_perl=0x00393f04) Line 2233 + + 0xd C perl512.dll!RunPerl(int argc=0x00000002, char * * argv=0x00283e08 +, char * * env=0x00284ed8) Line 270 + 0x9 C++ perl.exe!main(int argc=0x00000002, char * * argv=0x00283e08, char + * * env=0x00282c88) Line 23 + 0x12 C perl.exe!mainCRTStartup() Line 398 + 0xe C kernel32.dll!_BaseProcessStart@4() + 0x23
In Perl, the hang happened at
sub preview_call { my $buffer; my $rl = sysread($rfh,$buffer,1);<<<<<<<<<<<<<<<<<<<<<<<<<< if(defined($rl)){ print "$rl + $buffer\n"; while (Gtk2->events_pending()) {Gtk2->main_iteration();} return 1; }else{ print "undefined\n"; return 0; } }
Long story short, select() on Win32, in C and in Perl, only works on sockets. Most POSIXy code assumes all FDs/handles are the same "type", so the authors never try to get Win32 async I/O models into their non-blocking POSIX code. You need to call PeekNamedPipe from kernel32 before doing a sysread() or read() from Perl. If the buffer has zero bytes, your read() will hang until some bytes are written to the pipe, or the other end of the pipe is closed.

Here is some untested code for calling PeekNamedPipe
use Win32API::File; use Win32; use Win32::API; { my $api; die "PeekNamedPipe" if ! ($api= Win32::API::More->Import("kernel32", " BOOL PeekNamedPipe( HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage );")); } ########################## my ($TotalBytesAvail, $ret) = (0); my $hnd = Win32API::File::FdGetOsFHandle($rfh->fileno()); #get Win32 k +ernel handle from Perl land if($hnd == Win32API::File::INVALID_HANDLE_VALUE()) { die "bad hnd"; } $ret = PeekNamedPipe($hnd, undef, 0, undef, $TotalBytesAvail, undef); if(!$ret) { my $err = Win32::GetLastError(); die "PNP failed $err $^E"; } if($TotalBytesAvail) { #can safely read }
Code is recycled from https://rt.perl.org/Ticket/Display.html?id=120330.