Link to home
Start Free TrialLog in
Avatar of EKIM
EKIM

asked on

Kill process

Main question : how to kill a process (Delphi 5 or 7(as U want)  , XP )
Origin :
   I use Firebird Classic  as DB. For each connection, a new firebird process is created on the server. this would not be a problem, except when the Client lose the connection for any resaon (hard reboot, network problem...) : In such case, the process stay launched on the server, and its attached ressources stay reserved (ie Memory).

I am abble to retreive with instance is no more connected with a client, and get this PID.

I tried this, but it does not works:


procedure TForm1.KillProcess(PID: Cardinal);
var
  exitcode:UINT;
  x:THandle;
begin
  x:=Openprocess(PROCESS_ALL_ACCESS,false,PID);
  GetExitCodeProcess(x,ExitCode);
  TerminateProcess(x,Exitcode);
end;

 --> X always receive 0 from OpenProcess (why?)

I also tried this :

procedure TForm1.KillProcess(PID: Cardinal);
begin
  SendMessage(PID,wm_close,0,0);
end;

but it also does not seems to works...

Thanks for any help.

Ekim
Avatar of Wim ten Brink
Wim ten Brink
Flag of Netherlands image

Terminating the process won't be very useful since it might still lead to resources being used. In general, with using client-server techniques, the best thing to do is connect upon request and disconnect before returning a reply. Maybe maintain a pool of connections somewhere to speed up the connection speed. But you will always have this problem if you keep connections open between requests.
I knwo, it is a lot easier to keep it open. Performs a little better too. But you have to be aware that connections can be broken anytime. This is why most client-server solutions are stateless solutions. (The server closes and frees anything it doesn't need as soon as it has the reply ready.)
I think it's better to redesign your server-side code instead.

To forcefully close a process, you might want to call some kernel function to do this. I have forgotten which one, though. And it only works on NT systems. You also need appropiate privileges too. Killing processes are a real pain...
You might consider including a separate thread in your server-side code that just kills the process if a time-out occurs. Then again, instead of killing the process, the thread could just kill the connection and free the resources...
Avatar of EKIM
EKIM

ASKER

Are you serious ?
 - If I open/close the connection on each request It will take really too much time !
 - I cannot modify the Database Server source code !
Try this:

procedure TForm1.KillProcess(PID: Cardinal);
var
  exitcode:UINT;
  x:THandle;
begin
  x:=Openprocess(PROCESS_TERMINATE,false,PID);
  if x <> 0 then begin
    try
      GetExitCodeProcess(x,ExitCode);
      TerminateProcess(x,Exitcode);
    finally
      CloseHandle(x);
    end;
  end;
end;

Regards, Geo
Avatar of EKIM

ASKER

geobul : hu...  what is the difference with my code ?
ASKER CERTIFIED SOLUTION
Avatar of geobul
geobul

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
If you get 'Parameter is incorrect' it means that there is no such process (PID is wrong).
Avatar of EKIM

ASKER

GeoBul : while I was trying your code, I understood something : I was trying to kill the service rather than the applications this service launch on each connection.
I changed this, but it does not works if the service is logged on with 'Local System Account'...
And you're receiving 'Access is denied', right?
> Are you serious ?
Yes, I am...
Which is why I suggested the option of connection pooling. Microsoft is doing something like that in their ADO components and ODBC also has support for the pooling of connections. Basically, it just means that after you're done with a connection, you send it to some pool (array of connection) and keep it there until you can use it again. Because all the connections are stored in a global array, you could free those connections if they're in the pool for more than 5 minutes. But if a user requests new data, you take an open connection from this pool instead of opening a new one. If there are no connections in the pool, then you'll have to create a new connection. And once the user is done with the connection, you put it back into the pool.

>  - If I open/close the connection on each request It will take really too much time !
Have you even tried it? I know it will slow things down but are we talking about milliseconds, seconds or even minutes? Maybe if you need to retrieve a lot of data at once, you should use a different approach instead. In general, when you do client-server applications you should close resources on the server as soon as possible, because there could be 5000 other clients who also want to do stuff... And if you could re-use something for another user, then that would be perfect. Thus, connection-pooling...

> - I cannot modify the Database Server source code !
Well, that is a good excuse! ;-)
Okay, See http://help.madshi.net/Processes.htm for some process handling examples. You would need the Madshi components for this, though.
But there's a chance that the process that you're trying to kill is set up as something extremely secure and thus you might need proper access rights to kill it. If you don't have proper access rights, terminating the process will fail. This is especially true for services.
function KillTask(ExeFileName: string): integer;
const
PROCESS_TERMINATE=$0001;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
result := 0;
FSnapshotHandle := CreateToolhelp32Snapshot
(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle,
FProcessEntry32);
while integer(ContinueLoop) <> 0 do
begin
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
UpperCase(ExeFileName))
or (UpperCase(FProcessEntry32.szExeFile) =
UpperCase(ExeFileName))) then
Result := Integer(TerminateProcess(OpenProcess(
PROCESS_TERMINATE, BOOL(0),
FProcessEntry32.th32ProcessID), 0));
ContinueLoop := Process32Next(FSnapshotHandle,
FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;

This is good code for killing by exename.

For killing by PID (done off top of head but should work):

procedure TForm1.KillProcess(PID: Cardinal);
const
PROCESS_TERMINATE=$0001;
begin
    TerminateProcess(OpenProcess(PROCESS_TERMINATE, BOOL(0),PID), 0);
end;


Regards,

Hypoviax
Well, a bit off-topic, but is your db server running on multiprocessor machine? Because otherwise, there is not much sense in using the Classic Server. With the SuperServer, only one instance of the db server runs, but each connection will open up a new thread, but sharing the same cache. Which means, if there is a number of simultaneous connections requesting the same data, apart from the first request, everyone will be reading from the cache, making it much faster!

http://firebird.sourceforge.net/manual/qsg15-classic-or-super.html
I have no experience using Firebird but if you make the service logging under your account instead of Local System then you'll be able to kill its processes using your first code. Not sure if changing the Logon account is allowed, though.
you have to set the privileges before killing, like that:

procedure KillPrivilege;
var
   DebugValue : TLargeInteger;
   tkp : TTokenPrivileges ;
   PreviousState: TTokenPrivileges;
   dw:DWORD;
   h:THandle;
begin
   OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,h);
   lookupPrivilegeValue(nil,'SeDebugPrivilege', DebugValue);
   dw:=0;
   tkp.PrivilegeCount:=1;
   tkp.Privileges[0].Luid:=DebugValue;
   tkp.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED;
   AdjustTokenPrivileges(h,false,tkp, SizeOf(TTokenPrivileges),PreviousState ,dw);
end;


Avatar of EKIM

ASKER

Dragon Slayer : sys used : Windows Server2003.
We were using the super server but we frequently get a Firebird system crash... After looking deeper, it seems that the max memory allocated by W2003 to an application is 4Go (the system has 8Go). This 4Go was splitted (according W2003 params) to 2Go for Application and 2Go for System. It seems that when the transaction manager need more than 2Go, the whole system crsashes...  (instead of using swap)
Question is : 1) Why Super sever need so much memory ?? (DB is +/- 6Go, 40 Users)
                   2) Does W2003 or SuperServer frees memory properly
                   4) Does W2003 or SuperServer have problem tu re-use recently freed memory

Because we are a company, we cannot leave our customers in such situation, So we decided to install them the classic server witch does not have this problem, waiting for another solution. BUT, Classic server is not without any problem, specially when the TCP/IP connection is lost. This is why I'am trying to hook the fbirg task create process( as U can see I have a question on this subject in Programming/Delphi topic)   to link it with a User ID, and when thê same user ID tries to re-connect: I can know that there was already a connection(lost) to this user and then shoot it.

Geobul : yep, it works fine with my loggin, I think I will do like this... for the moment.

EKIM
Here is a bugtracker report from sourceforge that you might want to track... I don't know if it is relevant, but it might be... http://sourceforge.net/tracker/?group_id=9028&atid=109028&func=detail&aid=1021143