fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / Contrib / BackgroundLoader / OSGBackgroundLoader.cpp
blob52c8309f03d53a589187970b7c648bd508f6f4fe
1 #include "OSGBackgroundLoader.h"
3 #include "OSGThreadManager.h"
4 #include "OSGBaseInitFunctions.h"
5 #include <boost/lexical_cast.hpp>
6 #include "OSGChangeList.h"
7 #include <boost/format.hpp>
9 #include "OSGSingletonHolder.ins"
11 OSG_BEGIN_NAMESPACE
13 OSG_SINGLETON_INST(BackgroundLoaderBase, addPostFactoryExitFunction)
15 BackgroundLoaderBase::BackgroundLoaderBase(void) :
16 mPendingRequests ( ),
17 mFinishedRequests( ),
18 mLoadThreads ( ),
19 mFinishedLock (NULL ),
20 mLoadCondVar (NULL ),
21 mStopRunning (false)
23 mStopRunning = false;
24 mFinishedLock = Lock ::get("BackgroundLoader-FinishedLock", false);
25 mLoadCondVar = CondVar::get("BackgroundLoader-CondVar", false);
28 BackgroundLoaderBase::~BackgroundLoaderBase(void)
30 stop();
32 mFinishedLock = NULL;
33 mLoadCondVar = NULL;
36 void BackgroundLoaderBase::stop(void)
38 if (mLoadThreads.size() > 0)
40 OSG_ASSERT(!mStopRunning &&
41 "BackgroundLoaderBase::stop() Already stopped, but thread "
42 "is not NULL");
44 mStopRunning = true;
46 mLoadCondVar->broadcast();
48 for(std::vector<ThreadRefPtr>::iterator itr = mLoadThreads.begin();
49 itr != mLoadThreads.end ();
50 ++itr )
52 Thread::join(*itr);
54 (*itr) = NULL;
57 mLoadThreads.clear();
61 void BackgroundLoaderBase::addRequest(RequestPtr req)
63 mLoadCondVar->acquire();
65 mPendingRequests.push_back(req);
67 mLoadCondVar->release();
68 mLoadCondVar->signal ();
71 void BackgroundLoaderBase::removeRequest(RequestPtr req)
73 mLoadCondVar->acquire();
74 request_queue_t::iterator found = std::find(mPendingRequests.begin(),
75 mPendingRequests.end (),
76 req );
77 if (found != mPendingRequests.end())
79 mPendingRequests.erase(found);
82 mLoadCondVar->release();
83 // XXX: We should not need this.
84 mLoadCondVar->signal ();
87 void BackgroundLoaderBase::start(const UInt16 numThreads)
89 OSG_ASSERT(0 == mLoadThreads.size() &&
90 "Can't have threads before starting.");
92 for(UInt16 i = 0; i < numThreads; i++)
94 ThreadRefPtr new_thread =
95 dynamic_pointer_cast<Thread>(ThreadManager::the()->getThread(NULL,
96 false));
98 new_thread->runFunction(static_cast<Thread::ThreadFuncF>(loadProc),
99 Thread::getCurrentAspect(), this);
101 mLoadThreads.push_back(new_thread);
105 void BackgroundLoaderBase::processOne(void)
107 OSG_ASSERT(0 == mLoadThreads.size() &&
108 "processOne can not be called with background thread active.");
110 mLoadCondVar->acquire();
112 if(! mPendingRequests.empty())
114 OSG_ASSERT(!mPendingRequests.empty());
116 // Get the pending request with the highest priority.
117 RequestPtr req = RequestPtr();
119 request_queue_t::iterator next_i =
120 std::min_element(mPendingRequests.begin(),
121 mPendingRequests.end (),
122 Request::comparePriority);
124 req = *next_i;
126 // Erase our request from the pending list.
127 mPendingRequests.erase(next_i);
129 if(NULL != req.get())
131 req->execute();
133 commitChanges();
135 mFinishedLock->acquire();
137 mFinishedRequests.push_back(req);
139 mFinishedLock->release();
143 mLoadCondVar->release();
146 unsigned BackgroundLoaderBase::getNumPendingRequests(void)
148 unsigned ret_val(0);
150 mLoadCondVar->acquire();
152 ret_val = unsigned(mPendingRequests.size());
154 mLoadCondVar->release();
156 return ret_val;
159 BackgroundLoaderBase::desc_list_t
160 BackgroundLoaderBase::getPendingDescriptionList(void)
162 BackgroundLoaderBase::desc_list_t ret_list;
164 mLoadCondVar->acquire();
166 for(request_queue_t::iterator i = mPendingRequests.begin();
167 i != mPendingRequests.end ();
168 ++i )
170 std::string desc = boost::str(boost::format("[%4.2f]: %s") %
171 (*i)->getPriority() %
172 (*i)->getDescription());
174 ret_list.push_back(desc);
177 mLoadCondVar->release();
179 return ret_list;
182 void BackgroundLoaderBase::loadProc(void *arg)
184 // Get a pointer to the singleton object.
185 BackgroundLoaderBase *the = reinterpret_cast<BackgroundLoaderBase *>(arg);
187 OSG_ASSERT(NULL != the && "Should have a pointer to BackgroundLoader.");
189 while(false == the->mStopRunning)
191 // Wait on a new request.
192 the->mLoadCondVar->acquire();
194 while(false == the->mStopRunning && the->mPendingRequests.empty())
196 the->mLoadCondVar->wait();
199 // Early out if we are exiting the loop.
200 if(the->mStopRunning)
202 continue;
205 OSG_ASSERT(!the->mPendingRequests.empty() &&
206 "Can't have empty pending list.");
208 // Get the pending request with the highest priority.
209 RequestPtr req = RequestPtr();
211 request_queue_t::iterator next_i =
212 std::min_element(the->mPendingRequests.begin(),
213 the->mPendingRequests.end (),
214 Request::comparePriority );
216 req = *next_i;
218 // Erase our request from the pending list.
219 the->mPendingRequests.erase(next_i);
221 // Now that we have a request to process, release condition variable.
222 the->mLoadCondVar->release();
224 // If we have a valid request, execute it and commit changes.
225 if(NULL != req.get())
229 req->execute();
231 catch (std::exception& ex)
233 std::cout << "ERROR: Exception thrown in execute: "
234 << ex.what()
235 << std::endl;
237 catch(...)
239 std::cout << "ERROR: Unknown exception thrown in execute."
240 << std::endl;
243 // Commit our changes to our aspect (shared) and clear out change list
244 // since we don't need it around any more.
245 // OSG::commitChanges();
246 //OSG::Thread::getCurrentChangeList()->commitChangesAndClear();
248 the->mFinishedLock->acquire();
250 the->mFinishedRequests.push_back(req);
252 the->mFinishedLock->release();
257 void BackgroundLoaderBase::sync(unsigned reqLimit)
259 mFinishedLock->acquire();
261 if(0 == reqLimit)
263 reqLimit = unsigned(mFinishedRequests.size());
266 while((!mFinishedRequests.empty()) && (reqLimit-- != 0))
268 RequestPtr req = mFinishedRequests.front();
269 mFinishedRequests.pop_front();
273 req->sync();
275 catch (std::exception& ex)
277 std::cout << "ERROR: Exception thrown in sync: "
278 << ex.what()
279 << std::endl;
281 catch(...)
283 std::cout << "ERROR: Unknown exception thrown in sync." << std::endl;
286 req->mCompleted = true;
289 // XXX: Don't know if this is needed to keep the change list from growing
290 //out of control.
291 //OSG::Thread::getCurrentChangeList()->commitChangesAndClear();
293 mFinishedLock->release();
296 OSG_END_NAMESPACE