KONZEPT:
Event-Daemon des Wunderlandes
/secure/eventd.c
/sys/events.h
/etc/eventd.handlers
/etc/eventd.secure
/etc/eventd.trust
/etc/eventd.globtrust
AUTOR:
Holger@Wunderland 01.03.2003
EINLEITUNG:
Der Event-Daemon dient zur zentralen Verwaltung des Event-Systems im
Wunderland. Hier melden sich alle Objekte an, die Events empfangen
wollen. Die Events selbst werden hier verteilt und an die Empfaenger
zugestellt. Die Event-Informationen werden im /secure/memory.c
(memory(WL)) abgelegt, um ein Updaten des Daemons ohne Datenverlust
zu ermoeglichen. Diese Dokumentation beschreibt die Funktionen des
Daemons. Zur allgemeinen Dokumentation des Event-Systems dient als
Einstieg die Manpage events(WL).
PHILOSOPHIE:
Beim Design des Daemons wurde auf optimale Performance Wert gelegt.
Das heisst vor allem, dass in zeitkritischen Funktionen keine
call-other gemacht werden. Desweiteren wird oft Gebrauch von Alists,
Mappings und Closures (lfun-closures und lambda closures) gemacht.
Auch bei mehreren tausend Event-Lauschern erfolgt die Auswahl und
Sortierung der richtigen Empfaenger mit aeusserst geringen Kosten.
Die 'Performance' eines Events haengt damit im wesentlichen von der
'Qualitaet' des jeweiligen Event-Handlers und seiner Lauscher ab.
Diese sollten daher auch nicht unnoetig zeitaufwaendige Dinge tun.
Da ein Event einen anderen ausloesen kann, rufen sich manche Funk-
tionen des Daemons rekursiv selbst auf und koennen daher zu einem
Stack-Ueberlauf des Drivers fuehren (too deep recursion). Dies ist
aber kein Fehler des Daemons, sondern in aller Regel ein Fehler in
den Event-Lauschern. Der Daemon ist so aufgebaut, dass er derartige
Fehler verkraften kann.
Auch wenn die Handler und Lauscher, sowie das /secure/memory.c
Objekt buggen oder die Einstellungsfiles korrupt sind, soll der
Daemon selbst ladbar und weitgehend funktionstuechtig bleiben.
SEFUNS:
Folgende simulierte Driverfunktionen (sefuns) dienen zur Verarbei-
tung der Events. Alle sefuns haben eigne Manpages zur Beschreibung:
Name | Kurzbeschreibung
--------------------------+-----------------------------------------
listen_event(...) | Ein Objekt meldet sich als Lauscher an.
unlisten_event(...) | Ein Objekt meldet sich als Lauscher ab.
set_global_listener(...) | Ein Objekt will global lauschen.
send_event(...) | Ein Objekt erzeugt einen Event.
cancel_event(...) | Ein Objekt will einen Event abbrechen.
handle_event(...) | Ein Objekt verarbeitet einen Event.
In aller Regel sollte zumindest <events.h> includet werden, um die
darin enthaltenen Defines zu benutzen.
WICHTIGE DEFINES IM DAEMON:
Name | Kurzbeschreibung
---------------+----------------------------------------------------
PRELOADFILE | Liste aller Default-Handler, die bei Bedarf vom
| Daemon geladen werden.
SECUREFILE | Die Sicherheitseinstellungen einiger Events.
TRUSTFILE | Die 'erlaubten' Objekte bei geschuetzten Events.
GLOBTRUSTFILE | Die als globale Lauscher freigegebenen Objekte bei
| geschuetzten Events.
LOGFILE | Das Hauptlogfile des Daemons.
CORE_LOGFILE | Logfile in den der Event-Stack geschrieben wird bei
| einem Stackueberlauf (too deep recursion).
GLOBAL_LOGFILE | Logfile in dem globale Lauscher erfasst werden.
LISTEN_LOGFILE | Logfile in dem Lauscher bei geschuetzten Events
| erfasst werden.
MAX_STACK | Vorgegebene Maximal-Rekursion. Entspricht der
| maximalen Anzahl von Objekten auf dem Callerstack.
| Der Wert ist so gewaehlt (momentan 30), dass er
| einem 'harten Abbruch' durch den Driver zuvorkommt.
| Sollte der Driver-Stack erhoeht werden, kann auch
| MAX_STACK erhoeht werden, er sollte aber immer
| 'unter' dem Driver liegen, um das Debuggen zu
| vereinfachen. Siehe CORE_LOGFILE.
FUNKTIONEN DES DAEMONS:
Im folgenden werden alle momentan im Event-Daemon enthaltenen
Funktionen kurz erklaert. Bitte nur mit diesen Sefuns arbeiten und
nicht die Funktionen direkt aufrufen.
FUNKTION "create":
void create()
Hier werden die Einstellungsfiles ausgelesen (preload_handlers()
und preload_security()) und die globalen Variablen initialisiert.
Es wird versucht, bereits gespeicherte Daten aus dem secure/memory.c
Objekt zu holen. Schlaegt dies fehl, wird zumindest eine Art
'Notbetrieb' ermoeglicht.
ACHTUNG: Sollte secure/memory.c buggen, gehen bei einem Neuladen des
Daemons alle Informationen ueber die gerade angemeldeten Objekte
verloren! Ein Reboot wird unvermeidlich!
FUNKTION allowed():
private int allowed(object ob, string type, int prio,
closure callback)
ob - das Objekt, das sich als Lauscher anmelden will
type - der gewuenschte Event
prio - die gewuenschte Lauscher-Prioritaet
callback - die lfun closure, die dann aufgerufen werden soll
Rueckgabewerte:
1 - Objekt darf lauschen
0/Bug - Objekt darf nicht lauschen
Es werden verschiedene Ueberpruefungen vorgenommen, ob ein Objekt
sich als Lauscher auf einen bestimmten Event anmelden darf. Dies
haengt in erster Linie von den Einstellungen im SECUREFILE ab.
FUNKTION global_allowed():
private int global_allowed(object ob, string type)
ob - das Objekt, das sich als Lauscher anmelden will
type - der gewuenschte Event
Rueckgabewerte:
1 - Objekt darf lauschen
0/Bug - Objekt darf nicht lauschen
Es wird ueberprueft, ob ein Objekt sich als globaler Lauscher
auf einen Event anmelden darf. Globale Lauscher koennen Events
im ganzen MUD empfangen und sollten daher etwas restriktiv
behandelt werden. Ein globaler Lauscher auf ET_DEATH koennte
zum Beispiel jeden Tod eines Lebewesens absichtlich oder aufgrund
eines Bugs verhindern!
FUNKTION preload_handlers():
private mapping preload_handlers()
Rueckgabewert:
mapping - ein Mapping der Default-Handler Namen
Die Standard-Handler Objekte werden aus dem PRELOADFILE gelesen. Die
Handler werden aber NICHT sofort geladen, sondern erst beim ersten
Auftreten des Events. Dann muessen die Handler sich auch selbst als
Lauscher mit Prioritaet EPRIO_DEF_HANDLE und ggf. als globale
Lauscher anmelden. Die Preload-Funktion dient lediglich dazu die
benoetigten Handler ueberhaupt zu laden, wenn sie benoetigt werden
und macht damit einen Eintrag in die Mud-weiten preload-Listen des
Masters ueberfluessig.
FUNKTION preload_security():
private mapping preload_security()
Rueckgabewert:
mapping - ein Mapping mit Sicherheitseinstellungen
Wird einmalig beim Laden aufgerufen. Hier werden die Sicherheits-
Einstellungen der Events werden aus dem SECUREFILE ausgelesen. Nicht
jeder Event soll von jedem Objekt empfangen werden koennen. Welche
Einstellungen moeglich sind, ist im SECUREFILE als Kommentar be-
schrieben.
FUNKTION query_default_handlers():
public varargs mixed query_default_handlers(string type)
type - der gewuenschte Event (optional)
Rueckgabewert:
0 - wenn 'type' angegeben wurde und es keinen handler gibt
string - wenn 'type' angegeben wurde, der default-handler fuer
den Event 'type'
mapping - wenn 'type' nicht angegeben wurde alle defaulthandler
Liefert eine Kopie der internen Liste der Standard-Handler fuer die
einzelnen Event-Typen. Wird 'type' weggelassen wird die gesamte
Liste als Mapping geliefert, ansonsten nur den default-Handler des
jeweiligen Events.
FUNKTION listen():
public int listen(string type, int prio, mixed callback)
type - der gewuenschte Event
prio - die gewuenschte Lauscher-Prioritaet
callback - die alien lfun closure, die dann aufgerufen werden soll
Rueckgabewerte:
1 - erfolgreiche Anmeldung
0 - unvollstaendige Funktions-Argumente
-1 - Event-Typ existiert nicht (derzeit unbenutzt, der Daemon
weiss nicht, welche Typen existieren)
-2 - das Objekt darf sich nicht fuer diesen Event anmelden
Die Funktion dient dazu, sich beim Event-Daemon als Lauscher auf
einen bestimmten Event anzumelden. Angemeldet wird immer das
aufrufende Objekt. Es wird ueberprueft, ob die Argumente voll-
staendig sind und ob das Objekt berechtigt ist, dem Event zu
lauschen. Danach wird es in die interne Liste des Event-Typs ent-
sprechend seiner Prioritaet eingetragen (Vorsortierung fuer
spaetere Auswahl). Eine doppelte Anmeldung des gleichen Objekts mit
identischen Argumenten wird verhindert.
FUNKTION query_listeners():
public varargs mapping query_listeners(string type)
type - der gewuenschte Event (optional)
Rueckgabewerte:
0 - wenn 'type' angegeben wurde und es keine Lauscher gibt
mapping - die Liste aller Event-Lauscher oder nur fuer einen
bestimmten Event, wenn 'type' angegeben wurde.
Die Funktion liefert eine Kopie des kompletten Mappings aller Events
mit all seinen angemeldeten Objekten, oder wenn 'type' angegeben
wurde nur das Objekt-Mapping fuer den jeweiligen Event.
FUNKTION is_listening():
public mapping is_listening(object ob)
ob - ein Objekt, ueber das man Informationen haben moechte
Rueckgabewert:
0 - das Objekt lauscht keinem Event
mapping - ([ string typ: mixed alist ]) wobei 'alist' wie folgt
aussieht: ({ int *prios, closure *cls})
Die Funktion liefert Informationen darueber, welchen Events ein
Objekt lauscht. Da ein Objekt verschiedenen Events mit verschiedenen
Prioritaeten und Rueckruffunktionen angemeldet sein kann wird immer
ein Mapping mit einer Alist als Wert zurueckgegeben, das alle Infor-
mationen zu jedem Event-Typ (sortiert) enthaelt.
FUNKTION unlisten():
public void unlisten(string type, int prio, mixed callback)
type - der gewuenschte Event
prio - die gewuenschte Lauscher-Prioritaet
callback - die alien lfun closure, die dann aufgerufen werden soll
Ein Objekt meldet sich als Lauscher auf einen Event ab. Es wird
immer das aufrufende Objekt abgemeldet. Da ein Objekt mit mehreren
verschiedenen Prioritaeten und Rueckruffunktionen angemeldet sein
kann, muessen diese Parameter auch bei der Abmeldung angegeben
werden. Es wird daher nur jeweils der Eintrag entfernt, der mit
diesen Parametern (wie sie bei listen() angegeben wurden) ueberein-
stimmt.
FUNKTION set_global():
public int set_global(string type, status state)
type - der gewuenschte Event
state - 1 = global setzen, 0 = global loeschen
Rueckgabewerte:
1 - erfolgreich (global gesetzt/entfernt)
0 - unvollstaendige Funktions-Argumente
-1 - Event-Typ existiert nicht/nicht erlaubt
-2 - das Objekt darf diesem Typ nicht global lauschen
Die Funktion dient dazu das aufrufende Objekt als globalen Lauscher
fuer diesen Event zu setzen. Dies ist nur moeglich, wenn das Objekt
befugt ist, dem Event global zu lauschen. In aller Regel wird die
Funktion daher von Event-Handlern benutzt und muss zusammen mit
listen() aufgerufen werden.
FUNKTION query_global():
public varargs mixed query_global(string type)
type - der gewuenschte Event (optional)
Rueckgabewert:
0 - wenn 'type' uebergeben und keine globalen Lauscher
mapping - wenn 'type' nicht uebergeben wurde das gesamte Mapping
aller globalen Lauscher auf alle Events
object* - wenn 'type' angegeben wurde ein Array aus Objekten
Die Funktion liefert eine Kopie der globalen Lauscher entweder
fuer einen bestimmten Event, wenn 'type' angegeben wurde oder ein
Array aus Objekten der globalen Lauscher auf einen bestimmten Typ.
FUNKTION cancel_event():
public int cancel_event(mixed info)
info - irgendeine Information, die bei jedem Event-Typ anders
sein kann. Entspricht dem Argument 'info' der sefun
cancel_event(S). Wird kein 'info' oder 0 uebergeben,
setzt der Daemon defaultmaessig 1.
Rueckgabewert:
0 - wenn der Event nicht abgebrochen werden konnte oder wenn
der Event bereits als abgebrochen markiert war.
1 - wenn der Event als abgebrochen markiert wurde
Die Funktion dient dazu, einen Event als abgebrochen zu markieren.
Der Event ist damit aber noch nicht beendet, sondern wird erst noch
beendet werden. Der Aufruf muss im gleichen Backend-Cycle wie das
ausloesende send_event(S) aufgerufen werden. Ein Objekt, das nach
dem Abbruch noch Aktionen ausfuehren will, muss sich auch mit
Prioritaet EPRIO_C_HANDLE anmelden und empfaengt dann den Event,
wenn er tatsaechlich abgebrochen wurde.
Wurde der Event im Modus EM_NO_CANCEL gestartet, kann der Event
nicht abgebrochen werden. Ebenso kann der Event nicht von Objekten
abgebrochen werden, die nach dem 'handeln' (als Reagierer) lauschen.
Wurde der Event im Modus EM_STOP_CANCEL gestartet wird der Event
nach Aufruf von cancel_event() gestoppt werden, andere Objekte
empfangen ihn dann nicht mehr. Das ist nur sinnvoll, wenn ein Objekt
exklusiv den Event abbrechen koennen soll. Etwa bei 'privaten'
Events.
Wurde der Event NICHT im Modus EM_STOP_CANCEL gestartet (Standard)
wird die Verarbeitung _zunaechst_ fortgesetzt, um weiteren Objekten
die Moeglichkeit zu geben, den Event zu empfangen auch wenn er
abgebrochen werden wird (um Meldungen zu setzen etc.). Der Event
wird aber letztlich nicht ausgefuehrt und eines der Objekte, die
den Event abbrechen wollten (in aller Regel das letzte) bekommen
dann ueber einen Aufruf mit EPRIO_C_HANDLE die Moeglichkeit den
Abbruch zu verarbeiten. Siehe dazu auch die Konzeptseite events(WL)
und die Manpage der entsprechenden Sefun cancel_event(S).
Der Daemon haelt intern einen Zeiger auf den gerade laufenden Event
(den 'letzten' im EventStack des Daemons) und setzt das aufrufende
Objekt als Abbrecher in E_CANCELLER und 'info' als E_CANCELLED Wert.
Wie der 'info' Wert weiter verarbeitet wird, liegt in der Hand des
Handlers und kann variieren.
Bitte an dieser Funktion nur Aenderungen vornehmen, wenn genau ver-
standen wurde, wie die Rekursion im Daemon ablaeuft!
FUNKTION handle_event():
public int handle_event(mixed info)
info - irgendeine Information, die bei jedem Event-Typ anders
sein kann. Entspricht dem Argument 'info' der sefun
handle_event(S). Wird kein 'info' oder 0 uebergeben,
setzt der Daemon defaultmaessig 1.
Rueckgabewert:
0 - wenn der Event bereits als gehandelt markiert war.
1 - wenn der Event als gehandelt markiert wurde
Die Funktion dient dazu, einen Event als gehandelt zu markieren und
entspricht in seiner Funktionsweise weitgehend cancel_event(). Nur
Event-Handler sollten handle_event() aufrufen. Vorlagen fuer Event-
Handler finden sind in /global/handler/*.
Zum besseren Verstaendnis bitte die Konzeptseite events(WL) lesen.
FUNKTION process():
private mapping process(mixed *ev)
ev - Event-Daten
Rueckgabewert:
mapping - geht an den Aufrufer von send_event() zurueck.
DIE zentrale Funktion zu Arbeitung eines Events. Die Funktion laeuft
durch eine while()-Schleife bis alle uebergebenen Event-Daten in 'ev'
abgearbeitet worden sind. Es wird jeweils der letzte 'Datensatz' aus
'ev' genommen und verarbeitet. Loest die Abarbeitung dabei einen
weiteren Event aus, wird process() rekursiv vom Driver aufgerufen,
die Daten des vorherigen Aufrufs landen dabei im normalen Driver-
Stack und werden nach Abarbeitung der Rekursion fortgesetzt.
Wird der Driver-Stack dabei zu gross, ist die Rekursion zu tief
geworden. Das passiert jedoch sehr selten und in aller Regel nur
dann, wenn eine echte unendliche Rekursion vorliegt, etwa wenn sich
2 NPCs gegenseitig verfolgen und die ET_GO-Events sich verschach-
teln. Dieser Fall ist an sich unkritisch, der Driver bricht mit
einem 'too deep recursion' bug ab. Um das Debuggen zu erleichtern
greift der Daemon jedoch selbst ein, wenn er zu viele Objekte auf
dem caller_stack(E) des Drivers bemerkt. Die maximal moegliche
Anzahl an Objekten im caller_stack(E) ist durch das Define MAX_STACK
(siehe oben) vorgegeben. Stellt der Daemon eine Ueberschreitung von
MAX_STACK fest, schreibt er den gesamten Inhalt in das CORE_LOGFILE.
Nach mehrjaehrigem Test kann festgestellt werden, dass dieses Ver-
fahren ausreichend tiefe Rekursion ermoeglicht. Eine eigne Imple-
mentation des Stacks, der tiefere Rekursionen zulassen wuerde, ist
getestet worden und hat zu viele Probleme mit sich gebracht, wie
etwa den Umstand, dass der Stack nicht abgeraeumt werden kann, wenn
ein Bug auftritt (wenn man catch() nicht verwenden will) und aehn-
liches. Weiterhin waere die Performance eines Stacks auf LPC-Ebene
fragwuerdig.
Sollte es daher vorkommen, dass der Daemon zu oft die Verarbeitung
abbricht, muss die Stelle die die Rekursion ausloest, optimiert
werden. Alternativ kann natuerlich auch der Driver-Stack selbst er-
hoeht werden. Aber selbst eine Optimierung bestimmter NPCs ist bis
jetzt im WL nur ein einziges mal notwendig geworden in einem Fall
bei dem 10 NPCs einen Spieler und sich gegenseitig verfolgen
wollten. Dies sollte man dann eleganter loesen. :-)
Die Daten in 'ev' werden von send() aufbereitet. Sie enthalten
immer den aktuellen Event-Typ, die Event-Daten, den Sende-Modus und
eine Alist aus vorsortierten Prioritaeten und Alien Lfun Closures.
process() nimmt immer den letzten Eintrag in der Alist und ruft
die entsprechende Closure mit dem Event-Daten, der Prioritaet und
dem Modus als Argumente auf. Nach dem Aufruf werden die E_CANCELLED
und E_HANDELED Werte in den Event-Daten ueberprueft und entschieden,
ob die Verarbeitung fortgesetzt wird oder nicht. Wird sie fortge-
setzt, wird der letzte Eintrag in der Alist entfernt und im folgen-
den while()-Durchlauf der naechste 'letzte' Eintrag verwendet. Dies
laeuft entweder so lang, bis festgestellt wird, dass der Event ab-
gebrochen werden muss oder bis die Alist aus Prioritaeten und
Closures keine Elemente mehr enthaelt.
process() selbst sind die dabei verwendeten Prioriaeten und deren
Bedeutung egal. Jeder Event-Lauscher (Modifizierer, Abbrecher,
Handler, Reagierer, Abbruch-Reagierer) wird gleich behandelt. Die
verwendeten Werte sind also frei definiert. Siehe dazu auch
event_prioritaeten(WL). Aber Werte zwischen -1000 und +1000 haben
sich als sinnvoll erwiesen und sollten ausreichend Spielraum lassen.
Je nach Sende-Modus uebergibt der Daemon die Event-Daten an die
Lauscher als Referenz, einfache Kopie oder komplette Kopie. Die
Arbeit mit Referenzen ist dabei naturgemaess die schnellste, kann
aber unerwuenscht sein, wenn man zum Beispiel vermeiden will, dass
Daten im Event modifiziert werden (EM_COPY/EM_NO_MODIFY Modi).
Weiterhin bietet process() einige Debug-Modi bei dem Informationen
ueber alle Empfaenger gesammelt werden koennen. Es kann auch ein
'Fake-Event' (EM_FAKE in Verbindung mit EM_DEBUG) erzeugt werden,
der ueberhaupt nichts tut und nur zurueckliefert, wer den Event
empfangen haette, wenn er aufgetreten waere. EM_DEBUG ohne EM_FAKE
liefert zudem auch die von den Lauschern konsumierten eval-costs
und kann daher zum Optimieren oder zur Fehlersuche verwendet
werden.
FUNKTION continue_event():
public mapping continue_event(mapping data)
data - ein 'eingefrorenes' Ereignis
Wenn ein Ereignis EM_STOP_HANDLE oder EM_STOP_CANCEL gesetzt
hat, so wird das Ereignis an geeigneter Stelle eingefroren
(siehe auch events(WL) und event_senders(WL)). Wird entschieden,
dass dieses Ereignis nun 'wirklich' stattfinden soll, so kann dies
mit dieser Funktion geschehen: Das uebergebene, eingefrorere
Ereignis wird aufgetaut und endgueltig ausgefuehrt.
EM_STOP_* und diese Funktion sollte nur die Lib selbst benutzen.
FUNKTION send():
public mapping send(string type,mapping data,mixed dest,mixed mode)
type - der Event-Typ als String (event_types(WL))
data - die Event-Daten als Mapping (event_types(WL))
dest - Objekt oder Array aus Objekten an die der Event gesendet
werden soll.
mode - Ein Sende-Modus. Wird kein Modus angegeben, wird EM_SIMPLE
benutzt. Ansonsten:
EM_SIMPLE - Standard Modus - maximale Performance
EM_COPY - einfache Kopie des Daten-Mappings
EM_DEEP_COPY - echte Kopie des Daten-Mappings
EM_NO_MODIFY - macht genau das gleiche wie EM_DEEP_COPY. Ein
Modifizieren der Event-Daten ist dadurch un-
moeglich.
EM_NO_CANCEL - der Event kann durch niemanden abgebrochen
werden. cancel_event() returnt 0.
EM_FAKE - Simuliert den Event nur intern im Daemon
interessant i.V.m. EM_DEBUG, um alle Lauscher
auf einen Event zu finden
Einer der vorhergehenden Modi kann kombiniert werden mit:
EM_COMPLEX - Mehr Daten in E_RECEIVERS
EM_DEBUG - maximale Infos in E_DEBUG_INFO
EM_STOP_CANCEL - 'spekulative Ausfuehrung', siehe hierzu
auch event_senders(WL)
Diese Funktion bereitet die Event-Daten auf. Es werden aus den an-
gemeldeten Lauschern die herausgesucht, die sich im deep-inventory
der Zielobjekte aus 'dest' befinden. Sendet man also einen ET_GO
Event an einen Raum, dann werden all die Objekte ausgesucht, die
sich im deep-inventory des Raumes befinden UND sich als Lauscher
auf diesen Event angemeldet haben. Objekte die sich als globale
Lauscher angemeldet haben (z.B. Handler), muessen sich in keinem der
Zielobjekte befinden, sie werden in jedem Fall auch ausgewaehlt.
Gibt es keine Lauscher auf diesen Event, wird kein Event erzeugt,
was aber auch keinem auffaellt, da niemand in der Lage ist, es zu
bemerken. :-) Bei mehreren tausend Objekten im MUD und nur einigen
hundert die Events empfangen, werden ein Grossteil der Events
'abgearbeitet' ohne auch nur ein fremdes Objekt zu benachrichtigen.
Statistisch gesehen lauschen bei jedem Event meist weniger als 3
Objekte im 'Zielgebiet' einem Event.
Wurden alle Objekte gefunden, die den Event empfangen sollen, wird
die entstandende Alist aus Prioritaeten und Closures noch sortiert,
damit Objekte mit hohen Prioritaeten vor denen mit geringerer
Prioriaet den Event empfangen koennen. Die Sortierung erfolgt dabei
in aufsteigender Reihenfolge, da die Alist in process() vom Ende
beginnend abgearbeitet wird.
Wurden alle Objekte gefunden und sortiert, wird process() aufge-
rufen, das die eigentlich Abarbeitung und den Aufruf der Lauscher-
Closures uebernimmt.
Wird festgestellt, dass ein Objekt einen Event erzeugt, obwohl es
selbst dazu noch nich berechtigt ist (weil der Event noch gar nicht
gehandelt wurde), wird eine Warnung ausgegeben.
FUNKTION statistik():
public string statistik()
Diese Funktion liefert Informationen ueber die Event-Verarbeitung
des Daemons. Sie Funktion ist nur aktiv, wenn STATISTIK definiert
ist.
FUNKTION clean_me():
private void clean_me()
Diese Funktion wird durch reset() aufgerufen und dient als 'garbage
collector' ueber die globalen Variablen. Sie entfernt leere und
damit ueberfluessig gewordenen Eintraege um die Empfaenger-Suche
zu beschleunigen.
FUNKTION reset():
void reset()
Ruft clean_me() auf.
SIEHE AUCH:
events(WL), memory(WL), cancel_event(S), handle_event(S),
listen_event(S), send_event(S), unlisten_event(S),
event_prioritaeten(WL), event_listeners(WL), event_senders(WL),
event_types(WL), events_fuer_alle(WL), set_global_listener(S)
|