Benachrichtigungs-Listener verhält sich im Hintergrund seltsam

7

Ich habe Probleme damit, mein IRC-Bouncer / Benachrichtigungsskript zum Laufen zu bringen.

Dies ist ein Skript, das sich automatisch bei einem Remotecomputer anmeldet, eine Verbindung zu einer Bildschirmsitzung herstellt (oder eine startet, wenn derzeit keine vorhanden ist), in der weechat ausgeführt wird, und gleichzeitig eine andere SSH-Verbindung öffnet, die Netcat zum Lesen von Benachrichtigungen aus einer Socket-Datei verwendet In das ein Weechat-Add-On-Skript meine Benachrichtigungsnachrichten exportiert. Diese Benachrichtigungen werden dann in lib-notify (über notify-send) eingespeist, damit ich über Aktivitäten in weechat informiert werden kann.

Hier ist das Skript:

#!/bin/bash

BOUNCER="[email protected]"

function irc_notify() {
  ssh $BOUNCER "nc -k -l -U /tmp/weechat.notify.sock" | \
    while read type message; do
     notify-send -i weechat -u critical "$(echo -n $type | base64 -di -)" "$(echo -n $message | base64 -di -)"
    done
}

# Start listening for notifications
irc_notify &

# Attach to remote IRC Bouncer Screen
ssh $BOUNCER -t 'screen -d -R -S irc weechat'

# Cleanup Socket Listener
echo "cleaning up notification socket listener…"
ssh $BOUNCER 'pkill -f -x "nc -k -l -U /tmp/weechat.notify.sock"'

Das Setup funktioniert wirklich sehr gut, bis auf einen großen Fehler. Pro Aufruf des Skripts gelangten nur zwei Benachrichtigungen zu meinem Benachrichtigungsmanager. Danach nichts mehr.

Um Probleme mit dem Benachrichtigungsskript in weechat zu beseitigen, habe ich den zweiten ssh-Aufruf (der an die Bildschirmsitzung angehängt wird und weechat startet) entfernt und durch einen readBefehl zum Blockieren der Ausführung während des Tests ersetzt. Dann habe irbich auf dem Remote-Computer mit Ruby Nachrichten an den Socket gesendet.
Aber selbst wenn ich die Nachrichten manuell zu senden, immer noch nur zwei Nachrichten erscheinen , bevor es aufgehört zu arbeiten .

stracezeigte mir ein interessantes Verhalten (als ich mich an den gegabelten Prozess anhängte), bei dem es den Anschein hatte, dass die Nachrichten nach der ersten oder zweiten Nachricht nicht mehr durch Zeilenumbrüche beendet wurden. Aber nach ein paar mehr hörten sie auf, stracezusammen zu erscheinen.

Zu diesem Zeitpunkt entschied ich mich zu prüfen, ob etwas in meinem Skript seltsames Verhalten verursachte. Also habe ich in der Kommandozeile einfach die ssh connection ( ssh $BOUNCER "nc -k -l -U /tmp/weechat.notify.sock") direkt aufgerufen . Und siehe da, alle Nachrichten, die ich manuell gesendet habe, wurden angezeigt (natürlich immer noch base64-codiert).

Also habe ich die Logik hinzugefügt, um jede eingehende Nachricht zu dekodieren, wie ich sie in meinem Skript hatte, und sie hat auch für jede Nachricht perfekt funktioniert. Einschließlich, wenn ich diese Nachrichten in Notify-Send eingespeist habe.

An diesem Punkt entschied ich, dass etwas Seltsames passieren muss, als ich die Funktion gabelte . Ich habe jedoch keinen Unterschied in der Effektivität festgestellt, als ich die Befehle im Terminal hinterlegt habe. Also fragte ich mich, ob vielleicht etwas Seltsames passierte, weil es aus einem Skript heraus ausgeführt wurde.

Dann wurde es komisch…

Ich begann damit, die Logik aus der Funktion herauszubrechen und sie direkt aufzurufen, mit einem kaufmännischen Und am Ende der Pipe-Befehle. Wie so:

ssh $BOUNCER "nc -k -l -U /tmp/weechat.notify.sock" | \
  while read type message; do
    notify-send -i weechat -u critical "$(echo -n $type | base64 -di -)" "$(echo -n $message | base64 -di -)"
  done &

Sobald ich das tat, begannen die Nachrichten plötzlich zu funktionieren. Und sobald ich die Änderung rückgängig gemacht hatte, war ich mit demselben seltsamen Verhalten, das nur aus zwei Nachrichten bestand, wieder auf dem ersten Platz.

Aber dieses Update führte zu einem anderen seltsamen Verhalten. Sobald ich mich in der Bildschirmsitzung befand, musste ich jede Taste mehrmals drücken, bevor sie vom Programm registriert wurde. Als ob es eine Rassenbedingung gäbe, die um STDIN kämpft.

Als ich herausfand, dass sich die beiden SSH-Sitzungen möglicherweise darum stritten (obwohl ich nicht sicher war, warum), versuchte ich, STDIN beim ersten ssh-Befehl mit verschiedenen Mitteln zu schließen und / oder zu besetzen. : |Zum Beispiel durch Einleiten vor <&-oder </dev/nullnach dem Anbringen oder nach dem SSH-Teil des Rohrs. Und während dies die Rassenbedingung zu lösen schien, führte dies das Zwei-Nachrichten-Verhalten wieder ein.

Da ich dachte, dass es etwas damit zu tun haben könnte, dass ich mich auf mehreren Ebenen der Unterverarbeitung befinde , versuchte ich, dies zu reproduzieren, indem ich den SSH-Aufruf bash -cwie folgt umschloss : bash -c 'ssh $BOUNCER "nc -k -l -U /tmp/weechat.notify.sock" &'. Und auch dies zeigte das Zwei-Nachrichten-Verhalten.

Ich habe dies auch direkt auf dem Remote-Computer getestet (SSHing zu localhost und Einschließen von zwei bash -cAufrufen) und das gleiche fehlerhafte Verhalten festgestellt . Es scheint auch nicht mit Doppelgabeln zu tun zu haben, die verwaiste Prozesse verursachen. Da es keine Rolle zu spielen scheint, ob der Prozess verwaist ist oder nicht.

Ich habe auch überprüft, dass dies auch unter geschiehtzsh .

Es scheint, dass dies irgendwie mit der Art und Weise zusammenhängt, wie STDIN und STDOUT behandelt werden, wenn ein Prozess unter Ebenen der Unterverarbeitung ausgeführt wird.

Repro. Anleitung & straceAusgabe:

Um das Debuggen zu vereinfachen, habe ich SSH aus dem Bild entfernt und zwei vereinfachte Testskripte geschrieben, die das Verhalten vollständig lokal erfolgreich reproduzierten.

Mit dem socketBefehl von Jürgen Nickelsen habe ich einen lokalen UNIX Domain Socket ( socket -l -s ./test.sock) erstellt und konnte erneut Testnachrichten mit irbdem folgenden Ruby-Code senden :

require 'socket'
require 'base64'

SOCKET = './test.sock'

def send(subtitle, message)
  UNIXSocket.open(SOCKET) do |socket|
    socket.puts "#{Base64.strict_encode64(subtitle)} #{Base64.strict_encode64(message)}"
  end
end

send('test', 'hi')
send('test', 'hi')
send('test', 'hi')
send('test', 'hi')
send('test', 'hi')
send('test', 'hi')

Das erste Skript hat nur den Pipeline-Ausdruck hinterlegt (der, wie bereits erwähnt, eine unbegrenzte Anzahl von Nachrichten verarbeitet hat):

#!/bin/bash

# to aid in cleanup when using Ctrl-C to exit strace
trap "pkill -f -x 'nc -k -l -U $HOME/test.sock'; exit" SIGINT

# Start listening for notifications
nc -k -l -U $HOME/test.sock | \
  while read type message; do
    # write messages to a local file instead of sending to notification daemon for simplicity.
    echo "$(echo -n $type | base64 -di -)" "$(echo -n $message | base64 -di -)" >> /tmp/msg
  done &

read

Beim Ausführen mit wurde die folgende Ausgabe erstellt strace -f: http://pastebin.com/SMjti3qW

Das zweite Skript hat die Wrapping-Funktion (die das 2-and-done-Verhalten auslöst) im Hintergrund ausgeführt:

#!/bin/bash

# to aid in cleanup when using Ctrl-C to exit strace
trap "pkill -f -x 'nc -k -l -U $HOME/test.sock'; exit" SIGINT

# Start listening for notifications
function irc_notify() {
  nc -k -l -U $HOME/test.sock | \
    while read type message; do
      # write messages to a local file instead of sending to notification daemon for simplicity.
      echo "$(echo -n $type | base64 -di -)" "$(echo -n $message | base64 -di -)" >> /tmp/msg
    done
}

irc_notify &

read

Und was wiederum die folgende Ausgabe erzeugte, wenn es ausgeführt wurde mit strace -f: http://pastebin.com/WsrXX0EJ

Eine Sache, die mir beim Betrachten der straceAusgabe der obigen Skripte auffällt, ist die für den ncBefehl spezifische Ausgabe . Dies scheint einen der Hauptunterschiede zwischen der Ausführung dieser beiden Skripte aufzuzeigen.

Die "funktionierende" nc straceAusgabe des ersten Skripts :

accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3,

Das "2-and-done" -Verhalten des zweiten Skripts in der nc straceAusgabe:

accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 2 ([{fd=4, revents=POLLIN|POLLHUP}, {fd=0, revents=POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
shutdown(4, 1 /* send */)               = 0
close(0)                                = 0
poll([{fd=4, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 0
poll([{fd=0, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 2 ([{fd=0, revents=POLLIN|POLLHUP}, {fd=0, revents=POLLIN|POLLHUP}])
read(0, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
read(0, "", 2048)                       = 0
shutdown(0, 1 /* send */)               = 0
close(0)                                = 0
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
.......[truncated].......

Ich bin nicht dort, wo ich in Bezug auf meine straceLesbarkeit der Ausgabe sein möchte , daher bin ich mir nicht ganz sicher, was diese verschiedenen Ausgaben bedeuten - abgesehen von der Tatsache, dass eine offensichtlich funktioniert, während die andere nicht funktioniert.

Während ich die größere straceAusgabe durchgearbeitet habe , scheint es auch, dass Nachrichten nach den ersten beiden nicht mehr durch einen Zeilenumbruch beendet werden? Aber auch hier bin ich mir nicht sicher, was das bedeutet oder ob ich es richtig lese.

Und ich verstehe definitiv nicht, wie die verschiedenen Subverarbeitungstechniken oder sogar das Schließen von STDIN dieses Verhalten beeinflussen könnten.

Irgendeine Idee, was mir hier begegnet?

- -

tl; dr

Ich versuche herauszufinden, warum das Ausführen meines Benachrichtigungslisteners unter mehr als einer Unterverarbeitungsebene dazu führt, dass nur zwei Nachrichten verarbeitet werden. Andernfalls führt dies zu einer Rennbedingung für STDIN.

CRThaze
quelle
Beachten Sie, dass dies ssh -ndas Lesen von stdin verhindert, obwohl dies nicht die Ursache für das Hauptproblem zu sein scheint. Was zeigt straceder ncProzess im Vergleich zum Unterprozess? Ist ncEmpfangen und Emittieren Daten? Blockiert es? Hat das Schließen von stdout für den Unterprozess Auswirkungen?
Zackse
Das Hinzufügen -nzu ssh scheint den gleichen Effekt zu haben wie jeder andere Versuch, STDIN zu schließen (zwei und erledigtes Verhalten). Ebenso wie das Schließen von STDIN im Unterprozess. Ich lief jedoch straceweiter ncund es zeigt einige interessante Verhaltensunterschiede zwischen Szenarien, in denen alle Nachrichten durchkommen ( pastebin.com/tCSwtA99 ) und wenn nur zwei durchkommen ( pastebin.com/gZueVpb0 ). Ich bin nicht der Beste im Lesen von straceAusgaben. Möglicherweise muss ich einige Systemaufrufdokumentationen durchgehen, um dies zu verstehen.
CRThaze
Können Sie die Ausgabe von einfügen strace -f? Darauf folgen Gabeln, die Spuren aller erzeugten Unterprozesse enthalten.
Zackse
Das Hinzufügen -fzum nc stracehat keine Auswirkung, da es ncüberhaupt nicht gabelt. Ich würde Ihnen die vollständige Ausgabe des Ausführens auf dem clientseitigen Skript geben, aber das, was dies bietet, ist so lang und enthält so viele vertrauliche Informationen (von LDAP usw.), dass ich nicht richtig bereinigen kann, um sie hier einzufügen. Aber ich kann Ihnen sagen, was ich immer beobachte, wenn ich dies versuche, dass immer zwei Nachrichten weitergeleitet werden, aber die letzte scheint nicht richtig beendet zu sein (es fehlt ein Zeilenumbruchzeichen) oder so, und das scheint zu sein fallen mit dem Zeitpunkt zusammen nc, an dem poll()Nachrichten gesendet werden.
CRThaze
OK. Also habe ich dieses Verhalten reproduziert, nachdem ich SSH aus dem Bild entfernt und alles lokal ausgeführt hatte - was zu einer saubereren straceAusgabe führte. Ich habe zwei Versionen dieses Testskripts mit ausgeführt strace -f. eine, die den Piped-Ausdruck hinterlegt und unbegrenzt Testnachrichten verarbeitet ( pastebin.com/GDjxTJuJ ), und eine, die eine Umbruchfunktion hinterlegt und nur zwei Nachrichten verarbeitet, bevor sie unterbrochen wird ( pastebin.com/GMtkKefP ). Der strace -fAusgang dieser jeweiligen Skripte war 1) pastebin.com/SMjti3qW und 2) pastebin.com/WsrXX0EJ
CRThaze

Antworten:

1

Neuere Derivate von OpenBSD netcat, einschließlich FreeBSD [1] und Debian [2], unterstützen ein -dFlag, das das Lesen von stdin verhindert und das von Ihnen beschriebene Problem behebt.

Das Problem ist, dass netcat sowohl stdin als auch sein "Netzwerk" fd abfragt und stdin /dev/nullim zweiten Fall oben erneut geöffnet wird, wo die Shell-Funktion im Hintergrund ausgeführt wird, bevor die Pipeline erstellt wird. Das bedeutet eine sofortige EOF beim ersten Lesen von stdin (fd 0), aber netcat wird weiterhin poll(2)auf dem jetzt geschlossenen stdin fortfahren und eine Endlosschleife erzeugen.

Hier ist die Umleitung von stdin vor der Pipeline-Erstellung:

249 [pid 23186] open("/dev/null", O_RDONLY <unfinished ...>
251 [pid 23186] <... open resumed> )        = 3
253 [pid 23186] dup2(3, 0)                  = 0
254 [pid 23186] close(3)                    = 0

Wenn netcat (pid 23187) das erste Mal aufruft poll(2), liest es EOF von stdin und schließt fd 0:

444 [pid 23187] poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, 4294967295) = 2 ([{fd=4, revents=POLLIN|POLLHUP}, {fd=0, revents=POLLIN}])
448 [pid 23187] read(0,  <unfinished ...>
450 [pid 23187] <... read resumed> "", 2048) = 0
456 [pid 23187] close(0 <unfinished ...>
458 [pid 23187] <... close resumed> )       = 0

Der nächste Aufruf von accept(2)ergibt einen Client auf fd 0, der jetzt die niedrigste freie fd ist:

476 [pid 23187] accept(3,  <unfinished ...>
929 [pid 23187] <... accept resumed> {sa_family=AF_LOCAL, NULL}, [2]) = 0

Beachten Sie hier, dass netcat jetzt fd 0 poll(2)zweimal in die Argumente einfügt : einmal für STDIN_FILENO, was immer enthalten -dist, wenn der Befehlszeilenparameter fehlt , und einmal für den neu verbundenen Client:

930 [pid 23187] poll([{fd=0, events=POLLIN}, {fd=0, events=POLLIN}], 2, 4294967295) = 2 ([{fd=0, revents=POLLIN|POLLHUP}, {fd=0, revents=POLLIN|POLLHUP}])

Der Client sendet EOF- und Netcat-Verbindungsabbrüche:

936 [pid 23187] read(0,  <unfinished ...>
938 [pid 23187] <... read resumed> "", 2048) = 0
940 [pid 23187] shutdown(0, SHUT_WR <unfinished ...>
942 [pid 23187] <... shutdown resumed> )    = 0
944 [pid 23187] close(0 <unfinished ...>
947 [pid 23187] <... close resumed> )       = 0

Aber jetzt ist es in Schwierigkeiten, weil es weiterhin auf fd 0 abfragt, das jetzt geschlossen ist. Der Netcat-Code behandelt nicht den Fall, POLLNVALdass er im .reventsMember von festgelegt wird struct pollfd, und gerät daher in eine Endlosschleife, um nie wieder aufzurufen accept(2):

949 [pid 23187] poll([{fd=0, events=POLLIN}, {fd=-1}], 2, 4294967295 <unfinished ...>
951 [pid 23187] <... poll resumed> )        = 1 ([{fd=0, revents=POLLNVAL}])
953 [pid 23187] poll([{fd=0, events=POLLIN}, {fd=-1}], 2, 4294967295 <unfinished ...>
955 [pid 23187] <... poll resumed> )        = 1 ([{fd=0, revents=POLLNVAL}])
...

Im ersten Befehl, bei dem die Pipeline im Hintergrund ausgeführt wird, aber nicht in einer Shell-Funktion ausgeführt wird, bleibt stdin offen, sodass dieser Fall nicht auftritt.

Code-Referenzen (siehe readwriteFunktion):

  1. http://svnweb.freebsd.org/base/head/contrib/netcat/
  2. https://sources.debian.net/src/netcat-openbsd/1.105-7/
zackse
quelle
Ah! Dies erklärt, warum das Hintergrundwissen über die Funktion und verschiedene Methoden zum Schließen von STDIN zu genau demselben Verhalten führte. Weil sie alle zu einer Pipeline ins Nirgendwo führten nc. Ich hatte mich so sehr mit der Unterverarbeitung beschäftigt, als das Problem stattdessen in den Dateideskriptoren lag. Dies löste mein Problem vollständig und lieferte eine detaillierte Erklärung. Vielen Dank!
CRThaze
Frage: Sollte SIGTTIN nicht mit dieser Art von Verhalten umgehen und die Race-Bedingung auf STDIN verhindern? Bedeutet dies, dass ncdas Signal einfach nicht gewürdigt wird?
CRThaze
Wenn das übergeordnete Element STDIN nicht geschlossen (oder umgeleitet) und ncversucht hat, daraus zu lesen, erhält es SIGTTIN, da STDIN weiterhin an Ihr Terminal angeschlossen ist. Sie können dies beobachten, indem Sie cat &in Ihrer Shell laufen und feststellen, dass sie aufgrund von SIGTTIN sofort gestoppt wird. Im obigen Fall leitet das übergeordnete Element STDIN jedoch von weiter /dev/null, wodurch STDIN von Ihrem tty getrennt wird. Wenn dann ncfd 0 gelesen wird, liest es von /dev/null. Ist das sinnvoll?
Zackse
Ja, ich verstehe, wie das funktioniert, wenn nur zwei Nachrichten verarbeitet werden. Aber ich beziehe mich auf die Zeit, als ich auf den Race-Zustand stieß, als ich nur den Ausdruck mit den Pipes hinterlegte und dann feststellte, dass nur einige meiner Tastenanschläge von weechat über SSH gelesen wurden.
CRThaze
1
Um meinen früheren Kommentar zu korrigieren, ncwürde das Signal nur empfangen, read(2)wenn Sie seine Pipeline von einer interaktiven Shell (dh nicht von einem Skript) aus gestartet hätten, da es sich dann im Hintergrund befinden würde. In einem Shell-Skript, das im Vordergrund steht, sind die Unterprozesse ( ssh/ ncPipeline, ssh ... screen) Teil derselben Prozessgruppe, sodass kein Signal geliefert wird. Als Sie die Pipeline im Hintergrund erstellt haben, haben Sie tatsächlich einen Fall gesehen, in dem zwei Prozesse um STDIN "kämpften", da beide Teil derselben Vordergrundprozessgruppe waren, die Zugriff auf das steuernde Terminal hatte.
Zackse
1

Verschwindet das Problem, wenn Sie die Funktion wie folgt ausführen?

irc_notify </dev/null &

Wenn ja, liegt das Problem wahrscheinlich an zwei Prozessen, die gleichzeitig versuchen, aus stdin zu lesen. Das Ausführen aller ssh-Befehle mit -n, wie von zackse vorgeschlagen, könnte ebenfalls hilfreich sein, zumindest um zu debuggen, welche Prozesse um stdin kämpfen.

Onnonymous
quelle
Gleiches Ergebnis, als würde ich das nicht setzen </dev/null. Ich bekomme die Rennbedingung auf STDIN nicht, aber nur zwei Nachrichten schaffen es durch.
CRThaze