Index: Evidence/Evidence.cc
===================================================================
--- Evidence/Evidence.cc	(revision 255)
+++ 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
