Index: /Evidence/Alarm.cc
===================================================================
--- /Evidence/Alarm.cc	(revision 261)
+++ /Evidence/Alarm.cc	(revision 262)
@@ -28,5 +28,5 @@
 
 //
-// Data handling class
+// Class declaration
 //
 class AlarmHandler: public DimClient, public EvidenceServer {
@@ -148,5 +148,5 @@
 	List[i].Level = 0;
 	List[i].WarnedLevel = 0;
-	if (Server != "DIS_DNS") sendCommandNB((Server+"/EXIT").c_str(), (int) 0);
+	sendCommandNB((Server+"/ResetMessage").c_str(), (int) 0);
   }
   
Index: /Evidence/Bridge.cc
===================================================================
--- /Evidence/Bridge.cc	(revision 261)
+++ /Evidence/Bridge.cc	(revision 262)
@@ -50,20 +50,14 @@
 
   public:
-    Bridge(char *, int);
+    Bridge();
     ~Bridge();
 }; 
 
-// Constructor
-Bridge::Bridge(char *Name, int Port): EvidenceServer(SERVER_NAME) {
-
-  // Set primary DIM network to subscribe from
-  DimClient::setDnsNode(Name, Port);
-
-  // Initialise and request notification of configuration changes
+// Constructor (ConfigChanged() is automatically called at start-up)
+Bridge::Bridge(): EvidenceServer(SERVER_NAME) {
+
+  // Initialise
   ServerList = NULL;
   GetConfig("cmdallow", " ");
-  ActivateSignal(SIGUSR2);
-  
-  ConfigChanged();
 }
 
@@ -92,12 +86,15 @@
 
   // Check if configuratiomn changed
-  if (ExcludeString == GetConfig("exclude")) return;
-  ExcludeString = GetConfig("exclude");
-  
-  // Remove all previous subscriptions
-  Undo();
-
+  string NewExcludeString = GetConfig("exclude");
+
+  Lock();
+  if (ExcludeString != NewExcludeString) ExcludeString.swap(NewExcludeString);
+  Unlock();
+  if (ExcludeString == NewExcludeString) return;
+    
   // Compile regular expressions
   regex_t R;
+  vector<regex_t> RegEx;
+
   vector<string> Exclude = Tokenize(ExcludeString, " \t");
   for (int i=0; i<Exclude.size(); i++) {
@@ -111,6 +108,10 @@
   }
 
-  // Subscribe to top-level server list
+  // Remove previous data, set new regular expressions and subscribe to top-level server list
+  Lock();
+  Undo();
+  Bridge::RegEx = RegEx;
   ServerList = new DimInfo((char *) "DIS_DNS/SERVER_LIST", NO_LINK, this);
+  Unlock();
 }
 
@@ -267,7 +268,10 @@
 	exit(EXIT_FAILURE);
   }
-          
+
+  // Set primary DIM network to subscribe from
+  DimClient::setDnsNode(argv[1], argc>2 ? atoi(argv[2]) : DEFAULT_PORT);
+
   // Static ensures calling of destructor by exit()
-  static Bridge Class(argv[1], argc>2 ? atoi(argv[2]) : DEFAULT_PORT);
+  static Bridge Class;
   
   // Sleep until signal caught
Index: /Evidence/Config.cc
===================================================================
--- /Evidence/Config.cc	(revision 261)
+++ /Evidence/Config.cc	(revision 262)
@@ -11,5 +11,5 @@
 
   A mutex is used for preventing concurrent access to the configuration data from
-  the methods rpcHandler() and ConfigChanged().
+  the methods rpcHandler() and ReadConfig().
          
   Oliver Grimm, July 2010
@@ -48,5 +48,5 @@
     ~EvidenceConfig();
 	
-	void ConfigChanged(); 
+	void ReadConfig(); 
 };
 
@@ -56,5 +56,5 @@
 	DimRpc("ConfigRequest", "C", "C"), EvidenceServer(SERVER_NAME) {
 
-  ConfigModified = NULL;	// Will be allocated in ConfigChanged()
+  ConfigModified = NULL;	// Will be allocated in ReadConfig()
   ConfigContent = NULL;
   FileContent = NULL;
@@ -71,5 +71,5 @@
 
   // Create DIM services
-  ConfigChanged();
+  ReadConfig();
 }
 
@@ -106,5 +106,5 @@
 
 // Signalisation of configuration change
-void EvidenceConfig::ConfigChanged() {
+void EvidenceConfig::ReadConfig() {
 
   static int ModifyTime;
@@ -249,5 +249,5 @@
   while (!Config.ExitRequest) {
     if (Notify != -1) {
-	  if (read(Notify, &Event, sizeof(Event)) == sizeof(Event)) Config.ConfigChanged();
+	  if (read(Notify, &Event, sizeof(Event)) == sizeof(Event)) Config.ReadConfig();
 	}
     else pause();	  
Index: /Evidence/Doc/Evidence.tex
===================================================================
--- /Evidence/Doc/Evidence.tex	(revision 261)
+++ /Evidence/Doc/Evidence.tex	(revision 262)
@@ -130,5 +130,6 @@
 \item Provides a method for configuration requests. If the configuration data is not available, the application terminates with a  message of FATAL severity unless default data is given.
 \item Provides a method for safely translating DIM service data into text.
-\item Implements the virtual DIM methods \lstinline{exitHandler()}. It can be called through a standard DIM command \lstinline{SvrName/EXIT}, taking a single integer as argument. Upon first invocation, the handler just sets the flag \lstinline{ExitRequest} which should be handled by the application. Upon second invocation, it will call \lstinline{exit()}. A special functionality is given to the argument value 0: it instructs the server to reset its message severity to INFO, without exiting. This is used by the \lstinline{Alarm} server if it receives a command to reset an alarm level, but is also available to the user. The user application can override this handler.
+\item Implements the virtual DIM methods \lstinline{exitHandler()}. It can be called through a standard DIM command \lstinline{SvrName/EXIT}, taking a single integer as argument. Upon first invocation, the handler just sets the flag \lstinline{ExitRequest} which should be handled by the application. Upon second invocation, it will call \lstinline{exit()}. The user application can override this handler.
+\item Provides a DIM command \lstinline{SvrName/ResetMessage}. It will set the message service to INFO severity with the information which client issued the command. This can be used to remove a WARN, ERROR or FATAL serverity once the problem has been fixed. The \lstinline{Alarm} server uses this command if it is instructed to reset an alarm level. The command takes no arguments.
 \item Implements the virtual DIM methods \lstinline{errorHandler()}. The error handler will issue a message with ERROR severity that contains the DIM error code. The user application can override this handler.
 \item Installs signal handler for SIGQUIT (ctrl-backspace), SIGTERM, SIGINT (ctrl-c), and SIGHUP (terminal closed). The signal handler sets first \lstinline{ExitRequest}, and on second invocation calls \lstinline{exit()}. After instantiating the class, the programmer may override the handlers.
@@ -157,5 +158,5 @@
     void SendToLog(const char *, ...);
     string GetConfig(string, string = string());
-    void ActivateSignal(int);
+	virtual void ConfigChanged() {};
     void Lock();
     void Unlock();
@@ -163,4 +164,5 @@
     static bool ServiceOK(DimInfo *);
     static bool ServiceOK(DimRpcInfo *);
+	static bool ServiceOK(DimCurrentInfo *);
     static vector<string> Tokenize(const string &, const string & = " ");
 
@@ -179,11 +181,11 @@
 \underline{\lstinline{GetConfig()}} issues, on first invocation, a DIM remote procedure call to the configuration server to retrieve the required data and returns it as a string. The second argument gives the data to be returned in case the server is unavailable or cannot provide the requested data. If in this case the second string is empty, the program terminates with a FATAL message. Using the service \lstinline{Config/ModifyTime}, the server keeps track of changes to the configuration file in the background. Upon subsequent requests for the same configuration data, it only issues a remote procedure call again if the file changed in the meantime. If not, the same data already retrieved is returned. This way, this function can be repeatedly called, even at high rate, without generating unnecessary load to the configuration server (as the configuration file does not change frequently).
 
-\underline{\lstinline{ActivateSignal()}} is used to define a signal that should be emitted to the main thread in case the configuration file changes. See Sect.\,\ref{ConfigHandling} for details. No signal will be emitted if not set by this routine.
-
-The methods \underline{\lstinline{Lock()}} and \underline{\lstinline{Unlock()}} work on an internal mutex.\footnote{Its type is \lstinline{PTHREAD_MUTEX_ERRORCHECK}. In case an already locked mutex is re-locked, the corresponding system call will therefore return a error and thus avoid dead-locking. Error messages from \lstinline{Lock()} and \lstinline{Unlock()} are written to the console and to the log file. They are not published using \lstinline{Message()} since this method itself uses locking and calling it would result in an infinite recursion.} They are used by \lstinline{GetConfig()} but are also available for the user application to serialize access from multiple threads. If a signal is set by \lstinline{ActivateSignal()}, it is masked before locking and unmasked after unlocking. Calling functions in the locked state should be avoided as it might result in re-locking.
+The virtual method \underline{\lstinline{ConfigChanged()}} is executed in a separate thread when the configuration file changes. It can be reimplemented by the application. Calls to \lstinline{GetConfig()} from this method will be blocking and thus result in updated configuration data.
+
+The methods \underline{\lstinline{Lock()}} and \underline{\lstinline{Unlock()}} work on an internal mutex.\footnote{Its type is \lstinline{PTHREAD_MUTEX_ERRORCHECK}. In case an already locked mutex is re-locked, the corresponding system call will therefore return a error and thus avoid dead-locking. Error messages from \lstinline{Lock()} and \lstinline{Unlock()} are written to the console and to the log file. They are not published using \lstinline{Message()} since this method itself uses locking and calling it would result in an infinite recursion.} They are used by \lstinline{GetConfig()} but are also available for the user application to serialize access from multiple threads. Calling functions in the locked state should be avoided as it might result in re-locking.
 
 The static method \underline{\lstinline{ToString()}} translates the contents of a DIM service safely into a string that is returned. As no consistency between a service format and the contained data is guaranteed by DIM, precautions are necessary to avoid buffer overruns. The method currently handles the standardized message format \lstinline{"I:1;C"}, arrays of numbers and strings. All other formats are translated into a hex representation. The arguments are the DIM service format, a pointer to the service data and the data size in bytes. It is thread safe as it uses only the arguments and dynamically allocated storage.
 
-The two variants of the static method \underline{\lstinline{ServiceOK()}} take a pointer to a received service update or result of a remote procedure call (as available in the respective handlers) and safely checks if its contents is identical to the constant \lstinline{NO_LINK}. If so, they return false. If using the same constant in the service declaration, this provides a safe way of being informed if a particular service becomes unavailable. Then, the handler is called once for that service with the data content \lstinline{NO_LINK}.
+The static methods \underline{\lstinline{ServiceOK()}} take a pointer to a received service update or result of a remote procedure call (as available in the respective handlers) and safely checks if its contents is identical to the constant \lstinline{NO_LINK}. If so, they return false. If using the same constant in the service declaration, this provides a safe way of being informed if a particular service becomes unavailable. Then, the handler is called once for that service with the data content \lstinline{NO_LINK}.
 
 \underline{\lstinline{Tokenize()}} takes the string from the first argument, tokenizes it using the characters contained the second argument as delimeters, and returns a vector of strings containing all tokens.
@@ -358,5 +360,5 @@
 As a first step in achieving this, the application should not store the obtained configuration data internally, but always re-request it using the method \lstinline{GetConfig()} described in Sect.\,\ref{EvidenceServer-Methods}. This method will only issue a remote procedure call to the \lstinline{Config} server if the configuration file has been modified since the last invocation. So calling this method even at high rate will not load the configuration server at all if the configuraton file is unchanged, but will yield up-to-date information if it did change.
 
-The remote procedure call is blocking when called from the main thread, and non-blocking, using an \lstinline{rpcInfoHandler()}, when called from any other thread (especially also from the DIM handler thread). Blocking execution means that the remote procedure call will wait until the data has arrived from the server before returning to the application, whereas non-blocking execution will return immediately and invoke a handler later when the data arrived. This procedure is necessary since a blocking remote procedure call from \lstinline{infoHandler()} will result in a dead-lock.
+The remote procedure call is blocking when called from the main thread or from the method \lstinline{ConfigChanged()} (which runs in a separate thread). It is non-blocking, using an \lstinline{rpcInfoHandler()}, when called from any other thread, especially also from the DIM handler thread. Blocking execution means that the remote procedure call will wait until the data has arrived from the server before returning to the application, whereas non-blocking execution will return immediately and invoke a handler later when the data arrived. This procedure is necessary since a blocking remote procedure call from \lstinline{infoHandler()} will result in a dead-lock.
 
 In the non-blocking case, the call to \lstinline{GetConfig()} returns still the previous, non-updated data even if the configuration file changed. The result of the non-blocking remote procedure call can only be processed by DIM once the current and all queued handler invocations have finished. When this is done, updated data will be returned by subsequent calls to \lstinline{GetConfig()}.
@@ -364,9 +366,7 @@
 \subsection{\lstinline{ConfigChanged()}}
 
-An alternative, albeit for the programmer more demanding, procedure for semi-automatic updates on configuration information is to implement the method \lstinline{ConfigChanged()} in the user class. This method can be invoked through a signaling mechanism by the \lstinline{EvidenceServer} class. 
-
-To this end, first \lstinline{ActivateSignal()} has to be called with a signal number that should be used for announcing configuration changes (for example, \lstinline{SIGUSR1}). That signal is send to the main thread when the service \lstinline{Config/ModifyTime} changes. The signal is caught by the internal signal handler of the \lstinline{EvidenceServer} class which in turn calls the method \lstinline{ConfigChanged()}. It is declared as \lstinline{virtual} in the class and defined as an empty function. The user application can override this by declaring and defining the method itself. This method is then executed in the main thread and thus \lstinline{GetConfig()} will use blocking connections to get always up-to-date data.
-
-However, it must be kept in mind that this routine is running as part of the signal handler. The normal main thread execution was interrupted at an arbitrary point by the signal, thus suitable protection must be employed by the programmer when accessing common data structures. To ease that, the \lstinline{EvidenceServer} class contains the pair of methods \lstinline{Lock()} and \lstinline{Unlock()} that work on an class internal mutex. When the mutex is acquired, also the signal declared by \lstinline{ActivateSignal()} is disabled, thus preventing interruptions in case a configuration update occurs in the locked state. The mutex type is \lstinline{PTHREAD_MUTEX_ERRORCHECK} and therefore includes error checking: no dead-lock will occur if double locking, but the program will terminate with a \lstinline{FATAL} message.   
+An alternative, albeit for the programmer more demanding, procedure for semi-automatic updates on configuration information is to reimplement the virtual method \lstinline{ConfigChanged()} in the user class. This method is invoked as a separate thread by the \lstinline{EvidenceServer} class whenever the service \lstinline{Config/ModifyTime} changes (and also at program start-up). As it is not running within the DIM handler thread, \lstinline{GetConfig()} will use blocking connections to get immediately up-to-date data when called from \lstinline{ConfigChanged()}.
+
+Running in a separate thread requires suitable protection by the programmer when accessing common data structures. To ease that, the \lstinline{EvidenceServer} class contains the pair of methods \lstinline{Lock()} and \lstinline{Unlock()} that work on an class internal mutex. The mutex type is \lstinline{PTHREAD_MUTEX_ERRORCHECK} and therefore includes error checking: no dead-lock will occur if double locking, but the program will terminate with a \lstinline{FATAL} message.   
 
 
Index: /Evidence/Evidence.cc
===================================================================
--- /Evidence/Evidence.cc	(revision 261)
+++ /Evidence/Evidence.cc	(revision 262)
@@ -31,13 +31,10 @@
 //
 
-// Constructor
-EvidenceServer::Config::Config(string Name): DimRpcInfo("ConfigRequest", NO_LINK), Name(Name) {
-
-  // Initialise
+// Constructor: Subscribe to be informed on configuration file change
+EvidenceServer::Config::Config():	DimRpcInfo("ConfigRequest", NO_LINK),
+									DimCommand((This->Name+"/ResetMessage").c_str(), (char *) "") {
+
   CurrentItem = string();
   ConfigTimeStamp = 0;
-  ThreadID = pthread_self();
-
-  // Subscribe to be informed on configuration file change
   Service = new DimInfo("Config/ModifyTime", NO_LINK, this);
 }
@@ -49,23 +46,38 @@
 }
 
+// Reset message and severity
+void EvidenceServer::Config::commandHandler() {
+
+  This->Message(INFO, "Message reset by %s (ID %d)", getClientName(), getClientId());
+}
+
 // Track last modification time of configuration file
 void EvidenceServer::Config::infoHandler() {
 
+  pthread_t Thread;
+  int Ret;
+
+  if (!ServiceOK(DimInfo::getInfo())) return;
+return;
   This->Lock();
   ConfigTimeStamp = getInfo()->getInt();
   This->Unlock();
 
-  if (pthread_kill(ThreadID, This->ConfigSignal) != 0) {
-	This->Message(WARN, "Could not send signal to main thread");
-  }
-}
-
-// Receive answer to remote procedure call
+  // Launch ConfigChanged() as detached thread
+  if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) EvidenceServer::CallConfigChanged, (void *) NULL)) != 0) {
+    This->Message(ERROR, "pthread_create() failed in EvidenceServer::Config::infoHandler() (%s)\n", strerror(Ret));
+  }
+  else if ((Ret = pthread_detach(Thread)) != 0) {
+	This->Message(ERROR, "pthread_detach() failed in EvidenceServer::Config::infoHandler() (%s)\n", strerror(Ret));
+  }  
+}
+
+// Answer to remote procedure call: Update map
 void EvidenceServer::Config::rpcInfoHandler(){
 
   This->Lock();
-  // Update map
-  List[CurrentItem].Value = string(getString(), getSize()-1);
-  List[CurrentItem].Time = ConfigTimeStamp;
+  This->List[CurrentItem].Value = string(DimRpcInfo::getString(), DimRpcInfo::getSize()-1);
+  This->List[CurrentItem].Time = ConfigTimeStamp;
+
   // Clear to allow new rpc call
   CurrentItem.clear(); 
@@ -73,17 +85,185 @@
 }
 
-// Return configuration data if still up to date or empty string otherwise
-string EvidenceServer::Config::GetConfig(string Item, string Default) {
+// Request configuration data possible only when answer to previous request received
+string EvidenceServer::Config::RequestNB(string Item) {
+
+  This->Lock();
+  if (CurrentItem.empty()) {
+	CurrentItem = Item;
+	setData(((char *) Item.c_str()));
+  }
+  This->Unlock();
+}
+
+
+//////////////////////////
+// EvidenceServer Class //
+//////////////////////////
+
+// Initialise
+EvidenceServer *EvidenceServer::This = NULL;
+pthread_mutex_t EvidenceServer::Mutex;
+set<pthread_t> EvidenceServer::Threads;
+
+
+// Constructor
+EvidenceServer::EvidenceServer(string ServerName): Name(ServerName) {
+
+  // Initialize
+  MessageService = NULL;
+  MessageData = NULL;
+  ExitRequest = false;
+  This = this;
+  Threads.insert(pthread_self());
+
+  // Initialise mutex
+  int Ret;
+  pthread_mutexattr_t Attr;
+
+  if ((Ret = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
+    Message(FATAL, "pthread_mutex_settype() failed (%s)", strerror(Ret));
+  }
+  if ((Ret = pthread_mutex_init(&Mutex, &Attr)) != 0) {
+    Message(FATAL, "pthread_mutex_init() failed (%s)", strerror(Ret));
+  }
+
+  // Catch some signals
+  signal(SIGQUIT, &SignalHandler);  // CTRL-Backspace
+  signal(SIGTERM, &SignalHandler);  // Termination signal
+  signal(SIGINT, &SignalHandler);   // CTRL-C
+  signal(SIGHUP, &SignalHandler);   // Terminal closed
+  
+  // Catch C++ unhandled exceptions
+  set_terminate(Terminate);
+
+  // Message service and initial message
+  MessageService = new DimService((Name+"/Message").c_str(), (char *) "I:1;C", NULL, 0);
+
+  string Rev(EVIDENCE_REVISION); 
+  Message(INFO, "Server started (%s, compiled %s %s)", (Rev.substr(1, Rev.size()-3)).c_str(),__DATE__, __TIME__);
+
+  // Configuration class
+  ConfClass = new class Config();
+
+  // Start server
+  start(ServerName.c_str());
+  addExitHandler(this);
+}
+
+
+// Destructor: Free memory
+EvidenceServer::~EvidenceServer() {
+
+  Message(INFO, "Server stopped");
+
+  delete ConfClass;
+
+  int Ret;
+  if ((Ret = pthread_mutex_destroy(&Mutex)) != 0) {
+	Message(ERROR, "pthread_mutex_destroy() failed (%s)", strerror(Ret));
+  }
+  
+  delete MessageService;
+  delete[] MessageData;
+}
+
+
+// DIM exit handler
+void EvidenceServer::exitHandler(int Code) {
+
+  Message(INFO, "Exit handler called (DIM exit code %d)", Code);
+  exit(EXIT_SUCCESS);
+}
+
+// DIM error handler
+void EvidenceServer::errorHandler(int Severity, int Code, char *Text) {
+
+  Message(ERROR, "%s (DIM error code %d, DIM severity %d)\n", Text, Code, Severity);
+}
+
+
+// Set server message (if Severity is FATAL, exit() will be invoked)
+void EvidenceServer::Message(MessageType Severity, const char *Format, ...) {
+
+  static const char* StateString[] = {"Info", "Warn", "Error", "Fatal"};
+  static char ErrorString[] = "vasprintf() failed in Message()";
+  char *Text;
+  
+  // Assemble message from application
+  va_list ArgumentPointer;
+  va_start(ArgumentPointer, Format);
+  if (vasprintf(&Text, Format, ArgumentPointer) == -1) {
+	Text = ErrorString;
+	Severity = ERROR;
+  }
+  va_end(ArgumentPointer);
+
+  // Generate new Message structure and free text
+  struct Message *NewMsg = (struct Message *) new char [sizeof(struct Message)+strlen(Text)+1];
+  NewMsg->Severity = Severity;
+  strcpy(NewMsg->Text, Text);
+  if (Text != ErrorString) free(Text);
+  
+  // Send message to console and log file
+  printf("%s (%s): %s\n", MessageService->getName(), StateString[Severity], NewMsg->Text);
+  SendToLog("%s (%s): %s", MessageService->getName(), StateString[Severity], NewMsg->Text);
+
+  // Update DIM message service
+  if (MessageService != NULL) {
+	MessageService->updateService(NewMsg, sizeof(struct Message)+strlen(NewMsg->Text)+1);
+  }
+
+  // Delete old message
+  Lock();
+  delete[] MessageData;
+  MessageData = NewMsg;
+  Unlock();  
+
+  // Terminate if severity if FATAL  
+  if (Severity == FATAL) exit(EXIT_FAILURE);
+}
+
+
+// Send to central logging server with non-blocking command
+void EvidenceServer::SendToLog(const char *Format, ...) {
+
+  static char ErrorString[] = "vasprintf() failed in SendToLog()";
+  char *Buffer;
+  int Ret;
+
+  // Evaluate variable argument list
+  va_list ArgumentPointer;
+  va_start(ArgumentPointer, Format);
+  Ret = vasprintf(&Buffer, Format, ArgumentPointer);
+  va_end(ArgumentPointer);
+
+  // Send to logger
+  if (Ret != -1) {
+	DimClient::sendCommandNB("DColl/Log", Buffer);
+	free (Buffer);
+  }
+  else DimClient::sendCommandNB("DColl/Log", ErrorString);
+}
+
+
+// Get configuration data
+//
+// Program terminates if data is missing and no default given. Actual configuration
+// request will be made only if config file has modification since last request.
+// If called from infoHandler(), a non-blocking request will be made
+string EvidenceServer::GetConfig(string Item, string Default) {
 
   string Result;
-
+  bool Blocking = false;
+  
   // If up-to-date data in configuration list available, return this
-  This->Lock();
-  if ((List.count(Item) > 0) && (List[Item].Time >= ConfigTimeStamp)) Result = List[Item].Value;
-  This->Unlock();
+  Lock();
+  if ((List.count(Item) > 0) && (List[Item].Time >= ConfClass->ConfigTimeStamp)) Result = List[Item].Value;
+  if (Threads.count(pthread_self()) != 0) Blocking = true;
+  Unlock();
   if (!Result.empty()) return Result;
 
-  // Blocking configuration request if in main thread
-  if (pthread_self() == ThreadID) {
+  // Blocking configuration request
+  if (Blocking) {
 	DimRpcInfo Config((char *) "ConfigRequest", NO_LINK);
 	Config.setData((char *) (Name + " " + Item).c_str());
@@ -92,5 +272,5 @@
 	if (!EvidenceServer::ServiceOK(&Config)) {
       if (Default.empty()) {
-		This->Message(FATAL, "Configuration server unreachable, can't retrieve '%s'", Item.c_str());
+		Message(FATAL, "Configuration server unreachable, can't retrieve '%s'", Item.c_str());
 	  }
 	  else Result = Default;
@@ -103,26 +283,23 @@
 	// Update configuration map	
 	if (!Result.empty()) {
-	  This->Lock();
+	  Lock();
 	  List[Item].Value = Result;
-	  List[Item].Time = ConfigTimeStamp;
-	  This->Unlock();
+	  List[Item].Time = ConfClass->ConfigTimeStamp;
+	  Unlock();
 	}	
   }
 
-  // Non-blocking configuration request from other threads
-  if (pthread_self() != ThreadID) {
- 	This->Lock();
+  // Non-blocking configuration request
+  if (!Blocking) {
+ 	Lock();
 	if (List.count(Item) > 0) {
-	  // New request possible only when answer to previous request received
-	  if (CurrentItem.empty()) {
-		CurrentItem = Item;
-		setData(((char *) (Name + " " + Item).c_str()));
-	  }
-
-	  // Return current value
+	  ConfClass->RequestNB(Name + " " + Item);
 	  Result = List[Item].Value;
 	}
-	This->Unlock();
-  }
+	Unlock();
+  }
+
+  // Terminate if no configuration information found
+  if (Result.empty()) Message(FATAL, "Missing configuration data '%s'", Item.c_str());
 
   return Result;
@@ -130,197 +307,11 @@
 
 
-//////////////////////////
-// EvidenceServer Class //
-//////////////////////////
-
-// Initialise
-int EvidenceServer::ConfigSignal = 0;
-EvidenceServer *EvidenceServer::This = NULL;
-
-// Constructor
-EvidenceServer::EvidenceServer(string ServerName): Name(ServerName) {
-
-  // Initialize
-  MessageService = NULL;
-  MessageData = NULL;
-  ExitRequest = false;
-  This = this;
-
-  // Initialise mutex
-  int Ret;
-  pthread_mutexattr_t Attr;
-
-  if ((Ret = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
-    Message(FATAL, "pthread_mutex_settype() failed (%s)", strerror(Ret));
-  }
-  if ((Ret = pthread_mutex_init(&Mutex, &Attr)) != 0) {
-    Message(FATAL, "pthread_mutex_init() failed (%s)", strerror(Ret));
-  }
-
-  // Catch some signals
-  signal(SIGQUIT, &SignalHandler);  // CTRL-Backspace
-  signal(SIGTERM, &SignalHandler);  // Termination signal
-  signal(SIGINT, &SignalHandler);   // CTRL-C
-  signal(SIGHUP, &SignalHandler);   // Terminal closed
-  
-  // Catch C++ unhandled exceptions
-  set_terminate(Terminate);
-
-  // Configuration class (must be instantiate after signal handling installed)
-  ConfClass = new class Config(Name);
-
-  // Message service and initial message
-  MessageService = new DimService((Name+"/Message").c_str(), (char *) "I:1;C", NULL, 0);
-
-  string Rev(EVIDENCE_REVISION); 
-  Message(INFO, "Server started (%s, compiled %s %s)", (Rev.substr(1, Rev.size()-3)).c_str(),__DATE__, __TIME__);
-
-  // Start server
-  start(ServerName.c_str());
-  addExitHandler(this);
-}
-
-// Destructor: Free memory
-EvidenceServer::~EvidenceServer() {
-
-  Message(INFO, "Server stopped");
-
-  delete ConfClass;
-
-  int Ret;
-  if ((Ret = pthread_mutex_destroy(&Mutex)) != 0) {
-	Message(ERROR, "pthread_mutex_destroy() failed (%s)", strerror(Ret));
-  }
-  
-  delete MessageService;
-  delete[] MessageData;  
-}
-
-// DIM exit handler
-void EvidenceServer::exitHandler(int Code) {
-
-  if (Code == 0) Message(INFO, "Message cleared by %s (ID %d)", getClientName(), getClientId());
-  else {
-	Message(INFO, "Exit handler called (DIM exit code %d)", Code);
-	exit(EXIT_SUCCESS);
-  }
-}
-
-// DIM error handler
-void EvidenceServer::errorHandler(int Severity, int Code, char *Text) {
-
-  Message(ERROR, "%s (DIM error code %d, DIM severity %d)\n", Text, Code, Severity);
-}
-
-// Set server message (if Severity is FATAL, exit() will be invoked)
-void EvidenceServer::Message(MessageType Severity, const char *Format, ...) {
-
-  static const char* StateString[] = {"Info", "Warn", "Error", "Fatal"};
-  static char ErrorString[] = "vasprintf() failed in Message()";
-  char *Text;
-  
-  // Assemble message from application
-  va_list ArgumentPointer;
-  va_start(ArgumentPointer, Format);
-  if (vasprintf(&Text, Format, ArgumentPointer) == -1) {
-	Text = ErrorString;
-	Severity = ERROR;
-  }
-  va_end(ArgumentPointer);
-
-  // Generate new Message structure and free text
-  struct Message *NewMsg = (struct Message *) new char [sizeof(struct Message)+strlen(Text)+1];
-  NewMsg->Severity = Severity;
-  strcpy(NewMsg->Text, Text);
-  if (Text != ErrorString) free(Text);
-  
-  // Send message to console and log file
-  printf("%s (%s): %s\n", MessageService->getName(), StateString[Severity], NewMsg->Text);
-  SendToLog("%s (%s): %s", MessageService->getName(), StateString[Severity], NewMsg->Text);
-
-  // Update DIM message service
-  if (MessageService != NULL) {
-	MessageService->updateService(NewMsg, sizeof(struct Message)+strlen(NewMsg->Text)+1);
-  }
-
-  // Delete old message
-  Lock();
-  delete[] MessageData;
-  MessageData = NewMsg;
-  Unlock();  
-
-  // Terminate if severity if FATAL  
-  if (Severity == FATAL) exit(EXIT_FAILURE);
-}
-
-
-// Send to central logging server with non-blocking command
-void EvidenceServer::SendToLog(const char *Format, ...) {
-
-  static char ErrorString[] = "vasprintf() failed in SendToLog()";
-  char *Buffer;
-  int Ret;
-
-  // Evaluate variable argument list
-  va_list ArgumentPointer;
-  va_start(ArgumentPointer, Format);
-  Ret = vasprintf(&Buffer, Format, ArgumentPointer);
-  va_end(ArgumentPointer);
-
-  // Send to logger
-  if (Ret != -1) {
-	DimClient::sendCommandNB("DColl/Log", Buffer);
-	free (Buffer);
-  }
-  else DimClient::sendCommandNB("DColl/Log", ErrorString);
-}
-
-
-// Get configuration data
-//
-// Program terminates if data is missing and no default given. Actual configuration
-// request will be made only if config file has modification since last request.
-// If called from infoHandler(), a non-blocking request will be made
-string EvidenceServer::GetConfig(string Item, string Default) {
-
-  string Result = ConfClass->GetConfig(Item, Default);
-  if (Result.empty()) Message(FATAL, "Missing configuration data '%s'", Item.c_str());
-  return Result;
-}
-
-
-// Set signal emitted when configuraton file changes, signal handler calls ConfigChanged()
-void EvidenceServer::ActivateSignal(int Signal) {
-
-  struct sigaction S;
-
-  ConfigSignal = Signal;
-  S.sa_handler = &SignalHandler;
-  S.sa_flags = SA_RESTART;
-  sigaction(Signal, &S, NULL);
-}
-
-
 // Locking and unlocking functions.
-// Signal blocked before locking (pthread_mutex_lock() not asynch-signal safe).
 // Message() is not used to avoid infinite recursion
 void EvidenceServer::Lock() {
 
   int Ret;
-  sigset_t Set;
-
-  if (ConfigSignal != 0) {
-	Ret = abs(sigemptyset(&Set));
-	Ret += abs(sigaddset(&Set, ConfigSignal));
-	Ret += abs(pthread_sigmask(SIG_BLOCK, &Set, NULL));
-
-	if (Ret != 0) {
-	  printf("Signal masking failed in Lock()");
-	  SendToLog("Signal masking failed in Lock()");
-	  exit(EXIT_FAILURE);
-	}
-  }
-
-  if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
+
+  if ((Ret = pthread_mutex_lock(&EvidenceServer::Mutex)) != 0) {
 	printf("pthread_mutex_lock() failed in Lock() (%s)", strerror(Ret));
 	SendToLog("pthread_mutex_lock() failed in Lock() (%s)", strerror(Ret));
@@ -332,27 +323,30 @@
 
   int Ret;
-  sigset_t Set;
-
-  if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
+
+  if ((Ret = pthread_mutex_unlock(&EvidenceServer::Mutex)) != 0) {
 	printf("pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret));
 	SendToLog("pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret));
 	exit(EXIT_FAILURE);
-  }
-  
-  if (ConfigSignal != 0) {
-	Ret = abs(sigemptyset(&Set));
-	Ret += abs(sigaddset(&Set, ConfigSignal));
-	Ret += abs(pthread_sigmask(SIG_UNBLOCK, &Set, NULL));
-
-	if (Ret != 0) {
-	  printf("Signal unmasking failed in Unlock()");
-	  SendToLog("Signal unmasking failed in Unlock()");
-	  exit(EXIT_FAILURE);
-	}
-  }
+  }  
 }
 
 
 // ====== Static methods ======
+
+// Stub to call ConfigChanged() method of class as separate thread
+// Thread set is used to determine if blocking or non-blocking rpc is to be used
+void EvidenceServer::CallConfigChanged() {
+
+  EvidenceServer::Lock();
+  EvidenceServer::Threads.insert(pthread_self());
+  EvidenceServer::Unlock();
+
+  This->ConfigChanged();
+  
+  EvidenceServer::Lock();
+  EvidenceServer::Threads.erase(pthread_self());
+  EvidenceServer::Unlock();
+}
+
 
 // Signal handler (causes pause() and other syscalls to return)
@@ -360,10 +354,4 @@
 
   static bool Called = false;
-
-  // If signal indicates configuration change, invoke call-back
-  if (Signal == EvidenceServer::ConfigSignal) {
-    This->ConfigChanged();
-	return;
-  }
 
   // At first invocation just request exit
@@ -378,4 +366,5 @@
   exit(EXIT_FAILURE);
 }
+
 
 // C++ exception handler (derived from gcc __verbose_terminate_handler())
@@ -492,4 +481,10 @@
 }
 
+bool EvidenceServer::ServiceOK(DimCurrentInfo *Item) {
+
+  return !((Item->getSize() == strlen(NO_LINK)+1) &&  
+	  (memcmp(Item->getData(), NO_LINK, Item->getSize()) == 0));
+}
+
 
 // Tokenize std::string using given delimeter list
Index: /Evidence/Evidence.h
===================================================================
--- /Evidence/Evidence.h	(revision 261)
+++ /Evidence/Evidence.h	(revision 262)
@@ -10,4 +10,5 @@
 #include <vector>
 #include <map>
+#include <set>
 
 #include <exception>
@@ -20,31 +21,32 @@
 #define EVIDENCE_REVISION "$Revision$"
 
+void ConfigChanged();
+
 // Class declation of Evidence server
 class EvidenceServer: public DimServer {
 
 	// Internal class for configuration requests
-	class Config: public DimClient, public DimRpcInfo {
+	class Config: public DimInfo, public DimCommand, public DimRpcInfo {
 
-		std::string Name;
 		DimInfo *Service;
-		int ConfigTimeStamp;
 		std::string CurrentItem;
-		pthread_t ThreadID;
 
-		struct Item {
-		  std::string Value;
-		  int Time;
-		};
-		std::map<std::string, struct Item> List;
-
+		void commandHandler();
 		void infoHandler();
 		void rpcInfoHandler();
 
 	  public:
-		Config(std::string);
+		Config();
 		~Config();
 
-		std::string GetConfig(std::string, std::string);
+		int ConfigTimeStamp;
+		std::string RequestNB(std::string);
 	};
+
+	struct Item {
+	  std::string Value;
+	  int Time;
+	};
+	std::map<std::string, struct Item> List;
 
 	struct Message {
@@ -57,6 +59,6 @@
 	struct Message *MessageData;
 	class Config *ConfClass;
-	static int ConfigSignal;		// static since accessed in signal handler
-	pthread_mutex_t Mutex;
+	static pthread_mutex_t Mutex;
+	static std::set<pthread_t> Threads;
 	static EvidenceServer *This;
 
@@ -65,5 +67,5 @@
 	virtual void errorHandler(int, int, char *);
 	virtual void exitHandler(int);
-	virtual void ConfigChanged() {};
+    static void CallConfigChanged();	// static for phread_create()
 
   public:
@@ -74,12 +76,13 @@
 
 	void Message(MessageType, const char *, ...);
-	void SendToLog(const char *, ...);
+	static void SendToLog(const char *, ...);
 	std::string GetConfig(std::string, std::string = std::string());
-	void ActivateSignal(int);
-	void Lock();
-	void Unlock();
+	virtual void ConfigChanged() {};
+	static void Lock();
+	static void Unlock();
 	static std::string ToString(char *, void *, int);
 	static bool ServiceOK(DimInfo *);
 	static bool ServiceOK(DimRpcInfo *);
+	static bool ServiceOK(DimCurrentInfo *);
 	static std::vector<std::string> Tokenize(const std::string &, const std::string & = " ");
 
Index: /Evidence/readme.txt
===================================================================
--- /Evidence/readme.txt	(revision 261)
+++ /Evidence/readme.txt	(revision 262)
@@ -28,7 +28,5 @@
 23/6/2010	GetConfig() returns std::string. Non-blocking configuration request in case
 			GetConfig() not called from main thread. Access to configuration information
-			internally mutex protected. With ActivateSignal() a signal can be set that is send
-			to main thread upon configuration file change, the build-in signal handler then
-			invokes the (virtual) method ConfigChanged().
+			internally mutex protected.
 24/6/2010	Workaround for erroneous /SERVICE_LIST updates. Added static tokenize method to
 			Evidence class.
@@ -46,5 +44,6 @@
 21/7/2010	Lock()/Unlock() do not report errors via Message(), but print to console and use 
 			SendToLog(). That avoids a recursion problem since Message() also uses locking.
-			The general exitHandler() will react in a special way to code 0: it will reset
-			the message severity. This feature is used by Alarm if it receives a command to
-			reset an alarm level.
+26/7/2010	General command '/ResetMessage' will reset message text and severity. This feature is
+			used by Alarm if it receives a command to reset an alarm level.
+			ConfigChanged() is called as separate thread when configuration file changes. Thread ID
+			is checked in GetConfig() and also from this thread it will make blocking requests.
