Merge lp:~smspillaz/compiz-core/compiz-core.fix_969108.2 into lp:compiz-core
- compiz-core.fix_969108.2
- Merge into 0.9.7
Status: | Superseded | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~smspillaz/compiz-core/compiz-core.fix_969108.2 | ||||
Merge into: | lp:compiz-core | ||||
Diff against target: |
1314 lines (+1104/-7) 12 files modified
include/core/screen.h (+1/-0) plugins/CMakeLists.txt (+1/-0) plugins/move/src/move.cpp (+41/-5) plugins/move/src/move.h (+31/-2) src/CMakeLists.txt (+5/-0) src/queues/CMakeLists.txt (+61/-0) src/queues/include/core/queues.h (+360/-0) src/queues/src/queues.cpp (+113/-0) src/queues/tests/CMakeLists.txt (+18/-0) src/queues/tests/queues/src/test-queues.cpp (+231/-0) src/queues/tests/test-queues.cpp (+34/-0) src/queues/tests/test-queues.h (+208/-0) |
||||
To merge this branch: | bzr merge lp:~smspillaz/compiz-core/compiz-core.fix_969108.2 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel van Vugt | Pending | ||
Review via email: mp+100441@code.launchpad.net |
This proposal supersedes a proposal from 2012-04-02.
This proposal has been superseded by a proposal from 2012-04-03.
Commit message
Description of the change
== Problem ==
moveHandleMotio
== Solution ==
Added a new releasable queue structure, which allows observers to lock the queue and trigger releases at a later point and an accumulator to accumulate values to release in the future. Use this in order to queue up motion on windows and release in synchronization with repaints so that we only update the geometries where it matters.
== Tests ==
Test Suite included.
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal | # |
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal | # |
Also, this 1000 lines of code seems to be aimed at solving a problem that I planned on solving myself in only a dozen or so lines. Is it really necessary to introduce such vast complexity?
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
1) This isn't a rewrite
2) The only functional changes are in the form of
42 if (state & CompAction:
43 - ms->w->move (ms->savedX - ms->w->geometry ().x (),
44 - ms->savedY - ms->w->geometry ().y (), false);
45 + ms->addMovement (MoveWindow::get (ms->w), CompPoint (ms->savedX - ms->w->geometry ().x (),
46 + ms->savedY - ms->w->geometry ().y ()));
47
48 ms->w->syncPosition ();
49
50 @@ -484,8 +486,7 @@
51
52 if (dx || dy)
53 {
54 - w->move (wX + dx - w->geometry ().x (),
55 - wY + dy - w->geometry ().y (), false);
56 + ms->addMovement (MoveWindow::get (w), CompPoint (dx, dy));
62
63 bool
64 +MoveWindow:
65 +{
66 + window->move (d.x (), d.y (), false);
67 + return true;
68 +}
69 +
70 +void
71 +MoveScreen:
72 +{
73 + MoveWindow *mw = static_cast <MoveWindow *> (releasable);
74 + mw->cWindow-
75 +}
76 +
77 +bool
78 MoveScreen:
79 {
80 hasCompositing = true;
81 @@ -677,9 +692,27 @@
82 MoveScreen:
83 {
84 hasCompositing = false;
85 + queueLock.reset ();
86 cScreen-
87 }
88
89 +void
90 +MoveScreen:
91 +{
92 + if (queueLock)
93 + queueLock->unlock ();
94 +
95 + cScreen-
96 + cScreen-
97 +}
98 +
99 +void
100 +MoveScreen:
101 +{
102 + cScreen-
103 + pendingMovement
104 +}
105 +
113 - yConstrained (false)
114 + yConstrained (false),
115 + pendingMovement
116 + pendingMovements (new compiz:
123 CompositeScreen
124 + queueLock = pendingMovement
125 + cScreen-
That's fairly small
3) The reason the diff is so large is because 100 of 1200 lines are cmake and 600 of the 1200 lines are tests
4) This solution is aimed at making releasable queues more generic
5) Its blocking other work
Plenty of good reasons to merge this before precise.
Tim Penhey (thumper) wrote : Posted in a previous version of this proposal | # |
Making destructors pure virtual is only really necessary if there are no other pure virtual methods and you want to make the class abstract. Other than that they are just a PITA.
Mikkel Kamstrup Erlandsen (kamstrup) wrote : Posted in a previous version of this proposal | # |
I don't know the compiz coding standards, but for abstract code like this I'd expect at the very least 2 comments: 1) In queue.cpp/h explaining what the general idea behind all the interfaces are, 2) in the move.cpp explaining what it is using the clever queues for (ie. why a bog standard list is not good enough)
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal | # |
It isn't obvious what contracts the template interfaces QueueStorageInt
The pure destructors and NVPI clutter up the code.
In MoveScreen the new variables pendingMovement
I don't see why pendingMovement
There is no need for pendingMovements to be allocated on the heap instead of being a member variable. (The same change for pendingMovement
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
> It isn't obvious what contracts the template interfaces QueueStorageInt
> QueueInterface, and QueueLockInterface represent. E.g. I'd expect a lock to
> have "lock()" and "unlock()" methods or similar. Do they need to be
> templates?
QueueReleaseInt
QueueLockInterface takes a lock on a QueueUnlockable
QueueStorageInt
QueueInterface is the interface to the Queue itself, eg, pushing data into the queue.
>
> The pure destructors and NVPI clutter up the code.
>
> In MoveScreen the new variables pendingMovement
> queueLock could be private. (I suspect others could too - what is it with
> compiz and public data members?)
Ack, although I believe we're using this from MoveWindow.
>
> I don't see why pendingMovement
> is in initalizing pendingMovements. In any case, it should be of the usage
> type - shared_
You are correct.
I believe the reason I made it a member was merely for convenience, without that, this line
pendingMovements (new compiz:
would look something like
pendingMovements (new compiz:
(which is a bit of a monstrosity :( )
>
> There is no need for pendingMovements to be allocated on the heap instead of
> being a member variable. (The same change for pendingMovement
> would require a signature change for compiz:
> that's minor.)
I think the reason why I had it on the heap was because if it was on the stack then this would mean we'd pass QueueStorageInt
pendingMovements on the other hand could be on the stack.
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
> I don't know the compiz coding standards, but for abstract code like this I'd
> expect at the very least 2 comments: 1) In queue.cpp/h explaining what the
> general idea behind all the interfaces are, 2) in the move.cpp explaining what
> it is using the clever queues for (ie. why a bog standard list is not good
> enough)
Yes, I will add such comments. Thanks Mikkel
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
> Making destructors pure virtual is only really necessary if there are no other
> pure virtual methods and you want to make the class abstract. Other than that
> they are just a PITA.
Ack
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal | # |
> > It isn't obvious what contracts the template interfaces
> QueueStorageInt
> > QueueInterface, and QueueLockInterface represent. E.g. I'd expect a lock to
> > have "lock()" and "unlock()" methods or similar. Do they need to be
> > templates?
>
> QueueReleaseInt
> the type that is being stored. As such, they are templates.
Yes, but they are only instantiated on one type in real code. (And another in the tests.)
> >
> > The pure destructors and NVPI clutter up the code.
> >
> > In MoveScreen the new variables pendingMovement
> and
> > queueLock could be private. (I suspect others could too - what is it with
> > compiz and public data members?)
>
> Ack, although I believe we're using this from MoveWindow.
Not in the code I see.
> > I don't see why pendingMovement
> > is in initalizing pendingMovements. In any case, it should be of the usage
> > type - shared_
>
> You are correct.
>
> I believe the reason I made it a member was merely for convenience, without
> that, this line
>
> pendingMovements (new compiz:
> (boost:
> > (pendingMovemen
>
> would look something like
>
> pendingMovements (new compiz:
> (boost:
> > (compiz:
> compiz:
Or without the pointless cast...
pendingMovements (new compiz:
And if you don't repeat compiz:
pendingMovements (new cqi::Queue <CompPoint> (cqi::QueueStor
> > There is no need for pendingMovements to be allocated on the heap instead of
> > being a member variable. (The same change for pendingMovement
> > would require a signature change for compiz:
> but
> > that's minor.)
>
> I think the reason why I had it on the heap was because if it was on the stack
> then this would mean we'd pass QueueStorageInt
> we'd have to copy the temporary into the member variable inside of ::Queue .
> That would mean adding copying semantics to something which shouldn't really
> be copied anyways (QueueStorageIn
> be stored, it isn't a value type in itself).
I think there's a misunderstanding. But that's moot in view of the above discussion.
> pendingMovements on the other hand could be on the stack.
A data member. Then the "monsterous" line becomes:
pendingMovements (cqi::QueueStor
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
Code cleaned up. Resubmitted ... though it looks like I have more to do. Fun.
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal | # |
> QueueReleaseInt
> the type that is being stored. As such, they are templates.
> Yes, but they are only instantiated on one type in real code. (And another in the tests.)
I plan to use this in other parts of the code. It was almost generic as it was, and is quite useful as a separate mechanism IMO
Will use namespace aliases as recommended
Sam Spilsbury (smspillaz) wrote : | # |
Code cleaned up and resubmitted again
Alan Griffiths (alan-griffiths) wrote : | # |
Seems to work. And the functionality seems a good idea.
But, now we can read what they do, the names of the queues classes seem a bit awkward...
"QueueInterface" does only a small subset of what I'd expect a queue to do and adding "Interface" to the name seems verbose (not that I like Microsoft's "I" prefix either). "Appender" may be better?
"QueueLockInter
(I find the other names problematic too - but don't want to go on too much.)
On the design side, I don't like the fact that downcasts are required by the code using these classes. As a general principle templates should allow this to be avoided by propagating type information.
Sam Spilsbury (smspillaz) wrote : | # |
> Seems to work. And the functionality seems a good idea.
>
> But, now we can read what they do, the names of the queues classes seem a bit
> awkward...
>
> "QueueInterface" does only a small subset of what I'd expect a queue to do and
> adding "Interface" to the name seems verbose (not that I like Microsoft's "I"
> prefix either). "Appender" may be better?
The I/Interface/
>
> "QueueLockInter
> pre-release callback to request permission to release the queue.
QueueHoldInterface ?
>
> (I find the other names problematic too - but don't want to go on too much.)
>
> On the design side, I don't like the fact that downcasts are required by the
> code using these classes. As a general principle templates should allow this
> to be avoided by propagating type information.
550 + mItems[static_cast <QueueReleaseIn
551 +
552 + return true;
553 + }
554 +
555 + void doRelease ()
556 + {
557 + typename std::map <QueueReleaseIn
558 +
559 + for (; it != mItems.end (); it++)
560 + {
561 + QueueReleasable
These two are avoidable. I'll try something else. As for the downcast to MoveWindow, it should be possible to avoid that one by changing the boost::function to another interface like a QueueItemReadyC
- 3086. By Sam Spilsbury
-
Also notify interested data receivers they have data pending
- 3087. By Sam Spilsbury
-
Remove downcasts where possible
- 3088. By Sam Spilsbury
-
Actually hook up to itemPending
Unmerged revisions
- 3088. By Sam Spilsbury
-
Actually hook up to itemPending
- 3087. By Sam Spilsbury
-
Remove downcasts where possible
- 3086. By Sam Spilsbury
-
Also notify interested data receivers they have data pending
- 3085. By Sam Spilsbury
-
Remove the shared static cast
- 3084. By Sam Spilsbury
-
Namespace alias
- 3083. By Sam Spilsbury
-
Removed AccumulatedMapS
torage member - 3082. By Sam Spilsbury
-
Made pendingMovements not a shared ptr
- 3081. By Sam Spilsbury
-
Made pendingMovements private
- 3080. By Sam Spilsbury
-
Removed virtual destructors
- 3079. By Sam Spilsbury
-
Added documentation for the contract provided by queues
Preview Diff
1 | === added directory 'build' |
2 | === added directory 'build/src' |
3 | === modified file 'include/core/screen.h' |
4 | --- include/core/screen.h 2012-03-12 12:35:52 +0000 |
5 | +++ include/core/screen.h 2012-04-02 15:10:24 +0000 |
6 | @@ -39,6 +39,7 @@ |
7 | #include <core/valueholder.h> |
8 | |
9 | #include <boost/scoped_ptr.hpp> |
10 | +#include <boost/shared_ptr.hpp> |
11 | |
12 | class CompScreenImpl; |
13 | class PrivateScreen; |
14 | |
15 | === modified file 'plugins/CMakeLists.txt' |
16 | --- plugins/CMakeLists.txt 2012-01-20 09:46:31 +0000 |
17 | +++ plugins/CMakeLists.txt 2012-04-02 15:10:24 +0000 |
18 | @@ -16,6 +16,7 @@ |
19 | ${CMAKE_CURRENT_SOURCE_DIR}/../src/pluginclasshandler/include |
20 | ${CMAKE_CURRENT_SOURCE_DIR}/../src/point/include |
21 | ${CMAKE_CURRENT_SOURCE_DIR}/../src/rect/include |
22 | + ${CMAKE_CURRENT_SOURCE_DIR}/../src/queues/include |
23 | ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/geometry/include |
24 | ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/geometry-saver/include |
25 | ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/extents/include |
26 | |
27 | === modified file 'plugins/move/src/move.cpp' |
28 | --- plugins/move/src/move.cpp 2012-02-16 05:31:28 +0000 |
29 | +++ plugins/move/src/move.cpp 2012-04-02 15:10:24 +0000 |
30 | @@ -27,6 +27,8 @@ |
31 | #include <stdlib.h> |
32 | #include <string.h> |
33 | |
34 | +#include <boost/cast.hpp> |
35 | + |
36 | #include <X11/cursorfont.h> |
37 | |
38 | #include <core/atoms.h> |
39 | @@ -169,8 +171,8 @@ |
40 | if (ms->w) |
41 | { |
42 | if (state & CompAction::StateCancel) |
43 | - ms->w->move (ms->savedX - ms->w->geometry ().x (), |
44 | - ms->savedY - ms->w->geometry ().y (), false); |
45 | + ms->addMovement (MoveWindow::get (ms->w), CompPoint (ms->savedX - ms->w->geometry ().x (), |
46 | + ms->savedY - ms->w->geometry ().y ())); |
47 | |
48 | ms->w->syncPosition (); |
49 | |
50 | @@ -484,8 +486,7 @@ |
51 | |
52 | if (dx || dy) |
53 | { |
54 | - w->move (wX + dx - w->geometry ().x (), |
55 | - wY + dy - w->geometry ().y (), false); |
56 | + ms->addMovement (MoveWindow::get (w), CompPoint (dx, dy)); |
57 | |
58 | if (!ms->optionGetLazyPositioning ()) |
59 | w->syncPosition (); |
60 | @@ -666,6 +667,20 @@ |
61 | } |
62 | |
63 | bool |
64 | +MoveWindow::doRelease (const CompPoint &d) |
65 | +{ |
66 | + window->move (d.x (), d.y (), false); |
67 | + return true; |
68 | +} |
69 | + |
70 | +void |
71 | +MoveScreen::dispatchDamage (cq::QueueReleaseInterface *releasable) |
72 | +{ |
73 | + MoveWindow *mw = static_cast <MoveWindow *> (releasable); |
74 | + mw->cWindow->addDamage (); |
75 | +} |
76 | + |
77 | +bool |
78 | MoveScreen::registerPaintHandler(compiz::composite::PaintHandler *pHnd) |
79 | { |
80 | hasCompositing = true; |
81 | @@ -677,9 +692,27 @@ |
82 | MoveScreen::unregisterPaintHandler() |
83 | { |
84 | hasCompositing = false; |
85 | + queueLock.reset (); |
86 | cScreen->unregisterPaintHandler (); |
87 | } |
88 | |
89 | +void |
90 | +MoveScreen::preparePaint (int ms) |
91 | +{ |
92 | + if (queueLock) |
93 | + queueLock->unlock (); |
94 | + |
95 | + cScreen->preparePaint (ms); |
96 | + cScreen->preparePaintSetEnabled (this, false); |
97 | +} |
98 | + |
99 | +void |
100 | +MoveScreen::addMovement (MoveWindow *mw, const CompPoint &d) |
101 | +{ |
102 | + cScreen->preparePaintSetEnabled (this, true); |
103 | + pendingMovements.addPending (d, mw); |
104 | +} |
105 | + |
106 | MoveScreen::MoveScreen (CompScreen *screen) : |
107 | PluginClassHandler<MoveScreen,CompScreen> (screen), |
108 | cScreen (CompositeScreen::get (screen)), |
109 | @@ -689,7 +722,8 @@ |
110 | releaseButton (0), |
111 | grab (NULL), |
112 | hasCompositing (false), |
113 | - yConstrained (false) |
114 | + yConstrained (false), |
115 | + pendingMovements (cqi::AccumulatedMapStorage<CompPoint>::Ptr (new cqi::AccumulatedMapStorage <CompPoint> ())) |
116 | { |
117 | updateOpacity (); |
118 | |
119 | @@ -701,6 +735,8 @@ |
120 | if (cScreen) |
121 | { |
122 | CompositeScreenInterface::setHandler (cScreen); |
123 | + queueLock = pendingMovements.obtainLock (boost::bind (&MoveScreen::dispatchDamage, this, _1)); |
124 | + cScreen->preparePaintSetEnabled (this, false); |
125 | hasCompositing = |
126 | cScreen->compositingActive (); |
127 | } |
128 | |
129 | === modified file 'plugins/move/src/move.h' |
130 | --- plugins/move/src/move.h 2012-02-01 17:49:07 +0000 |
131 | +++ plugins/move/src/move.h 2012-04-02 15:10:24 +0000 |
132 | @@ -27,10 +27,13 @@ |
133 | |
134 | #include <core/screen.h> |
135 | #include <core/pluginclasshandler.h> |
136 | +#include <core/queues.h> |
137 | |
138 | #include <composite/composite.h> |
139 | #include <opengl/opengl.h> |
140 | |
141 | +namespace cqi = compiz::queues::impl; |
142 | +namespace cq = compiz::queues; |
143 | |
144 | #define NUM_KEYS (sizeof (mKeys) / sizeof (mKeys[0])) |
145 | |
146 | @@ -50,6 +53,8 @@ |
147 | { "Down", 0, 1 } |
148 | }; |
149 | |
150 | +class MoveWindow; |
151 | + |
152 | class MoveScreen : |
153 | public ScreenInterface, |
154 | public CompositeScreenInterface, |
155 | @@ -68,6 +73,10 @@ |
156 | |
157 | bool registerPaintHandler (compiz::composite::PaintHandler *pHnd); |
158 | void unregisterPaintHandler (); |
159 | + void preparePaint (int ms); |
160 | + |
161 | + void addMovement (MoveWindow *mw, const CompPoint &d); |
162 | + void dispatchDamage (cq::QueueReleaseInterface *); |
163 | |
164 | CompWindow *w; |
165 | int savedX; |
166 | @@ -94,29 +103,49 @@ |
167 | bool hasCompositing; |
168 | |
169 | bool yConstrained; |
170 | + |
171 | + private: |
172 | + |
173 | + cqi::Queue <CompPoint> pendingMovements; |
174 | + boost::shared_ptr <cq::QueueLockInterface> queueLock; |
175 | }; |
176 | |
177 | class MoveWindow : |
178 | public GLWindowInterface, |
179 | - public PluginClassHandler<MoveWindow,CompWindow> |
180 | + public PluginClassHandler<MoveWindow,CompWindow>, |
181 | + public cq::QueueReleasableInterface <CompPoint> |
182 | { |
183 | public: |
184 | MoveWindow (CompWindow *window) : |
185 | PluginClassHandler<MoveWindow,CompWindow> (window), |
186 | window (window), |
187 | gWindow (GLWindow::get (window)), |
188 | - cWindow (CompositeWindow::get (window)) |
189 | + cWindow (CompositeWindow::get (window)), |
190 | + mRemoveInterface (NULL) |
191 | { |
192 | if (gWindow) |
193 | GLWindowInterface::setHandler (gWindow, false); |
194 | }; |
195 | |
196 | + ~MoveWindow () |
197 | + { |
198 | + if (mRemoveInterface) |
199 | + mRemoveInterface->removeReleasable (this); |
200 | + } |
201 | + |
202 | bool glPaint (const GLWindowPaintAttrib &, const GLMatrix &, |
203 | const CompRegion &, unsigned int); |
204 | |
205 | CompWindow *window; |
206 | GLWindow *gWindow; |
207 | CompositeWindow *cWindow; |
208 | + |
209 | + private: |
210 | + |
211 | + bool doRelease (const CompPoint &d); |
212 | + void doSetRemoveInterface (cq::QueueReleaseRemoveInterface *removeInterface) { mRemoveInterface = removeInterface; } |
213 | + |
214 | + cq::QueueReleaseRemoveInterface *mRemoveInterface; |
215 | }; |
216 | |
217 | #define MOVE_SCREEN(s) \ |
218 | |
219 | === modified file 'src/CMakeLists.txt' |
220 | --- src/CMakeLists.txt 2012-03-13 10:17:02 +0000 |
221 | +++ src/CMakeLists.txt 2012-04-02 15:10:24 +0000 |
222 | @@ -8,6 +8,7 @@ |
223 | add_subdirectory( point ) |
224 | add_subdirectory( rect ) |
225 | add_subdirectory( window ) |
226 | +add_subdirectory( queues ) |
227 | |
228 | IF (COMPIZ_BUILD_TESTING) |
229 | add_subdirectory( privatescreen/tests ) |
230 | @@ -54,6 +55,9 @@ |
231 | ${CMAKE_CURRENT_SOURCE_DIR}/point/include |
232 | ${CMAKE_CURRENT_SOURCE_DIR}/point/src |
233 | |
234 | + ${CMAKE_CURRENT_SOURCE_DIR}/queues/include |
235 | + ${CMAKE_CURRENT_SOURCE_DIR}/queues/src |
236 | + |
237 | ${CMAKE_CURRENT_SOURCE_DIR}/rect/include |
238 | ${CMAKE_CURRENT_SOURCE_DIR}/rect/src |
239 | |
240 | @@ -159,6 +163,7 @@ |
241 | compiz_window_geometry_saver |
242 | compiz_window_extents |
243 | compiz_window_constrainment |
244 | + compiz_queues |
245 | -Wl,-no-whole-archive |
246 | # ${CORE_MOD_LIBRARIES} |
247 | ) |
248 | |
249 | === added directory 'src/queues' |
250 | === added file 'src/queues/CMakeLists.txt' |
251 | --- src/queues/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
252 | +++ src/queues/CMakeLists.txt 2012-04-02 15:10:24 +0000 |
253 | @@ -0,0 +1,61 @@ |
254 | +pkg_check_modules ( |
255 | + GLIBMM |
256 | + REQUIRED |
257 | + glibmm-2.4 glib-2.0 |
258 | +) |
259 | + |
260 | +INCLUDE_DIRECTORIES ( |
261 | + ${CMAKE_CURRENT_SOURCE_DIR}/include |
262 | + ${CMAKE_CURRENT_SOURCE_DIR}/src |
263 | + |
264 | + ${CMAKE_CURRENT_SOURCE_DIR}/queues/include |
265 | + ${CMAKE_CURRENT_SOURCE_DIR}/queues/src |
266 | + |
267 | + ${compiz_SOURCE_DIR}/include |
268 | + |
269 | + ${Boost_INCLUDE_DIRS} |
270 | + |
271 | + ${GLIBMM_INCLUDE_DIRS} |
272 | +) |
273 | + |
274 | +LINK_DIRECTORIES (${GLIBMM_LIBRARY_DIRS}) |
275 | + |
276 | +SET ( |
277 | + PUBLIC_HEADERS |
278 | + ${CMAKE_CURRENT_SOURCE_DIR}/include/core/queues.h |
279 | +) |
280 | + |
281 | +SET ( |
282 | + PRIVATE_HEADERS |
283 | +) |
284 | + |
285 | +SET( |
286 | + SRCS |
287 | + ${CMAKE_CURRENT_SOURCE_DIR}/src/queues.cpp |
288 | +) |
289 | + |
290 | +ADD_LIBRARY( |
291 | + compiz_queues STATIC |
292 | + |
293 | + ${SRCS} |
294 | + |
295 | + ${PUBLIC_HEADERS} |
296 | + ${PRIVATE_HEADERS} |
297 | +) |
298 | + |
299 | +IF (COMPIZ_BUILD_TESTING) |
300 | +ADD_SUBDIRECTORY( ${CMAKE_CURRENT_SOURCE_DIR}/tests ) |
301 | +ENDIF (COMPIZ_BUILD_TESTING) |
302 | + |
303 | +SET_TARGET_PROPERTIES( |
304 | + compiz_queues PROPERTIES |
305 | + PUBLIC_HEADER "${PUBLIC_HEADERS}" |
306 | +) |
307 | + |
308 | +install (FILES ${PUBLIC_HEADERS} DESTINATION ${COMPIZ_CORE_INCLUDE_DIR}) |
309 | + |
310 | +TARGET_LINK_LIBRARIES( |
311 | + compiz_queues |
312 | + |
313 | + ${GLIBMM_LIBRARIES} |
314 | +) |
315 | |
316 | === added directory 'src/queues/include' |
317 | === added directory 'src/queues/include/core' |
318 | === added file 'src/queues/include/core/queues.h' |
319 | --- src/queues/include/core/queues.h 1970-01-01 00:00:00 +0000 |
320 | +++ src/queues/include/core/queues.h 2012-04-02 15:10:24 +0000 |
321 | @@ -0,0 +1,360 @@ |
322 | +/* |
323 | + * Copyright © 2012 Canonical Ltd. |
324 | + * |
325 | + * Permission to use, copy, modify, distribute, and sell this software |
326 | + * and its documentation for any purpose is hereby granted without |
327 | + * fee, provided that the above copyright notice appear in all copies |
328 | + * and that both that copyright notice and this permission notice |
329 | + * appear in supporting documentation, and that the name of |
330 | + * Canonical Ltd. not be used in advertising or publicity pertaining to |
331 | + * distribution of the software without specific, written prior permission. |
332 | + * Canonical Ltd. makes no representations about the suitability of this |
333 | + * software for any purpose. It is provided "as is" without express or |
334 | + * implied warranty. |
335 | + * |
336 | + * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
337 | + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN |
338 | + * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
339 | + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS |
340 | + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
341 | + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION |
342 | + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
343 | + * |
344 | + * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com> |
345 | + */ |
346 | + |
347 | +#ifndef _COMPQUEUES_H |
348 | +#define _COMPQUEUES_H |
349 | + |
350 | +#include <vector> |
351 | +#include <map> |
352 | +#include <boost/shared_ptr.hpp> |
353 | +#include <boost/function.hpp> |
354 | +#include <boost/bind.hpp> |
355 | +#include <boost/noncopyable.hpp> |
356 | + |
357 | +namespace compiz |
358 | +{ |
359 | + namespace queues |
360 | + { |
361 | + class QueueReleaseInterface; |
362 | + |
363 | + /** |
364 | + * A QueueReleaseRemoveInterface describes an interface |
365 | + * provided to an object inheriting QueueReleaseInterface |
366 | + * to call back into the queue storage to remove queued items |
367 | + * relating to a QueueReleaseInterface when the object implementing |
368 | + * the QueueReleaseInterface is destroyed |
369 | + */ |
370 | + class QueueReleaseRemoveInterface |
371 | + { |
372 | + public: |
373 | + |
374 | + virtual ~QueueReleaseRemoveInterface () {} |
375 | + |
376 | + void removeReleasable (QueueReleaseInterface *r) { doRemoveReleasable (r); } |
377 | + |
378 | + protected: |
379 | + |
380 | + virtual void doRemoveReleasable (QueueReleaseInterface *) = 0; |
381 | + }; |
382 | + |
383 | + /** |
384 | + * A QueueReleaseInterface is implemented by an object interested in some |
385 | + * data on the object in the future when an object implementing a QueueInterface |
386 | + * decides it is appropriate to release that data. This class is a base to the |
387 | + * template QueueReleasableInterface which knows about the data type being released */ |
388 | + class QueueReleaseInterface |
389 | + { |
390 | + public: |
391 | + |
392 | + virtual ~QueueReleaseInterface () {} |
393 | + |
394 | + void setRemoveInterface (QueueReleaseRemoveInterface *r) { doSetRemoveInterface (r); } |
395 | + |
396 | + protected: |
397 | + |
398 | + virtual void doSetRemoveInterface (QueueReleaseRemoveInterface *) = 0; |
399 | + }; |
400 | + |
401 | + /** |
402 | + * A QueueReleasableInterface is implemented by an object interested in some |
403 | + * future data when an object implementing a QueueInterface decides it is appropriate |
404 | + * to dispatch this data. release () is a callback into the object to inform it that |
405 | + * new data is ready to be proccessed |
406 | + */ |
407 | + template <class T> |
408 | + class QueueReleasableInterface : |
409 | + public QueueReleaseInterface |
410 | + { |
411 | + public: |
412 | + |
413 | + virtual ~QueueReleasableInterface () {} |
414 | + |
415 | + bool release (const T &t) { return doRelease (t); } |
416 | + |
417 | + protected: |
418 | + |
419 | + virtual bool doRelease (const T &t) = 0; |
420 | + }; |
421 | + |
422 | + /** |
423 | + * A QueueLockInterface is implemented by an object which wishes to hold a lock |
424 | + * on a QueueInterface to prevent it from releasing data until the owner of the |
425 | + * QueueLockInterface decides is appropriate. QueueLockInterfaces provide an unlock () |
426 | + * method to indicate that data which is held in the queue is ok by the owner to be |
427 | + * processed. callback () is invoked by a QueueInterface which wishes to indicate |
428 | + * that some data on a QueueReleaseInterface is pending processing but not yet |
429 | + * released (so that the owner may decide whether or not it is appropriate to release |
430 | + * the lock) |
431 | + */ |
432 | + class QueueLockInterface |
433 | + { |
434 | + public: |
435 | + |
436 | + virtual ~QueueLockInterface () {} |
437 | + |
438 | + typedef boost::shared_ptr <QueueLockInterface> Ptr; |
439 | + |
440 | + bool unlock () { return doUnlock (); } |
441 | + void callback (QueueReleaseInterface *releasable) { return doCallback (releasable); } |
442 | + |
443 | + private: |
444 | + |
445 | + virtual bool doUnlock () = 0; |
446 | + virtual void doCallback (QueueReleaseInterface *releasable) = 0; |
447 | + }; |
448 | + |
449 | + /** |
450 | + * A QueueUnlockInterface is implemented by an object which has data to be dispatched |
451 | + * to other interested owners. QueueUnlockInterface is provided to implementors of |
452 | + * QueueLockInterface as a means to call-back and decrement the lock count of the queue. |
453 | + * Locks must also register their existence on the unlock interface |
454 | + */ |
455 | + class QueueUnlockInterface |
456 | + { |
457 | + public: |
458 | + |
459 | + virtual ~QueueUnlockInterface () {} |
460 | + |
461 | + void release () { doRelease (); } |
462 | + bool registerLock (QueueLockInterface *lock) { return doRegisterLock (lock); } |
463 | + bool unregisterLock (QueueLockInterface *lock) { return doUnregisterLock (lock); } |
464 | + |
465 | + private: |
466 | + |
467 | + virtual void doRelease () = 0; |
468 | + virtual bool doRegisterLock (QueueLockInterface *) = 0; |
469 | + virtual bool doUnregisterLock (QueueLockInterface *) = 0; |
470 | + }; |
471 | + |
472 | + typedef boost::function <void (QueueReleaseInterface *)> pendingItemsFunc; |
473 | + |
474 | + /** |
475 | + * A QueueLockGeneratorInterface provides an interface to construct a lock - the implementation |
476 | + * determines what type of lock to construct, and what the lock has control over |
477 | + */ |
478 | + class QueueLockGeneratorInterface |
479 | + { |
480 | + public: |
481 | + |
482 | + virtual ~QueueLockGeneratorInterface () {} |
483 | + boost::shared_ptr <QueueLockInterface> obtainLock (const pendingItemsFunc &func) { return doObtainLock (func); } |
484 | + |
485 | + private: |
486 | + |
487 | + virtual boost::shared_ptr <QueueLockInterface> doObtainLock (const pendingItemsFunc &) = 0; |
488 | + }; |
489 | + |
490 | + /** |
491 | + * A QueueInterface provides the front-end for adding data to a queue to be dispatched |
492 | + * on a QueueReleasableInterface at some point in the future. |
493 | + */ |
494 | + template <class T> |
495 | + class QueueInterface |
496 | + { |
497 | + public: |
498 | + |
499 | + virtual ~QueueInterface () {} |
500 | + |
501 | + void addPending (const T &t, |
502 | + QueueReleasableInterface <T> *r) { doAddPending (t, r); } |
503 | + |
504 | + protected: |
505 | + |
506 | + virtual void doAddPending (const T &, |
507 | + QueueReleasableInterface <T> *) = 0; |
508 | + }; |
509 | + |
510 | + /** |
511 | + * A QueueStorageInterface is an abstraction as to how data should be stored in a QueueInterface |
512 | + * and how it should be released when data is ready to be dispatched |
513 | + */ |
514 | + template <class T> |
515 | + class QueueStorageInterface : |
516 | + public QueueReleaseRemoveInterface |
517 | + { |
518 | + public: |
519 | + |
520 | + virtual ~QueueStorageInterface () {} |
521 | + |
522 | + typedef boost::shared_ptr <QueueStorageInterface <T> > Ptr; |
523 | + |
524 | + bool store (QueueReleasableInterface<T> *r, const T &t) { return doStore (r, t); } |
525 | + void release () { doRelease (); } |
526 | + |
527 | + protected: |
528 | + |
529 | + virtual bool doStore (QueueReleasableInterface<T> *i, const T &) = 0; |
530 | + virtual void doRelease () = 0; |
531 | + }; |
532 | + |
533 | + namespace impl |
534 | + { |
535 | + |
536 | + typedef boost::function <void ()> notifyReleaseFunc; |
537 | + |
538 | + template <class T> |
539 | + class AccumulatedMapStorage : |
540 | + public QueueStorageInterface <T> |
541 | + { |
542 | + public: |
543 | + |
544 | + typedef typename boost::shared_ptr <AccumulatedMapStorage <T> > Ptr; |
545 | + |
546 | + private: |
547 | + |
548 | + bool doStore (QueueReleasableInterface<T> *i, const T &t) |
549 | + { |
550 | + mItems[static_cast <QueueReleaseInterface *> (i)] += t; |
551 | + |
552 | + return true; |
553 | + } |
554 | + |
555 | + void doRelease () |
556 | + { |
557 | + typename std::map <QueueReleaseInterface *, T>::iterator it = mItems.begin (); |
558 | + |
559 | + for (; it != mItems.end (); it++) |
560 | + { |
561 | + QueueReleasableInterface <T> *releasable = static_cast <QueueReleasableInterface <T> *> (it->first); |
562 | + |
563 | + releasable->release (it->second); |
564 | + } |
565 | + |
566 | + mItems.clear (); |
567 | + } |
568 | + |
569 | + void doRemoveReleasable (compiz::queues::QueueReleaseInterface *r) |
570 | + { |
571 | + typename std::map <QueueReleaseInterface *, T>::iterator it = mItems.find (r); |
572 | + |
573 | + if (it != mItems.end ()) |
574 | + mItems.erase (it); |
575 | + } |
576 | + |
577 | + std::map <QueueReleaseInterface *, T> mItems; |
578 | + }; |
579 | + |
580 | + class QueueLock : |
581 | + public QueueLockInterface |
582 | + { |
583 | + public: |
584 | + |
585 | + QueueLock (QueueUnlockInterface *unlockable, const pendingItemsFunc &f); |
586 | + ~QueueLock (); |
587 | + |
588 | + private: |
589 | + |
590 | + bool doUnlock (); |
591 | + void doCallback (QueueReleaseInterface *releasable); |
592 | + |
593 | + QueueUnlockInterface *mUnlockable; |
594 | + pendingItemsFunc mPendingDispatch; |
595 | + }; |
596 | + |
597 | + class QueueImpl : |
598 | + public QueueUnlockInterface, |
599 | + public QueueLockGeneratorInterface |
600 | + { |
601 | + public: |
602 | + |
603 | + QueueImpl (const notifyReleaseFunc &f) : |
604 | + mNotifyFunc (f) |
605 | + { |
606 | + } |
607 | + |
608 | + void reset (); |
609 | + void notify (compiz::queues::QueueReleaseInterface *); |
610 | + |
611 | + private: |
612 | + |
613 | + void doRelease (); |
614 | + bool doRegisterLock (QueueLockInterface *lock); |
615 | + bool doUnregisterLock (QueueLockInterface *lock); |
616 | + |
617 | + QueueLockInterface::Ptr doObtainLock (const pendingItemsFunc &); |
618 | + |
619 | + notifyReleaseFunc mNotifyFunc; |
620 | + std::vector <QueueLockInterface *> mLocks; |
621 | + unsigned int mLockCount; |
622 | + }; |
623 | + |
624 | + template <class T> |
625 | + class Queue : |
626 | + boost::noncopyable, |
627 | + public QueueInterface <T>, |
628 | + public QueueLockGeneratorInterface, |
629 | + public QueueUnlockInterface |
630 | + |
631 | + { |
632 | + public: |
633 | + |
634 | + Queue (const typename QueueStorageInterface<T>::Ptr &storage) : |
635 | + mImpl (boost::bind (&QueueStorageInterface<T>::release, storage.get ())), |
636 | + mStorage (storage) |
637 | + { |
638 | + } |
639 | + |
640 | + private: |
641 | + |
642 | + void doAddPending (const T &t, |
643 | + QueueReleasableInterface <T> *release) |
644 | + { |
645 | + release->setRemoveInterface (static_cast <QueueReleaseRemoveInterface *> (mStorage.get ())); |
646 | + |
647 | + mStorage->store (release, t); |
648 | + mImpl.reset (); |
649 | + mImpl.notify (release); |
650 | + mImpl.release (); |
651 | + } |
652 | + |
653 | + boost::shared_ptr <QueueLockInterface> doObtainLock (const pendingItemsFunc &f) |
654 | + { |
655 | + return mImpl.obtainLock (f); |
656 | + } |
657 | + |
658 | + void doRelease () |
659 | + { |
660 | + return mImpl.release (); |
661 | + } |
662 | + |
663 | + bool doRegisterLock (QueueLockInterface *lock) |
664 | + { |
665 | + return mImpl.registerLock (lock); |
666 | + } |
667 | + |
668 | + bool doUnregisterLock (QueueLockInterface *lock) |
669 | + { |
670 | + return mImpl.unregisterLock (lock); |
671 | + } |
672 | + |
673 | + QueueImpl mImpl; |
674 | + typename compiz::queues::QueueStorageInterface<T>::Ptr mStorage; |
675 | + }; |
676 | + } |
677 | + } |
678 | +} |
679 | + |
680 | + |
681 | +#endif |
682 | |
683 | === added directory 'src/queues/src' |
684 | === added file 'src/queues/src/queues.cpp' |
685 | --- src/queues/src/queues.cpp 1970-01-01 00:00:00 +0000 |
686 | +++ src/queues/src/queues.cpp 2012-04-02 15:10:24 +0000 |
687 | @@ -0,0 +1,113 @@ |
688 | +/* |
689 | + * Copyright © 2012 Canonical Ltd. |
690 | + * |
691 | + * Permission to use, copy, modify, distribute, and sell this software |
692 | + * and its documentation for any purpose is hereby granted without |
693 | + * fee, provided that the above copyright notice appear in all copies |
694 | + * and that both that copyright notice and this permission notice |
695 | + * appear in supporting documentation, and that the name of |
696 | + * Canonical Ltd. not be used in advertising or publicity pertaining to |
697 | + * distribution of the software without specific, written prior permission. |
698 | + * Canonical Ltd. makes no representations about the suitability of this |
699 | + * software for any purpose. It is provided "as is" without express or |
700 | + * implied warranty. |
701 | + * |
702 | + * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
703 | + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN |
704 | + * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
705 | + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS |
706 | + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
707 | + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION |
708 | + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
709 | + * |
710 | + * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com> |
711 | + */ |
712 | + |
713 | +#include <core/queues.h> |
714 | +#include <cstdio> |
715 | + |
716 | +using namespace compiz::queues; |
717 | +using namespace compiz::queues::impl; |
718 | + |
719 | +void |
720 | +QueueImpl::reset () |
721 | +{ |
722 | + mLockCount = mLocks.size () + 1; |
723 | +} |
724 | + |
725 | +void |
726 | +QueueImpl::notify (QueueReleaseInterface *releasable) |
727 | +{ |
728 | + for (std::vector <QueueLockInterface *>::iterator it = mLocks.begin (); it != mLocks.end (); it++) |
729 | + (*it)->callback (releasable); |
730 | +} |
731 | + |
732 | +void |
733 | +QueueImpl::doRelease () |
734 | +{ |
735 | + if (!mLockCount) |
736 | + return; |
737 | + |
738 | + mLockCount--; |
739 | + |
740 | + if (mLockCount) |
741 | + return; |
742 | + |
743 | + /* Release all queued items */ |
744 | + mNotifyFunc (); |
745 | +} |
746 | + |
747 | +bool |
748 | +QueueImpl::doRegisterLock (QueueLockInterface *lock) |
749 | +{ |
750 | + std::vector<QueueLockInterface *>::iterator it = std::find (mLocks.begin (), mLocks.end (), lock); |
751 | + |
752 | + if (it != mLocks.end ()) |
753 | + return false; |
754 | + |
755 | + mLocks.push_back (lock); |
756 | + return true; |
757 | +} |
758 | + |
759 | +bool |
760 | +QueueImpl::doUnregisterLock (QueueLockInterface *lock) |
761 | +{ |
762 | + std::vector<QueueLockInterface *>::iterator it = std::find (mLocks.begin (), mLocks.end (), lock); |
763 | + |
764 | + if (it == mLocks.end ()) |
765 | + return false; |
766 | + |
767 | + mLocks.erase (it); |
768 | + return true; |
769 | +} |
770 | + |
771 | +QueueLockInterface::Ptr |
772 | +QueueImpl::doObtainLock (const pendingItemsFunc &f) |
773 | +{ |
774 | + return QueueLockInterface::Ptr (new QueueLock (this, f)); |
775 | +} |
776 | + |
777 | +QueueLock::QueueLock (QueueUnlockInterface *unlockable, const pendingItemsFunc &pending) : |
778 | + mUnlockable (unlockable), |
779 | + mPendingDispatch (pending) |
780 | +{ |
781 | + mUnlockable->registerLock (this); |
782 | +} |
783 | + |
784 | +QueueLock::~QueueLock () |
785 | +{ |
786 | + mUnlockable->unregisterLock (this); |
787 | +} |
788 | + |
789 | +bool |
790 | +QueueLock::doUnlock () |
791 | +{ |
792 | + mUnlockable->release (); |
793 | + return true; |
794 | +} |
795 | + |
796 | +void |
797 | +QueueLock::doCallback (QueueReleaseInterface *releasable) |
798 | +{ |
799 | + mPendingDispatch (releasable); |
800 | +} |
801 | |
802 | === added directory 'src/queues/tests' |
803 | === added file 'src/queues/tests/CMakeLists.txt' |
804 | --- src/queues/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
805 | +++ src/queues/tests/CMakeLists.txt 2012-04-02 15:10:24 +0000 |
806 | @@ -0,0 +1,18 @@ |
807 | +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) |
808 | + |
809 | +add_library (compiz_queues_test |
810 | + ${CMAKE_CURRENT_SOURCE_DIR}/test-queues.cpp) |
811 | + |
812 | +add_executable (compiz_test_queues |
813 | + ${CMAKE_CURRENT_SOURCE_DIR}/queues/src/test-queues.cpp) |
814 | + |
815 | +target_link_libraries (compiz_test_queues |
816 | + compiz_queues_test |
817 | + compiz_queues |
818 | + ${GTEST_BOTH_LIBRARIES} |
819 | + ${GMOCK_LIBRARY} |
820 | + ${GMOCK_MAIN_LIBRARY} |
821 | + ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. |
822 | + ) |
823 | + |
824 | +gtest_add_tests (compiz_test_queues "" ${CMAKE_CURRENT_SOURCE_DIR}/queues/src/test-queues.cpp) |
825 | |
826 | === added directory 'src/queues/tests/queues' |
827 | === added directory 'src/queues/tests/queues/src' |
828 | === added file 'src/queues/tests/queues/src/test-queues.cpp' |
829 | --- src/queues/tests/queues/src/test-queues.cpp 1970-01-01 00:00:00 +0000 |
830 | +++ src/queues/tests/queues/src/test-queues.cpp 2012-04-02 15:10:24 +0000 |
831 | @@ -0,0 +1,231 @@ |
832 | +/* |
833 | + * Copyright © 2011 Canonical Ltd. |
834 | + * |
835 | + * Permission to use, copy, modify, distribute, and sell this software |
836 | + * and its documentation for any purpose is hereby granted without |
837 | + * fee, provided that the above copyright notice appear in all copies |
838 | + * and that both that copyright notice and this permission notice |
839 | + * appear in supporting documentation, and that the name of |
840 | + * Canonical Ltd. not be used in advertising or publicity pertaining to |
841 | + * distribution of the software without specific, written prior permission. |
842 | + * Canonical Ltd. makes no representations about the suitability of this |
843 | + * software for any purpose. It is provided "as is" without express or |
844 | + * implied warranty. |
845 | + * |
846 | + * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
847 | + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN |
848 | + * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
849 | + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS |
850 | + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
851 | + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION |
852 | + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
853 | + * |
854 | + * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com> |
855 | + */ |
856 | + |
857 | +#include "test-queues.h" |
858 | +#include <boost/cast.hpp> |
859 | + |
860 | +class CompQueuesTestQueues : |
861 | + public CompQueuesTest |
862 | +{ |
863 | + public: |
864 | + |
865 | + CompQueuesTestQueues (); |
866 | + ~CompQueuesTestQueues (); |
867 | + |
868 | +}; |
869 | + |
870 | +CompQueuesTestQueues::CompQueuesTestQueues () |
871 | +{ |
872 | +} |
873 | + |
874 | +CompQueuesTestQueues::~CompQueuesTestQueues () |
875 | +{ |
876 | +} |
877 | + |
878 | +TEST_F(CompQueuesTestQueues, TestSetRemoveReleasables) |
879 | +{ |
880 | + boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ()); |
881 | + impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage)); |
882 | + |
883 | + MockQueueReleasable <int> releasable; |
884 | + |
885 | + releasable.DelegateToFake (); |
886 | + |
887 | + EXPECT_CALL (releasable, doSetRemoveInterface (_)); |
888 | + EXPECT_CALL (*mockStorage, doStore (_, 7)); |
889 | + EXPECT_CALL (*mockStorage, doRelease ()); |
890 | + EXPECT_CALL (*mockStorage, doRemoveReleasable (_)); |
891 | + |
892 | + q.addPending (7, &releasable); |
893 | +} |
894 | + |
895 | +TEST_F(CompQueuesTestQueues, TestReleaseNoLocks) |
896 | +{ |
897 | + boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ()); |
898 | + impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage)); |
899 | + |
900 | + MockQueueReleasable <int> releasable; |
901 | + |
902 | + releasable.DelegateToFake (); |
903 | + |
904 | + EXPECT_CALL (releasable, doSetRemoveInterface (_)); |
905 | + EXPECT_CALL (*mockStorage, doStore (_, 7)); |
906 | + EXPECT_CALL (*mockStorage, doRelease ()); |
907 | + EXPECT_CALL (*mockStorage, doRemoveReleasable (_)); |
908 | + |
909 | + q.addPending (7, &releasable); |
910 | +} |
911 | + |
912 | +TEST_F(CompQueuesTestQueues, TestReleaseWithLockUnlock) |
913 | +{ |
914 | + boost::shared_ptr <impl::AccumulatedMapStorage <int> > actualStorage (new impl::AccumulatedMapStorage <int> ()); |
915 | + boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ()); |
916 | + |
917 | + mockStorage->Delegate (static_cast <QueueStorageInterface <int> *> (actualStorage.get ())); |
918 | + |
919 | + impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage)); |
920 | + QueueLockGeneratorDelegate <impl::QueueLock> gen (static_cast <QueueUnlockInterface *> (&q)); |
921 | + StrictMock <MockPendingItems> pi; |
922 | + |
923 | + MockQueue <int> mq; |
924 | + |
925 | + mq.Delegate (&q, &gen); |
926 | + |
927 | + boost::function <void (QueueReleaseInterface *)> callback (boost::bind (&PendingItemsInterface::pending, static_cast <PendingItemsInterface *> (&pi), _1)); |
928 | + |
929 | + EXPECT_CALL (mq, doObtainLock (_)); |
930 | + |
931 | + QueueLockInterface::Ptr lock (mq.obtainLock (callback)); |
932 | + |
933 | + StrictMock <MockQueueReleasable <int> > releasable; |
934 | + |
935 | + releasable.DelegateToFake (); |
936 | + |
937 | + EXPECT_CALL (releasable, doSetRemoveInterface (_)); |
938 | + EXPECT_CALL (*mockStorage, doStore (_, 7)); |
939 | + EXPECT_CALL (*mockStorage, doRemoveReleasable (_)); |
940 | + EXPECT_CALL (pi, doPending (_)); |
941 | + |
942 | + q.addPending (7, &releasable); |
943 | + |
944 | + EXPECT_CALL (*mockStorage, doRelease ()); |
945 | + EXPECT_CALL (releasable, doRelease (7)); |
946 | + |
947 | + lock->unlock (); |
948 | +} |
949 | + |
950 | +TEST_F(CompQueuesTestQueues, TestReleaseWithLockNoUnlock) |
951 | +{ |
952 | + boost::shared_ptr <impl::AccumulatedMapStorage <int> > actualStorage (new impl::AccumulatedMapStorage <int> ()); |
953 | + boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ()); |
954 | + |
955 | + mockStorage->Delegate (static_cast <QueueStorageInterface <int> *> (actualStorage.get ())); |
956 | + |
957 | + impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage)); |
958 | + QueueLockGeneratorDelegate <impl::QueueLock> gen (static_cast <QueueUnlockInterface *> (&q)); |
959 | + StrictMock <MockPendingItems> pi; |
960 | + |
961 | + MockQueue <int> mq; |
962 | + |
963 | + mq.Delegate (&q, &gen); |
964 | + |
965 | + boost::function <void (QueueReleaseInterface *)> callback (boost::bind (&PendingItemsInterface::pending, static_cast <PendingItemsInterface *> (&pi), _1)); |
966 | + |
967 | + EXPECT_CALL (mq, doObtainLock (_)); |
968 | + |
969 | + QueueLockInterface::Ptr lock (mq.obtainLock (callback)); |
970 | + |
971 | + StrictMock <MockQueueReleasable <int> > releasable; |
972 | + |
973 | + releasable.DelegateToFake (); |
974 | + |
975 | + EXPECT_CALL (releasable, doSetRemoveInterface (_)); |
976 | + EXPECT_CALL (*mockStorage, doStore (_, 7)); |
977 | + EXPECT_CALL (*mockStorage, doRemoveReleasable (_)); |
978 | + EXPECT_CALL (pi, doPending (_)); |
979 | + |
980 | + q.addPending (7, &releasable); |
981 | +} |
982 | + |
983 | +TEST_F(CompQueuesTestQueues, TestRemoveReleasableLocked) |
984 | +{ |
985 | + boost::shared_ptr <impl::AccumulatedMapStorage <int> > actualStorage (new impl::AccumulatedMapStorage <int> ()); |
986 | + boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ()); |
987 | + |
988 | + mockStorage->Delegate (static_cast <QueueStorageInterface <int> *> (actualStorage.get ())); |
989 | + |
990 | + impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage)); |
991 | + QueueLockGeneratorDelegate <impl::QueueLock> gen (static_cast <QueueUnlockInterface *> (&q)); |
992 | + StrictMock <MockPendingItems> pi; |
993 | + |
994 | + MockQueue <int> mq; |
995 | + |
996 | + mq.Delegate (&q, &gen); |
997 | + |
998 | + boost::function <void (QueueReleaseInterface *)> callback (boost::bind (&PendingItemsInterface::pending, static_cast <PendingItemsInterface *> (&pi), _1)); |
999 | + |
1000 | + EXPECT_CALL (mq, doObtainLock (_)); |
1001 | + |
1002 | + QueueLockInterface::Ptr lock (mq.obtainLock (callback)); |
1003 | + |
1004 | + boost::shared_ptr <StrictMock <MockQueueReleasable <int> > > releasable (new StrictMock <MockQueueReleasable <int> > ()); |
1005 | + |
1006 | + releasable->DelegateToFake (); |
1007 | + |
1008 | + EXPECT_CALL (*releasable, doSetRemoveInterface (_)); |
1009 | + EXPECT_CALL (*mockStorage, doStore (_, 7)); |
1010 | + EXPECT_CALL (*mockStorage, doRemoveReleasable (_)); |
1011 | + EXPECT_CALL (pi, doPending (_)); |
1012 | + |
1013 | + q.addPending (7, releasable.get ()); |
1014 | + |
1015 | + releasable.reset (); |
1016 | + |
1017 | + EXPECT_CALL (*mockStorage, doRelease ()); |
1018 | + |
1019 | + lock->unlock (); |
1020 | +} |
1021 | + |
1022 | +TEST_F(CompQueuesTestQueues, TestAccumulation) |
1023 | +{ |
1024 | + boost::shared_ptr <impl::AccumulatedMapStorage <int> > actualStorage (new impl::AccumulatedMapStorage <int> ()); |
1025 | + boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ()); |
1026 | + |
1027 | + mockStorage->Delegate (static_cast <QueueStorageInterface <int> *> (actualStorage.get ())); |
1028 | + |
1029 | + impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage)); |
1030 | + QueueLockGeneratorDelegate <impl::QueueLock> gen (static_cast <QueueUnlockInterface *> (&q)); |
1031 | + StrictMock <MockPendingItems> pi; |
1032 | + |
1033 | + MockQueue <int> mq; |
1034 | + |
1035 | + mq.Delegate (&q, &gen); |
1036 | + |
1037 | + boost::function <void (QueueReleaseInterface *)> callback (boost::bind (&PendingItemsInterface::pending, static_cast <PendingItemsInterface *> (&pi), _1)); |
1038 | + |
1039 | + EXPECT_CALL (mq, doObtainLock (_)); |
1040 | + |
1041 | + QueueLockInterface::Ptr lock (mq.obtainLock (callback)); |
1042 | + |
1043 | + StrictMock <MockQueueReleasable <int> > releasable; |
1044 | + |
1045 | + releasable.DelegateToFake (); |
1046 | + |
1047 | + EXPECT_CALL (releasable, doSetRemoveInterface (_)).Times (3); |
1048 | + EXPECT_CALL (*mockStorage, doStore (_, 7)); |
1049 | + EXPECT_CALL (*mockStorage, doStore (_, 8)); |
1050 | + EXPECT_CALL (*mockStorage, doStore (_, 9)); |
1051 | + EXPECT_CALL (*mockStorage, doRemoveReleasable (_)); |
1052 | + EXPECT_CALL (pi, doPending (_)).Times (3); |
1053 | + |
1054 | + q.addPending (7, &releasable); |
1055 | + q.addPending (8, &releasable); |
1056 | + q.addPending (9, &releasable); |
1057 | + |
1058 | + EXPECT_CALL (*mockStorage, doRelease ()); |
1059 | + EXPECT_CALL (releasable, doRelease (24)); |
1060 | + |
1061 | + lock->unlock (); |
1062 | +} |
1063 | |
1064 | === added file 'src/queues/tests/test-queues.cpp' |
1065 | --- src/queues/tests/test-queues.cpp 1970-01-01 00:00:00 +0000 |
1066 | +++ src/queues/tests/test-queues.cpp 2012-04-02 15:10:24 +0000 |
1067 | @@ -0,0 +1,34 @@ |
1068 | +/* |
1069 | + * Copyright © 2011 Canonical Ltd. |
1070 | + * |
1071 | + * Permission to use, copy, modify, distribute, and sell this software |
1072 | + * and its documentation for any purpose is hereby granted without |
1073 | + * fee, provided that the above copyright notice appear in all copies |
1074 | + * and that both that copyright notice and this permission notice |
1075 | + * appear in supporting documentation, and that the name of |
1076 | + * Canonical Ltd. not be used in advertising or publicity pertaining to |
1077 | + * distribution of the software without specific, written prior permission. |
1078 | + * Canonical Ltd. makes no representations about the suitability of this |
1079 | + * software for any purpose. It is provided "as is" without express or |
1080 | + * implied warranty. |
1081 | + * |
1082 | + * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
1083 | + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN |
1084 | + * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
1085 | + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS |
1086 | + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
1087 | + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION |
1088 | + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
1089 | + * |
1090 | + * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com> |
1091 | + */ |
1092 | + |
1093 | +#include "test-queues.h" |
1094 | + |
1095 | +CompQueuesTest::CompQueuesTest () |
1096 | +{ |
1097 | +} |
1098 | + |
1099 | +CompQueuesTest::~CompQueuesTest () |
1100 | +{ |
1101 | +} |
1102 | |
1103 | === added file 'src/queues/tests/test-queues.h' |
1104 | --- src/queues/tests/test-queues.h 1970-01-01 00:00:00 +0000 |
1105 | +++ src/queues/tests/test-queues.h 2012-04-02 15:10:24 +0000 |
1106 | @@ -0,0 +1,208 @@ |
1107 | +/* |
1108 | + * Copyright © 2011 Canonical Ltd. |
1109 | + * |
1110 | + * Permission to use, copy, modify, distribute, and sell this software |
1111 | + * and its documentation for any purpose is hereby granted without |
1112 | + * fee, provided that the above copyright notice appear in all copies |
1113 | + * and that both that copyright notice and this permission notice |
1114 | + * appear in supporting documentation, and that the name of |
1115 | + * Canonical Ltd. not be used in advertising or publicity pertaining to |
1116 | + * distribution of the software without specific, written prior permission. |
1117 | + * Canonical Ltd. makes no representations about the suitability of this |
1118 | + * software for any purpose. It is provided "as is" without express or |
1119 | + * implied warranty. |
1120 | + * |
1121 | + * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
1122 | + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN |
1123 | + * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
1124 | + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS |
1125 | + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
1126 | + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION |
1127 | + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
1128 | + * |
1129 | + * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com> |
1130 | + */ |
1131 | + |
1132 | +#ifndef _COMPIZ_TEST_QUEUES_H |
1133 | +#define _COMPIZ_TEST_QUEUES_H |
1134 | + |
1135 | +#include <gmock/gmock.h> |
1136 | +#include <gtest/gtest.h> |
1137 | +#include <core/queues.h> |
1138 | +#include <iostream> |
1139 | +#include <boost/bind.hpp> |
1140 | + |
1141 | +using ::testing::Invoke; |
1142 | +using ::testing::_; |
1143 | +using ::testing::StrictMock; |
1144 | +using ::testing::AtLeast; |
1145 | + |
1146 | +class CompQueuesTest : public ::testing::Test |
1147 | +{ |
1148 | +public: |
1149 | + |
1150 | + CompQueuesTest (); |
1151 | + virtual ~CompQueuesTest (); |
1152 | + |
1153 | +}; |
1154 | + |
1155 | +using namespace compiz::queues; |
1156 | + |
1157 | +class MockQueueReleaseRemovable : |
1158 | + public QueueReleaseRemoveInterface |
1159 | +{ |
1160 | + public: |
1161 | + |
1162 | + |
1163 | +}; |
1164 | + |
1165 | +class ReleaseRemovableDelegate : |
1166 | + public QueueReleaseInterface |
1167 | +{ |
1168 | + public: |
1169 | + |
1170 | + ReleaseRemovableDelegate (void *releasable) : |
1171 | + mReleasable (releasable) |
1172 | + { |
1173 | + } |
1174 | + |
1175 | + ~ReleaseRemovableDelegate () |
1176 | + { |
1177 | + if (mInterface) |
1178 | + mInterface->removeReleasable (static_cast <QueueReleaseInterface *> (mReleasable)); |
1179 | + } |
1180 | + |
1181 | + void doSetRemoveInterface (QueueReleaseRemoveInterface *interface) |
1182 | + { |
1183 | + mInterface = interface; |
1184 | + } |
1185 | + |
1186 | + private: |
1187 | + |
1188 | + QueueReleaseRemoveInterface *mInterface; |
1189 | + void *mReleasable; |
1190 | +}; |
1191 | + |
1192 | +template <class T> |
1193 | +class MockQueueReleasable : |
1194 | + public QueueReleasableInterface <T> |
1195 | +{ |
1196 | + public: |
1197 | + |
1198 | + MOCK_METHOD1_T (doSetRemoveInterface, void (QueueReleaseRemoveInterface *)); |
1199 | + MOCK_METHOD1_T (doRelease, bool (const T &)); |
1200 | + |
1201 | + MockQueueReleasable () : |
1202 | + mRemovableDelegate (this) |
1203 | + { |
1204 | + } |
1205 | + |
1206 | + void DelegateToFake () |
1207 | + { |
1208 | + ON_CALL (*this, doSetRemoveInterface (_)).WillByDefault (Invoke (&mRemovableDelegate, &ReleaseRemovableDelegate::doSetRemoveInterface)); |
1209 | + } |
1210 | + |
1211 | + private: |
1212 | + |
1213 | + ReleaseRemovableDelegate mRemovableDelegate; |
1214 | +}; |
1215 | + |
1216 | +class MockQueueLock : |
1217 | + public QueueLockInterface |
1218 | +{ |
1219 | + public: |
1220 | + |
1221 | + MOCK_METHOD0 (doUnlock, bool ()); |
1222 | + MOCK_METHOD0 (doCallback, void ()); |
1223 | +}; |
1224 | + |
1225 | +class MockQueueUnlockable : |
1226 | + public QueueUnlockInterface |
1227 | +{ |
1228 | + public: |
1229 | + |
1230 | + MOCK_METHOD0 (doRelease, void ()); |
1231 | + MOCK_METHOD1 (doRegisterLock, bool (QueueLockInterface *)); |
1232 | + MOCK_METHOD1 (doUnregisterLock, bool (QueueLockInterface *)); |
1233 | +}; |
1234 | + |
1235 | +template <class T> |
1236 | +class QueueLockGeneratorDelegate : |
1237 | + public QueueLockGeneratorInterface |
1238 | +{ |
1239 | + public: |
1240 | + |
1241 | + QueueLockGeneratorDelegate (QueueUnlockInterface *unlockable) : |
1242 | + mUnlockable (unlockable) |
1243 | + { |
1244 | + } |
1245 | + |
1246 | + boost::shared_ptr <QueueLockInterface> doObtainLock (const pendingItemsFunc &f) |
1247 | + { |
1248 | + return typename boost::shared_ptr <T> (new T (mUnlockable, f)); |
1249 | + } |
1250 | + |
1251 | + private: |
1252 | + |
1253 | + QueueUnlockInterface *mUnlockable; |
1254 | +}; |
1255 | + |
1256 | +class PendingItemsInterface |
1257 | +{ |
1258 | + public: |
1259 | + |
1260 | + void pending (QueueReleaseInterface *lock) { doPending (lock); } |
1261 | + |
1262 | + protected: |
1263 | + |
1264 | + virtual void doPending (QueueReleaseInterface *lock) = 0; |
1265 | +}; |
1266 | + |
1267 | +class MockPendingItems : |
1268 | + public PendingItemsInterface |
1269 | +{ |
1270 | + public: |
1271 | + |
1272 | + MOCK_METHOD1 (doPending, void (QueueReleaseInterface *)); |
1273 | +}; |
1274 | + |
1275 | +template <class T> |
1276 | +class MockQueue : |
1277 | + public QueueInterface <T>, |
1278 | + public QueueLockGeneratorInterface |
1279 | +{ |
1280 | + public: |
1281 | + |
1282 | + MOCK_METHOD2_T (doAddPending, void (const T &, QueueReleasableInterface <T> *r)); |
1283 | + MOCK_METHOD1_T (doObtainLock, boost::shared_ptr <QueueLockInterface> (const pendingItemsFunc &)); |
1284 | + |
1285 | + |
1286 | + void Delegate (QueueInterface <T> *queue, QueueLockGeneratorInterface *gen) |
1287 | + { |
1288 | + if (queue) |
1289 | + ON_CALL (*this, doAddPending (_, _)).WillByDefault (Invoke (static_cast <QueueInterface <T> *> (queue), &QueueInterface <T>::addPending)); |
1290 | + |
1291 | + if (gen) |
1292 | + ON_CALL (*this, doObtainLock (_)).WillByDefault (Invoke (static_cast <QueueLockGeneratorInterface *> (gen), &QueueLockGeneratorInterface::obtainLock)); |
1293 | + } |
1294 | +}; |
1295 | + |
1296 | +template <class T> |
1297 | +class MockQueueStorage : |
1298 | + public QueueStorageInterface <T> |
1299 | +{ |
1300 | + public: |
1301 | + |
1302 | + MOCK_METHOD1_T (doRemoveReleasable, void (QueueReleaseInterface *)); |
1303 | + MOCK_METHOD2_T (doStore, bool (QueueReleasableInterface <T> *, const T &)); |
1304 | + MOCK_METHOD0_T (doRelease, void ()); |
1305 | + |
1306 | + void Delegate (QueueStorageInterface <T> *storage) |
1307 | + { |
1308 | + ON_CALL (*this, doRemoveReleasable (_)).WillByDefault (Invoke (storage, &QueueStorageInterface<T>::removeReleasable)); |
1309 | + ON_CALL (*this, doStore (_, _)).WillByDefault (Invoke (storage, &QueueStorageInterface<T>::store)); |
1310 | + ON_CALL (*this, doRelease ()).WillByDefault (Invoke (storage, &QueueStorageInterface<T>::release)); |
1311 | + } |
1312 | +}; |
1313 | + |
1314 | +#endif |
Again, I can't endorse a major rewrite of critical functionality this late.