Browse Source

Merge pull request #23 from GWRon/feat_freeprocesskill

[FreeProcess] Add TProcess.Kill() to allow forceful process termination
Brucey 6 years ago
parent
commit
219e60035a
2 changed files with 117 additions and 51 deletions
  1. 49 20
      freeprocess.mod/freeprocess.bmx
  2. 68 31
      freeprocess.mod/freeprocess.c

+ 49 - 20
freeprocess.mod/freeprocess.bmx

@@ -31,7 +31,7 @@ Import brl.filesystem
 
 
 Import "freeprocess.c"
 Import "freeprocess.c"
 
 
-'note: Once fdProcessStatus() returns 0 OR fdTerminateProcess() is called,
+'note: Once fdProcessStatus() returns 0 OR fdTerminateProcess()/fdKillProcess is called,
 'processhandle should be assumed to be invalid, and neither function should be called
 'processhandle should be assumed to be invalid, and neither function should be called
 'again.
 'again.
 Extern
 Extern
@@ -43,6 +43,7 @@ Function fdAvail:Int(fd:Int)
 Function fdProcess:Int(exe$,in_fd:Int Ptr,out_fd:Int Ptr,err_fd:Int Ptr,flags:Int)="fdProcess"
 Function fdProcess:Int(exe$,in_fd:Int Ptr,out_fd:Int Ptr,err_fd:Int Ptr,flags:Int)="fdProcess"
 Function fdProcessStatus:Int(processhandle:Int)
 Function fdProcessStatus:Int(processhandle:Int)
 Function fdTerminateProcess:Int(processhandle:Int)
 Function fdTerminateProcess:Int(processhandle:Int)
+Function fdKillProcess:Int(processhandle:Int)
 End Extern
 End Extern
 
 
 Const HIDECONSOLE:Int=1
 Const HIDECONSOLE:Int=1
@@ -54,11 +55,11 @@ Type TPipeStream Extends TStream
 	Field	readhandle:Int,writehandle:Int
 	Field	readhandle:Int,writehandle:Int
 
 
 	Method Close()
 	Method Close()
-		If readhandle 
+		If readhandle
 			fdClose(readhandle)
 			fdClose(readhandle)
 			readhandle=0
 			readhandle=0
 		EndIf
 		EndIf
-		If writehandle 
+		If writehandle
 			fdClose(writehandle)
 			fdClose(writehandle)
 			writehandle=0
 			writehandle=0
 		EndIf
 		EndIf
@@ -71,15 +72,15 @@ Type TPipeStream Extends TStream
 	Method Write:Long( buf:Byte Ptr,count:Long )
 	Method Write:Long( buf:Byte Ptr,count:Long )
 		Return fdWrite(writehandle,buf,count)
 		Return fdWrite(writehandle,buf,count)
 	End Method
 	End Method
-	
+
 	Method Flush()
 	Method Flush()
 		fdFlush(writehandle)
 		fdFlush(writehandle)
 	End Method
 	End Method
-		
+
 	Method ReadAvail:Int()
 	Method ReadAvail:Int()
 		Return fdAvail(readhandle)
 		Return fdAvail(readhandle)
 	End Method
 	End Method
-	
+
 	Method ReadPipe:Byte[]()
 	Method ReadPipe:Byte[]()
 		Local	bytes:Byte[],n:Int
 		Local	bytes:Byte[],n:Int
 		n=ReadAvail()
 		n=ReadAvail()
@@ -87,9 +88,9 @@ Type TPipeStream Extends TStream
 			bytes=New Byte[n]
 			bytes=New Byte[n]
 			Read(bytes,n)
 			Read(bytes,n)
 			Return bytes
 			Return bytes
-		EndIf	
+		EndIf
 	End Method
 	End Method
-	
+
 	Method ReadLine$()	'nonblocking - returns empty string if no data available
 	Method ReadLine$()	'nonblocking - returns empty string if no data available
 		Local	n:Long,r:Long,p0:Int,p1:Int,line$
 		Local	n:Long,r:Long,p0:Int,p1:Int,line$
 		n=ReadAvail()
 		n=ReadAvail()
@@ -113,7 +114,7 @@ Type TPipeStream Extends TStream
 				If bufferpos MemMove(readbuffer,Varptr readbuffer[n],Size_T(bufferpos))
 				If bufferpos MemMove(readbuffer,Varptr readbuffer[n],Size_T(bufferpos))
 				Return line$
 				Return line$
 			EndIf
 			EndIf
-		Next			
+		Next
 	End Method
 	End Method
 
 
 	Function Create:TPipeStream( in:Int,out:Int )
 	Function Create:TPipeStream( in:Int,out:Int )
@@ -126,7 +127,7 @@ Type TPipeStream Extends TStream
 End Type
 End Type
 
 
 Type TProcess
 Type TProcess
-	Global ProcessList:TList 
+	Global ProcessList:TList
 	Field	name$
 	Field	name$
 	Field	handle:Int
 	Field	handle:Int
 	Field	pipe:TPipeStream
 	Field	pipe:TPipeStream
@@ -137,24 +138,24 @@ Type TProcess
 		detached = True
 		detached = True
 		Return 1
 		Return 1
 	End Method
 	End Method
-	
+
 	Method Attach:Int()
 	Method Attach:Int()
 		detached = False
 		detached = False
 		Return 1
 		Return 1
 	End Method
 	End Method
 	Method Status:Int()
 	Method Status:Int()
-		If handle 
+		If handle
 			If fdProcessStatus(handle) Return 1
 			If fdProcessStatus(handle) Return 1
 			handle=0
 			handle=0
 		EndIf
 		EndIf
 		Return 0
 		Return 0
 	End Method
 	End Method
-	
+
 	Method Close()
 	Method Close()
 		If pipe pipe.Close;pipe=Null
 		If pipe pipe.Close;pipe=Null
 		If err err.Close;err=Null
 		If err err.Close;err=Null
 	End Method
 	End Method
-	
+
 	Method Terminate:Int()
 	Method Terminate:Int()
 		Local res:Int
 		Local res:Int
 		If handle
 		If handle
@@ -164,9 +165,20 @@ Type TProcess
 		Return res
 		Return res
 	End Method
 	End Method
 
 
+	'the less nicer version of "terminate()" as it does not allow
+	'the process to finish its stuff
+	Method Kill:Int()
+		Local res:Int
+		If handle
+			res=fdKillProcess( handle )
+			handle=0
+		EndIf
+		Return res
+	End Method
+
 	Function Create:TProcess(name$,flags:Int)
 	Function Create:TProcess(name$,flags:Int)
 		Local	p:TProcess
 		Local	p:TProcess
-		Local	infd:Int,outfd:Int,errfd:Int	
+		Local	infd:Int,outfd:Int,errfd:Int
 ?MacOS
 ?MacOS
 		If FileType(name)=2
 		If FileType(name)=2
 			Local a$=StripExt(StripDir(name))
 			Local a$=StripExt(StripDir(name))
@@ -180,12 +192,12 @@ Type TProcess
 		If Not p.handle Return Null
 		If Not p.handle Return Null
 		p.pipe=TPipeStream.Create(infd,outfd)
 		p.pipe=TPipeStream.Create(infd,outfd)
 		p.err=TPipeStream.Create(errfd,0)
 		p.err=TPipeStream.Create(errfd,0)
-		p.detached = False 
+		p.detached = False
 		If Not ProcessList ProcessList=New TList
 		If Not ProcessList ProcessList=New TList
 		ProcessList.AddLast p
 		ProcessList.AddLast p
 		Return p
 		Return p
 	End Function
 	End Function
-	
+
 	Function FlushZombies()
 	Function FlushZombies()
 		If Not ProcessList Return
 		If Not ProcessList Return
 		Local live:TList=New TList
 		Local live:TList=New TList
@@ -194,17 +206,26 @@ Type TProcess
 		Next
 		Next
 		ProcessList=live
 		ProcessList=live
 	End Function
 	End Function
-	
+
 	Function TerminateAll() NoDebug
 	Function TerminateAll() NoDebug
 		If Not ProcessList Return
 		If Not ProcessList Return
 		For Local p:TProcess=EachIn ProcessList
 		For Local p:TProcess=EachIn ProcessList
-			If p.detached = False Then 
+			If p.detached = False Then
 				p.Terminate
 				p.Terminate
 			EndIf
 			EndIf
 		Next
 		Next
 		ProcessList=Null
 		ProcessList=Null
 	End Function
 	End Function
-	
+
+	Function KillAll() NoDebug
+		If Not ProcessList Return
+		For Local p:TProcess=EachIn ProcessList
+			If p.detached = False Then
+				p.Kill
+			EndIf
+		Next
+		ProcessList=Null
+	End Function
 End Type
 End Type
 
 
 Rem
 Rem
@@ -245,4 +266,12 @@ Function TerminateProcess:Int(process:TProcess)
 	Return process.Terminate()
 	Return process.Terminate()
 End Function
 End Function
 
 
+Rem
+bbdoc: Forcefully End Process
+returns: 1 if forceful termination of program was successful and 0 otherwise.
+End Rem
+Function KillProcess:Int(process:TProcess)
+	Return process.Kill()
+End Function
+
 OnEnd TProcess.TerminateAll
 OnEnd TProcess.TerminateAll

+ 68 - 31
freeprocess.mod/freeprocess.c

@@ -39,16 +39,30 @@ int fdTerminateProcess(int pid){
 	return -1;
 	return -1;
 }
 }
 
 
+
+//returns 0 for success, -1 for error
+//
+int fdKillProcess(int pid){
+
+	if( !killpg( pid,SIGKILL ) ){
+		int status=0;
+		waitpid( pid,&status,0 );
+		return 0;
+	}
+	return -1;
+}
+
+
 static char **makeargv( const char *cmd ){
 static char **makeargv( const char *cmd ){
 	int n,c;
 	int n,c;
 	char *p;
 	char *p;
 	static char *args,**argv;
 	static char *args,**argv;
-	
+
 	if( args ) free( args );
 	if( args ) free( args );
 	if( argv ) free( argv );
 	if( argv ) free( argv );
 	args=(char*)malloc( strlen(cmd)+1 );
 	args=(char*)malloc( strlen(cmd)+1 );
 	strcpy( args,cmd );
 	strcpy( args,cmd );
-	
+
 	n=0;
 	n=0;
 	p=args;
 	p=args;
 	while( c=*p++ ){
 	while( c=*p++ ){
@@ -91,17 +105,17 @@ int fdProcess( BBString *bbcmd,int *procin,int *procout,int *procerr,int flags)
 {
 {
 	char 	*const*argv;
 	char 	*const*argv;
 	int   	procid;
 	int   	procid;
-	
+
 	const char *cmd=bbTmpUTF8String(bbcmd);
 	const char *cmd=bbTmpUTF8String(bbcmd);
-	
+
 	//Set-up interprocess communication
 	//Set-up interprocess communication
 	if (pipe(in)) return 0;
 	if (pipe(in)) return 0;
   	if (pipe(out)) return 0;
   	if (pipe(out)) return 0;
   	if (pipe(errfd)) return 0;
   	if (pipe(errfd)) return 0;
-	
+
 	//Fork process (returned value used to distinguish between child and parent process)
 	//Fork process (returned value used to distinguish between child and parent process)
 	procid=vfork();	//vfork() avoids memory overhead of fork()
 	procid=vfork();	//vfork() avoids memory overhead of fork()
-	
+
 	//Child process
 	//Child process
 	if (procid==0)
 	if (procid==0)
 	{
 	{
@@ -110,37 +124,37 @@ int fdProcess( BBString *bbcmd,int *procin,int *procout,int *procerr,int flags)
 		#else
 		#else
 			setpgid(0,0);	//but OS X doesn't like it, therefore resort to using setpgid().
 			setpgid(0,0);	//but OS X doesn't like it, therefore resort to using setpgid().
 		#endif
 		#endif
-		
+
 		dup2(out[PIPEREAD],STDIN_FILENO);
 		dup2(out[PIPEREAD],STDIN_FILENO);
 		close(out[PIPEWRITE]);
 		close(out[PIPEWRITE]);
-		
+
 		dup2(in[PIPEWRITE],STDOUT_FILENO);
 		dup2(in[PIPEWRITE],STDOUT_FILENO);
 		close(in[PIPEREAD]);
 		close(in[PIPEREAD]);
-		
-		dup2(errfd[PIPEWRITE],STDERR_FILENO);		
+
+		dup2(errfd[PIPEWRITE],STDERR_FILENO);
 		close(errfd[PIPEREAD]);
 		close(errfd[PIPEREAD]);
-		
+
 		argv=makeargv(cmd);
 		argv=makeargv(cmd);
 		execvp(argv[0],argv);
 		execvp(argv[0],argv);
-		
+
 		_exit( -1 );
 		_exit( -1 );
-		
+
 		return 0;	//Supposedly, we need this for some compilers.
 		return 0;	//Supposedly, we need this for some compilers.
-		
+
 	}
 	}
-	
+
 	//Parent process
 	//Parent process
-	
+
 	if(procid==-1) return 0;	//Return if child process couldn't be started.
 	if(procid==-1) return 0;	//Return if child process couldn't be started.
-	
+
 	close(out[PIPEREAD]);		//Close the end of the pipes in that the child
 	close(out[PIPEREAD]);		//Close the end of the pipes in that the child
 	close(in[PIPEWRITE]);		//process is using.
 	close(in[PIPEWRITE]);		//process is using.
 	close(errfd[PIPEWRITE]);
 	close(errfd[PIPEWRITE]);
-	
+
 	*procin=in[PIPEREAD];		//And return the end of the pipes that we should
 	*procin=in[PIPEREAD];		//And return the end of the pipes that we should
 	*procout=out[PIPEWRITE];	//be using.
 	*procout=out[PIPEWRITE];	//be using.
 	*procerr=errfd[PIPEREAD];
 	*procerr=errfd[PIPEREAD];
-	
+
 	return procid;
 	return procid;
 }
 }
 
 
@@ -155,6 +169,17 @@ extern int _bbusew;
 #include <tlhelp32.h>
 #include <tlhelp32.h>
 
 
 int TerminateProcessGroup(HANDLE prochandle,int procid)
 int TerminateProcessGroup(HANDLE prochandle,int procid)
+{
+	//for now we just do a kill instead of politely asking all
+	//sub-windows (gui only) to gracefully end.
+	return KillProcessGroup(prochandle, procid);
+}
+
+
+// In the Windows world "TerminateProcess" kills a process without
+// gracefully asking to stop I/O and other operations first.
+// So there is a name clash between Linux' SIGKILL and Windows' TERMINATE
+int KillProcessGroup(HANDLE prochandle,int procid)
 {
 {
 	HANDLE snapshot,child;
 	HANDLE snapshot,child;
 	PROCESSENTRY32 procinfo;
 	PROCESSENTRY32 procinfo;
@@ -192,7 +217,7 @@ int fdClose(int fd)
 
 
 BBLONG fdRead(int fd,char *buffer,BBLONG bytes)
 BBLONG fdRead(int fd,char *buffer,BBLONG bytes)
 {
 {
-	int		res; 
+	int		res;
 	long	count;
 	long	count;
 	res=ReadFile((HANDLE)fd,buffer,bytes,&count,0);
 	res=ReadFile((HANDLE)fd,buffer,bytes,&count,0);
 	if (res) return count;
 	if (res) return count;
@@ -215,7 +240,7 @@ int fdFlush(int fd)
 	return res;
 	return res;
 }
 }
 
 
-int fdAvail(int fd) 
+int fdAvail(int fd)
 {
 {
 	int		res;
 	int		res;
 	long	avail;
 	long	avail;
@@ -228,13 +253,13 @@ int fdAvail(int fd)
 int fdProcessStatus( int pid ){
 int fdProcessStatus( int pid ){
 
 
 	PROCESS_INFORMATION *pi=(PROCESS_INFORMATION *)pid;
 	PROCESS_INFORMATION *pi=(PROCESS_INFORMATION *)pid;
-	
+
 	long exitcode;
 	long exitcode;
-	
+
 	if( GetExitCodeProcess( pi->hProcess,&exitcode ) ){
 	if( GetExitCodeProcess( pi->hProcess,&exitcode ) ){
 
 
 		if( exitcode==STILL_ACTIVE ) return 1;
 		if( exitcode==STILL_ACTIVE ) return 1;
-		
+
 		CloseHandle( pi->hProcess );
 		CloseHandle( pi->hProcess );
 		free( pi );
 		free( pi );
 	}
 	}
@@ -245,9 +270,21 @@ int fdProcessStatus( int pid ){
 int fdTerminateProcess( int pid ){
 int fdTerminateProcess( int pid ){
 
 
 	PROCESS_INFORMATION *pi=(PROCESS_INFORMATION *)pid;
 	PROCESS_INFORMATION *pi=(PROCESS_INFORMATION *)pid;
-	
+
 	int res=TerminateProcessGroup( pi->hProcess,pi->dwProcessId );
 	int res=TerminateProcessGroup( pi->hProcess,pi->dwProcessId );
-	
+
+	CloseHandle( pi->hProcess );
+	free( pi );
+
+	return res;
+}
+
+//returns 0 for success
+int fdKillProcess( int pid ){
+	PROCESS_INFORMATION *pi=(PROCESS_INFORMATION *)pid;
+
+	int res=KillProcessGroup( pi->hProcess,pi->dwProcessId );
+
 	CloseHandle( pi->hProcess );
 	CloseHandle( pi->hProcess );
 	free( pi );
 	free( pi );
 
 
@@ -286,7 +323,7 @@ int fdProcess( BBString *cmd,int *procin,int *procout,int *procerr,int flags)
 	}
 	}
 
 
 	pi=(PROCESS_INFORMATION*)calloc(1,sizeof(PROCESS_INFORMATION));
 	pi=(PROCESS_INFORMATION*)calloc(1,sizeof(PROCESS_INFORMATION));
-	
+
 	if( _bbusew ){
 	if( _bbusew ){
 		STARTUPINFOW si={sizeof(si)};
 		STARTUPINFOW si={sizeof(si)};
 
 
@@ -320,7 +357,7 @@ int fdProcess( BBString *cmd,int *procin,int *procout,int *procerr,int flags)
 		}
 		}
 		res=CreateProcess( 0,bbTmpCString(cmd),0,0,-1,pflags,0,0,&si,pi );
 		res=CreateProcess( 0,bbTmpCString(cmd),0,0,-1,pflags,0,0,&si,pi );
 	}
 	}
-	
+
 	if( !res ){
 	if( !res ){
 		CloseHandle( istr );
 		CloseHandle( istr );
 		CloseHandle( ostr );
 		CloseHandle( ostr );
@@ -330,9 +367,9 @@ int fdProcess( BBString *cmd,int *procin,int *procout,int *procerr,int flags)
 		CloseHandle( p_estr );
 		CloseHandle( p_estr );
 		return 0;
 		return 0;
 	}
 	}
-	
+
 	CloseHandle( pi->hThread );
 	CloseHandle( pi->hThread );
-	
+
 	*procin=(int)istr;
 	*procin=(int)istr;
 	*procout=(int)ostr;
 	*procout=(int)ostr;
 	*procerr=(int)estr;
 	*procerr=(int)estr;
@@ -340,7 +377,7 @@ int fdProcess( BBString *cmd,int *procin,int *procout,int *procerr,int flags)
 	CloseHandle( p_istr );
 	CloseHandle( p_istr );
 	CloseHandle( p_ostr );
 	CloseHandle( p_ostr );
 	CloseHandle( p_estr );
 	CloseHandle( p_estr );
-	
+
 	return (int)pi;
 	return (int)pi;
 }
 }