<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dw="https://www.dreamwidth.org">
  <id>tag:dreamwidth.org,2011-04-07:750757</id>
  <title>Swami Dhyan Nataraj</title>
  <subtitle>Swami Dhyan Nataraj</subtitle>
  <author>
    <name>Swami Dhyan Nataraj</name>
  </author>
  <link rel="alternate" type="text/html" href="https://nataraj.dreamwidth.org/"/>
  <link rel="self" type="text/xml" href="https://nataraj.dreamwidth.org/data/atom"/>
  <updated>2024-05-09T12:08:14Z</updated>
  <dw:journal username="nataraj" type="personal"/>
  <entry>
    <id>tag:dreamwidth.org,2011-04-07:750757:996069</id>
    <link rel="alternate" type="text/html" href="https://nataraj.dreamwidth.org/996069.html"/>
    <link rel="self" type="text/xml" href="https://nataraj.dreamwidth.org/data/atom/?itemid=996069"/>
    <title>Как форкнуть процесс в соседний виртуальный терминал</title>
    <published>2024-05-09T12:06:09Z</published>
    <updated>2024-05-09T12:08:14Z</updated>
    <category term="linux"/>
    <category term="dev"/>
    <dw:security>public</dw:security>
    <dw:reply-count>8</dw:reply-count>
    <content type="html">&lt;p&gt;Я люблю работать в консоли. Люблю автоматизацию скриптами. И если надо что-то массово параллельно обработать, то запустить все это в разных окнах tmux'а или screen'а, и любоваться процессом. И вот чего мне не хватало, так это возможности в каком-нибудь сложном скрипте наделать дочерних процессов и разложить их по разным окнам tmux'а. Кажется что естественная хотелка, а вот как сделать -- не понятно. И вот дошли руки разобраться как же такой фокус делается&lt;/p&gt;

&lt;p&gt;&lt;a name="cutid1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Переносим процесс в другую консоль&lt;/h1&gt;

&lt;p&gt;Для начала рассмотрим более простую задачу: как вообще в принципе перенести процесс из одной консоли в другую. В древние времена эта задача решалась ручной перепривязкой потоков ввода-вывода процесса к другому tty или каким-то подобным образом. В современном линуксе для этого есть утилита &lt;a href="https://github.com/nelhage/reptyr"&gt;reptyr&lt;/a&gt; которая автоматически стырит для вас процесс из соседнего терминала и привяжет его к текущему. &lt;/p&gt;

&lt;p&gt;Предположим у вас есть программа:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    #!/usr/bin/perl

    print "My PID is $$\n"; # print current process PID;
    sleep 10;

    while(1){
      print ++$i, "\n";
      sleep 1;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Эта программа выводит в консоль свой PID, и через некоторое время начинает в той же консоли считать секунды.&lt;/p&gt;

&lt;p&gt;Если запустить эту программу в одной консоли, а в соседней консоли выполнить команду &lt;/p&gt;

&lt;p&gt;&lt;code&gt;reptyr [PID-number]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;где &lt;code&gt;PID-number&lt;/code&gt; номер процесса который напечатала наша тестовая программа в самом начале, то выполнение программы в исходной консоли прекратиться, а в новой продолжиться как ни в чем ни бывало.&lt;/p&gt;

&lt;p&gt;Достаточно просто.&lt;/p&gt;

&lt;h1&gt;Перенос дочернего процесса в другую консоль&lt;/h1&gt;

&lt;p&gt;Однако если вы попробуете проделать тот же самый фокус не с отдельно работающей программой, а с дочерним процессом &lt;code&gt;reptyr&lt;/code&gt; на вас наругается:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    [-] Process 739989 (test2.pl) shares 739990's process group. Unable to attach.
    (This most commonly means that 739990 has sub-processes).
    Unable to attach to pid 739990: Invalid argument
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Дело в том, что когда вы делаете форк, порожденный процесс оказывается в одной группе с родительским процессом (и родительский процесс оказывается лидером группы), и по какой-то причине &lt;code&gt;reptyr&lt;/code&gt; с такой ситуацией не справляется. Поэтому прежде чем тырить дочерний процесс, надо сначала вывести его из группы. Делается это вызовом &lt;code&gt;setpgid&lt;/code&gt;, в котором дочерний процесс назначается сам себе лидером группы, и таким образом выходит из группы родительского процесса. После этого &lt;code&gt;reptyr&lt;/code&gt; вполне справляется с переносом дочернего процесса в новую консоль. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    #!/usr/bin/perl

    use POSIX;

    $pid = fork();
    if ($pid)
    {
      # parent process
      print "Child PID is $pid\n";
      sleep 10;
      while (1) {print ".\n"; sleep 1};
    } else
    {
      # child process
      (setpgid($$,$$) != -1)           || die "Can't set own group: $!";
      sleep 10;
      while (1) {print ++$i,"\n"; sleep 1};
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Эта программа выводит на экран &lt;code&gt;PID&lt;/code&gt; порожденного дочернего процесса, после чего спустя десять секунд, родительский процесс начинает выводить на экран точки с частотой один раз в секунду, а дочерний процесс начинает эти секунды вслух считать. Если не предпринимать никаких действий выводы обоих процессов будут смешаны в одной консоли, в которой их запустили. &lt;/p&gt;

&lt;p&gt;Однако если в соседнем терминале запустить&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reptyr [child-PID-number]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;где &lt;code&gt;child-PID-number&lt;/code&gt; -- &lt;code&gt;PID&lt;/code&gt; дочернего процесса напечатанный нашей программой, то в результате вывод дочернего процесса (цифры) переедет в новую консоль, а вывод родительского процесса (точки) останется в той консоли в которой его изначально запустили. &lt;/p&gt;

&lt;p&gt;Чего собственно говоря и хотелось добиться.&lt;/p&gt;

&lt;h1&gt;Материалы для раздумий&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Статья в которой подробно объясняется материал групп и сессий: &lt;a href="https://blog.nelhage.com/2011/02/changing-ctty/"&gt;https://blog.nelhage.com/2011/02/changing-ctty/&lt;/a&gt; Понимание этого материала помогло таки найти финальное решение&lt;/li&gt;
&lt;li&gt;Мои попытки выспросить нужное решение на linux.org.ru: &lt;a href="https://www.linux.org.ru/forum/development/17555795"&gt;https://www.linux.org.ru/forum/development/17555795&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Заметка на stackoverflow написанная по результатм: &lt;a href="https://stackoverflow.com/questions/78428371/how-to-fork-process-into-another-virtual-terminal/78428372"&gt;https://stackoverflow.com/questions/78428371/how-to-fork-process-into-another-virtual-terminal/78428372&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;/p&gt;
&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=nataraj&amp;ditemid=996069" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
</feed>
