Verhindern, dass MSYS ‘bash’ Prozesse beendet, die ^C abfangen

Lesezeit: 7 Minuten

Benutzer-Avatar
zwöl

Ich habe eine Windows-Anwendung im Konsolenmodus (von Unix portiert), die ursprünglich so konzipiert war, dass sie beim Empfang sauber beendet wird ^C (Unix SIGINT). Ein sauberer Exit besteht in diesem Fall darin, möglicherweise ziemlich lange darauf zu warten, dass entfernte Netzwerkverbindungen beendet werden. (Ich weiß, dass dies nicht das normale Verhalten von ist ^C aber ich bin nicht in der Lage, es zu ändern.) Das Programm ist Single-Threaded.

Ich kann fangen ^C mit entweder signal(SIGINT) (wie unter Unix) oder mit SetConsoleCtrlHandler. Beide funktionieren ordnungsgemäß, wenn das Programm unter CMD.EXE ausgeführt wird. Wenn ich jedoch die “bash”-Shell verwende, die mit MSYS geliefert wird (ich verwende die MinGW-Umgebung, um das Programm zu erstellen, da dies mir erlaubt, die Unix-Makefiles wiederzuverwenden), dann wird das Programm zwangsweise für eine zufällige, kurze Zeit (weniger als 100 Millisekunden) nach dem ^C. Dies ist nicht akzeptabel, da das Programm, wie ich bereits erwähnt habe, warten muss, bis Remote-Netzwerkverbindungen geschlossen werden.

Es ist sehr wahrscheinlich, dass Leute dieses Programm unter MSYS bash ausführen wollen. Außerdem bricht dieser Effekt die Testsuite. Ich konnte keine Möglichkeit finden, das Problem zu umgehen, weder innerhalb des Programms (ideal) noch durch Einstellungen in der Shell (akzeptabel). Kann jemand etwas empfehlen?

  • Sie können verwenden <signal.h> alles, was Sie unter Windows wollen, aber das Betriebssystem wird nicht generiert SIGINT Wenn Sie Strg-C in einem Konsolenfenster eingeben, nützt es Ihnen nichts.

    – zol

    16. August 2011 um 21:55 Uhr


  • Gibt es eine Möglichkeit, die Netzwerkverbindung robuster zu machen? Selbst wenn Sie das Herunterfahren des Programms richtig handhaben, was passiert, wenn jemand über das Netzkabel stolpert?

    – Markieren Sie Lösegeld

    16. August 2011 um 22:20 Uhr

  • <signal.h> funktioniert bei mir mit dem Microsoft CRT unter Windows. Mein Handler hat sich bei registriert signal() wird mit angerufen SIGINT wenn ich im Konsolenfenster Strg+C eingebe.

    – Brian Nixon

    16. August 2011 um 23:03 Uhr

  • @Brian: Eigentlich denke ich, dass das mein Fehler war: siehe stackoverflow.com/questions/7085604/… — Erstellen CTRL_C_EVENT von einem anderen Prozess scheint auf Kernel32-Ebene nicht unterstützt zu werden, was mich glauben ließ, dass die Signal-Handler nichts Konstruktives taten.

    – zol

    16. August 2011 um 23:50 Uhr

  • @Zack Klingt so, als hätten Sie die Antwort gefunden – vielleicht ist es an der Zeit, diese Frage zu schließen, damit Leute wie ich keine Zeit damit verbringen, sie zu beantworten? 😉

    – Roman Starkow

    17. August 2011 um 22:17 Uhr

Benutzer-Avatar
Quercus

Ich hatte genau das gleiche Problem – ich hatte ein Programm mit einem SIGINT/SIGTERM-Handler geschrieben. Dieser Handler erledigte Aufräumarbeiten, die manchmal eine Weile dauerten. Wenn ich das Programm innerhalb von msys bash ausführte, führte Strg-c dazu, dass mein SIGINT-Handler ausgelöst wurde, aber es wurde nicht beendet – das Programm wurde (“von außen” sozusagen) beendet, bevor es seine Bereinigung abschließen konnte Arbeit.

Aufbauend auf der Antwort von phs und dieser Antwort auf eine ähnliche Frage: https://stackoverflow.com/a/23678996/2494650, habe ich mir die folgende Lösung ausgedacht. Es ist wahnsinnig einfach und könnte einige Nebenwirkungen haben, die ich noch entdecken muss, aber es hat das Problem für mich behoben.

Erstellen Sie eine ~/.bashrc-Datei mit der folgenden Zeile:

trap '' SIGINT

Das ist es. Dies fängt das Sigint-Signal ab und verhindert, dass msys bash Ihr Programm “von außen” beendet. Es lässt jedoch irgendwie immer noch das SIGINT-Signal zu Ihrem Programm durch, sodass es seine ordnungsgemäße Bereinigung/Abschaltung durchführen kann. Ich kann Ihnen nicht genau sagen, warum es so funktioniert, aber es funktioniert – zumindest bei mir.

Viel Glück!

  • Ich denke, dies könnte mit dem Signalhandler von Cygwin Bash zusammenhängen, der unterbrochene Systemaufrufe stört. Ich erinnere mich, dass von POSIX-Signalhandlern nicht erwartet wird, dass sie Systemaufrufe ausführen, um Störungen zu vermeiden. Ich weiß nicht, wie Bash trap in Linux implementiert, aber es scheint, dass es die Falle immer vervollständigt, indem es sowohl die Falle zurücksetzt als auch auf einen leeren Handler setzt. Ein Beispielskript zeigt ein instabiles Verhalten von trap – in Cygwin, wenn es mit Timeout 2s aufgerufen wird (was SIGTERM sendet), gist.github.com/ilatypov/2d8d8043ef6592ebd6064906b773c6c7

    – Aal ghEEz

    4. November 2016 um 15:56 Uhr


  • Nebeneffekt entdeckt – ^c zum Leeren des aktuell eingegebenen Befehls funktioniert nicht mehr. (z. B. asdf eingeben und dann ^c)

    – Lexi

    12. März 2017 um 11:59 Uhr

  • FYI – dieser Trick funktioniert anscheinend für 32-Bit, aber nicht für 64-Bit … nicht sicher warum.

    – Dan Esparza

    12. Oktober 2018 um 13:15 Uhr

Das könnte an der Berüchtigten liegen mintty “Input/Output-Interaktion mit fremden Programmen” Problem (bzw Minze Ausgabe Nr. 56). In diesem Fall manifestiert es sich als Strg-C, das das Programm abrupt beendet, anstatt als Signal an das Programm weitergegeben zu werden, das abgefangen und verarbeitet werden muss. Der Beweis für diese Theorie basiert auf der ausführlichen Erklärung von zwol: „Windows-Anwendung im Konsolenmodus“, „[application is] entworfen, um einen sauberen Ausgang zu machen, wenn es empfangen wird ^C“, “[application] funktioniert korrekt, wenn das Programm unter CMD.EXE ausgeführt wird” aber “[when using the terminal] das kommt mit MSYS […] Programm wird zwangsweise beendet” (zum Zeitpunkt des Schreibens (2018) verwendet MSYS standardmäßig mintty als Terminal).

Leider mintty ist kein vollständiger Ersatz für die Windows-Konsole und verschiedene Verhaltensweisen, die von “nativen” Windows-Programmen erwartet werden, sind nicht implementiert. Sie könnten jedoch Freude daran haben, solche nativen Programme einzupacken winzig wenn sie in mintty laufen …

Auch andere Fragen beschreiben dieses Verhalten: siehe https://superuser.com/questions/606201/how-to-politely-kill-windows-process-from-cygwin und https://superuser.com/questions/1039098/how-to-make-mintty-close-gracefully-on-ctrl-c .

Arg – 5 Minuten Bearbeitung des Kommentars. Folgendes wollte ich schreiben:

Als Problemumgehung würde ich vorschlagen, anstatt zu versuchen, das CTRL-C-Ereignis abzufangen, das auch an die Shell weitergegeben wird, ENABLED_PROCESSED_INPUT auf stdin auszuschalten, sodass CTRL-C als Tastatureingabe und nicht als Signal gemeldet wird:

DWORD mode;
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hstdin, &mode);
SetConsoleMode(hstdin, mode & ~ENABLE_PROCESSED_INPUT); /* disable CTRL-C processing as a signal */

Sie könnten dann Tastatureingaben in Ihrem Haupt-Thread verarbeiten, während der Rest des Programms seine Arbeit in einem separaten Thread erledigt, und ein Ereignis auf Bereinigung setzen, wenn STRG-C empfangen wird.

  • Ich mag diese Idee. Ich werde es das nächste Mal versuchen, wenn ich zu Windows-Problemen zurückkehre, und Sie wissen lassen, wie es läuft.

    – zol

    7. September 2011 um 21:07 Uhr

Wenn Sie Ihr Programm mit MSYS-Bash ausführen, führen Sie die ausführbare Datei direkt aus, oder gibt es ein Wrapping-Shell-Skript (Bash)?

Wenn dies der Fall ist, wird möglicherweise ein benutzerdefinierter Strg-C-Handler mit der registriert trap Befehl (der einen Schlaf gefolgt von einem Kill ausführt.) Wenn so etwas existiert, ändern oder entfernen Sie es.

Wenn es keine gibt trap registriert ist oder kein Wrapping-Skript vorhanden ist, sollten Sie erwägen, ein solches Skript zu erstellen und Ihren eigenen Trap hinzuzufügen, um das Standardverhalten zu überschreiben. Sie können ein Beispiel sehen, wie es verwendet wird hier oder an bashs Manpage (im Abschnitt SHELL BUILTINS).

Strg-C ist SIGINT? Ich dachte, Strg-Z sei SIGINT, aber Strg-C sei SIGTERM. Prüfe das.

  • Nun, technisch gesehen hat Windows kein SIGINT oder SIGTERM. Strg-Z generiert EOF bei der Standardeingabe, und Strg-C bewirkt, dass ein “Konsolensteuerungsereignis” generiert wird. Es gibt zwei dokumentierte Konsolensteuerungsereignisse: Strg-C und Strg-BREAK. MSVCRT scheint beide intern SIGINT zuzuordnen. Sehen msdn.microsoft.com/en-us/library/ms683155%28v=VS.85%29.aspx

    – zol

    6. September 2011 um 16:41 Uhr

  • Selbst unter UNIX sendet Strg-C normalerweise SIGINT und Strg-Z sendet normalerweise SIGTSTP (Terminal Stop).

    – CB Bailey

    6. September 2011 um 19:34 Uhr

Benutzer-Avatar
Ameisenhaufen

Haben Sie eine CYGWIN-Umgebungseinstellung (in Systemsteuerung/Umgebungsvariablen)? Versuchen Sie, CYGWIN=notty zu setzen und starten Sie neu, öffnen Sie eine neue MSYS-Bash-Shell – bleibt das Problem bestehen?

  • Nun, technisch gesehen hat Windows kein SIGINT oder SIGTERM. Strg-Z generiert EOF bei der Standardeingabe, und Strg-C bewirkt, dass ein “Konsolensteuerungsereignis” generiert wird. Es gibt zwei dokumentierte Konsolensteuerungsereignisse: Strg-C und Strg-BREAK. MSVCRT scheint beide intern SIGINT zuzuordnen. Sehen msdn.microsoft.com/en-us/library/ms683155%28v=VS.85%29.aspx

    – zol

    6. September 2011 um 16:41 Uhr

  • Selbst unter UNIX sendet Strg-C normalerweise SIGINT und Strg-Z sendet normalerweise SIGTSTP (Terminal Stop).

    – CB Bailey

    6. September 2011 um 19:34 Uhr

1381950cookie-checkVerhindern, dass MSYS ‘bash’ Prozesse beendet, die ^C abfangen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy