Модераторы: xvr

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> неблокируемый ввод процесса 
:(
    Опции темы
massiv
Дата 10.10.2009, 01:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 27.9.2009

Репутация: нет
Всего: нет



пытаюсь написать что то вроде автоматизации для инсталляхи. Потомок запускает инсталляху, родитель пишет в неё (отвечает на вопросы). Столкнулся с проблемой: как родитель узнает что потомок готов для того что бы в него писали? Пытаюсь использовать неблокируемый вывод, но что то  не так......Вопрос в следующем: всё ли я делаю правильно? возможно есть способы проще? Код с коментами ниже (дял примера беру инсталляху открытого интеловского компилятора (в нём диалогом много smile )):

Код

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/poll.h>

int main() 
{
  int file_pipes[2];
  const char some_data[] = "q\n";  // это для примера ввод: зашли в инсталляху и сразу вышли из неё
  pid_t fork_res;
  int status;
  int val, wc;
  struct pollfd fds;
 
  if (pipe(file_pipes) == 0) {  // создаём канал

    fork_res = fork();

    if (fork_res == (pid_t) -1) {
      fprintf(stderr, "Fork failure\n");
      exit(EXIT_FAILURE);
    }

    if (fork_res == (pid_t) 0) {   // 
      close(0);     // закрываем стандартный ввод
      dup(file_pipes[0]);        //  дублируем file_pipes[0]  как input
      close(file_pipes[0]);
      close(file_pipes[1]);            // теперь у потомка единственный дескриптор 0 связанный с каналом. всё что будем писать из родителя будет идти в input потомка

      execlp("/l_cproc_p_11.0.606_ia32/install.sh", "/l_cproc_p_11.0.606_ia32/install.sh", (char *) 0);

      exit(EXIT_FAILURE);
    }else {
      close(file_pipes[0]);

      val = fcntl(file_pipes[1], F_GETFL, 0);
      fcntl(file_pipes[1], F_SETFL, val | O_NONBLOCK);        // делаем дескриптор записи неблокируемым

      fds.fd = file_pipes[1];           // дальше идёт poll
      fds.events = POLLOUT;

      while (fds.events) {
    if (poll(&fds, 1, 0) < 0) {
      perror("poll");
      return 1;
    }

    if (fds.revents) {
      wc = write(file_pipes[1], some_data, strlen(some_data));         // говорим инсталляхе quit

      // if (wc < 0) {
      //  perror("write");
      //  return 1;
      // } else if (!wc) {
      //   fds.events = 0;
      // } else {
      //   some_data[wc] = '\0';
      // }
    }
      }
     

       close(file_pipes[1]);
    }
  }

  exit(EXIT_SUCCESS);
}

 
PM MAIL   Вверх
MAKCim
Дата 10.10.2009, 09:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



massiv, 
что _должно_ быть и что _не так_?

Добавлено через 2 минуты и 14 секунд
Цитата(massiv @  10.10.2009,  01:30 Найти цитируемый пост)
как родитель узнает что потомок готов для того что бы в него писали?

зачем знать?
сначала пишем, потом читаем, потом опять пишем и т. д.
и для чего здесь неблокируемый I/O?


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
massiv
Дата 10.10.2009, 10:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 27.9.2009

Репутация: нет
Всего: нет



Цитата

зачем знать?
сначала пишем, потом читаем, потом опять пишем и т. д.
и для чего здесь неблокируемый I/O? 



Разница в том , что родителю нужно осуществить последовательно несколько вводов, ввод нужно осуществлять только тогда когда потомок ждём ввода, на деле же получается так: запускаются два процесса, параллельно, например потомок ещё выводит диалоговое окно, а родитель успевает записать в его инпут 1-й , 2-й и 3-й символ, в то время как должен дождаться когда потомок выведет первый диалог и остановится в ожидании ввода  - тогда родитель должен записать в него 1-й символ, дождаться когда  когда потомок выведет второе диалоговое окно и только тогда родитель пишет в него 2-й символ,  ну и наконец  потомок выводит третье диалоговое окно и ждёт ввода - родитель пишет в него 3-й символ.  Если записать вот так, без всяких блокировок:

Код

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>

int main() 
{
  int file_pipes[2];
  pid_t fork_res;
  int status;
 
  if (pipe(file_pipes) == 0) {  // создаём канал
    fork_res = fork();
    if (fork_res == (pid_t) -1) {
      fprintf(stderr, "Fork failure\n");
      exit(EXIT_FAILURE);
    }
    if (fork_res == (pid_t) 0) {   // 
      close(0);     // закрываем стандартный ввод
      dup(file_pipes[0]);        //  дублируем file_pipes[0]  как input
      close(file_pipes[0]);
      close(file_pipes[1]);            // теперь у потомка единственный дескриптор 0 связанный с каналом. всё что будем писать из родителя будет идти в input потомка
      execlp("/l_cproc_p_11.0.606_ia32/install.sh", "/l_cproc_p_11.0.606_ia32/install.sh", (char *) 0);
      exit(EXIT_FAILURE);
    }else {
      close(file_pipes[0]);
      
     write(file_pipes[1],  "1\n", 4);    
     write(file_pipes[1],  "2\n", 4); 
     write(file_pipes[1],  "3\n", 4);      

    }
      }
     
       close(file_pipes[1]);
    }
  }
  exit(EXIT_SUCCESS);
}



то  три вызова write в родителе выполнятся сразу же друг за другом и им всё равно что в этот момент происходит с потомком, готов ли он к вводу. Нужно как то "распараллелить" два процесса, вот в чём проблема
PM MAIL   Вверх
MAKCim
Дата 10.10.2009, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(massiv @  10.10.2009,  10:57 Найти цитируемый пост)
то  три вызова write в родителе выполнятся сразу же друг за другом и им всё равно что в этот момент происходит с потомком, готов ли он к вводу. Нужно как то "распараллелить" два процесса, вот в чём проблема 

когда потомок захочет прочитать, он дернет read да и все
pipe - это буферизированная структура, данные в нем храняться, пока с другого конца не будет осуществлено чтение


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
massiv
Дата 10.10.2009, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 27.9.2009

Репутация: нет
Всего: нет



Цитата(MAKCim @ 10.10.2009,  14:10)
Цитата(massiv @  10.10.2009,  10:57 Найти цитируемый пост)
то  три вызова write в родителе выполнятся сразу же друг за другом и им всё равно что в этот момент происходит с потомком, готов ли он к вводу. Нужно как то "распараллелить" два процесса, вот в чём проблема 

когда потомок захочет прочитать, он дернет read да и все
pipe - это буферизированная структура, данные в нем храняться, пока с другого конца не будет осуществлено чтение

нет, не получается, у меня начинает создаваться впечатление что дело в терминале, как то он себя не так ведёт, после 3-го write потомок должен ожидать ввода, НО в него почему то что то записывается, что - я не знаю, инсталляха уходит в бесконечный цикл (всё время пишет что некорректный ввод), приходится с другова терминала убивать её ( ^C  не помогает).  Почему такое происходит? Может быть пожно от потомка получать какой нибудь сигнал когда он останавливается в ожидании ввода и только потом писать в него???
PM MAIL   Вверх
MAKCim
Дата 10.10.2009, 18:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



massiv, 
не знаю, что у вас там с терминалом, но вот такая тестовая программа и скрипт работают как надо
Код

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

/* program.c */

int main(int argc, char *argv[], char *envp[])
{
    pid_t pid;
    int pfd[2];

    if (argc < 2)
    {
        printf("usage: %s command [argument1] [argument2] ... [argumentN]\n", argv[0]);
        return 0;
    }
    
    if (pipe(pfd) < 0)
    {
        printf("pipe() failed [%s]\n", strerror(errno));
        return -1;
    }

    if ((pid = fork()) < 0)
    {
        printf("fork() failed [%s]\n", strerror(errno));
        return -1;
    }
    else if (pid == 0)
    {
        if (dup2(pfd[0], STDIN_FILENO) < 0)
        {
            printf("dup2() failed [%s]\n", strerror(errno));
            return -1;
        }

        close(pfd[0]);
        close(pfd[1]);

        if (execve(argv[1], argv + 1, envp) < 0)    
        {
            printf("execve() failed [%s]\n", strerror(errno));
            return -1;
        }
    }

    close(pfd[0]);
    
    {
        const char **str;
        const char *arr[] = 
        {
            "It's answer 1\n", 
            "It's answer 2\n", 
            "It's answer 3\n",
            NULL
        };

        for (str = arr; *str; ++str)
        {
            if (write(pfd[1], *str, strlen(*str)) < 0)
            {
                printf("write() failed [%s]\n", strerror(errno));
                return -1;
            }
        }
    }

    for (;;)
    {
        pause();
    }

    return 0;
}

Код

#!/bin/sh

# script.sh

echo "<question1>?"

# read answer on question 1
read answer

echo "answer1: $answer"

echo "<question2>?"

# read answer on question 2
read answer

echo "answer2: $answer"

echo "<question3>?"

# read answer on question 3
read answer

echo "answer3: $answer"

вызов
Код

# ./program ./script.sh



--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
massiv
Дата 10.10.2009, 20:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 27.9.2009

Репутация: нет
Всего: нет



Да действительно, проблем нет ,  попробовал ваш тестовый пример запустить со своей программной, всё корректно.  Видимо инсталляха какая то особенная. Прочитал в теме выше от  "Вывод строки из дочернего процесса"  от Hromonin,  там пишут что библиотека ncurses ведёт себя по особенному , не применятет напрямую stdin, stdout, похоже моя инсталляха написана именно на ней.
PM MAIL   Вверх
MAKCim
Дата 10.10.2009, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



massiv, 
протрассируйте через strace -f
многое прояснится




--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
massiv
Дата 11.10.2009, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 27.9.2009

Репутация: нет
Всего: нет



а есть ли ещё какой нибудь способ читать/писать   запущенный exec процесс из основного помимо использования каналов?
PM MAIL   Вверх
MAKCim
Дата 11.10.2009, 14:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



massiv, 
любой ipc


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
massiv
  Дата 12.10.2009, 07:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 27.9.2009

Репутация: нет
Всего: нет



ладно, спасибо smile 


Почитал про очереди сообщений, думаю что здесь их можно применить. Создание очереди , отправка/ получение сообщений, тут всё понятно , но как связать очередь с запученным execl  процессом,  ведь execl заменяет потомка запущенной программой,  и я уже никак не могу контроллировать потомка, я знаю только его PID и всё...

Это сообщение отредактировал(а) massiv - 12.10.2009, 13:42
PM MAIL   Вверх
svlary
Дата 13.10.2009, 06:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 8.9.2009

Репутация: 4
Всего: 4



Цитата

но как связать очередь с запученным execl  процессом

    Для этого и придуман механизм генерации КЛЮЧЕЙ по имени ФАЙЛА. Т.е. Вы выделяете в разарабатываемой системе некий "самый главный" файл, без которооо она точно - работать не будет. А дальше генерируете КЛЮЧИ - столько, сколько Вам надо, и создаете (по ключам) очереди.  Поскольку файл во всех Ваших программах используется ОДИН, то сгенерированные ключи будут одинаковы, а занчит, вы получите по ключам доступ к одим и тем же очередям :

Код

#define KEY_GEN_FILE "/usr/local/bin/MAIN"
#define NUM_MSG_QEUE 7

    for (j=0; j<NUM_MSG_QEUE; j++) {
                       // Создаем ключ
            key = ftok(KEY_GEN_FILE, j);
            if( key == -1 ){
                syslog(LOG_CRIT, "SI: Create key %d error : %m", j);
                return -1;
            }
            // Создаем новую очередь
            qid = msgget(key, oflag | IPC_CREAT);
            if( qid == -1 ){
                syslog(LOG_CRIT, "SI: Create queue %d error : %d(%m)", j, errno);
                return -1;
            }
            syslog(LOG_INFO, "Create queue ID %d for %s process.", qid, proc_name[j]);
        }

Этот код (с флагом IPC_CREAT) должен быть в корневом процессе системы. В остальных процессах - без этого флага и только для того значения j, которое соответствует очереди этого процесса.  Тут есть еще один тонкий момент... В то время. когда корневой процесс пытается СОЗДАТЬ очередь, она уже может СУЩЕСТВОВАТЬ, т.к. была создана ранеее. И даже более того - в этой очереди могут находиться сообщения. Что делать в такой ситуации - это уже Вам решать.
PM MAIL   Вверх
massiv
Дата 15.10.2009, 16:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 27.9.2009

Репутация: нет
Всего: нет



Дело в том, что под "связать очередь с запученным execl  процессом"  я имел ввиду связать главный процесс (он выполняет функцию msgsend) с инпутом сторонней программы? То есть я хочу сделать с применением очередей тоже, что было реализовано выше с помощью каналов.
PM MAIL   Вверх
svlary
Дата 16.10.2009, 04:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 8.9.2009

Репутация: 4
Всего: 4



Цитата(massiv @  15.10.2009,  16:39 Найти цитируемый пост)
я хочу сделать с применением очередей тоже, что было реализовано выше с помощью каналов. 

  А в чем проблема ? Обе программы имеют один и тот же КЛЮЧ очереди. Обе программы открывают одну и ту же очередь с помощью msgget. Одна  программа ложит сообщение в очередь с помощью msgsnd, другая - забирает это сообщение с помощью msgrcv.  Все это практически одинаково с open, write и read.

Добавлено через 2 минуты и 29 секунд
Цитата(massiv @  15.10.2009,  16:39 Найти цитируемый пост)
связать ... функцию msgsend ...с инпутом
 - А вот это сделать в принципе невозможно. Очередь сообщений - это не файл и перенаправить ее на stdin невозможно.

PM MAIL   Вверх
massiv
Дата 16.10.2009, 13:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 27.9.2009

Репутация: нет
Всего: нет



Цитата(massiv @ 11.10.2009,  14:13)
а есть ли ещё какой нибудь способ читать/писать   запущенный exec процесс из основного помимо использования каналов?

на этот вопрос , MAKCim ответил , что можно использовать любой IPC smile  то есть как я понимаю из ваших слов, такую автоматизацию (читайте мой самый первый пост) можно реализовать только используя каналы?
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0779 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.