Читаем Linux программирование в примерах полностью

Строки 1836–1837 создают первый канал, ptoc. Строки 1839–1845 создают второй канал, закрывая при неудачном создании и первый. Это важно. Небрежность в закрытии открытых, но не используемых каналов ведет к утечкам дескрипторов файлов. Как и память, дескрипторы файлов являются конечным ресурсом, и когда они иссякают, то теряются.[103] То же верно и для открытых файлов: убедитесь, что ваш обрабатывающий ошибки код всегда закрывает все открытые файлы и каналы, которые не нужны, когда происходит ошибка.

save_errno сохраняет значения errno, установленные pipe(), на тот редкий случай, когда close() может завершиться неудачей (строка 1840). Затем errno восстанавливается в строке 1843.

1906 if ((pid = fork()) < 0) {

1907  save_errno = errno;

1908  close(ptoc[0]); close(ptoc[1]);

1909  close(ctop[0]); close(ctop[1]);

1910  errno = save_errno;

1911  return FALSE;

1912 }

Строки 1906–1912 порождают процесс, на этот раз закрывая оба канала, если fork() потерпит неудачу. Здесь также первоначальное значение errno сохраняется и восстанавливается для последующего использования при диагностике.

1914 if (pid == 0) { /* порожденный процесс */

1915  if (close(1) == -1)

1916   fatal(_("close of stdout in child failed (%s)"),

1917    strerror(errno));

1918  if (dup(ctop[1]) != 1)

1919   fatal(_{"moving pipe to stdout in child failed (dup: %s)"), strerror(errno));

1920  if (close(0) == -1)

1921   fatal(_("close of stdin in child failed (%s)"),

1922    strerror(errno));

1923  if (dup(ptoc[0]) != 0)

1924   fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno));

1925  if (close(ptoc[0]) == -1 || close(ptoc[1]) == -1

1926   || close(ctop[0]) == -1 || close(ctop[1]) == -1)

1927   fatal(_("close of pipe failed (%s)"), strerror(errno));

1928  /* stderr HE дублируется в stdout потомка */

1929  execl("/bin/sh", "sh", "-c", str, NULL);

1930  _exit(errno == ENOENT ? 127 : 126);

1931 }

Строки 1914–1931 обрабатывают код потомка, с соответствующей проверкой ошибок и сообщениями на каждом шагу. Строка 1915 закрывает стандартный вывод. Строка 1918 копирует записываемый конец канала от потомка к родителю на 1. Строка 1920 закрывает стандартный ввод, а строка 1923 копирует читаемый конец канала от родителя к потомку на 0. Если это все работает, стандартные ввод и вывод теперь на месте и подключены к родителю.

Строки 1925–1926 закрывают все четыре первоначальные дескрипторы файлов каналов, поскольку они больше не нужны. Строка 1928 напоминает нам, что стандартная ошибка остается на месте. Это лучшее решение, поскольку пользователь увидит ошибки от сопроцесса. Программа awk, которая должна перехватить стандартную ошибку, может использовать в команде обозначение '2>&1' для перенаправления стандартной ошибки сопроцесса или записи в отдельный файл.

Наконец, строки 1929–1930 пытаются запустить для оболочки execl() и соответственно выходят, если это не удается.

1934 /* родитель */

1935 rp->pid = pid;

1936 rp->iop = iop_alloc(ctop[0], str, NULL);

1937 if (rp->iop == NULL) {

1938  (void)close(ctop[0]);

1939  (void)close(ctop[1]);

1940  (void)close(ptoc[0]);

1941  (void)close(ptoc[1]);

1942  (void)kill(pid, SIGKILL); /* overkill? (pardon pun) */

1943

1944  return FALSE;

1945 }

Первым шагом родителя является настройка входного конца от сопроцесса. Указатель rp указывает на struct redirect, которая содержит поле для сохранения PID порожденного процесса, FILE* для вывода и указатель IOBUF* с именем iop. IOBUF является внутренней структурой данных gawk для осуществления ввода. Она, в свою очередь, хранит копию нижележащего дескриптора файла.

Перейти на страницу:

Похожие книги

C++ Primer Plus
C++ Primer Plus

C++ Primer Plus is a carefully crafted, complete tutorial on one of the most significant and widely used programming languages today. An accessible and easy-to-use self-study guide, this book is appropriate for both serious students of programming as well as developers already proficient in other languages.The sixth edition of C++ Primer Plus has been updated and expanded to cover the latest developments in C++, including a detailed look at the new C++11 standard.Author and educator Stephen Prata has created an introduction to C++ that is instructive, clear, and insightful. Fundamental programming concepts are explained along with details of the C++ language. Many short, practical examples illustrate just one or two concepts at a time, encouraging readers to master new topics by immediately putting them to use.Review questions and programming exercises at the end of each chapter help readers zero in on the most critical information and digest the most difficult concepts.In C++ Primer Plus, you'll find depth, breadth, and a variety of teaching techniques and tools to enhance your learning:• A new detailed chapter on the changes and additional capabilities introduced in the C++11 standard• Complete, integrated discussion of both basic C language and additional C++ features• Clear guidance about when and why to use a feature• Hands-on learning with concise and simple examples that develop your understanding a concept or two at a time• Hundreds of practical sample programs• Review questions and programming exercises at the end of each chapter to test your understanding• Coverage of generic C++ gives you the greatest possible flexibility• Teaches the ISO standard, including discussions of templates, the Standard Template Library, the string class, exceptions, RTTI, and namespaces

Стивен Прата

Программирование, программы, базы данных