[Aptitude-svn-commit] r4128 - in branches/aptitude-0.3/aptitude: . src src/mine src/vscreen

Daniel Burrows dburrows at costa.debian.org
Tue Sep 20 06:20:44 UTC 2005


Author: dburrows
Date: Tue Sep 20 06:20:39 2005
New Revision: 4128

Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/src/broken_indicator.cc
   branches/aptitude-0.3/aptitude/src/mine/cmine.cc
   branches/aptitude-0.3/aptitude/src/mine/cmine.h
   branches/aptitude-0.3/aptitude/src/vscreen/vscreen.cc
   branches/aptitude-0.3/aptitude/src/vscreen/vscreen.h
Log:
Use events, not slots, to register timeouts; closes a nasty race condition.

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Tue Sep 20 06:20:39 2005
@@ -1,5 +1,18 @@
 2005-09-19  Daniel Burrows  <dburrows at debian.org>
 
+	* src/broken_indicator.cc, src/mine/cmine.cc, src/vscreen/vscreen.cc:
+
+	  It turns out that sigc++ isn't really threadsafe -- thanks to
+	  weak references and deletion callbacks, read access to a slot
+	  created in one thread can be interefered with (disastrously) by
+	  the deletion of an apparently unrelated object in another
+	  thread.  As it's virtually impossible to guarantee that this
+	  doesn't occur, I have decided to just avoid touching slots
+	  anywhere but the main thread.  The easiest way to make this
+	  explicit is to require a vscreen_event to be passed to the
+	  timeout thread (although a heap structure containing a slot
+	  could also be safe).
+
 	* src/solutions_screen.cc:
 
 	  Make pressing Enter (or whatever is bound to InfoScreen) on an

Modified: branches/aptitude-0.3/aptitude/src/broken_indicator.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/broken_indicator.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/broken_indicator.cc	Tue Sep 20 06:20:39 2005
@@ -77,6 +77,24 @@
     update();
   }
 
+  class tick_timeout_event;
+  friend class tick_timeout_event;
+
+  class tick_timeout_event : public vscreen_event
+  {
+    ref_ptr<broken_indicator> b;
+  public:
+    tick_timeout_event(broken_indicator *_b)
+      : b(_b)
+    {
+    }
+
+    void dispatch()
+    {
+      b->tick_timeout();
+    }
+  };
+
 protected:
   broken_indicator()
     :spin_count(0)
@@ -91,10 +109,11 @@
 
     update();
 
-    vscreen_addtimeout(sigc::mem_fun(this, &broken_indicator::tick_timeout),
+    vscreen_addtimeout(new tick_timeout_event(this),
 		       aptcfg->FindI(PACKAGE "::Spin-Interval", 500));
   }
 
+private:
   static fragment *key_hint_fragment()
   {
     wstring next=global_bindings.readable_keyname("NextSolution");
@@ -125,7 +144,7 @@
 	vscreen_update();
       }
 
-    vscreen_addtimeout(sigc::mem_fun(this, &broken_indicator::tick_timeout),
+    vscreen_addtimeout(new tick_timeout_event(this),
 		       aptcfg->FindI(PACKAGE "::Spin-Interval", 500));
   }
 

Modified: branches/aptitude-0.3/aptitude/src/mine/cmine.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/mine/cmine.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/mine/cmine.cc	Tue Sep 20 06:20:39 2005
@@ -70,9 +70,25 @@
     return 1;
 }
 
+class cmine::update_header_event : public vscreen_event
+{
+  ref_ptr<cmine> cm;
+
+public:
+  update_header_event(cmine *_cm)
+    : cm(_cm)
+  {
+  }
+
+  void dispatch()
+  {
+    cm->update_header();
+  }
+};
+
 void cmine::update_header()
 {
-  timeout_num=vscreen_addtimeout(sigc::mem_fun(*this, &cmine::update_header), 500);
+  timeout_num = vscreen_addtimeout(new update_header_event(this), 500);
 
   vscreen_update();
 };
@@ -413,7 +429,7 @@
 cmine::cmine():board(NULL), prevwidth(0), prevheight(0)
 {
   set_board(easy_game());
-  vscreen_addtimeout(sigc::mem_fun(*this, &cmine::update_header), 500);
+  vscreen_addtimeout(new update_header_event(this), 500);
   //set_status(_("n - New Game  Cursor keys - move cursor  f - flag  enter - check  ? - help"));
 }
 

Modified: branches/aptitude-0.3/aptitude/src/mine/cmine.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/mine/cmine.h	(original)
+++ branches/aptitude-0.3/aptitude/src/mine/cmine.h	Tue Sep 20 06:20:39 2005
@@ -52,6 +52,9 @@
   void checkend();
   // Checks whether the game is over, prints cute message if so.
 
+  class update_header_event;
+  friend class update_header_event;
+
   void update_header();
   // Updates the displayed header information (time, etc)
 

Modified: branches/aptitude-0.3/aptitude/src/vscreen/vscreen.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/vscreen/vscreen.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/vscreen/vscreen.cc	Tue Sep 20 06:20:39 2005
@@ -374,31 +374,15 @@
     }
   };
 
-  class timeout_event : public vscreen_event
-  {
-    sigc::slot0<void> slot;
-
-  public:
-    timeout_event(const sigc::slot0<void> &_slot)
-      :slot(_slot)
-    {
-    }
-
-    void dispatch()
-    {
-      slot();
-    }
-  };
-
 
   /** Information about a single time-out. */
   struct timeout_info
   {
-    sigc::slot0<void> f;
+    vscreen_event *ev;
     timeval activate_time; // tells when this timeout should be triggered
-    timeout_info(const sigc::slot0<void> &_f,
+    timeout_info(vscreen_event *_ev,
 		 const timeval &_activate_time)
-      :f(_f), activate_time(_activate_time)
+      :ev(_ev), activate_time(_activate_time)
     {
     }
 
@@ -444,7 +428,7 @@
 	if(timeval_subtract(&result, &i->second.activate_time, &curtime) == 1 ||
 	   result.tv_sec == 0 && result.tv_usec <= 10)
 	  {
-	    vscreen_post_event(new timeout_event(i->second.f));
+	    vscreen_post_event(i->second.ev);
 	    timeouts.erase(i);
 	  }
       }
@@ -595,7 +579,7 @@
    *  \return the ID number of the new timeout; can be used later to
    *          remove the timeout before it triggers.
    */
-  int add_timeout(const sigc::slot0<void> &slot, int msecs)
+  int add_timeout(vscreen_event *ev, int msecs)
   {
     threads::mutex::lock l(timeouts_mutex);
 
@@ -619,7 +603,7 @@
     else
       rval = timeouts.rbegin()->first + 1;
 
-    timeouts[rval] = timeout_info(slot, activate_time);
+    timeouts[rval] = timeout_info(ev, activate_time);
 
     timeout_added.wake_all();
 
@@ -1057,12 +1041,12 @@
   pending_updates = update_state();
 }
 
-int vscreen_addtimeout(const sigc::slot0<void> &slot, int msecs)
+int vscreen_addtimeout(vscreen_event *ev, int msecs)
 {
   if(msecs < 0)
     return -1;
 
-  return timeout_thread::get_instance().add_timeout(slot, msecs);
+  return timeout_thread::get_instance().add_timeout(ev, msecs);
 }
 
 void vscreen_deltimeout(int num)

Modified: branches/aptitude-0.3/aptitude/src/vscreen/vscreen.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/vscreen/vscreen.h	(original)
+++ branches/aptitude-0.3/aptitude/src/vscreen/vscreen.h	Tue Sep 20 06:20:39 2005
@@ -130,9 +130,15 @@
  */
 void vscreen_resume();
 
-int vscreen_addtimeout(const sigc::slot0<void> &slot, int msecs);
-// Adds a timer which will expire in the given number of milliseconds; when it
-// does, to is called.  Returns the timeout's ID, used to delete it.
+/** Invoke the given vscreen_event in at least msencs from the current
+ *  time.
+ *
+ *  \return a numerical identifier of the new event; you can use this
+ *          number to delete it.
+ */
+int vscreen_addtimeout(vscreen_event *ev, int msecs);
+
+/** Delete the event with the given identifier. */
 void vscreen_deltimeout(int id);
 
 void vscreen_handleresize();



More information about the Aptitude-svn-commit mailing list