[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