grendel-1.0.0a7/backup/
grendel-1.0.0a7/bin/
grendel-1.0.0a7/boards/
grendel-1.0.0a7/clans/
grendel-1.0.0a7/documentation/todo/
grendel-1.0.0a7/help/
grendel-1.0.0a7/logs/
grendel-1.0.0a7/players/
grendel-1.0.0a7/progs/
grendel-1.0.0a7/races/
grendel-1.0.0a7/src/contrib/
grendel-1.0.0a7/src/modules/speller/
grendel-1.0.0a7/src/modules/status/
grendel-1.0.0a7/src/tests/
grendel-1.0.0a7/src/tests/dunit/
{
	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.