Merge lp:~nick-dedekind/unity/lp1044823.glib.Source into lp:unity

Proposed by Nick Dedekind
Status: Merged
Approved by: Nick Dedekind
Approved revision: no longer in the source branch.
Merged at revision: 2657
Proposed branch: lp:~nick-dedekind/unity/lp1044823.glib.Source
Merge into: lp:unity
Diff against target: 228 lines (+53/-27)
3 files modified
UnityCore/GLibSource.cpp (+12/-15)
UnityCore/GLibSource.h (+10/-9)
tests/test_glib_source.cpp (+31/-3)
To merge this branch: bzr merge lp:~nick-dedekind/unity/lp1044823.glib.Source
Reviewer Review Type Date Requested Status
Marco Trevisan (Treviño) Approve
Michal Hruby (community) Approve
Review via email: mp+122597@code.launchpad.net

Commit message

Fixed ability to delete glib::Source wrapper during its callback.

Description of the change

Fixed ability to delete glib::Source wrapper during its callback.
Updated gtests to better test deletion during callback.

To post a comment you must log in.
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Callback pointer moved into callback data to ensure lambda function "context" is valid if Source is deleted during the callback.

Revision history for this message
Michal Hruby (mhr3) wrote :

83 + Callback callback_fn_;
93 - Callback callback_;

I think these two changes are everything that's needed to make it work, unless I'm missing something the two new bools aren't really necessary.

98 === modified file 'dash/previews/PreviewContainer.cpp'

Guess this shouldn't be part of this MP?

review: Needs Fixing
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

I believe we should keep the bools so that if you call Source::Remove (directly, or on destruction) during the callback, then the Remove will not destroy the GSource immediately, and will cause the callback to return false to destroy when it's complete.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Removed crossed-over MP files.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Removed management of gsource destruction during callback (let glib handle it).

Revision history for this message
Michal Hruby (mhr3) wrote :

Looks good to me now. +1

review: Approve
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Looking good, let's see if we can have more Callback const& bits around ;)

review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/1183/console reported an error when processing this lp:~nick-dedekind/unity/lp1044823.glib.Source branch.
Not merging it.

Revision history for this message
Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/1204/console reported an error when processing this lp:~nick-dedekind/unity/lp1044823.glib.Source branch.
Not merging it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UnityCore/GLibSource.cpp'
2--- UnityCore/GLibSource.cpp 2012-07-18 14:24:49 +0000
3+++ UnityCore/GLibSource.cpp 2012-09-05 08:40:28 +0000
4@@ -69,13 +69,12 @@
5 return static_cast<Priority>(prio);
6 }
7
8-bool Source::Run(Callback callback)
9+bool Source::Run(Callback const& callback)
10 {
11 if (!source_ || source_id_ || IsRunning())
12 return false;
13
14- callback_ = callback;
15- callback_data_ = new CallBackData(this);
16+ callback_data_ = new CallBackData(this, callback);
17
18 g_source_set_callback(source_, SourceCallback, callback_data_, DestroyCallback);
19 source_id_ = g_source_attach(source_, nullptr);
20@@ -101,16 +100,14 @@
21 if (!data)
22 return G_SOURCE_REMOVE;
23
24- auto self = static_cast<CallBackData*>(data)->self;
25+ auto cb_data = static_cast<CallBackData*>(data);
26
27- if (self && self->callback_ && self->callback_())
28+ if (cb_data && cb_data->callback_fn_ && cb_data->callback_fn_())
29 {
30 return G_SOURCE_CONTINUE;
31 }
32- else
33- {
34- return G_SOURCE_REMOVE;
35- }
36+
37+ return G_SOURCE_REMOVE;
38 }
39
40 void Source::DestroyCallback(gpointer data)
41@@ -133,7 +130,7 @@
42 }
43
44
45-Timeout::Timeout(unsigned int milliseconds, Callback cb, Priority prio)
46+Timeout::Timeout(unsigned int milliseconds, Callback const& cb, Priority prio)
47 {
48 Init(milliseconds, prio);
49 Run(cb);
50@@ -151,7 +148,7 @@
51 }
52
53
54-TimeoutSeconds::TimeoutSeconds(unsigned int seconds, Callback cb, Priority prio)
55+TimeoutSeconds::TimeoutSeconds(unsigned int seconds, Callback const& cb, Priority prio)
56 {
57 Init(seconds, prio);
58 Run(cb);
59@@ -169,7 +166,7 @@
60 }
61
62
63-Idle::Idle(Callback cb, Priority prio)
64+Idle::Idle(Callback const& cb, Priority prio)
65 {
66 Init(prio);
67 Run(cb);
68@@ -255,7 +252,7 @@
69 return nullptr;
70 }
71
72-Source::Ptr SourceManager::AddTimeout(unsigned int milliseconds, Source::Callback cb, std::string const& nick)
73+Source::Ptr SourceManager::AddTimeout(unsigned int milliseconds, Source::Callback const& cb, std::string const& nick)
74 {
75 auto timeout = std::make_shared<Timeout>(milliseconds);
76
77@@ -280,7 +277,7 @@
78 return nullptr;
79 }
80
81-Source::Ptr SourceManager::AddTimeoutSeconds(unsigned int seconds, Source::Callback cb, std::string const& nick)
82+Source::Ptr SourceManager::AddTimeoutSeconds(unsigned int seconds, Source::Callback const& cb, std::string const& nick)
83 {
84 auto timeout = std::make_shared<TimeoutSeconds>(seconds);
85
86@@ -305,7 +302,7 @@
87 return nullptr;
88 }
89
90-Source::Ptr SourceManager::AddIdle(Source::Callback cb, std::string const& nick)
91+Source::Ptr SourceManager::AddIdle(Source::Callback const& cb, std::string const& nick)
92 {
93 auto idle = std::make_shared<Idle>();
94
95
96=== modified file 'UnityCore/GLibSource.h'
97--- UnityCore/GLibSource.h 2012-07-16 11:03:32 +0000
98+++ UnityCore/GLibSource.h 2012-09-05 08:40:28 +0000
99@@ -77,7 +77,7 @@
100 * This Run a source using the @callback function as Source's callback.
101 * The method will return false if the source is already running, true otherwise.
102 */
103- bool Run(Callback callback);
104+ bool Run(Callback const& callback);
105 bool IsRunning() const;
106
107 /**
108@@ -104,11 +104,13 @@
109 private:
110 struct CallBackData
111 {
112- CallBackData(Source* src)
113+ CallBackData(Source* src, Callback const& callback)
114 : self(src)
115+ , callback_fn_(callback)
116 {}
117
118 Source* self;
119+ Callback callback_fn_;
120 };
121
122 static gboolean SourceCallback(gpointer data);
123@@ -116,7 +118,6 @@
124
125 unsigned int source_id_;
126 CallBackData* callback_data_;
127- Callback callback_;
128 };
129
130
131@@ -133,7 +134,7 @@
132 {
133 public:
134 Timeout(unsigned int milliseconds, Priority prio = Priority::DEFAULT);
135- Timeout(unsigned int milliseconds, Callback cb, Priority prio = Priority::DEFAULT);
136+ Timeout(unsigned int milliseconds, Callback const& cb, Priority prio = Priority::DEFAULT);
137
138 private:
139 void Init(unsigned int milliseconds, Priority prio);
140@@ -153,7 +154,7 @@
141 {
142 public:
143 TimeoutSeconds(unsigned int seconds, Priority prio = Priority::DEFAULT);
144- TimeoutSeconds(unsigned int seconds, Callback cb, Priority prio = Priority::DEFAULT);
145+ TimeoutSeconds(unsigned int seconds, Callback const& cb, Priority prio = Priority::DEFAULT);
146
147 private:
148 void Init(unsigned int seconds, Priority prio);
149@@ -173,7 +174,7 @@
150 {
151 public:
152 Idle(Priority prio = Priority::DEFAULT_IDLE);
153- Idle(Callback cb, Priority prio = Priority::DEFAULT_IDLE);
154+ Idle(Callback const& cb, Priority prio = Priority::DEFAULT_IDLE);
155
156 private:
157 void Init(Priority prio);
158@@ -206,13 +207,13 @@
159 bool Add(Source::Ptr const& source, std::string const& nick = "");
160
161 Source::Ptr AddTimeout(unsigned int milliseconds, std::string const& nick = "");
162- Source::Ptr AddTimeout(unsigned int milliseconds, Source::Callback cb, std::string const& nick = "");
163+ Source::Ptr AddTimeout(unsigned int milliseconds, Source::Callback const& cb, std::string const& nick = "");
164
165 Source::Ptr AddTimeoutSeconds(unsigned int seconds, std::string const& nick = "");
166- Source::Ptr AddTimeoutSeconds(unsigned int seconds, Source::Callback cb, std::string const& nick = "");
167+ Source::Ptr AddTimeoutSeconds(unsigned int seconds, Source::Callback const& cb, std::string const& nick = "");
168
169 Source::Ptr AddIdle(std::string const& nick = "");
170- Source::Ptr AddIdle(Source::Callback cb, std::string const& nick = "");
171+ Source::Ptr AddIdle(Source::Callback const& cb, std::string const& nick = "");
172
173 bool Remove(std::string const& nick);
174 bool Remove(unsigned int id);
175
176=== modified file 'tests/test_glib_source.cpp'
177--- tests/test_glib_source.cpp 2012-07-09 11:21:08 +0000
178+++ tests/test_glib_source.cpp 2012-09-05 08:40:28 +0000
179@@ -247,11 +247,14 @@
180 unsigned int local_callback_call_count = 0;
181
182 Source::UniquePtr timeout(new Timeout(10, [&] {
183+ unsigned int id = timeout->Id();
184 local_callback_called = true;
185- ++local_callback_call_count;
186+ local_callback_call_count++;
187+
188 timeout.reset();
189-
190- // this function would be called more than once if we had not removed the source.
191+ // resetting the ptr should destroy the source.
192+ EXPECT_TRUE(g_main_context_find_source_by_id(NULL, id) == nullptr);
193+ // this function would be called more than once (local_callback_call_count > 1) if we had not removed the source.
194 return true;
195 }));
196
197@@ -262,6 +265,31 @@
198 EXPECT_EQ(local_callback_call_count, 1);
199 }
200
201+TEST(TestGLibTimeout, AutoRemoveSourceOnCallback)
202+{
203+ bool local_callback_called = false;
204+ unsigned int local_callback_call_count = 0;
205+
206+ Source::UniquePtr timeout(new Timeout(10, [&] {
207+ local_callback_called = true;
208+ ++local_callback_call_count;
209+
210+ // return false to remove source.
211+ return false;
212+ }));
213+ unsigned int id = timeout->Id();
214+
215+ Utils::WaitForTimeoutMSec(100);
216+
217+ timeout.reset();
218+ EXPECT_EQ(local_callback_called, true);
219+ EXPECT_EQ(local_callback_call_count, 1);
220+
221+ // source should be removed by now.
222+ EXPECT_TRUE(g_main_context_find_source_by_id(NULL, id) == nullptr);
223+}
224+
225+
226 // GLib TimeoutSeconds tests
227
228 TEST(TestGLibTimeoutSeconds, Construction)