in reply to Re^3: Read STDOUT from Win32::Job while process is running
in thread Read STDOUT from Win32::Job while process is running

For some reason (that I haven't yet investigated), with ActivePerl I then get undefined references to `CreateJobObjectA', `SetInformationJobObject', `AssignProcessToJobObject'

Well ... I investigated and investigated ... then investigated a bit more ... and still couldn't see what the problem was.
So I then gave up and posted to the ActiveState users list - and about half an hour later Mark Dootson replied with the explanation and solution.

When this linking problem occurs, we'll find that lib/CORE/win32.h begins with something like:
#ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0400 #endif
But we need _WIN32_WINNT to be >= 0x0500 - which I achieved by altering the above code to:
#ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0500 #endif
That then enables the script to run to completion, and I think it also takes care of the '...undefined; assuming extern returning int' warnings with Microsoft compilers.

Cheers,
Rob

Replies are listed 'Best First'.
Re^5: Read STDOUT from Win32::Job while process is running
by Dirk80 (Pilgrim) on Mar 11, 2012 at 08:49 UTC

    Wow, thank you so much for taking time to investigate and even writing to ActiveState. It's working now and I'm happy.

    Here the successful output:

    E:\perl\Win32-JobAdd-0.01>dmake cp lib/Win32/JobAdd.pm blib\lib\Win32\JobAdd.pm C:\Perl\bin\perl.exe C:\Perl\lib\ExtUtils\xsubpp -typemap C:\Perl\lib +\ExtUtils\ typemap JobAdd.xs > JobAdd.xsc && C:\Perl\bin\perl.exe -MExtUtils::Co +mmand -e " mv" -- JobAdd.xsc JobAdd.c Please specify prototyping behavior for JobAdd.xs (see perlxs manual) C:/Perl/site/bin/gcc.exe -c -I. -DNDEBUG -DWIN32 -D_CONSOLE -D +NO_STRICT -DHAVE_DES_FCRYPT -DUSE_SITECUSTOMIZE -DPRIVLIB_LAST_IN_INC -DPERL_IMP +LICIT_CONT EXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_MSVCRT_READFIX -DHASATTRIB +UTE -fno-s trict-aliasing -mms-bitfields -O2 -DVERSION=\"0.01\" -DXS_V +ERSION=\"0 .01\" "-IC:\Perl\lib\CORE" JobAdd.c JobAdd.xs: In function `createJobObject': JobAdd.xs:18: warning: passing arg 1 of `SetInformationJobObject' make +s pointer from integer without a cast JobAdd.xs: In function `assignProcessToJobObject': JobAdd.xs:24: warning: passing arg 1 of `AssignProcessToJobObject' mak +es pointer from integer without a cast Running Mkbootstrap for Win32::JobAdd () C:\Perl\bin\perl.exe -MExtUtils::Command -e "chmod" -- 644 JobAdd.bs C:\Perl\bin\perl.exe -MExtUtils::Mksymlists \ -e "Mksymlists('NAME'=>\"Win32::JobAdd\", 'DLBASE' => 'JobAdd', ' +DL_FUNCS' => { }, 'FUNCLIST' => [], 'IMPORTS' => { }, 'DL_VARS' => []);" Set up gcc environment - 3.4.5 (mingw-vista special r3) dlltool --def JobAdd.def --output-exp dll.exp C:\Perl\site\bin\g++.exe -o blib\arch\auto\Win32\JobAdd\JobAdd.dll -Wl +,--base-fi le -Wl,dll.base -mdll -L"C:\Perl\lib\CORE" JobAdd.o -Wl,--image-base,0 +x2e0b0000 C:\Perl\lib\CORE\perl510.lib -lkernel32 -luser32 -lgdi32 -lwinspool - +lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32 -lm +pr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32 -lmsvcrt dll.exp dlltool --def JobAdd.def --base-file dll.base --output-exp dll.exp C:\Perl\site\bin\g++.exe -o blib\arch\auto\Win32\JobAdd\JobAdd.dll -md +ll -L"C:\P erl\lib\CORE" JobAdd.o -Wl,--image-base,0x2e0b0000 C:\Perl\lib\CORE\p +erl510.lib -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell3 +2 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32 -lmpr -lwinmm -lversion -lodbc32 + -lodbccp3 2 -lcomctl32 -lmsvcrt dll.exp C:\Perl\bin\perl.exe -MExtUtils::Command -e "chmod" -- 755 blib\arch\a +uto\Win32\ JobAdd\JobAdd.dll C:\Perl\bin\perl.exe -MExtUtils::Command -e "cp" -- JobAdd.bs blib\arc +h\auto\Win 32\JobAdd\JobAdd.bs C:\Perl\bin\perl.exe -MExtUtils::Command -e "chmod" -- 644 blib\arch\a +uto\Win32\ JobAdd\JobAdd.bs
Re^5: Read STDOUT from Win32::Job while process is running
by BrowserUk (Patriarch) on Mar 11, 2012 at 12:35 UTC
    Well ... I investigated and investigated ... then investigated a bit more ... and still couldn't see what the problem was. So I then gave up and posted to the ActiveState users list - and about half an hour later Mark Dootson replied with the explanation and solution.

    Well done and thank you.++

    Rather than requiring the Perl sources modification -- which might be needed by something somewhere -- adding the define before the inclusion of the Perl headers achieves the same thing in a self-contained way. I've also cleaned up a couple of the warnings -- though traded them for others in some cases, but I'm not sure there is a better way?

    The result looks like this:

    #define _WIN32_WINNT 0x0500 #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE #define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x2000 #endif int createJobObject( char *name ) { HANDLE job; JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0, }; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_J +OB_CLOSE; job = CreateJobObjectA( NULL, name ); SetInformationJobObject( job, 9, &jeli, sizeof(jeli) ); return (int)job; } int assignProcessToJobObject( int job, int pid ) { HANDLE hProc = OpenProcess( PROCESS_SET_QUOTA |PROCESS_TERMINATE, +0, pid ); return (int)AssignProcessToJobObject( (HANDLE)job, hProc ); } int closeHandle( int handle ) { return (int)CloseHandle( (HANDLE)handle ); } MODULE = Win32::JobAdd PACKAGE = Win32::JobAdd int createJobObject (name) char * name int assignProcessToJobObject (job, pid) int job int pid int closeHandle (handle) int handle

    Salient part of the build trace:

    JobAdd.c JobAdd.xs(18) : warning C4311: 'type cast' : pointer truncation from ' +HANDLE' to 'int' JobAdd.xs(24) : warning C4312: 'type cast' : conversion from 'int' to +'HANDLE' of greater size JobAdd.xs(28) : warning C4312: 'type cast' : conversion from 'int' to +'HANDLE' of greater size link -out:blib\arch\auto\Win32\JobAdd\JobAdd.dll -dll -nologo +-nodefaultlib -debug -opt:ref,icf -ltcg ... Creating library blib\arch\auto\Win32\JobAdd\JobAdd.lib and object +blib\arch\auto\Win32\JobAdd\JobAdd.exp

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

      adding the define before the inclusion of the Perl headers achieves the same thing in a self-contained way

      Yes - I was looking at the Inline::C approach which, afaik, doesn't provide that option - it always inserts the inclusion of perl.h and friends *before* any C code that the author of the script provides.

      Hmm ... maybe Inline::C should provide an option that allows one to place C code ahead of those inclusions. (TODO ?)

      In this particular instance I think that modifying CORE/win32.h should be safe (no guarantees, but :-) - so long as you're running on XP or higher.
      After all, if CORE/win32.h did its job properly I think it would assign the actual value associated with the OS on which perl was running, not just provide a minimum supported value.

      Cheers,
      Rob
        Hmm ... maybe Inline::C should provide an option that allows one to place C code ahead of those inclusions. (TODO ?)

        I wonder if, in this case, it wouldn't be possible to pass a -D_WIN32_WINNT=0x0500 to the compiler CCFLAGS?

        After all, if CORE/win32.h did its job properly I think it would assign the actual value associated with the OS on which perl was running, not just provide a minimum supported value.

        Agreed. But the whole (MS) concept of a define that you specify to say that you want at least version x.xxx, then preventing anything later than version x.xx being included, is a weird way to write header files.

        As you say, the best solution to the problem that creates, would be for win32.h to define it to be "the current OS version" at compile time, but I can't find a ready source for that information amongst the MSC pre-defines.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        The start of some sanity?

      Thanks again to all of you helping me so much.

      Here I want to post the solution of my original problem.

      #!/usr/bin/perl use strict; use threads; use Thread::Queue; use Win32::JobAdd; ## A shared var to communicate progess between work thread and TK my $Q = new Thread::Queue; my $job:shared = createJobObject( 'counter_and_calc_job' ); sub work{ my $pid = open PROC, q[perl -le "$|=1; system 1, 'calc.exe'; print and select(undef,und +ef,undef,0.1) for 1 .. 1000" |] or die $!; assignProcessToJobObject( $job, $pid ); while( <PROC> ) { $Q->enqueue( $_ ); } close PROC; } threads->new( \&work )->detach; ## For lowest memory consumption require (not use) ## Tk::* after you've started the work thread. require Tk::ProgressBar; my $mw = MainWindow->new; my $pb = $mw->ProgressBar()->pack(); my $button = $mw->Button(-text => 'CANCEL', -command => sub { closeHandle( $job ) } )->pa +ck(); my $repeat; $repeat = $mw->repeat( 100 => sub { while( $Q->pending ) { my $progress = $Q->dequeue; return unless $progress; $repeat->cancel if $progress == 100; $pb->value( $progress ) } }); $mw->MainLoop;

      This code solves my two problems. Being able to read from a child process, but also being able to kill the whole process tree instead of only killing the child process and to have zombie processes.

      If you press the "Cancel" Button then the calculator and the child process which counts from 1 to 1000 are killed. Even if you quit the gui with the cross in the right upper corner the grandchild process "calculator" is killed.

      Without a job environment in a Win32 environment the grandchild calculator would stay as a zombie process.

      Feedback to this code is welcome.

      Cheers, Dirk