Index: Evidence/Alarm.cc
===================================================================
--- Evidence/Alarm.cc	(revision 253)
+++ Evidence/Alarm.cc	(revision 255)
@@ -124,7 +124,10 @@
   // Identify status service
   for (int i=0; i<List.size(); i++) if (getInfo() == List[i].Subscription) {
-	// Update level: unavailable or current severity of status  
+	// Update level: unavailable or current severity of status (safely extracted)  
 	if (!ServiceOK(getInfo())) List[i].Level = 4;
-	else if (getInfo()->getInt() > List[i].Level) List[i].Level = getInfo()->getInt();
+	else {
+	  int Severity = atoi(ToString(getInfo()->getFormat(), getInfo()->getData(), getInfo()->getSize()).c_str());
+	  if (Severity > List[i].Level) List[i].Level = Severity;
+	}
   }
 
@@ -140,9 +143,10 @@
   if (getCommand() != Command || Server.empty()) return;
  
-  // Reset alarm level and publish/log action
+  // Reset alarm level, publish/log action and reset server message severity
   for (int i=0; i<List.size(); i++) if (List[i].Server == Server) {
     Message(INFO, "Alarm level of server %s reset by %s (ID %d)", Server.c_str(), getClientName(), getClientId());
 	List[i].Level = 0;
 	List[i].WarnedLevel = 0;
+	if (Server != "DIS_DNS") sendCommandNB((Server+"/EXIT").c_str(), (int) 0);
   }
   
@@ -155,5 +159,5 @@
 
   ostringstream Buf;
-  int Alarm, Ret;  
+  int Alarm = 0, Ret;  
 
   Lock();
@@ -223,5 +227,5 @@
       }
 	  if (!Exist) Alarm.List[i].Level = 4;
-	  else if (Alarm.List[i].Level = -1) Alarm.List[i].Level = 0;
+	  else if (Alarm.List[i].Level == -1) Alarm.List[i].Level = 0;
     }
     
Index: Evidence/Doc/Evidence.tex
===================================================================
--- Evidence/Doc/Evidence.tex	(revision 253)
+++ Evidence/Doc/Evidence.tex	(revision 255)
@@ -39,5 +39,5 @@
 \maketitle
 
-This report describes the design and basic functionality of the \E control system. This essentially is a C++ class and a set of programs running on Linux for controlling small scale experiments. It is based on CERN's DIM library for interprocess communication over TCP/IP connections.
+This report describes the design and basic functionality of the \E control system. This essentially is a C++ class and a set of programs running on Linux for controlling small scale experiments. It is based on CERN's DIM library for interprocess communication over TCP/IP connections. \lstinline{$Rev$}
 
 \tableofcontents
@@ -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()} and \lstinline{errorHandler()}. The exit handler can be called through a standard DIM command and will, upon first invocation, just set the flag \lstinline{ExitRequest} which then should be handled by the application. Upon second invocation, it will call \lstinline{exit()}. The error handler will issue a message with ERROR severity.The user application can override these handlers.
+\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{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.
 \item Catches un-handled C++ exceptions and extracts as much information from the exception as possible.\footnote{This termination handler is taken directly from the code of the \lstinline{g++} compiler and is thus compiler specific.} That information is also published as a message.
@@ -140,5 +141,5 @@
 \label{EvidenceServer-Methods}
 
-The \lstinline{public} part of the header file \lstinline{Evidence.h} is as follows. The namespace designation \lstinline{std} has been left out for clarity in this listing. 
+The \lstinline{public} part of the header file \lstinline{Evidence.h} is as follows. The namespace designation \lstinline{std} has been left out for clarity in this listing.
 
 \begin{lstlisting}[numbers=left,numberstyle=\tiny,stepnumber=2,numbersep=5pt]
@@ -180,5 +181,5 @@
 \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.} 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. 
+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 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.
Index: Evidence/Evidence.cc
===================================================================
--- Evidence/Evidence.cc	(revision 253)
+++ Evidence/Evidence.cc	(revision 255)
@@ -122,6 +122,6 @@
 	  // Return current value
 	  Result = List[Item].Value;
-	  This->Unlock();
 	}
+	This->Unlock();
   }
 
@@ -200,6 +200,9 @@
 void EvidenceServer::exitHandler(int Code) {
 
-  Message(INFO, "Exit handler called (DIM exit code %d)", Code);
-  exit(EXIT_SUCCESS);
+  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);
+  }
 }
 
@@ -241,20 +244,19 @@
   }
 
-  // Terminate if severity if FATAL  
-  if (Severity == FATAL) exit(EXIT_FAILURE);
-
   // Delete old message
-  // Note that Lock()/Unlock() might fail with a FATAL message. To avoid an infinite loop,
-  // check for FATAL severity is done before here.
   Lock();
   delete[] MessageData;
   MessageData = NewMsg;
   Unlock();  
-}
-
-
-// Set to central logging server with non-blocking command (may be used in DIM handler)
+
+  // 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;
@@ -271,5 +273,5 @@
 	free (Buffer);
   }
-  else Message(ERROR, "Could not create logging text in SendToLog(), vasprintf() failed");
+  else DimClient::sendCommandNB("DColl/Log", ErrorString);
 }
 
@@ -300,6 +302,7 @@
 
 
-// Locking and unlocking for list access
-// Signal blocked before locking to avoid dead-lock by calling GetConfig() from ConfigChanged().
+// 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() {
 
@@ -312,9 +315,15 @@
 	Ret += abs(pthread_sigmask(SIG_BLOCK, &Set, NULL));
 
-	if (Ret != 0) Message(FATAL, "Signal masking failed in Lock()");
+	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) {
-	Message(FATAL, "pthread_mutex_lock() failed in Lock() (%s)", strerror(Ret));
+	printf("pthread_mutex_lock() failed in Lock() (%s)", strerror(Ret));
+	SendToLog("pthread_mutex_lock() failed in Lock() (%s)", strerror(Ret));
+	exit(EXIT_FAILURE);
   }
 }
@@ -326,5 +335,7 @@
 
   if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
-	Message(FATAL, "pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret));
+	printf("pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret));
+	SendToLog("pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret));
+	exit(EXIT_FAILURE);
   }
   
@@ -334,5 +345,9 @@
 	Ret += abs(pthread_sigmask(SIG_UNBLOCK, &Set, NULL));
 
-	if (Ret != 0) Message(FATAL, "Signal unmasking failed in Unlock()");
+	if (Ret != 0) {
+	  printf("Signal unmasking failed in Unlock()");
+	  SendToLog("Signal unmasking failed in Unlock()");
+	  exit(EXIT_FAILURE);
+	}
   }
 }
Index: Evidence/readme.txt
===================================================================
--- Evidence/readme.txt	(revision 253)
+++ Evidence/readme.txt	(revision 255)
@@ -1,3 +1,2 @@
-Short description of Evidence control system
 
 This directory contains the backbone of the control system. See directory Doc for documentation.
@@ -44,3 +43,8 @@
 			second-last message will not be freed correctly if severity is FATAL). Added
 			History server configuration parameters to adjust buffer size.
-
+20/7/2010	SendToLog() does not call Message() in case of error, but writes error message to log.
+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.
