// $Id: clean.pas,v 1.9 2001/05/11 14:25:02 druid Exp $ unit clean; interface uses Windows, 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) private t_log : string; protected procedure AutoSave; procedure SyncWrite; procedure SyncWritelog(s:string); procedure Execute; override; public constructor Create; end; implementation uses SysUtils, chars, conns, constants, dtypes, area, util, timers, Winsock2, mudthread, mudsystem; constructor GCleanThread.Create; begin inherited Create(false); SyncWritelog('Started cleanup thread.'); SetThreadPriority(Handle, THREAD_PRIORITY_IDLE); freeonterminate := true; end; procedure GCleanThread.SyncWrite; begin write_console(t_log); end; procedure GCleanThread.SyncWritelog(s:string); begin t_log := s; Synchronize(SyncWrite); end; procedure GCleanThread.AutoSave; var ch : GCharacter; node : GListNode; begin SyncWritelog('Autosaving characters...'); node := char_list.head; while (node <> nil) do begin ch := node.element; if (not ch.IS_NPC) then GPlayer(ch).save(ch.name^); node := node.next; end; 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 : GConnection; begin a := 0; repeat 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 := node.element; if (GGameThread(conn.thread).last_update + THREAD_TIMEOUT < Now()) then begin bugreport('update_main', 'timers.pas', 'Thread of ' + conn.ch.name^ + ' probably died', 'The server has detected a malfunctioning user thread and will terminate it.'); 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); closesocket(conn.socket); 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; TerminateThread(conn.thread.handle, 1); node := node_next; continue; end; node := node_next; end; {$ENDIF} if (GTimerThread(timer_thread).last_update + THREAD_TIMEOUT < Now()) then begin bugreport('update_main', 'timers.pas', 'Timer thread probably died', 'The server has detected that the timer is malfunctioning and will try to restart it.'); TerminateThread(timer_thread.handle, 1); timer_thread := GTimerThread.Create; end; cleanChars; cleanObjects; until (Terminated); SyncWritelog('Simple task thread terminated.'); end; end.