@@ -15,6 +15,14 @@ namespace SourceGit.Native
1515 [ SupportedOSPlatform ( "macOS" ) ]
1616 internal class MacOS : OS . IBackend
1717 {
18+ [ DllImport ( "/usr/lib/libSystem.B.dylib" , SetLastError = true ) ]
19+ private static extern int kill ( int pid , int sig ) ;
20+
21+ public MacOS ( )
22+ {
23+ _setsidExecutable = Path . Combine ( Path . GetDirectoryName ( Environment . ProcessPath ) , "setsid" ) ;
24+ }
25+
1826 public void SetupApp ( AppBuilder builder )
1927 {
2028 builder . With ( new MacOSPlatformOptions ( )
@@ -122,10 +130,46 @@ public void OpenWithDefaultEditor(string file)
122130 Process . Start ( "open" , file . Quoted ( ) ) ;
123131 }
124132
133+ public bool SupportSetSid ( )
134+ {
135+ return File . Exists ( _setsidExecutable ) ;
136+ }
137+
138+ public string GetSetSidExecutable ( )
139+ {
140+ return _setsidExecutable ;
141+ }
142+
125143 public void TerminateProcess ( Process proc )
126144 {
127- proc . Kill ( true ) ;
145+ if ( ! SupportSetSid ( ) )
146+ {
147+ proc . Kill ( true ) ;
148+ return ;
149+ }
150+
151+ if ( kill ( - proc . Id , 15 ) != 0 )
152+ {
153+ // If the process already exited, we can just ignore the error.
154+ if ( Marshal . GetLastPInvokeError ( ) == 3 /* ESRCH */ )
155+ return ;
156+
157+ // Actually, this will not be called since the process is
158+ // spawned by us (EPERM will not happen), and SIGTERM (15)
159+ // is a valid signal (EINVAL will not happen).
160+ // See https://www.man7.org/linux/man-pages/man2/kill.2.html
161+ try
162+ {
163+ proc . Kill ( true ) ;
164+ }
165+ catch
166+ {
167+ // Ignore any errors when trying to kill the process
168+ }
169+ }
128170 }
171+
172+ private string _setsidExecutable = null ;
129173 }
130174
131175 [ SupportedOSPlatform ( "macOS" ) ]
0 commit comments