<?xml version='1.0' encoding='utf-8' ?>

<rss version='2.0' xmlns:lj='http://www.livejournal.org/rss/lj/1.0/' xmlns:atom10='http://www.w3.org/2005/Atom'>
<channel>
  <title>Swami Dhyan Nataraj</title>
  <link>https://nataraj.dreamwidth.org/</link>
  <description>Swami Dhyan Nataraj - Dreamwidth Studios</description>
  <lastBuildDate>Thu, 09 May 2024 12:06:09 GMT</lastBuildDate>
  <generator>LiveJournal / Dreamwidth Studios</generator>
  <lj:journal>nataraj</lj:journal>
  <lj:journaltype>personal</lj:journaltype>
  <image>
    <url>https://v2.dreamwidth.org/12569540/750757</url>
    <title>Swami Dhyan Nataraj</title>
    <link>https://nataraj.dreamwidth.org/</link>
    <width>100</width>
    <height>100</height>
  </image>

<item>
  <guid isPermaLink='true'>https://nataraj.dreamwidth.org/996069.html</guid>
  <pubDate>Thu, 09 May 2024 12:06:09 GMT</pubDate>
  <title>Как форкнуть процесс в соседний виртуальный терминал</title>
  <link>https://nataraj.dreamwidth.org/996069.html</link>
  <description>&lt;p&gt;Я люблю работать в консоли. Люблю автоматизацию скриптами. И если надо что-то массово параллельно обработать, то запустить все это в разных окнах tmux&apos;а или screen&apos;а, и любоваться процессом. И вот чего мне не хватало, так это возможности в каком-нибудь сложном скрипте наделать дочерних процессов и разложить их по разным окнам tmux&apos;а. Кажется что естественная хотелка, а вот как сделать -- не понятно. И вот дошли руки разобраться как же такой фокус делается&lt;/p&gt;

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

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

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

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

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

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

    while(1){
      print ++$i, &quot;\n&quot;;
      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&apos;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 &quot;Child PID is $pid\n&quot;;
      sleep 10;
      while (1) {print &quot;.\n&quot;; sleep 1};
    } else
    {
      # child process
      (setpgid($$,$$) != -1)           || die &quot;Can&apos;t set own group: $!&quot;;
      sleep 10;
      while (1) {print ++$i,&quot;\n&quot;; 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=&quot;https://blog.nelhage.com/2011/02/changing-ctty/&quot;&gt;https://blog.nelhage.com/2011/02/changing-ctty/&lt;/a&gt; Понимание этого материала помогло таки найти финальное решение&lt;/li&gt;
&lt;li&gt;Мои попытки выспросить нужное решение на linux.org.ru: &lt;a href=&quot;https://www.linux.org.ru/forum/development/17555795&quot;&gt;https://www.linux.org.ru/forum/development/17555795&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Заметка на stackoverflow написанная по результатм: &lt;a href=&quot;https://stackoverflow.com/questions/78428371/how-to-fork-process-into-another-virtual-terminal/78428372&quot;&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=&quot;https://www.dreamwidth.org/tools/commentcount?user=nataraj&amp;ditemid=996069&quot; width=&quot;30&quot; height=&quot;12&quot; alt=&quot;comment count unavailable&quot; style=&quot;vertical-align: middle;&quot;/&gt; comments</description>
  <comments>https://nataraj.dreamwidth.org/996069.html</comments>
  <category>linux</category>
  <category>dev</category>
  <lj:security>public</lj:security>
  <lj:reply-count>8</lj:reply-count>
</item>
</channel>
</rss>
