2013-02-07 5 views
9

Ich benutze libuv. Ich habe http://nikhilm.github.com/uvbook/processes.html gelesen und kann immer noch nicht herausfinden, wie man den stdout eines Kindprozesses feststellt, so dass es im Elternteil verfügbar ist (aber nicht an der Stelle des Muttersterns).Capture die stdout eines Kindprozesses mit libuv

Mein Code ist zur Zeit:

#include <stdio.h> 
#include <stdlib.h> 
#include "../../libuv/include/uv.h" 

uv_loop_t *loop; 
uv_process_t child_req; 
uv_process_options_t options; 
uv_pipe_t apipe; 

void on_child_exit(uv_process_t *req, int exit_status, int term_signal) { 
    fprintf(stderr, "Process exited with status %d, signal %d\n", exit_status, term_signal); 
    uv_close((uv_handle_t*) req, NULL); 
} 

uv_buf_t alloc_buffer(uv_handle_t *handle, size_t len) { 
    printf("alloc_buffer called\n"); 
    uv_buf_t buf; 
    buf.base = malloc(len); 
    buf.len = len; 
    return buf; 
} 

void read_apipe(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { 
    printf("read %li bytes from the child process\n", nread); 
} 

int main(int argc, char *argv[]) { 
    printf("spawn_test\n"); 
    loop = uv_default_loop(); 

    char* args[3]; 
    args[0] = "dummy"; 
    args[1] = NULL; 
    args[2] = NULL; 

    uv_pipe_init(loop, &apipe, 0); 
    uv_pipe_open(&apipe, 0); 

    options.stdio_count = 3; 
    uv_stdio_container_t child_stdio[3]; 
    child_stdio[0].flags = UV_IGNORE; 
    child_stdio[1].flags = UV_INHERIT_STREAM; 
    child_stdio[1].data.stream = (uv_stream_t *) &apipe; 
    child_stdio[2].flags = UV_IGNORE; 
    options.stdio = child_stdio; 

    options.exit_cb = on_child_exit; 
    options.file = args[0]; 
    options.args = args; 

    uv_read_start((uv_stream_t*)&apipe, alloc_buffer, read_apipe); 
    if (uv_spawn(loop, &child_req, options)) { 
     fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop))); 
     return 1; 
    } 

    return uv_run(loop, UV_RUN_DEFAULT); 
} 

dummy.c:

#include <unistd.h> 
#include <stdio.h> 

int main() { 
    printf("child starting\n"); 
    sleep(1); 
    printf("child running\n"); 
    sleep(2); 
    printf("child ending\n"); 
    return 0; 
} 

Ich habe das nagende Gefühl, dass ich nicht ganz den Punkt der libuv Pfeifen noch verstehen.

Antwort

5

Ich habe die Lösung gefunden:

  1. ich die falschen Fahnen hatten, sollten sie UV_CREATE_PIPE | UV_READABLE_PIPE nicht UV_INHERIT_STREAM gewesen.
  2. Ich musste uv_read_start nach uv_spawn anrufen. Ich gehe davon aus, dass keine Datenverluste möglich sind, da uv_run noch nicht aufgerufen wurde.
  3. Die obigen zwei Fixes zeigten alle Ausgaben von dummy bis zur Ankunft, anstatt in drei Knoten (wie es in der Befehlszeile geschieht). Eine fflush in dummy.c behoben dies.

spawn_test:

#include <stdio.h> 
#include <stdlib.h> 
#include "../../libuv/include/uv.h" 

uv_loop_t *loop; 
uv_process_t child_req; 
uv_process_options_t options; 
uv_pipe_t apipe; 

void on_child_exit(uv_process_t *req, int exit_status, int term_signal) { 
    fprintf(stderr, "Process exited with status %d, signal %d\n", exit_status, term_signal); 
    uv_close((uv_handle_t*) req, NULL); 
} 

uv_buf_t alloc_buffer(uv_handle_t *handle, size_t len) { 
    printf("alloc_buffer called, requesting a %lu byte buffer\n"); 
    uv_buf_t buf; 
    buf.base = malloc(len); 
    buf.len = len; 
    return buf; 
} 

void read_apipe(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { 
    printf("read %li bytes in a %lu byte buffer\n", nread, buf.len); 
    if (nread + 1 > buf.len) return; 
    buf.base[nread] = '\0'; // turn it into a cstring 
    printf("read: |%s|", buf.base); 
} 

int main(int argc, char *argv[]) { 
    printf("spawn_test\n"); 
    loop = uv_default_loop(); 

    char* args[3]; 
    args[0] = "dummy"; 
    args[1] = NULL; 
    args[2] = NULL; 

    uv_pipe_init(loop, &apipe, 0); 
    uv_pipe_open(&apipe, 0); 

    options.stdio_count = 3; 
    uv_stdio_container_t child_stdio[3]; 
    child_stdio[0].flags = UV_IGNORE; 
    child_stdio[1].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; 
    child_stdio[1].data.stream = (uv_stream_t *) &apipe; 
    child_stdio[2].flags = UV_IGNORE; 
    options.stdio = child_stdio; 

    options.exit_cb = on_child_exit; 
    options.file = args[0]; 
    options.args = args; 

    if (uv_spawn(loop, &child_req, options)) { 
     fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop))); 
     return 1; 
    } 
    uv_read_start((uv_stream_t*)&apipe, alloc_buffer, read_apipe); 

    return uv_run(loop, UV_RUN_DEFAULT); 
} 

dummy.c:

#include <unistd.h> 
#include <stdio.h> 

int main() { 
    printf("child starting\n"); 
    fflush(stdout); 
    sleep(1); 
    printf("child running\n"); 
    fflush(stdout); 
    sleep(2); 
    printf("child ending\n"); 
    fflush(stdout); 
    return 0; 
} 
4

Sehen Sie, wie sie es in der libuv Unit-Test tun libuv/test/test-stdio-over-pipes.c:

  • Rufen Sie nicht uv_pipe_open
  • Flags für stdin des Kindes: UV_CREATE_PIPE | UV_READABLE_PIPE
  • Flags für Kinder stdout und stderr: UV_CREATE_PIPE | UV_WRITABLE_PIPE

Es gibt auch eine issue auf Windows, wo uv_spawn zurückkehren könnte Null, obwohl es ein Fehler aufgetreten ist, und in diesen Fällen Sie Überprüfen Sie process.spawn_error, die nur unter Windows existiert.

Verwandte Themen