{
Summary:
Cleaning (system janitor) thread
## $Id: clean.pas,v 1.9 2004/04/10 22:24:03 druid Exp $
}
unit clean;
interface
uses
{$IFDEF Win32}
Windows,
{$ENDIF}
Classes;
{ This is the misc. thread function, also known as the 'simple task thread'.
This thread takes care of autosaves and autocleans,
and serves as a watchdog for both the timer thread and the individual
user threads. }
type
GCleanThread = class(TThread)
protected
procedure AutoSave();
procedure Execute; override;
public
constructor Create();
end;
implementation
uses
{$IFDEF LINUX}
Libc,
{$ENDIF}
SysUtils,
chars,
player,
console,
mudsystem,
constants,
timers,
util,
conns,
dtypes,
debug;
constructor GCleanThread.Create();
begin
inherited Create(false);
writeConsole('Started cleanup thread.');
{$IFDEF WIN32}
SetThreadPriority(Handle, THREAD_PRIORITY_IDLE);
{$ENDIF}
freeonterminate := true;
end;
procedure GCleanThread.AutoSave();
var
ch : GCharacter;
iterator : GIterator;
begin
writeConsole('Autosaving characters...');
iterator := char_list.iterator();
while (iterator.hasNext()) do
begin
ch := GCharacter(iterator.next());
if (not ch.IS_NPC) then
GPlayer(ch).save(ch.name);
end;
iterator.Free();
end;
// kill a non-responsive thread after 30 seconds
const
THREAD_TIMEOUT = 0.5 / 1440.0;
procedure GCleanThread.Execute;
var
a : integer;
node, node_next : GListNode;
conn : GPlayerConnection;
begin
a := 0;
repeat
try
sleep(10000);
inc(a);
if (a = 15) then
begin
AutoSave();
a := 0;
end;
{$IFNDEF NOCRASHDETECTION}
node := connection_list.head;
while (node <> nil) do
begin
node_next := node.next;
conn := GPlayerConnection(node.element);
if (conn.last_update = 0) then
begin
writeConsole('Stale thread detected, system is unstable!');
end
else
if (conn.last_update + THREAD_TIMEOUT < Now()) then
begin
bugreport('GCleanThread.Execute', 'clean.pas', 'Thread of ' + conn.ch.name + ' probably died (last update at: ' + TimeToStr(conn.last_update) + ')');
conn.ch.emptyBuffer();
conn.send('Your previous command possibly triggered an illegal action on this server.'#13#10);
conn.send('The administration has been notified, and you have been disconnected'#13#10);
conn.send('to prevent any data loss.'#13#10);
conn.send('Your character is linkless, and it would be wise to reconnect as soon'#13#10);
conn.send('as possible.'#13#10);
conn.ch.conn := nil;
act(AT_REPORT,'$n has lost $s link.',false,conn.ch,nil,nil,TO_ROOM);
SET_BIT(conn.ch.flags,PLR_LINKLESS);
conn.Free();
{$IFDEF LINUX}
pthread_kill(conn.ThreadID, 9);
{$ENDIF}
{$IFDEF WIN32}
TerminateThread(conn.handle, 1);
{$ENDIF}
node := node_next;
continue;
end;
node := node_next;
end;
{$ENDIF}
if (GTimerThread(timer_thread).lastUpdate + THREAD_TIMEOUT < Now()) then
begin
bugreport('GCleanThread.Execute', 'clean.pas', 'Timer thread probably died');
{$IFDEF LINUX}
pthread_kill(timer_thread.ThreadID, 9);
{$ENDIF}
{$IFDEF WIN32}
TerminateThread(timer_thread.handle, 1);
{$ENDIF}
timer_thread := GTimerThread.Create;
end;
// cleanExtractedChars();
except
{$IFDEF LINUX}
on E : EQuit do break;
{$ENDIF}
on E : EControlC do break;
on E : Exception do reportException(E);
end;
until (Terminated);
end;
end.