Tarantool CE/EE Documentation portal logo
Помощь
Обновлена 15 сентября 2026 г. в 08:55

Модуль popen

Общие сведения

Начиная с: 2.4.1

В Tarantool есть встроенный модуль popen, предназначенный для выполнения внешних программ. Он работает аналогично модулю subprocess() в Python или Open3 в Ruby. Однако в popen нет вспомогательных средств, которые предоставляют эти языки; он предоставляет только базовые функции. Для создания объекта popen использует системный вызов vfork(), поэтому вызывающий поток блокируется до тех пор, пока не начинается выполнение дочернего процесса.

В модуле popen есть две функции для создания объекта popen:

  • popen.shell — похожа на системный вызов libc popen
  • popen.new — для создания объекта popen с более специфичными параметрами

Обе функции возвращают дескриптор, который мы будем называть popen_handle или ph. Через дескриптор вы можете выполнять методы.

Указатель

Ниже приведен перечень всех функций popen и методов дескриптора ph.

Имя

Назначение

popen.shell()

Выполнение shell-команды

popen.new()

Запуск дочерней программы в новом процессе

popen_handle:read()

Считывание данных из дочернего процесса

popen_handle:write()

Запись строки в поток stdin дочернего процесса

popen_handle:shutdown()

Закрытие концов std*-дескрипторов со стороны родителя

popen_handle:terminate()

Отправка сигнала SIGTERM дочернему процессу

popen_handle:kill()

Отправка сигнала SIGKILL дочернему процессу

popen_handle:signal()

Отправка сигнала дочернему процессу

popen_handle:info()

Получение информации о дескрипторе popen

popen_handle:wait()

Ожидание завершения или получения сигнала дочерним процессом

popen_handle:close()

Закрытие дескриптора popen

Константы модуля

Константы модуля

Поля дескриптора

Поля дескриптора

popen.shell(command[, mode])

Выполнение shell-команды.

Параметры:

  • command (string) — выполняемая команда, обязательный параметр
  • mode (string) — режим обмена данными, необязательный параметр

Возвращает

(при успешном выполнении) дескриптор popen, который мы будем называть popen_handle или ph

(при неудачном выполнении) nil, err

Возможные ошибки: если один из параметров задан некорректно, функция возвращает IllegalParams: неправильно задан тип или значение параметра. Другие возможные ошибки смотрите в разделе popen.new().

Возможные значения режима передачи данных mode:

Несколько символов режима можно задать вместе, например 'rw', 'rRw'.

Функция shell — это сокращение для popen.new({command}, opts) с opts.shell.setsid и opts.shell.group_signal, установленными в true, и значениями opts.stdin, opts.stdout и opts.stderr, установленными на основе параметра mode.

По умолчанию все потоки std* наследуются от родителя, если это не изменено с помощью режима: 'r' для stdout, 'R' для stderr или 'w' для stdin.

Пример:

Этот пример эквивалентен команде sh -c date. Он запускает процесс, выполняет 'date', считывает вывод и закрывает объект popen (ph).

local popen = require('popen')-- Запуск программы и сохранение ее дескриптора.local ph = popen.shell('date', 'r')-- Считывание вывода программы и удаление следующей строки.local date = ph:read():rstrip()-- Освобождение ресурсов. Процесс принудительно завершается (но 'date'-- все равно завершает работу).ph:close()print(date)

В Unix текстовый файл определяется как последовательность строк. Каждая строка завершается символом новой строки (\n). Это же соглашение обычно применяется к текстовому выводу команды. Поэтому при перенаправлении в файл файл будет корректным.

Однако внутри приложение обычно работает со строками, которые не завершаются символом новой строки (например, строки сообщений об ошибках). Символ новой строки обычно добавляется прямо перед записью строки в stdout, консоль или лог. Поэтому в примере выше был использован метод rstrip().

popen.new(argv[, opts])

Выполнение дочерней программы в новом процессе.

Параметры:

  • argv (array) — массив: программа для запуска и параметры командной строки, обязательный параметр; абсолютный путь к программе требуется, когда opts.shell равен false (по умолчанию)
  • opts (table) — таблица параметров, необязательный параметр

Возвращает

(при успешном выполнении) дескриптор popen, который мы будем называть popen_handle или ph

(при неудачном выполнении) nil, err

Возможные ошибки:

  • IllegalParams: некорректный тип или значение параметра
  • IllegalParams: установлен групповой сигнал, но не установлен setsid

Возможные причины ошибок при возвращении nil, err:

  • SystemError: сбой dup(), fcntl(), pipe(), vfork() или close() в родительском процессе
  • SystemError: (временное ограничение) родительский процесс закрыл stdin, stdout или stderr

Возможные элементы opts:

  • opts.stdin (действие над STDIN_FILENO)
  • opts.stdout (действие над STDOUT_FILENO)
  • opts.stderr (действие над STDERR_FILENO)

Возможные действия файлового дескриптора в таблице opts:

  • popen.opts.INHERIT (== 'inherit') [по умолчанию] — наследовать файловый дескриптор от родителя
  • popen.opts.DEVNULL (== 'devnull') — открыть /dev/null на месте файлового дескриптора
  • popen.opts.CLOSE (== 'close') — закрыть файловый дескриптор
  • popen.opts.PIPE (== 'pipe') — передавать данные от файлового дескриптора родителю или от родителя к файловому дескриптору через канал (pipe)

Таблица opts может содержать таблицу env переменных среды для использования внутри процесса. Каждый элемент opts.env может быть парой ключ-значение (где ключ — имя переменной, а значение — значение переменной).

  • Если opts.env не задан, наследуется текущее окружение.
  • Если opts.env — пустая таблица, окружение будет отброшено.
  • Если opts.env — непустая таблица, окружение будет заменено.

Таблица opts может содержать следующие элементы типа boolean:

Имя

По умолчанию

Назначение

opts.shell

false

Если true, дочерний процесс запускается через sh -c "${opts.argv}". Если false, исполняемый файл вызывается напрямую.

opts.setsid

false

Если true, программа запускается в новой сессии. Если false, программа запускается в сессии и группе процессов экземпляра Tarantool.

opts.close_fds

true

Если true, все унаследованные от родителя файловые дескрипторы закрываются. Если false, они не закрываются.

opts.restore_signals

true

Если true, все обработчики сигналов, измененные в родительском процессе, сбрасываются. Если false, они наследуются.

opts.group_signal

false

Если true, сигнал отправляется группе дочерних процессов, но только если включен opts.setsid. Если false, сигнал отправляется только дочернему процессу.

opts.keep_child

false

Если true, SIGKILL не отправляется дочернему процессу (или группе процессов при включенном opts.group_signal). Если false, SIGKILL отправляется дочернему процессу (или группе процессов при включенном opts.group_signal) при вызове popen_handle:close() или когда Lua GC освобождает дескриптор.

Возвращаемый дескриптор ph дает доступ к методу popen_handle:close() для явного освобождения всех занятых ресурсов, включая сам дочерний процесс, если не установлено поле opts.keep_child. Однако, если метод close() не вызывается для дескриптора в течение его жизни, Lua GC запустит то же самое действие по освобождению ресурсов.

Начиная с версии 3.2.0 в таблицу opts добавлена опция inherit_fds. Она позволяет задать номера файловых дескрипторов, которые должны остаться открытыми в дочернем процессе, если установлен флаг close_fds.

Tarantool рекомендует использовать opts.setsid вместе с opts.group_signal, если дочерний процесс может создать собственные дочерние процессы и их все нужно будет завершить одновременно.

Сигнал не будет отправлен, если дочерний процесс уже был завершен. В противном случае мы можем случайно завершить другой процесс, который имеет тот же идентификатор процесса после освобождения его предыдущим. Это означает, что если дочерний процесс завершается до того, как завершаются его дочерние процессы, то функция не будет отправлять сигнал группе процессов, даже когда установлены opts.setsid и opts.group_signal.

Используйте os.environ(), чтобы передать копию текущей среды с несколькими заменами (см. Пример 2 ниже).

Пример 1:

В этом примере выполняется аналог команды sh -c date. Происходит запуск процесса, выполняется 'date', считывается результат и объект popen (ph) закрывается.

local popen = require('popen')local ph = popen.new({'/bin/date'}, {    stdout = popen.opts.PIPE,})local date = ph:read():rstrip()ph:close()print(date) -- e.g. Thu 16 Apr 2020 01:40:56 AM MSK

Пример 2:

Пример 2 похож на пример 1, но задает переменную среды и использует встроенную shell-команду 'echo', чтобы показать ее.

local popen = require('popen')local env = os.environ()env['FOO'] = 'bar'local ph = popen.new({'echo "${FOO}"'}, {    stdout = popen.opts.PIPE,    shell = true,    env = env,})local res = ph:read():rstrip()ph:close()print(res) -- bar

Пример 3:

Пример 3 показывает, как перехватить дочерний поток stderr.

local popen = require('popen')local ph = popen.new({'echo hello >&2'}, { -- !!    stderr = popen.opts.PIPE,              -- !!    shell = true,})local res = ph:read({stderr = true}):rstrip()ph:close()print(res) -- hello

Пример 4:

Пример 4 показывает, как запустить потоковую программу (например, grep, sed и т.д.), записать данные в ее поток stdin и считать данные из stdout.

В этом примере предполагается, что входные данные достаточно малы, чтобы поместиться в буфер канала (обычно его размер равен 64 КиБ, но это зависит от конкретной платформы и ее конфигурации).

Если процесс записывает большое количество данных, он приостановится при выполнении popen_handle:write(). Для разрешения этой проблемы вызывайте popen_handle:read() в цикле в другом файбере (запустите его перед первым вызовом :write()).

Если процесс записывает длинный текст в stderr, он может приостановиться при выполнении write(), потому что буфер канала stderr заполнился. Для решения этой проблемы считывайте из stderr в отдельном файбере.

local function call_jq(input, filter)    -- Запуск процесса jq, соединение с stdin, stdout и stderr.    local jq_argv = {'/usr/bin/jq', '-M', '--unbuffered', filter}    local ph, err = popen.new(jq_argv, {        stdin = popen.opts.PIPE,        stdout = popen.opts.PIPE,        stderr = popen.opts.PIPE,    })    if ph == nil then return nil, err end    -- Запись входных данных в дочерний stdin и отправка EOF.    local ok, err = ph:write(input)    if not ok then return nil, err end    ph:shutdown({stdin = true})    -- Считывание всех данных до EOF.    local chunks = {}    while true do        local chunk, err = ph:read()        if chunk == nil then            ph:close()            return nil, err        end        if chunk == '' then break end -- EOF        table.insert(chunks, chunk)    end    -- Считывание данных диагностики из stderr (при наличии).    local err = ph:read({stderr = true})    if err ~= '' then        ph:close()        return nil, err    end    -- Соединение всех частей вместе, обрезка символа конца строки.    return table.concat(chunks):rstrip()end

popen_handle

popen_handle:read([opts])

Считывание данных из дочернего процесса.

Параметры:

  • ph (handle) — дескриптор дочернего процесса, созданного с помощью popen.new() или popen.shell()
  • opts (table) — параметры

Возможные элементы opts:

  • opts.stdout (boolean, по умолчанию true; если true, чтение ведется из stdout)
  • opts.stderr (boolean, по умолчанию false; если true, чтение ведется из stderr)
  • opts.timeout (number, по умолчанию 100 лет; временная квота в секундах)

Иными словами: по умолчанию read() читает из stdout, но читает из stderr, если установить opts.stderr в true. Одновременно установить opts.stdout и opts.stderr в true нельзя.

Возвращает

(при успешном выполнении) строку со считанным значением, пустую строку при EOF

(при неудачном выполнении) nil, err

Возможные ошибки:

Эти ошибки возникают при некорректных параметрах или при отмене файбера:

  • IllegalParams: некорректный тип или значение параметра
  • IllegalParams: вызов на закрытом дескрипторе
  • IllegalParams: установлены одновременно opts.stdout и opts.stderr
  • IllegalParams: запрошенная операция ввода-вывода не поддерживается дескриптором (stdout / stderr не соединен каналом)
  • IllegalParams: попытка операции над закрытым файловым дескриптором
  • FiberIsCancelled: отменено внешним кодом

nil, err возвращается в следующих случаях сбоя:

  • SocketError: ошибка ввода-вывода при read()
  • TimedOut: превышена квота opts.timeout
  • LuajitError: ("not enough memory"): нет памяти для Lua-строки

popen_handle:write(str[, opts])

Запись строки str в поток stdin дочернего процесса.

Параметры:

  • ph (handle) — дескриптор дочернего процесса, созданного с помощью popen.new() или popen.shell()
  • str (string) — записываемая строка
  • opts (table) — параметры

Возвращает

(при успешном выполнении) true

(при неудачном выполнении) nil, err

Тип возвращаемого значения

boolean

Возможные элементы opts: opts.timeout (number, по умолчанию 100 лет, временная квота в секундах).

Возможные ошибки:

  • IllegalParams: некорректный тип или значение параметра
  • IllegalParams: вызов на закрытом дескрипторе
  • IllegalParams: длина строки больше SSIZE_MAX
  • IllegalParams: запрошенная операция ввода-вывода не поддерживается дескриптором (stdin не соединен каналом)
  • IllegalParams: попытка операции над закрытым файловым дескриптором
  • FiberIsCancelled: отменено внешним кодом

Возможные причины ошибок, когда возвращается nil, err:

  • SocketError: ошибка ввода-вывода при write()
  • TimedOut: превышена квота opts.timeout

write() может передать управление (yield) и заблокировать файбер, если дочерний процесс не считывает данные из stdin и буфер канала заполнился. Размер буфера зависит от платформы. Если сомневаетесь, обратите внимание на опцию opts.timeout.

Когда опция opts.timeout не установлена, write() блокирует файбер до момента полной записи данных или возникновения ошибки записи.

popen_handle:shutdown([opts])

Закрытие канала с std* со стороны родителя.

Параметры:

  • ph (handle) — дескриптор дочернего процесса, созданного с помощью popen.new() или popen.shell()
  • opts (table) — параметры

Возвращает

(при успешном выполнении) true

Тип возвращаемого значения

boolean

Возможные элементы opts:

  • opts.stdin (boolean) — закрыть со стороны родителя конец stdin
  • opts.stdout (boolean) — закрыть со стороны родителя конец stdout
  • opts.stderr (boolean) — закрыть со стороны родителя конец stderr

Мы можем использовать термин std* для указания на любой из этих элементов.

Возможные ошибки:

  • IllegalParams: некорректный параметр дескриптора
  • IllegalParams: вызов на закрытом дескрипторе
  • IllegalParams: не выбран ни stdin, ни stdout, ни stderr
  • IllegalParams: запрошенная операция ввода-вывода не поддерживается дескриптором (один из std* не соединен каналом)

Основная цель использования shutdown() — отправка EOF в дочерний поток stdin. Однако stdout / stderr может быть уже закрыт со стороны родительского процесса.

shutdown() не завершается ошибкой на уже закрытых файловых дескрипторах (идемпотентность). Однако она завершается ошибкой при попытке закрыть конец канала, которого никогда не существовало. Иными словами, здесь можно использовать только те опции std*, которые были установлены в popen.opts.PIPE при создании дескриптора (для popen.shell(): 'r' соответствует stdout, 'R' — stderr, 'w' — stdin).

shutdown() не закрывает никакие файловые дескрипторы при завершении с ошибкой: либо закрываются все запрашиваемые дескрипторы (при успешном выполнении), либо ни один из них.

Пример:

local popen = require('popen')local ph = popen.shell('sed s/foo/bar/', 'rw')ph:write('lorem foo ipsum')ph:shutdown({stdin = true})local res = ph:read()ph:close()print(res) -- lorem bar ipsum

popen_handle:terminate()

Отправка сигнала SIGTERM дочернему процессу.

Параметры:

  • ph (handle) — дескриптор дочернего процесса, созданного с помощью popen.new() или popen.shell()

Возвращает

описание ошибок и возвращаемых значений см. в разделе popen_handle:signal()

terminate() просто отправляет сигнал SIGTERM. Он не освобождает никакие ресурсы (такие как память для дескрипторов popen и файловые дескрипторы).

popen_handle:kill()

Отправка сигнала SIGKILL дочернему процессу.

Параметры:

  • ph (handle) — дескриптор дочернего процесса, созданного с помощью popen.new() или popen.shell()

Возвращает

описание ошибок и возвращаемых значений см. в разделе popen_handle:signal()

kill() просто отправляет сигнал SIGKILL. Он не освобождает никакие ресурсы (такие как память для дескрипторов popen и файловые дескрипторы).

popen_handle:signal(signo)

Отправка сигнала дочернему процессу.

Параметры:

  • ph (handle) — дескриптор дочернего процесса, созданного с помощью popen.new() или popen.shell()
  • signo (number) — отправляемый сигнал

Возвращает

(при успешном выполнении) true (сигнал отправлен)

(при неудачном выполнении) nil, err

Возможные ошибки:

  • IllegalParams: некорректный параметр дескриптора
  • IllegalParams: вызов на закрытом дескрипторе

Возможные значения ошибок при возвращении nil, err:

  • SystemError: процесс больше не существует (это также может возвращаться для процесса-зомби или когда все процессы в группе — зомби (но см. примечание про Mac OS ниже)
  • SystemError: недопустимый номер сигнала
  • SystemError: нет прав на отправку сигнала процессу или группе процессов (это возвращается в Mac OS при отправке сигнала группе процессов, где лидер группы — зомби (или когда все процессы в ней — зомби, детали неясны); это также может возникать по другим причинам, детали неясны)

Если для дескриптора установлены opts.setsid и opts.group_signal, сигнал отправляется группе процессов, а не отдельному процессу. Для подробной информации по групповым сигналам смотрите popen.new(). Внимание: на Mac OS процесс в группе может не получить сигнал, особенно если он только что был разветвлен (возможно это происходит из-за состояния гонки).

Примечание: Некоторые сигналы имеют разные номера на разных платформах. Поэтому в этом модуле мы предлагаем константы popen.signal.SIG*.

popen_handle:info()

Получение информации о дескрипторе popen.

Параметры:

  • ph (handle) — дескриптор дочернего процесса, созданного с помощью popen.new() или popen.shell()

Возвращает

(при успешном выполнении) отформатированный результат

Тип возвращаемого значения

res

Возможные ошибки:

  • IllegalParams: некорректный параметр дескриптора
  • IllegalParams: вызов на закрытом дескрипторе

Результат выводится в следующем формате:

{    pid = <number> or <nil>,    command = <string>,    opts = <table>,    status = <table>,    stdin = one-of(        popen.stream.OPEN   (== 'open'),        popen.stream.CLOSED (== 'closed'),        nil,    ),    stdout = one-of(        popen.stream.OPEN   (== 'open'),        popen.stream.CLOSED (== 'closed'),        nil,    ),    stderr = one-of(        popen.stream.OPEN   (== 'open'),        popen.stream.CLOSED (== 'closed'),        nil,    ),}

pid — это идентификатор процесса, когда тот находится в рабочем состоянии; для завершенного процесса pid имеет значение nil.

command — это конкатенация аргументов, разделенных пробелами, которые были переданы в execve(). Аргументы, состоящие из нескольких слов, заключаются в кавычки. Кавычки внутри аргументов не экранируются.

opts – это таблица параметров дескриптора, описанная в разделе opts функции popen.new(). opts.env здесь не отображается, потому что карта переменных среды не хранится в дескрипторе.

status — это таблица, отображающая состояние процесса в следующем формате:

{    state = one-of(        popen.state.ALIVE    (== 'alive'),        popen.state.EXITED   (== 'exited'),        popen.state.SIGNALED (== 'signaled'),    )    -- Отображается при состоянии процесса 'завершенный'.    exit_code = <number>,    -- Отображается при состоянии процесса 'принимающий сигнал'.    signo = <number>,    signame = <string>,}

stdin, stdout и stderr отражают состояние конца канала со стороны родителя. Если поток не соединен каналом, поле отсутствует (nil). Если соединен, состояние может быть popen.stream.OPEN (== 'open') или popen.stream.CLOSED (== 'closed'). Состояние можно изменить с 'open' на 'closed' вызовом popen_handle:shutdown({std... = true}).

Пример 1:

(в консоли Tarantool)

tarantool> require('popen').new({'/usr/bin/touch', '/tmp/foo'})---- command: /usr/bin/touch /tmp/foo  opts:    close_fds: true    group_signal: false    keep_child: false    restore_signals: true    setsid: false    shell: false    stderr: inherit    stdin: inherit    stdout: inherit  pid: 9499  status:    state: alive...

Пример 2:

(в консоли Tarantool)

tarantool> require('popen').shell('grep foo', 'wrR')---- command: sh -c 'grep foo'  opts:    close_fds: true    group_signal: true    keep_child: false    restore_signals: true    setsid: true    shell: true    stderr: pipe    stdin: pipe    stdout: pipe  pid: 10497  status:    state: alive  stderr: open  stdin: open  stdout: open...

popen_handle:wait([timeout])

Ожидание, пока дочерний процесс не завершится или не получит сигнал.

Параметры:

  • ph (handle) — дескриптор дочернего процесса, созданного с помощью popen.new() или popen.shell()
  • timeout (number) — начиная с версии 3.2.0. Параметр определяет период в секундах, в течение которого метод ожидает завершения. Значение по умолчанию — "infinity".

Возвращает

(при успешном выполнении) отформатированный результат

(при неудачном выполнении) nil, err

Тип возвращаемого значения

res

Возможные ошибки:

  • IllegalParams: некорректный параметр дескриптора
  • IllegalParams: вызов на закрытом дескрипторе
  • FiberIsCancelled: отменено внешним кодом

Возможные причины ошибок при возвращении nil, err:

  • TimedOut: начиная с версии 3.2.0. Ошибка означает, что метод не достиг положительного результата, но превысил заданный timeout.
  • ChannelIsClosed: начиная с версии 3.2.0. Ошибка возвращается, когда целевой дескриптор popen закрывается во время выполнения операции :wait().

Отформатированный результат представляет собой таблицу состояний процесса (аналогично компоненту status таблицы, возвращаемой через popen_handle:info()).

Пример использования параметра timeout:

local ph = popen.new(<...>)local res, err = ph:wait({timeout = 1})if res == nil then-- Timeout is reached.assert(err.type == 'TimedOut')<...>end

popen_handle:close()

Закрытие дескриптора popen.

Параметры:

  • ph (handle) — дескриптор дочернего процесса, созданного с помощью popen.new() или popen.shell()

Возвращает

(при успешном выполнении) true

(при неудачном выполнении) nil, err

Тип возвращаемого значения

res

Возможные ошибки:

  • IllegalParams: некорректный параметр дескриптора

Возможные результаты диагностики, когда возвращается nil, err (не рассматривайте эти случаи как ошибки):

  • SystemError: нет прав на отправку сигнала процессу или группе процессов. (Эта диагностика может появляться из-за поведения Mac OS при работе с зомби-процессами, когда установлен opts.group_signal, см. popen_handle:signal(). Также может появляться по другим причинам, детали неясны.) Если известно, что процесс был завершен, то в результате всегда возвращается true (например, после выполнения popen_handle:wait() не будет отправлено никакого сигнала, так что никакой ошибки не может возникнуть).

close() принудительно завершает процесс через SIGKILL и освобождает все ресурсы, связанные с дескриптором popen.

Подробная информация об отправке сигналов:

  • Сигнал отправляется только если не установлен opts.keep_child.
  • Сигнал отправляется только если процесс активен согласно информации, доступной на текущей итерации цикла событий. (Здесь возможна ситуация: сигнал может быть отправлен зомби-процессу; это безвредно.)
  • Сигнал отправляется процессу или группе процессов в зависимости от opts.group_signal. (Подробнее об отправке сигналов группе см. popen.new()).

Ресурсы освобождаются вне зависимости от того, успешно ли отправился сигнал: дескрипторы файлов закрываются, память освобождается, а дескриптор popen помечается как закрытый.

Над закрытым дескриптором невозможно выполнять никакие операции кроме close(), которая всегда выполняется успешно над закрытым дескриптором (идемпотентность).

close() может вернуть true или nil, err, но она всегда освобождает ресурсы дескриптора. Поэтому для того, кто отправил сигнал, любое возвращаемое значение означает успешное выполнение. Возвращаемые значения только дают информацию для логирования или составления отчетов.

Поля дескриптора

popen_handle.pidpopen_handle.commandpopen_handle.optspopen_handle.statuspopen_handle.stdinpopen_handle.stdoutpopen_handle.stderr

За более подробной информацией обратитесь к popen_handle:info().

Константы модуля

- popen.opts  - INHERIT (== 'inherit')  - DEVNULL (== 'devnull')  - CLOSE   (== 'close')  - PIPE    (== 'pipe')- popen.signal  - SIGKILL (== 9)  - SIGTERM (== 15)  - ...- popen.state  - ALIVE    (== 'alive')  - EXITED   (== 'exited')  - SIGNALED (== 'signaled')- popen.stream  - OPEN    (== 'open')  - CLOSED  (== 'closed')