{
    "mode": "perldoc",
    "parameter": "POE::Wheel::Run",
    "section": "",
    "url": "https://www.chedong.com/phpMan.php/perldoc/POE%3A%3AWheel%3A%3ARun/json",
    "generated": "2026-06-12T17:38:04Z",
    "synopsis": "#!/usr/bin/perl\nuse warnings;\nuse strict;\nuse POE qw( Wheel::Run );\nPOE::Session->create(\ninlinestates => {\nstart           => \\&onstart,\ngotchildstdout => \\&onchildstdout,\ngotchildstderr => \\&onchildstderr,\ngotchildclose  => \\&onchildclose,\ngotchildsignal => \\&onchildsignal,\n}\n);\nPOE::Kernel->run();\nexit 0;\nsub onstart {\nmy $child = POE::Wheel::Run->new(\nProgram => [ \"/bin/ls\", \"-1\", \"/\" ],\nStdoutEvent  => \"gotchildstdout\",\nStderrEvent  => \"gotchildstderr\",\nCloseEvent   => \"gotchildclose\",\n);\n$[KERNEL]->sigchild($child->PID, \"gotchildsignal\");\n# Wheel events include the wheel's ID.\n$[HEAP]{childrenbywid}{$child->ID} = $child;\n# Signal events include the process ID.\n$[HEAP]{childrenbypid}{$child->PID} = $child;\nprint(\n\"Child pid \", $child->PID,\n\" started as wheel \", $child->ID, \".\\n\"\n);\n}\n# Wheel event, including the wheel's ID.\nsub onchildstdout {\nmy ($stdoutline, $wheelid) = @[ARG0, ARG1];\nmy $child = $[HEAP]{childrenbywid}{$wheelid};\nprint \"pid \", $child->PID, \" STDOUT: $stdoutline\\n\";\n}\n# Wheel event, including the wheel's ID.\nsub onchildstderr {\nmy ($stderrline, $wheelid) = @[ARG0, ARG1];\nmy $child = $[HEAP]{childrenbywid}{$wheelid};\nprint \"pid \", $child->PID, \" STDERR: $stderrline\\n\";\n}\n# Wheel event, including the wheel's ID.\nsub onchildclose {\nmy $wheelid = $[ARG0];\nmy $child = delete $[HEAP]{childrenbywid}{$wheelid};\n# May have been reaped by onchildsignal().\nunless (defined $child) {\nprint \"wid $wheelid closed all pipes.\\n\";\nreturn;\n}\nprint \"pid \", $child->PID, \" closed all pipes.\\n\";\ndelete $[HEAP]{childrenbypid}{$child->PID};\n}\nsub onchildsignal {\nprint \"pid $[ARG1] exited with status $[ARG2].\\n\";\nmy $child = delete $[HEAP]{childrenbypid}{$[ARG1]};\n# May have been reaped by onchildclose().\nreturn unless defined $child;\ndelete $[HEAP]{childrenbywid}{$child->ID};\n}",
    "sections": {
        "NAME": {
            "content": "POE::Wheel::Run - portably run blocking code and programs in subprocesses\n",
            "subsections": []
        },
        "SYNOPSIS": {
            "content": "#!/usr/bin/perl\n\nuse warnings;\nuse strict;\n\nuse POE qw( Wheel::Run );\n\nPOE::Session->create(\ninlinestates => {\nstart           => \\&onstart,\ngotchildstdout => \\&onchildstdout,\ngotchildstderr => \\&onchildstderr,\ngotchildclose  => \\&onchildclose,\ngotchildsignal => \\&onchildsignal,\n}\n);\n\nPOE::Kernel->run();\nexit 0;\n\nsub onstart {\nmy $child = POE::Wheel::Run->new(\nProgram => [ \"/bin/ls\", \"-1\", \"/\" ],\nStdoutEvent  => \"gotchildstdout\",\nStderrEvent  => \"gotchildstderr\",\nCloseEvent   => \"gotchildclose\",\n);\n\n$[KERNEL]->sigchild($child->PID, \"gotchildsignal\");\n\n# Wheel events include the wheel's ID.\n$[HEAP]{childrenbywid}{$child->ID} = $child;\n\n# Signal events include the process ID.\n$[HEAP]{childrenbypid}{$child->PID} = $child;\n\nprint(\n\"Child pid \", $child->PID,\n\" started as wheel \", $child->ID, \".\\n\"\n);\n}\n\n# Wheel event, including the wheel's ID.\nsub onchildstdout {\nmy ($stdoutline, $wheelid) = @[ARG0, ARG1];\nmy $child = $[HEAP]{childrenbywid}{$wheelid};\nprint \"pid \", $child->PID, \" STDOUT: $stdoutline\\n\";\n}\n\n# Wheel event, including the wheel's ID.\nsub onchildstderr {\nmy ($stderrline, $wheelid) = @[ARG0, ARG1];\nmy $child = $[HEAP]{childrenbywid}{$wheelid};\nprint \"pid \", $child->PID, \" STDERR: $stderrline\\n\";\n}\n\n# Wheel event, including the wheel's ID.\nsub onchildclose {\nmy $wheelid = $[ARG0];\nmy $child = delete $[HEAP]{childrenbywid}{$wheelid};\n\n# May have been reaped by onchildsignal().\nunless (defined $child) {\nprint \"wid $wheelid closed all pipes.\\n\";\nreturn;\n}\n\nprint \"pid \", $child->PID, \" closed all pipes.\\n\";\ndelete $[HEAP]{childrenbypid}{$child->PID};\n}\n\nsub onchildsignal {\nprint \"pid $[ARG1] exited with status $[ARG2].\\n\";\nmy $child = delete $[HEAP]{childrenbypid}{$[ARG1]};\n\n# May have been reaped by onchildclose().\nreturn unless defined $child;\n\ndelete $[HEAP]{childrenbywid}{$child->ID};\n}\n",
            "subsections": []
        },
        "DESCRIPTION": {
            "content": "POE::Wheel::Run executes a program or block of code in a subprocess, created the usual way:\nusing fork(). The parent process may exchange information with the child over the child's STDIN,\nSTDOUT and STDERR filehandles.\n\nIn the parent process, the POE::Wheel::Run object represents the child process. It has methods\nsuch as PID() and kill() to query and manage the child process.\n\nPOE::Wheel::Run's put() method sends data to the child's STDIN. Child output on STDOUT and\nSTDERR may be dispatched as events within the parent, if requested.\n\nPOE::Wheel::Run can also notify the parent when the child has closed its output filehandles.\nSome programs remain active, but they close their output filehandles to indicate they are done\nwriting.\n\nA more reliable way to detect child exit is to use POE::Kernel's sigchild() method to wait for\nthe wheel's process to be reaped. It is in fact vital to use sigchild() in all circumstances\nsince without it, POE will not try to reap child processes.\n\nFailing to use sigchild() has in the past led to wedged machines. Long-running programs have\nleaked processes, eventually consuming all available slots in the process table and requiring\nreboots.\n\nBecause process leaks are so severe, POE::Kernel will check for this condition on exit and\ndisplay a notice if it finds that processes are leaking. Developers should heed these warnings.\n\nPOE::Wheel::Run communicates with the child process in a line-based fashion by default. Programs\nmay override this by specifying some other POE::Filter object in \"StdinFilter\", \"StdoutFilter\",\n\"StdioFilter\" and/or \"StderrFilter\".\n",
            "subsections": []
        },
        "PUBLIC METHODS": {
            "content": "",
            "subsections": [
                {
                    "name": "Constructor",
                    "content": "POE::Wheel subclasses tend to perform a lot of setup so that they run lighter and faster.\nPOE::Wheel::Run's constructor is no exception.\n\nnew"
                },
                {
                    "name": "new",
                    "content": "represent a child process with certain specified qualities. It also provides an OO- and\nevent-based interface for asynchronously interacting with the process.\n\nConduit\nConduit specifies the inter-process communications mechanism that will be used to pass data\nbetween the parent and child process. Conduit may be one of \"pipe\", \"socketpair\", \"inet\", \"pty\",\nor \"pty-pipe\". POE::Wheel::Run will use the most appropriate Conduit for the run-time (not the\ncompile-time) operating system, but this varies from one OS to the next.\n\nInternally, POE::Wheel::Run passes the Conduit type to POE::Pipe::OneWay and POE::Pipe::TwoWay.\nThese helper classes were created to make IPC portable and reusable. They do not require the\nrest of POE.\n\nThree Conduit types use pipes or pipelike inter-process communication: \"pipe\", \"socketpair\" and\n\"inet\". They determine whether the internal IPC uses pipe(), socketpair() or Internet sockets.\nThese Conduit values are passed through to POE::Pipe::OneWay or POE::Pipe::TwoWay internally.\n\nThe \"pty\" conduit type runs the child process under a pseudo-tty, which is created by IO::Pty.\nPseudo-ttys (ptys) convince child processes that they are interacting with terminals rather than\npipes. This may be used to trick programs like ssh into believing it's secure to prompt for a\npassword, although passphraseless identities might be better for that.\n\nThe \"pty\" conduit cannot separate STDERR from STDOUT, but the \"pty-pipe\" mode can.\n\nThe \"pty-pipe\" conduit uses a pty for STDIN and STDOUT and a one-way pipe for STDERR. The\nadditional pipe keeps STDERR output separate from STDOUT.\n\nThe IO::Pty module is only loaded if \"pty\" or \"pty-pipe\" is used. It's not a dependency until\nit's actually needed.\n\nWinsize\nWinsize sets the child process' terminal size. Its value should be an arrayref with four\nelements. The first two elements must be the number of lines and columns for the child's\nterminal window, respectively. The second pair of elements describe the terminal's X and Y\ndimensions in pixels. If the last pair is missing, they will be calculated from the lines and\ncolumns using a 9x16 cell size.\n\n$[HEAP]{child} = POE::Wheel::Run->new(\n# ... among other things ...\nWinsize => [ 25, 80, 720, 400 ],\n);\n\nWinsize is only valid for conduits that use pseudo-ttys: \"pty\" and \"pty-pipe\". Other conduits\ndon't simulate terminals, so they don't have window sizes.\n\nWinsize defaults to the parent process' window size, assuming the parent process has a terminal\nto query.\n\nCloseOnCall\nCloseOnCall, when true, turns on close-on-exec emulation for subprocesses that don't actually\ncall exec(). These would be instances when the child is running a block of code rather than\nexecuting an external program. For example:\n\n$[HEAP]{child} = POE::Wheel::Run->new(\n# ... among other things ...\nCloseOnCall => 1,\nProgram => \\&somefunction,\n);\n\nCloseOnCall is off (0) by default.\n\nCloseOnCall works by closing all file descriptors greater than $^F in the child process before\ncalling the application's code. For more details, please the discussion of $^F in perlvar.\n\nStdioDriver\nStdioDriver specifies a single POE::Driver object to be used for both STDIN and STDOUT. It's\nequivalent to setting \"StdinDriver\" and \"StdoutDriver\" to the same POE::Driver object.\n\nPOE::Wheel::Run will create and use a POE::Driver::SysRW driver of one isn't specified. This is\nby far the most common use case, so it's the default.\n\nStdinDriver\n\"StdinDriver\" sets the POE::Driver used to write to the child process' STDIN IPC conduit. It is\nalmost never needed. Omitting it will allow POE::Wheel::Run to use an internally created\nPOE::Driver::SysRW object.\n\nStdoutDriver\n\"StdoutDriver\" sets the POE::Driver object that will be used to read from the child process'\nSTDOUT conduit. It's almost never needed. If omitted, POE::Wheel::Run will internally create and\nuse a POE::Driver::SysRW object.\n\nStderrDriver\n\"StderrDriver\" sets the driver that will be used to read from the child process' STDERR conduit.\nAs with \"StdoutDriver\", it's almost always preferable to let POE::Wheel::Run instantiate its own\ndriver.\n\nCloseEvent\nCloseEvent contains the name of an event that the wheel will emit when the child process closes\nits last open output handle. This is a consistent notification that the child is done sending\noutput. Please note that it does not signal when the child process has exited. Programs should\nuse sigchild() to detect that.\n\nWhile it is impossible for ErrorEvent or StdoutEvent to happen after CloseEvent, there is no\nsuch guarantee for CHLD, which may happen before or after CloseEvent.\n\nIn addition to the usual POE parameters, each CloseEvent comes with one of its own:\n\n\"ARG0\" contains the wheel's unique ID. This can be used to keep several child processes separate\nwhen they're managed by the same session.\n\nA sample close event handler:\n\nsub closestate {\nmy ($heap, $wheelid) = @[HEAP, ARG0];\n\nmy $child = delete $heap->{child}->{$wheelid};\nprint \"Child \", $child->PID, \" has finished.\\n\";\n}\n\nErrorEvent\nErrorEvent contains the name of an event to emit if something fails. It is optional; if omitted,\nthe wheel will not notify its session if any errors occur. However, POE::Wheel::Run->new() will\nstill throw an exception if it fails.\n\n\"ARG0\" contains the name of the operation that failed. It may be 'read', 'write', 'fork', 'exec'\nor the name of some other function or task. The actual values aren't yet defined. They will\nprobably not correspond so neatly to Perl builtin function names.\n\n\"ARG1\" and \"ARG2\" hold numeric and string values for $!, respectively. \"$!\" will eq \"\" for read\nerror 0 (child process closed the file handle).\n\n\"ARG3\" contains the wheel's unique ID.\n\n\"ARG4\" contains the name of the child filehandle that has the error. It may be \"STDIN\",\n\"STDOUT\", or \"STDERR\". The sense of \"ARG0\" will be the opposite of what you might normally\nexpect for these handles. For example, POE::Wheel::Run will report a \"read\" error on \"STDOUT\"\nbecause it tried to read data from the child's STDOUT handle.\n\nA sample error event handler:\n\nsub errorstate {\nmy ($operation, $errnum, $errstr, $wheelid) = @[ARG0..ARG3];\n$errstr = \"remote end closed\" if $operation eq \"read\" and !$errnum;\nwarn \"Wheel $wheelid generated $operation error $errnum: $errstr\\n\";\n}\n\nNote that unless you deactivate the signal pipe, you might also see \"EIO\" (5) error during read\noperations.\n\nStdinEvent\nStdinEvent contains the name of an event that Wheel::Run emits whenever everything queued by its"
                },
                {
                    "name": "put",
                    "content": "POE::Wheel::ReadWrite's FlushedEvent.\n\nStdinEvent comes with only one additional parameter: \"ARG0\" contains the unique ID for the wheel\nthat sent the event.\n\nStdoutEvent\nStdoutEvent contains the name of an event that Wheel::Run emits whenever the child process\nwrites something to its STDOUT filehandle. In other words, whatever the child prints to STDOUT,\nthe parent receives a StdoutEvent---provided that the child prints something compatible with the\nparent's StdoutFilter.\n\nStdoutEvent comes with two parameters. \"ARG0\" contains the information that the child wrote to\nSTDOUT. \"ARG1\" holds the unique ID of the wheel that read the output.\n\nsub stdoutstate {\nmy ($heap, $input, $wheelid) = @[HEAP, ARG0, ARG1];\nprint \"Child process in wheel $wheelid wrote to STDOUT: $input\\n\";\n}\n\nStderrEvent\nStderrEvent behaves exactly as StdoutEvent, except for data the child process writes to its\nSTDERR filehandle.\n\nStderrEvent comes with two parameters. \"ARG0\" contains the information that the child wrote to\nSTDERR. \"ARG1\" holds the unique ID of the wheel that read the output.\n\nsub stderrstate {\nmy ($heap, $input, $wheelid) = @[HEAP, ARG0, ARG1];\nprint \"Child process in wheel $wheelid wrote to STDERR: $input\\n\";\n}\n\nRedirectStdout\nThis is a filehandle or filename to which standard output will be redirected. It is an error to\nuse this option together with StdoutEvent. This is useful in case your program needs to have\nstandard I/O, but do not actually care for its contents to be visible to the parent.\n\nRedirectStderr\nJust like RedirectStdout, but with standard error. It is an error to use this together with\nStderrEvent\n\nRedirectStdin\nThis is a filehandle or filename which the child process will use as its standard input. It is\nan error to use this option with StdinEvent\n\nRedirectOutput\nThis will redirect stderr and stdout to the same filehandle. This is equivalent to do doing\nsomething like\n\n$ something > /path/to/output 2>&1\n\nin bourne shell.\n\nNoStdin\nWhile output filehandles will be closed if there are no events to be received on them, stdin is\nopen by default - because lack of an event handler does not necessarily mean there is no desired\ninput stream. This option explicitly disables the creation of an IPC stdin conduit.\n\nStdioFilter\nStdioFilter, if used, must contain an instance of a POE::Filter subclass. This filter describes\nhow the parent will format put() data for the child's STDIN, and how the parent will parse the\nchild's STDOUT.\n\nIf STDERR will also be parsed, then a separate StderrFilter will also be needed.\n\nStdioFilter defaults to a POE::Filter::Line instance, but only if both StdinFilter and\nStdoutFilter are not specified. If either StdinFilter or StdoutFilter is used, then StdioFilter\nis illegal.\n\nStdinFilter\nStdinFilter may be used to specify a particular STDIN serializer that is different from the\nSTDOUT parser. If specified, it conflicts with StdioFilter. StdinFilter's value, if specified,\nmust be an instance of a POE::Filter subclass.\n\nWithout a StdinEvent, StdinFilter is illegal.\n\nStdoutFilter\nStdoutFilter may be used to specify a particular STDOUT parser that is different from the STDIN\nserializer. If specified, it conflicts with StdioFilter. StdoutFilter's value, if specified,\nmust be an instance of a POE::Filter subclass.\n\nWithout a StdoutEvent, StdoutFilter is illegal.\n\nStderrFilter\nStderrFilter may be used to specify a filter for a child process' STDERR output. If omitted,\nPOE::Wheel::Run will create and use its own POE::Filter::Line instance, but only if a\nStderrEvent is specified.\n\nWithout a StderrEvent, StderrFilter is illegal.\n\nGroup\nGroup contains a numeric group ID that the child process should run within. By default, the\nchild process will run in the same group as the parent.\n\nGroup is not fully portable. It may not work on systems that have no concept of user groups.\nAlso, the parent process may need to run with elevated privileges for the child to be able to\nchange groups.\n\nUser\nUser contains a numeric user ID that should own the child process. By default, the child process\nwill run as the same user as the parent.\n\nUser is not fully portable. It may not work on systems that have no concept of users. Also, the\nparent process may need to run with elevated privileges for the child to be able to change\nusers.\n\nNoSetSid\nWhen true, NoSetSid disables setsid() in the child process. By default, the child process calls"
                },
                {
                    "name": "setsid",
                    "content": "NoSetPgrp\nWhen true, NoSetPgrp disables setprgp() in the child process. By default, the child process\ncalls setpgrp() to change its process group, if the OS supports that.\n"
                },
                {
                    "name": "setsid",
                    "content": "Priority\nPriority adjusts the child process' niceness or priority level, depending on which (if any) the\nunderlying OS supports. Priority contains a numeric offset which will be added to the parent's\npriority to determine the child's.\n\nThe priority offset may be negative, which in UNIX represents a higher priority. However UNIX\nrequires elevated privileges to increase a process' priority.\n\nProgram\nProgram specifies the program to exec() or the block of code to run in the child process.\nProgram's type is significant.\n\nIf Program holds a scalar, its value will be executed as exec($program). Shell metacharacters\nare significant, per exec(SCALAR) semantics.\n\nIf Program holds an array reference, it will executed as exec(@$program). As per exec(ARRAY),\nshell metacharacters will not be significant.\n\nIf Program holds a code reference, that code will be called in the child process. This mode\nallows POE::Wheel::Run to execute long-running internal code asynchronously, while the usual\nmodes execute external programs. The child process will exit after that code is finished, in\nsuch a way as to avoid DESTROY and END block execution. See \"Coderef Execution Side Effects\" for\nmore details.\n\nperlfunc has more information about exec() and the different ways to call it.\n\nPlease avoid calling exit() explicitly when executing a subroutine. The child process inherits\nall objects from the parent, including ones that may perform side effects. POE::Wheel::Run takes\nspecial care to avoid object destructors and END blocks in the child process, but calling exit()\nwill trigger them.\n\nProgramArgs\nIf specified, ProgramArgs should refer to a list of parameters for the program being run.\n\nmy @parameters = qw(foo bar baz);  # will be passed to Program\nProgramArgs => \\@parameters;\n\nevent EVENTTYPE => EVENTNAME, ..."
                },
                {
                    "name": "event",
                    "content": "occurs. EVENTTYPE may be one of the event parameters described in POE::Wheel::Run's\nconstructor.\n\nThis example changes the events that $wheel emits for STDIN flushing and STDOUT activity:\n\n$wheel->event(\nStdinEvent  => 'new-stdin-event',\nStdoutEvent => 'new-stdout-event',\n);\n\nUndefined EVENTNAMEs disable events.\n\nput RECORDS"
                },
                {
                    "name": "put",
                    "content": "These records will first be serialized according to the wheel's StdinFilter. The serialized\nRECORDS will be flushed asynchronously once the current event handler returns.\n\ngetstdinfilter"
                },
                {
                    "name": "get_stind_filter",
                    "content": "records for the child's STDIN filehandle. The return object may be used according to its own\ninterface.\n\ngetstdoutfilter"
                },
                {
                    "name": "get_stdout_filter",
                    "content": "process writes to STDOUT.\n\ngetstderrfilter"
                },
                {
                    "name": "get_stderr_filter",
                    "content": "process writes to STDERR.\n\nsetstdiofilter FILTEROBJECT\nSet StdinFilter and StdoutFilter to the same new FILTEROBJECT. Unparsed STDOUT data will be\nparsed later by the new FILTEROBJECT. However, data already put() will remain serialized by the\nold filter.\n\nsetstdinfilter FILTEROBJECT\nSet StdinFilter to a new FILTEROBJECT. Data already put() will remain serialized by the old\nfilter.\n\nsetstdoutfilter FILTEROBJECT\nSet StdoutFilter to a new FILTEROBJECT. Unparsed STDOUT data will be parsed later by the new\nFILTEROBJECT.\n\nsetstderrfilter FILTEROBJECT\nSet StderrFilter to a new FILTEROBJECT. Unparsed STDERR data will be parsed later by the new\nFILTEROBJECT.\n\npausestdout\nPause reading of STDOUT from the child. The child process may block if the STDOUT IPC conduit\nfills up. Reading may be resumed with resumestdout().\n\npausestderr\nPause reading of STDERR from the child. The child process may block if the STDERR IPC conduit\nfills up. Reading may be resumed with resumestderr().\n\nresumestdout\nResume reading from the child's STDOUT filehandle. This is only meaningful if pausestdout() has\nbeen called and remains in effect.\n\nresumestderr\nResume reading from the child's STDERR filehandle. This is only meaningful if pausestderr() has\nbeen called and remains in effect.\n\nshutdownstdin"
                },
                {
                    "name": "shutdown_stdin",
                    "content": "It is extremely useful for running utilities that expect to receive EOF on STDIN before they\nrespond.\n\nID\nID() returns the wheel's unique ID. Every event generated by a POE::Wheel::Run object includes a\nwheel ID so that it can be matched to the wheel that emitted it. This lets a single session\nmanage several wheels without becoming confused about which one generated what event.\n\nID() is not the same as PID().\n\nPID\nPID() returns the process ID for the child represented by the POE::Wheel::Run object. It's often\nused as a parameter to sigchild().\n\nPID() is not the same as ID().\n\nkill SIGNAL\nPOE::Wheel::Run's kill() method sends a SIGNAL to the child process the object represents."
                },
                {
                    "name": "kill",
                    "content": "signal names present in %SIG.\n"
                },
                {
                    "name": "kill",
                    "content": "since the POE::Wheel::Run object only affects at most a single process.\n"
                },
                {
                    "name": "kill",
                    "content": "getdriveroutmessages"
                },
                {
                    "name": "get_driver_out_messages",
                    "content": "POE::Wheel::Run's POE::Driver output queue. It is often used to tell whether the wheel has more\ninput for the child process.\n\nIn most cases, StdinEvent may be used to trigger activity when all data has been sent to the\nchild process.\n\ngetdriveroutoctets"
                },
                {
                    "name": "get_driver_out_octets",
                    "content": "POE::Driver output queue. It is often used to tell whether the wheel has more input for the\nchild process.\n"
                }
            ]
        },
        "TIPS AND TRICKS": {
            "content": "MSWin32 Support\nIn the past POE::Wheel::Run did not support MSWin32 and users had to use custom work-arounds.\nThen Chris Williams ( BINGOS ) arrived and saved the day with his POE::Wheel::Run::Win32 module.\nAfter some testing, it was decided to merge the win32 code into POE::Wheel::Run. Everyone was\nhappy!\n\nHowever, after some investigation Apocalypse ( APOCAL ) found out that in some situations it\nstill didn't behave properly. The root cause was that the win32 code path in POE::Wheel::Run\ndidn't exit cleanly. This means DESTROY and END blocks got executed! After talking with more\npeople, the solution was not pretty.\n\nThe problem is that there is no equivalent of POSIX::exit() for MSWin32. Hopefully, in a future\nversion of Perl this can be fixed! In the meantime, POE::Wheel::Run will use CORE::kill() to\nterminate the child. However, this comes with a caveat: you will leak around 1KB per exec. The\ncode has been improved so the chance of this happening has been reduced.\n\nAs of now the most reliable way to trigger this is to exec an invalid binary. The definition of\n\"invalid binary\" depends on different things, but what it means is that Win32::Job->spawn()\nfailed to run. This will force POE::Wheel::Run to use the workaround to exit the child. If this\nhappens, a very big warning will be printed to the STDERR of the child and the parent process\nwill receive it.\n\nIf you are a Perl MSWin32 hacker, PLEASE help us with this situation! Go read rt.cpan.org bug\n#56417 and talk with us/p5p to see where you can contribute.\n\nThanks again for your patience as we continue to improve POE::Wheel::Run on MSWin32!\n\nkill() and ClosedEvent on Windows\nWindows will often fail to report EOF on pipes when subprocesses are killed. The work-around is\nto catch the signal in the subprocess, and exit normally:\n\nmy $child = POE::Wheel::Run->new(\nProgram => sub {\n$SIG{INT} = sub { exit };\n...;\n},\n...,\n);\n\nBe sure to kill() the subprocess using the same signal that it catches and exits upon. Remember,\nnot all signals can be caught by user code.\n\n$child->kill(\"INT\");\n",
            "subsections": [
                {
                    "name": "Execution Environment",
                    "content": "It's common to scrub a child process' environment, so that only required, secure values exist.\nThis amounts to clearing the contents of %ENV and repopulating it.\n\nEnvironment scrubbing is easy when the child process is running a subroutine, but it's not so\neasy---or at least not as intuitive---when executing external programs.\n\nThe way we do it is to run a small subroutine in the child process that performs the exec() call\nfor us.\n\nProgram => \\&execwithscrubbedenv,\n\nsub execwithscrubbedenv {\ndelete @ENV{keys @ENV};\n$ENV{PATH} = \"/bin\";\nexec(@programandargs);\n}\n\nThat deletes everything from the environment and sets a simple, secure PATH before executing a\nprogram.\n"
                },
                {
                    "name": "Coderef Execution Side Effects",
                    "content": "The child process is created by fork(), which duplicates the parent process including a copy of\nPOE::Kernel, all running Session instances, events in the queue, watchers, open filehandles, and\nso on.\n\nWhen executing an external program, the UNIX exec() call immediately replaces the copy of the\nparent with a completely new program.\n\nWhen executing internal coderefs, however, we must preserve the code and any memory it might\nreference. This leads to some potential side effects.\n\nDESTROY and END Blocks Run Twice\nObjects that were created in the parent process are copied into the child. When the child exits\nnormally, any DESTROY and END blocks are executed there. Later, when the parent exits, they may\nrun again.\n\nPOE::Wheel::Run takes steps to avoid running DESTROY and END blocks in the child process. It\nuses POSIX::exit() to bypass them. If that fails, it may even kill() itself.\n\nIf an application needs to exit explicitly, for example to return an error code to the parent\nprocess, then please use POSIX::exit() rather than Perl's core exit().\n\nPOE::Kernel's run() method was never called\nThis warning is displayed from POE::Kernel's DESTROY method. It's a side effect of calling"
                },
                {
                    "name": "exit",
                    "content": "child process receives a copy of POE::Kernel where run() wasn't called, even if it was called\nlater in the parent process.\n\nThe most direct solution is to call POSIX::exit() rather than exit(). This will bypass\nPOE::Kernel's DESTROY, and the message it emits.\n\nRunning POE::Kernel in the Child\nCalling \"POE::Kernel->run()\" in the child process effectively resumes the copy of the parent\nprocess. This is rarely (if ever) desired.\n\nMore commonly, an application wants to run an entirely new POE::Kernel instance in the child\nprocess. This is supported by first stop()ping the copied instance, starting one or more new\nsessions, and calling run() again. For example:\n\nProgram => sub {\n# Wipe the existing POE::Kernel clean.\n$poekernel->stop();\n\n# Start a new session, or more.\nPOE::Session->create(\n...\n);\n\n# Run the new sessions.\nPOE::Kernel->run();\n}\n\nStrange things are bound to happen if the program does not call \"stop\" in POE::Kernel before\n\"run\" in POE::Kernel. However this is vaguely supported in case it's the right thing to do at\nthe time.\n"
                }
            ]
        },
        "SEE ALSO": {
            "content": "POE::Wheel describes wheels in general.\n\nThe SEE ALSO section in POE contains a table of contents covering the entire POE distribution.\n\nCAVEATS & TODOS\nPOE::Wheel::Run's constructor should emit proper events when it fails. Instead, it just dies,\ncarps or croaks. This isn't necessarily bad; a program can trap the death in new() and move on.\n\nPriority is a delta, not an absolute niceness value.\n\nIt might be nice to specify User by name rather than just UID.\n\nIt might be nice to specify Group by name rather than just GID.\n\nPOE::Pipe::OneWay and Two::Way don't require the rest of POE. They should be spun off into a\nseparate distribution for everyone to enjoy.\n\nIf StdinFilter and StdoutFilter seem backwards, remember that it's the filters for the child\nprocess. StdinFilter is the one that dictates what the child receives on STDIN. StdoutFilter\ntells the parent how to parse the child's STDOUT.\n\nAUTHORS & COPYRIGHTS\nPlease see POE for more information about authors and contributors.\n",
            "subsections": []
        }
    },
    "summary": "POE::Wheel::Run - portably run blocking code and programs in subprocesses",
    "flags": [],
    "examples": [],
    "see_also": []
}