Страниц: [1]
  Печать  
Автор Тема: Чтение stdout, stderr дочернего процесса  (Прочитано 2885 раз)
Goofy
Full Member
***
Offline Offline

Сообщений: 122


Просмотр профиля
« : Апреля 27, 2011, 09:23:20 pm »

Поток номер 1:

Код:
int cmd_spawn ( sch_cmd_desc_t *cmd, char *executable, char **argv ) {
int spawned_process_rv;
int rv = EOK;
int out[2];
int err[2];
int fd_map[3];
FILE *msg_stream;
FILE *err_stream;
pid_t pid;
int oldstate;

char path[PATH_MAX + 1];
char buff[PATH_MAX + 1];
char *exec_path = NULL;

struct inheritance inherit;

pthread_t report_msg_thread_tid;
pthread_t report_err_thread_tid;

argv[0] = executable;

if ( pipe( out ) == -1 ) {
err_report_strerror (__func__". pipe creation error");
report_err ( cmd, "pipe creation failed" );
rv = errno;
goto pipe_failed;
}
if ( pipe( err ) == -1 ) {
err_report_strerror (__func__". pipe creation error");
report_err ( cmd, "pipe creation failed" );
rv = errno;
goto pipe_failed1;
}

// Поиск директории для бинарника
if ( ( confstr(_CS_PATH, path, sizeof (path) ) == 0 )
|| ( ( exec_path = pathfind_r(path, executable, "x", buff, sizeof (buff) ) ) == NULL ) ) {
report_err ( cmd, "%s can not be found", executable );
return -1;
}

fd_map[STDIN_FILENO] = STDIN_FILENO;
fd_map[STDOUT_FILENO] = out [1];
fd_map[STDERR_FILENO] = err [1];
// Открываем поток стандартного вывода
if ( ( msg_stream = fdopen ( out [0], "r" ) ) == NULL ) {
err_report_strerror (__func__". stream reopening error");
} else {
fwide(msg_stream, -1);
}
// Открываем поток сообщений ошибок
if ( ( err_stream = fdopen ( err [0], "r" ) ) == NULL ) {
err_report_strerror (__func__". stream reopening error");
} else {
fwide( err_stream, -1);
}

memset ( &inherit, 0 , sizeof ( inherit ) );

inherit.flags = SPAWN_SETSID;
// Запускаем процесс
pid = spawn( exec_path,
            3,
            fd_map,
            &inherit,
            argv,
            NULL );

if ( (int)pid == -1 ) {
err_report_strerror (__func__". spawn error");
report_err ( cmd, "spawn failed: %s", strerror ( errno ) );
goto spawn_failed;
}

if ( ( report_msg_thread_tid = cmd_spawn_pipe_deliver_thread_start ( cmd, msg_stream, MSG ) ) == -1 ) {
report_err ( cmd, "stdout reading thread failed to start: %s", strerror ( errno ) );
}

if ( ( report_err_thread_tid = cmd_spawn_pipe_deliver_thread_start ( cmd, err_stream, ERR ) ) == -1 ) {
report_err ( cmd, "stderr reading thread failed to start: %s", strerror ( errno ) );
}

//Добавляем в стек функцию посылки SIGTERM сигнала дочернему процессу
pthread_cleanup_push ( ( void* ) termination_handler, &pid );
// Отмена потока приёма отчётов
pthread_cleanup_push ( ( void* ) deliver_thread_termination_handler, &report_msg_thread_tid );
pthread_cleanup_push ( ( void* ) deliver_thread_termination_handler, &report_err_thread_tid );

// Окончание выподнения дочернего процесса
waitpid( pid,
               &spawned_process_rv,
               WEXITED );
    
...

запускает дочерний процесс и ждёт его завершения, при этом запущены потоки 2, 3:

Код:
int cmd_spawn_pipe_deliver_thread ( struct _spawn_opt *opt ) {

char  tmp_exec_str[200];

pthread_cleanup_push ( &free_handler, opt );

while ( fgets ( tmp_exec_str, MAX_REPORT_STR_SIZE, opt -> stream ) != NULL ) {
  //tmp_exec_str[ strlen ( tmp_exec_str ) ] = 0;
  switch ( opt -> type ) {
  case MSG:
  report_msg ( opt -> cmd, "%s", tmp_exec_str );
  break;
 
  case ERR:
  report_err ( opt -> cmd, "%s", tmp_exec_str );
  break;
  }
}
if ( errno != EOK ) {
err_report (__func__". fgets error %s", strerror ( errno ) );
}

pthread_cleanup_pop ( 1 );

return EOK;
}

Которые при работе дочернего процесса транслируют на уровень выше стандартный вывод и стандартный канал ошибок через pipe.

Тестовые дочерний процесс:
Код:
while ( j -- > 0 ) {
printf ( "line\n" );
fprintf ( stderr, "errline\n" );
delay ( 500 );
}

Проблема в том, что stdout доставляеся только после завершения процесса, тогда как stderr транслирует сообщения по ходу их появления.
Не подскажите, в чем я ошибся, что недоглядел или не учёл?
Записан
lesav
Sr. Member
****
Offline Offline

Сообщений: 262



Просмотр профиля
« Ответ #1 : Апреля 27, 2011, 09:45:21 pm »

flush (stdout) ?
Записан

lesav
Sr. Member
****
Offline Offline

Сообщений: 262



Просмотр профиля
« Ответ #2 : Апреля 27, 2011, 09:47:32 pm »

Пардон
fflush(stdout);
Записан

Goofy
Full Member
***
Offline Offline

Сообщений: 122


Просмотр профиля
« Ответ #3 : Апреля 28, 2011, 05:23:07 am »

Это ведь на стороне дочернего приложения?
В идеале бы избежать любых модификаций внешнего приложения, ибо иной раз модификация невозможна

Кстати, у ping"а, стандартный вывод читается as it comes. Подозреваю что без fflush()
Записан
darkelf
QOR.Moderator
*****
Offline Offline

Сообщений: 259


Просмотр профиля
« Ответ #4 : Апреля 28, 2011, 09:45:04 am »

Это ведь на стороне дочернего приложения?
В идеале бы избежать любых модификаций внешнего приложения, ибо иной раз модификация невозможна
Насколько я знаю иначе - никак. Данные буферизируются на уровне libc, и извне заставить их выдать раньше никак нельзя. Обычно в программах или закладывают доп.ключ, или анализируют происходит вывод на tty (isatty()) или куда ещё и на основании этого включают построчную буферизацию (setvbuf()) или периодически вызывают сброс буфера (fflush()).
« Последнее редактирование: Апреля 28, 2011, 09:47:06 am от darkelf » Записан
Страниц: [1]
  Печать  
 
Перейти в: