]> git.mxchange.org Git - simgear.git/blob - simgear/bvh/BVHPager.cxx
Tweak HTTP code to always sleep.
[simgear.git] / simgear / bvh / BVHPager.cxx
1 // Copyright (C) 2008 - 2012  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17
18 #include "BVHPager.hxx"
19
20 #include <list>
21
22 #include <simgear/threads/SGThread.hxx>
23 #include <simgear/threads/SGGuard.hxx>
24
25 #include "BVHPageNode.hxx"
26 #include "BVHPageRequest.hxx"
27
28 namespace simgear {
29
30 struct BVHPager::_PrivateData : protected SGThread {
31     typedef SGSharedPtr<BVHPageRequest> _Request;
32     typedef std::list<_Request> _RequestList;
33     typedef std::list<SGSharedPtr<BVHPageNode> > _PageNodeList;
34     
35     struct _LockedQueue {
36         void _push(const _Request& request)
37         {
38             SGGuard<SGMutex> scopeLock(_mutex);
39             _requestList.push_back(request);
40         }
41         _Request _pop()
42         {
43             SGGuard<SGMutex> scopeLock(_mutex);
44             if (_requestList.empty())
45                 return _Request();
46             _Request request;
47             request.swap(_requestList.front());
48             _requestList.pop_front();
49             return request;
50         }
51     private:
52         SGMutex _mutex;
53         _RequestList _requestList;
54     };
55     
56     struct _WorkQueue {
57         void _stop()
58         {
59             _push(_Request());
60         }
61         void _push(const _Request& request)
62         {
63             SGGuard<SGMutex> scopeLock(_mutex);
64             bool needSignal = _requestList.empty();
65             _requestList.push_back(request);
66             if (needSignal)
67                 _waitCondition.signal();
68         }
69         _Request _pop()
70         {
71             SGGuard<SGMutex> scopeLock(_mutex);
72             while (_requestList.empty())
73                 _waitCondition.wait(_mutex);
74             _Request request;
75             request.swap(_requestList.front());
76             _requestList.pop_front();
77             return request;
78         }
79     private:
80         SGMutex _mutex;
81         SGWaitCondition _waitCondition;
82         _RequestList _requestList;
83     };
84
85     _PrivateData() :
86         _started(false),
87         _useStamp(0)
88     {
89     }
90     virtual ~_PrivateData()
91     {
92         _stop();
93     }
94
95     virtual void run()
96     {
97         for (;;) {
98             _Request request = _pendingRequests._pop();
99             // This means stop working
100             if (!request.valid())
101                 return;
102             request->load();
103             _processedRequests._push(request);
104         }
105     }
106
107     bool _start()
108     {
109         if (_started)
110             return true;
111         if (!start())
112             return false;
113         _started = true;
114         return true;
115     }
116     
117     void _stop()
118     {
119         if (!_started)
120             return;
121         // send a stop request ...
122         _pendingRequests._stop();
123         // ... and wait for the thread to finish
124         join();
125         _started = false;
126     }
127
128     void _use(BVHPageNode& pageNode)
129     {
130         if (pageNode._requested) {
131             // move it forward in the lru list
132             _pageNodeList.splice(_pageNodeList.end(), _pageNodeList,
133                                  pageNode._iterator);
134         } else {
135             _Request request = pageNode.newRequest();
136             if (!request.valid())
137                 return;
138
139             pageNode._iterator = _pageNodeList.insert(_pageNodeList.end(),
140                                                       &pageNode);
141             pageNode._requested = true;
142
143             if (_started) {
144                 _pendingRequests._push(request);
145             } else {
146                 request->load();
147                 request->insert();
148             }
149         }
150         pageNode._useStamp = _useStamp;
151     }
152
153     void _update(unsigned expiry)
154     {
155         // Insert all processed requests
156         for (;;) {
157             SGSharedPtr<BVHPageRequest> request;
158             request = _processedRequests._pop();
159             if (!request.valid())
160                 break;
161             request->insert();
162         }
163
164         // ... and throw away stuff that is not used for a long time
165         unsigned useStamp = _useStamp - expiry;
166         _PageNodeList::iterator i = _pageNodeList.begin();
167         while (i != _pageNodeList.end()) {
168             // Ok, this means if the highest bit in the below difference
169             // is set which is aequivalent to having a negative difference
170             // but being wraparound save.
171             unsigned diff = (*i)->_useStamp - useStamp;
172             // test the sign bit of the difference
173             if (!(diff & (~((~0u) >> 1))))
174                 break;
175             (*i)->clear();
176             (*i)->_requested = false;
177             i = _pageNodeList.erase(i);
178         }
179     }
180
181     bool _started;
182     unsigned _useStamp;
183     _WorkQueue _pendingRequests;
184     _LockedQueue _processedRequests;
185     // Store the rcu list of loaded nodes so that they can expire
186     _PageNodeList _pageNodeList;
187 };
188
189 BVHPager::BVHPager() :
190     _privateData(new _PrivateData)
191 {
192 }
193
194 BVHPager::~BVHPager()
195 {
196     delete _privateData;
197     _privateData = 0;
198 }
199
200 bool
201 BVHPager::start()
202 {
203     return _privateData->_start();
204 }
205
206 void
207 BVHPager::stop()
208 {
209     _privateData->_stop();
210 }
211
212 void
213 BVHPager::use(BVHPageNode& pageNode)
214 {
215     _privateData->_use(pageNode);
216 }
217
218 void
219 BVHPager::update(unsigned expiry)
220 {
221     _privateData->_update(expiry);
222 }
223
224 void
225 BVHPager::setUseStamp(unsigned stamp)
226 {
227     _privateData->_useStamp = stamp;
228 }
229
230 unsigned
231 BVHPager::getUseStamp() const
232 {
233     return _privateData->_useStamp;
234 }
235
236 }