summaryrefslogtreecommitdiff
path: root/src/mongo/util/background.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/background.h')
-rw-r--r--src/mongo/util/background.h155
1 files changed, 155 insertions, 0 deletions
diff --git a/src/mongo/util/background.h b/src/mongo/util/background.h
new file mode 100644
index 00000000000..496a1f44f88
--- /dev/null
+++ b/src/mongo/util/background.h
@@ -0,0 +1,155 @@
+// @file background.h
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "concurrency/spin_lock.h"
+
+namespace mongo {
+
+ /**
+ * Background thread dispatching.
+ * subclass and define run()
+ *
+ * It is ok to call go(), that is, run the job, more than once -- if the
+ * previous invocation has finished. Thus one pattern of use is to embed
+ * a backgroundjob in your object and reuse it (or same thing with
+ * inheritance). Each go() call spawns a new thread.
+ *
+ * Thread safety:
+ * note when job destructs, the thread is not terminated if still running.
+ * generally if the thread could still be running, allocate the job dynamically
+ * and set deleteSelf to true.
+ *
+ * go() and wait() are not thread safe
+ * run() will be executed on the background thread
+ * BackgroundJob object must exist for as long the background thread is running
+ */
+
+ class BackgroundJob : boost::noncopyable {
+ protected:
+ /**
+ * sub-class must intantiate the BackgrounJob
+ *
+ * @param selfDelete if set to true, object will destruct itself after the run() finished
+ * @note selfDelete instantes cannot be wait()-ed upon
+ */
+ explicit BackgroundJob(bool selfDelete = false);
+
+ virtual string name() const = 0;
+
+ /**
+ * define this to do your work.
+ * after this returns, state is set to done.
+ * after this returns, deleted if deleteSelf true.
+ *
+ * NOTE:
+ * if run() throws, the exception will be caught within 'this' object and will ultimately lead to the
+ * BackgroundJob's thread being finished, as if run() returned.
+ *
+ */
+ virtual void run() = 0;
+
+ public:
+ enum State {
+ NotStarted,
+ Running,
+ Done
+ };
+
+ virtual ~BackgroundJob() { }
+
+ /**
+ * starts job.
+ * returns immediatelly after dispatching.
+ *
+ * @note the BackgroundJob object must live for as long the thread is still running, ie
+ * until getState() returns Done.
+ */
+ BackgroundJob& go();
+
+ /**
+ * wait for completion.
+ *
+ * @param msTimeOut maximum amount of time to wait in millisecons
+ * @return true if did not time out. false otherwise.
+ *
+ * @note you can call wait() more than once if the first call times out.
+ * but you cannot call wait on a self-deleting job.
+ */
+ bool wait( unsigned msTimeOut = 0 );
+
+ // accessors
+ State getState() const;
+ bool running() const;
+
+ private:
+ struct JobStatus;
+ boost::shared_ptr<JobStatus> _status; // shared between 'this' and body() thread
+
+ void jobBody( boost::shared_ptr<JobStatus> status );
+
+ };
+
+ /**
+ * these run "roughly" every minute
+ * instantiate statically
+ * class MyTask : public PeriodicTask {
+ * public:
+ * virtual string name() const { return "MyTask; " }
+ * virtual void doWork() { log() << "hi" << endl; }
+ * } myTask;
+ */
+ class PeriodicTask {
+ public:
+ PeriodicTask();
+ virtual ~PeriodicTask();
+
+ virtual void taskDoWork() = 0;
+ virtual string taskName() const = 0;
+
+ class Runner : public BackgroundJob {
+ public:
+ virtual ~Runner(){}
+
+ virtual string name() const { return "PeriodicTask::Runner"; }
+
+ virtual void run();
+
+ void add( PeriodicTask* task );
+ void remove( PeriodicTask* task );
+
+ private:
+
+ SpinLock _lock;
+
+ // these are NOT owned by Runner
+ // Runner will not delete these
+ // this never gets smaller
+ // only fields replaced with nulls
+ vector<PeriodicTask*> _tasks;
+
+ };
+
+ static Runner* theRunner;
+
+ };
+
+
+
+
+} // namespace mongo