summaryrefslogtreecommitdiff
path: root/util/background.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'util/background.cpp')
-rw-r--r--util/background.cpp146
1 files changed, 74 insertions, 72 deletions
diff --git a/util/background.cpp b/util/background.cpp
index ec5483c..746d14c 100644
--- a/util/background.cpp
+++ b/util/background.cpp
@@ -1,4 +1,4 @@
-//background.cpp
+// @file background.cpp
/* Copyright 2009 10gen Inc.
*
@@ -16,103 +16,105 @@
*/
#include "pch.h"
-#include "goodies.h"
+
+#include "concurrency/mutex.h"
+
#include "background.h"
-#include <list>
+
+#include "mongoutils/str.h"
namespace mongo {
- BackgroundJob *BackgroundJob::grab = 0;
- mongo::mutex BackgroundJob::mutex("BackgroundJob");
+ // both the BackgroundJob and the internal thread point to JobStatus
+ struct BackgroundJob::JobStatus {
+ JobStatus( bool delFlag )
+ : deleteSelf(delFlag), m("backgroundJob"), state(NotStarted) { }
- /* static */
- void BackgroundJob::thr() {
- assert( grab );
- BackgroundJob *us = grab;
- assert( us->state == NotStarted );
- us->state = Running;
- grab = 0;
+ const bool deleteSelf;
+
+ mongo::mutex m; // protects state below
+ boost::condition finished; // means _state == Done
+ State state;
+ };
+
+ BackgroundJob::BackgroundJob( bool selfDelete ) {
+ _status.reset( new JobStatus( selfDelete ) );
+ }
+ // Background object can be only be destroyed after jobBody() ran
+ void BackgroundJob::jobBody( boost::shared_ptr<JobStatus> status ) {
+ LOG(1) << "BackgroundJob starting: " << name() << endl;
{
- string nm = us->name();
- setThreadName(nm.c_str());
+ scoped_lock l( status->m );
+ massert( 13643 , mongoutils::str::stream() << "backgroundjob already started: " << name() , status->state == NotStarted );
+ status->state = Running;
}
+ const string threadName = name();
+ if( ! threadName.empty() )
+ setThreadName( threadName.c_str() );
+
try {
- us->run();
+ run();
}
- catch ( std::exception& e ){
- log( LL_ERROR ) << "backgroundjob error: " << e.what() << endl;
+ catch ( std::exception& e ) {
+ log( LL_ERROR ) << "backgroundjob " << name() << "error: " << e.what() << endl;
}
catch(...) {
- log( LL_ERROR ) << "uncaught exception in BackgroundJob" << endl;
+ log( LL_ERROR ) << "uncaught exception in BackgroundJob " << name() << endl;
+ }
+
+ {
+ scoped_lock l( status->m );
+ status->state = Done;
+ status->finished.notify_all();
}
- us->state = Done;
- bool delSelf = us->deleteSelf;
- us->ending();
- if( delSelf )
- delete us;
+
+ if( status->deleteSelf )
+ delete this;
}
BackgroundJob& BackgroundJob::go() {
- scoped_lock bl(mutex);
- assert( grab == 0 );
- grab = this;
- boost::thread t(thr);
- while ( grab )
- sleepmillis(2);
+ boost::thread t( boost::bind( &BackgroundJob::jobBody , this, _status ) );
return *this;
}
- bool BackgroundJob::wait(int msMax, unsigned maxsleep) {
- unsigned ms = 1;
- Date_t start = jsTime();
- while ( state != Done ) {
- sleepmillis(ms);
- if( ms*2<maxsleep ) ms*=2;
- if ( msMax && ( int( jsTime() - start ) > msMax) )
- return false;
+ bool BackgroundJob::wait( unsigned msTimeOut ) {
+ scoped_lock l( _status->m );
+ while ( _status->state != Done ) {
+ if ( msTimeOut ) {
+ // add msTimeOut millisecond to current time
+ boost::xtime xt;
+ boost::xtime_get( &xt, boost::TIME_UTC );
+
+ unsigned long long ns = msTimeOut * 1000000ULL; // milli to nano
+ if ( xt.nsec + ns < 1000000000 ) {
+ xt.nsec = (xtime::xtime_nsec_t) (xt.nsec + ns);
+ }
+ else {
+ xt.sec += 1 + ns / 1000000000;
+ xt.nsec = ( ns + xt.nsec ) % 1000000000;
+ }
+
+ if ( ! _status->finished.timed_wait( l.boost() , xt ) )
+ return false;
+
+ }
+ else {
+ _status->finished.wait( l.boost() );
+ }
}
return true;
}
- void BackgroundJob::go(list<BackgroundJob*>& L) {
- for( list<BackgroundJob*>::iterator i = L.begin(); i != L.end(); i++ )
- (*i)->go();
+ BackgroundJob::State BackgroundJob::getState() const {
+ scoped_lock l( _status->m);
+ return _status->state;
}
- /* wait for several jobs to finish. */
- void BackgroundJob::wait(list<BackgroundJob*>& L, unsigned maxsleep) {
- unsigned ms = 1;
- {
- x:
- sleepmillis(ms);
- if( ms*2<maxsleep ) ms*=2;
- for( list<BackgroundJob*>::iterator i = L.begin(); i != L.end(); i++ ) {
- assert( (*i)->state != NotStarted );
- if( (*i)->state != Done )
- goto x;
- }
- }
- }
-
- void PeriodicBackgroundJob::run(){
- // want to handle first one differently so inShutdown is obeyed nicely
- sleepmillis( _millis );
-
- while ( ! inShutdown() ){
- try {
- runLoop();
- }
- catch ( std::exception& e ){
- log( LL_ERROR ) << "PeriodicBackgroundJob [" << name() << "] error: " << e.what() << endl;
- }
- catch ( ... ){
- log( LL_ERROR ) << "PeriodicBackgroundJob [" << name() << "] unknown error" << endl;
- }
-
- sleepmillis( _millis );
- }
+ bool BackgroundJob::running() const {
+ scoped_lock l( _status->m);
+ return _status->state == Running;
}
} // namespace mongo