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"
13 OSG_SINGLETON_INST(BackgroundLoaderBase
, addPostFactoryExitFunction
)
15 BackgroundLoaderBase::BackgroundLoaderBase(void) :
19 mFinishedLock (NULL
),
24 mFinishedLock
= Lock ::get("BackgroundLoader-FinishedLock", false);
25 mLoadCondVar
= CondVar::get("BackgroundLoader-CondVar", false);
28 BackgroundLoaderBase::~BackgroundLoaderBase(void)
36 void BackgroundLoaderBase::stop(void)
38 if (mLoadThreads
.size() > 0)
40 OSG_ASSERT(!mStopRunning
&&
41 "BackgroundLoaderBase::stop() Already stopped, but thread "
46 mLoadCondVar
->broadcast();
48 for(std::vector
<ThreadRefPtr
>::iterator itr
= mLoadThreads
.begin();
49 itr
!= mLoadThreads
.end ();
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 (),
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
,
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
);
126 // Erase our request from the pending list.
127 mPendingRequests
.erase(next_i
);
129 if(NULL
!= req
.get())
135 mFinishedLock
->acquire();
137 mFinishedRequests
.push_back(req
);
139 mFinishedLock
->release();
143 mLoadCondVar
->release();
146 unsigned BackgroundLoaderBase::getNumPendingRequests(void)
150 mLoadCondVar
->acquire();
152 ret_val
= unsigned(mPendingRequests
.size());
154 mLoadCondVar
->release();
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 ();
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();
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
)
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
);
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())
231 catch (std::exception
& ex
)
233 std::cout
<< "ERROR: Exception thrown in execute: "
239 std::cout
<< "ERROR: Unknown exception thrown in execute."
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();
263 reqLimit
= unsigned(mFinishedRequests
.size());
266 while((!mFinishedRequests
.empty()) && (reqLimit
-- != 0))
268 RequestPtr req
= mFinishedRequests
.front();
269 mFinishedRequests
.pop_front();
275 catch (std::exception
& ex
)
277 std::cout
<< "ERROR: Exception thrown in sync: "
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
291 //OSG::Thread::getCurrentChangeList()->commitChangesAndClear();
293 mFinishedLock
->release();