Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Re: Read STDOUT from Win32::Job while process is running

by BrowserUk (Pope)
on Mar 08, 2012 at 19:23 UTC ( #958520=note: print w/replies, xml ) Need Help??


in reply to Read STDOUT from Win32::Job while process is running

Win32::Job is fine when you don't need to do anything with the processes it spawns for you, but it limited otherwise.

The following Inline::C code will form a job from any pids you give, including those return by the forking open and system 1, ...; etc.

This example starts a perl one-liner that in turn start the windows calculator and notepad. 10 seconds after the jobs are started, they will disappear. The final sleep is there to show you that the closeHandle() worked:

#! perl -slw use strict; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C', NAME => 'JobObject', CLEAN_AFTER_BUILD => +0; #include <windows.h> int createJobObject( char *name ) { HANDLE job; JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0, }; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_J +OB_CLOSE; job = (int)CreateJobObjectA( NULL, name ); SetInformationJobObject( job, 9, &jeli, sizeof(jeli) ); return job; } int assignProcessToJobObject( int job, int pid ) { HANDLE hProc = OpenProcess( PROCESS_SET_QUOTA |PROCESS_TERMINATE, +0, pid ); return (int)AssignProcessToJobObject( job, hProc ); } int closeHandle( int handle ) { return (int)CloseHandle( (HANDLE)handle ); } END_C my $job = createJobObject( 'fred' ); print $job; my $pid = open O, q[\perl64\bin\perl.exe -E"system 1, 'calc.exe'; syst +em 1, 'notepad.exe'; sleep 100" |] or die $^E; print assignProcessToJobObject( $job, $pid ); sleep 10; print closeHandle( $job ); # kill 21, $pid; sleep 10

You call createJobObject() with a name to get a job handle; assignProcessToJobObject(), with that job handle and the pid for each process you want added to the job; and call closeHandle( $job ) when you want the job to terminate all the processes it includes.

You can also use kill on the process(es) you started and all their children will also die.

However, if you allow your script to end without killing the kids or closing the job handle, you process will block until the kids go away of their own accord.

That could probably be worked up into a module if there was any demand for it.


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?

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

    Thank you for that great answer. In theory I understand completely what your code is doing.

    But my problem is that I don't get it running. I get the following messages:

    Starting Build Preprocess Stage Finished Build Preprocess Stage Starting Build Parse Stage Finished Build Parse Stage Starting Build Glue 1 Stage Finished Build Glue 1 Stage Starting Build Glue 2 Stage Finished Build Glue 2 Stage Starting Build Glue 3 Stage Finished Build Glue 3 Stage Starting Build Compile Stage Starting "perl Makefile.PL" Stage Set up gcc environment - 3.4.5 (mingw-vista special r3) Writing Makefile for JobObject Finished "perl Makefile.PL" Stage Starting "make" Stage warning: extra args ignored after '-e'

    And then the script continues running endlessly without starting any processes.

    When I tried it with the debugger I could not even reach the first perl statement and got the same messages.

    When your code is running here on my computer, I'd like to put your code into a module and then post it here.

    I ask myself if I'm doing weird things because nobody seems to need this functionality. I would assume that many people would need this useful functionality.

    Thank you alot.

      I can't help you with I::C on mingw. Hopefully, syphilis will wander by sometime.

      In the meantime, I've built a crude package -- no docs or tests etc. -- from the 3 functions. It builds and runs here. If you give me your mail addy (via /msg) I'll send you the dist.


      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?

      warning: extra args ignored after '-e'

      This warning doesn't ring any bells with me.
      How did you install Inline ? (You need to build and install it from source - eg doing a 'ppm install' won't do.)
      Knowing the output of 'perl -V' would also help - as, too, would knowing any additional diagnostics that you're getting.

      The code, as posted by BrowserUk, won't compile for me using the MinGW port of gcc-3.4.5, because of a deficiency in winnt.h.
      In that file you'll need to add:
      #define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x2000
      For some reason (that I haven't yet investigated), with ActivePerl I then get undefined references to `CreateJobObjectA', `SetInformationJobObject', `AssignProcessToJobObject' - which is odd, because these symbols are all defined in libbkernel32.a and we link to that library. (It may just be that we need to link to libkernel32.a *before* JobObject.o.)
      Anyway, if you get to the same snag we can dig a bit deeper then.
      First we need to work out what that warning is all about.

      Cheers,
      Rob
        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

        Thanks alot for your answer. I installed it via "ppm". I'll install it via cpan to avoid the warning.

        Now BrowserUk developed a Win32-JobAdd package which contains the same C code in a xs file. And you're right I had to set the value 0x2000 for the constant. And now I get exactly the undefined references which you describe.

        Here the messages:

        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 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 JobAdd.o:JobAdd.c:(.text+0x3f): undefined reference to `CreateJobObjec +tA' JobAdd.o:JobAdd.c:(.text+0x5f): undefined reference to `SetInformation +JobObject' JobAdd.o:JobAdd.c:(.text+0xa1): undefined reference to `AssignProcessT +oJobObject ' collect2: ld returned 1 exit status dmake.exe: Error code 129, while making 'blib\arch\auto\Win32\JobAdd\ +JobAdd.dll '

        Cheers,

        Dirk

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://958520]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (6)
As of 2021-12-09 11:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    R or B?



    Results (36 votes). Check out past polls.

    Notices?