From ac1c784d4584db16b39da1f9c87e6b665632b1a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergi=20Hern=C3=A0ndez=20Juan?= <shernand@iri.upc.edu>
Date: Tue, 8 Nov 2011 14:57:53 +0000
Subject: [PATCH] Solved a bug where two ore more threads were awaken by the
 same event activation. Now a new activation is necessary to wake each of the
 waiting threads.

---
 src/events/eventserver.cpp        | 108 ++++++++++++++++--------------
 src/examples/test_bothservers.cpp |  56 +++++++++-------
 2 files changed, 92 insertions(+), 72 deletions(-)

diff --git a/src/events/eventserver.cpp b/src/events/eventserver.cpp
index 9559b9a..941a8c6 100644
--- a/src/events/eventserver.cpp
+++ b/src/events/eventserver.cpp
@@ -198,6 +198,7 @@ int CEventServer::wait_first(std::list<std::string> events,int timeout)
   int error,max_fd=0,pos=-1;
   fd_set wait_set;
   CTime time_out;
+  bool end=false;
   timeval time;
 
   if(timeout>0)
@@ -206,48 +207,12 @@ int CEventServer::wait_first(std::list<std::string> events,int timeout)
     time=time_out.getTimeInTimeval();
   }
   this->access_events.enter();
-  FD_ZERO(&wait_set);
-  for(it=events.begin();it!=events.end();it++)
-  {
-    if ((event=this->search_event(*it)) == (std::list<CEvent>::iterator)NULL)
-    {
-      this->access_events.exit();
-      /* handle exceptions */
-      throw CEventServerException(_HERE_,"Unknown event",*it);
-    }
-    else
-    {
-      FD_SET(event->get_fd(),&wait_set);
-      if(event->get_fd()>max_fd)
-        max_fd=event->get_fd();
-      if(it!=events.begin())
-        event_list+=",";
-      event_list+=*it;
-    }
-  }
-  
-  this->access_events.exit();
-  if(timeout>0)
-    error=select(max_fd+1,&wait_set,NULL,NULL,&time);
-  else
-    error=select(max_fd+1,&wait_set,NULL,NULL,NULL);
-  if(error==-1)
-  {
-    /* handle exceptions */
-    throw CEventServerException(_HERE_,"Unexpected error while waiting the activation of one the events",event_list);
-  }
-  else if(error==0)
-  {
-    /* handle exceptions */
-    throw CEventTimeoutException(event_list);
-  }
-  else
+  while(!end)
   {
-    this->access_events.enter();
+    FD_ZERO(&wait_set);
     for(it=events.begin();it!=events.end();it++)
     {
-      pos++;
-      if((event=this->search_event(*it))==(std::list<CEvent>::iterator)NULL)
+      if ((event=this->search_event(*it)) == (std::list<CEvent>::iterator)NULL)
       {
         this->access_events.exit();
         /* handle exceptions */
@@ -255,11 +220,53 @@ int CEventServer::wait_first(std::list<std::string> events,int timeout)
       }
       else
       {
-        if(FD_ISSET(event->get_fd(),&wait_set))
+        FD_SET(event->get_fd(),&wait_set);
+        if(event->get_fd()>max_fd)
+          max_fd=event->get_fd();
+        if(it!=events.begin())
+          event_list+=",";
+        event_list+=*it;
+      }
+    }
+  
+    this->access_events.exit();
+    if(timeout>0)
+      error=select(max_fd+1,&wait_set,NULL,NULL,&time);
+    else
+      error=select(max_fd+1,&wait_set,NULL,NULL,NULL);
+    if(error==-1)
+    {
+      /* handle exceptions */
+      throw CEventServerException(_HERE_,"Unexpected error while waiting the activation of one the events",event_list);
+    }
+    else if(error==0)
+    {
+      /* handle exceptions */
+      throw CEventTimeoutException(event_list);
+    }
+    else
+    {
+      this->access_events.enter();
+      for(it=events.begin();it!=events.end();it++)
+      {
+        pos++;
+        if((event=this->search_event(*it))==(std::list<CEvent>::iterator)NULL)
         {
-          event->reset();
           this->access_events.exit();
-          return pos;
+          /* handle exceptions */
+          throw CEventServerException(_HERE_,"Unknown event",*it);
+        }
+        else
+        {
+          if(FD_ISSET(event->get_fd(),&wait_set))
+          {
+            if(event->is_set())
+            {
+              event->reset();
+              this->access_events.exit();
+              return pos;
+            }
+          }
         }
       }
     }
@@ -338,14 +345,17 @@ void CEventServer::wait_all(std::list<std::string> events,int timeout)
         {
           if(FD_ISSET(event->get_fd(),&wait_set))
 	  {
-	    event->reset();
-	    it=events.erase(it);
-	    if(events.size()==0)
-	      end=true;
-            else
+            if(event->is_set())
             {
-              if(timeout>0)
-                time=time_out.getTimeInTimeval();
+              event->reset();
+              it=events.erase(it);
+              if(events.size()==0)
+                end=true;
+              else
+              {
+                if(timeout>0)
+                  time=time_out.getTimeInTimeval();
+              }
             }
       	  }
         }
diff --git a/src/examples/test_bothservers.cpp b/src/examples/test_bothservers.cpp
index a144cae..8d62130 100644
--- a/src/examples/test_bothservers.cpp
+++ b/src/examples/test_bothservers.cpp
@@ -62,18 +62,18 @@ void *thread1_function(void *param)
   event_list1.push_back(event1_id);
   std::cout << "Thread1 - Waiting for event " << event1_id << std::endl;
   thread_log.log((const std::string)"Thread1 - Waiting for event" + event1_id);
-  event_server->wait_all(event_list1);
+  event_server->wait_first(event_list1);
   std::cout << "Thread1 - Event " << event1_id << " received" << std::endl;
-  thread_log.log((const std::string)"Thread1 - Event " + event1_id + " received");
-  std::cout << "Thread1 - Sending event " << event2_id << std::endl;
-  thread_log.log((const std::string)"Thread1 - Sending event" + event2_id);
-  event_server->set_event(event2_id);
-  sleep(2);
-  std::cout << "Thread1 - Sending event " << event3_id << std::endl;
-  thread_log.log((const std::string)"Thread1 - Sending event" + event3_id);
-  event_server->set_event(event3_id);
-  std::cout << "Thread1 - Ending" << std::endl;
-  thread_log.log((const std::string)"Thread1 - Ending");
+//  thread_log.log((const std::string)"Thread1 - Event " + event1_id + " received");
+//  std::cout << "Thread1 - Sending event " << event2_id << std::endl;
+//  thread_log.log((const std::string)"Thread1 - Sending event" + event2_id);
+//  event_server->set_event(event2_id);
+//  sleep(2);
+//  std::cout << "Thread1 - Sending event " << event3_id << std::endl;
+//  thread_log.log((const std::string)"Thread1 - Sending event" + event3_id);
+//  event_server->set_event(event3_id);
+//  std::cout << "Thread1 - Ending" << std::endl;
+//  thread_log.log((const std::string)"Thread1 - Ending");
 
   pthread_exit(NULL);
 }
@@ -92,18 +92,23 @@ void *thread2_function(void *param)
   CEventServer *event_server=CEventServer::instance();
   CLog thread_log("thread2");
 
-  event_list2.push_back(event2_id);
-  event_list2.push_back(event3_id);
-  std::cout << "Thread2 - Sending event " << event1_id << std::endl;
-  thread_log.log((const std::string)"Thread2 - Sending event " + event1_id);
-  event_server->set_event(event1_id);
-  std::cout << "Thread2 - Waiting for event " << event2_id << std::endl;
-  thread_log.log((const std::string)"Thread2 - Waiting for event " + event2_id);
-  event_server->wait_all(event_list2);
-  std::cout << "Thread2 - Event " << event2_id << " and " << event3_id << " received" << std::endl;
-  thread_log.log((const std::string)"Thread2 - Event " + event2_id + " and " + event3_id + " received");
-  std::cout << "Thread2 - Ending" << std::endl;
-  thread_log.log((const std::string)"Thread2 - Ending");
+  event_list2.push_back(event1_id);
+  std::cout << "Thread2 - Waiting for event " << event1_id << std::endl;
+  thread_log.log((const std::string)"Thread2 - Waiting for event" + event1_id);
+  event_server->wait_first(event_list2);
+  std::cout << "Thread2 - Event " << event1_id << " received" << std::endl;
+//  event_list2.push_back(event2_id);
+//  event_list2.push_back(event3_id);
+//  std::cout << "Thread2 - Sending event " << event1_id << std::endl;
+//  thread_log.log((const std::string)"Thread2 - Sending event " + event1_id);
+//  event_server->set_event(event1_id);
+//  std::cout << "Thread2 - Waiting for event " << event2_id << std::endl;
+//  thread_log.log((const std::string)"Thread2 - Waiting for event " + event2_id);
+//  event_server->wait_all(event_list2);
+//  std::cout << "Thread2 - Event " << event2_id << " and " << event3_id << " received" << std::endl;
+//  thread_log.log((const std::string)"Thread2 - Event " + event2_id + " and " + event3_id + " received");
+//  std::cout << "Thread2 - Ending" << std::endl;
+//  thread_log.log((const std::string)"Thread2 - Ending");
 
   pthread_exit(NULL);
 }
@@ -163,6 +168,11 @@ int main(int argc,char *argv[])
   sleep(3);
   main_log.log((const std::string)"Starting thread 2 ...");
   thread_server->start_thread(thread2_id);
+  sleep(3);
+  event_server->set_event(event1_id);
+  sleep(2);
+  event_server->set_event(event1_id);
+  sleep(2);
   thread_server->end_thread(thread2_id);
   thread_server->end_thread(thread1_id);
   std::cout << "End of the program" << std::endl;
-- 
GitLab