blob: 55515282526d783953582963f495b6762fc5a9e4 [file] [log] [blame]
Roger Meier3faaedf2011-10-02 10:51:45 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23#include "BoostThreadFactory.h"
24#include "Exception.h"
25
26#include <cassert>
27
28#include <boost/weak_ptr.hpp>
29#include <boost/thread.hpp>
30
31namespace apache { namespace thrift { namespace concurrency {
32
33using boost::shared_ptr;
34using boost::weak_ptr;
35
36/**
37 * The boost thread class.
38 *
39 * @version $Id:$
40 */
41class BoostThread: public Thread {
42 public:
43
44 enum STATE {
45 uninitialized,
46 starting,
47 started,
48 stopping,
49 stopped
50 };
51
52 static void* threadMain(void* arg);
53
54 private:
55 std::auto_ptr<boost::thread> thread_;
56 STATE state_;
57 weak_ptr<BoostThread> self_;
58 bool detached_;
59
60 public:
61
62 BoostThread(bool detached, shared_ptr<Runnable> runnable) :
63 state_(uninitialized),
64 detached_(detached) {
65 this->Thread::runnable(runnable);
66 }
67
68 ~BoostThread() {
69 if(!detached_) {
70 try {
71 join();
72 } catch(...) {
73 // We're really hosed.
74 }
75 }
76 }
77
78 void start() {
79 if (state_ != uninitialized) {
80 return;
81 }
82
83 // Create reference
84 shared_ptr<BoostThread>* selfRef = new shared_ptr<BoostThread>();
85 *selfRef = self_.lock();
86
87 thread_ = std::auto_ptr<boost::thread>(new boost::thread(boost::bind(threadMain, (void*)selfRef)));
88
89 if(detached_)
90 thread_->detach();
91
92 state_ = starting;
93 }
94
95 void join() {
96 if (!detached_ && state_ != uninitialized) {
97 thread_->join();
98 }
99 }
100
101 Thread::id_t getId() {
102 return thread_.get() ? thread_->get_id() : boost::thread::id();
103 }
104
105 shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
106
107 void runnable(shared_ptr<Runnable> value) { Thread::runnable(value); }
108
109 void weakRef(shared_ptr<BoostThread> self) {
110 assert(self.get() == this);
111 self_ = weak_ptr<BoostThread>(self);
112 }
113};
114
115void* BoostThread::threadMain(void* arg) {
116 shared_ptr<BoostThread> thread = *(shared_ptr<BoostThread>*)arg;
117 delete reinterpret_cast<shared_ptr<BoostThread>*>(arg);
118
119 if (thread == NULL) {
120 return (void*)0;
121 }
122
123 if (thread->state_ != starting) {
124 return (void*)0;
125 }
126
127 thread->state_ = started;
128 thread->runnable()->run();
129
130 if (thread->state_ != stopping && thread->state_ != stopped) {
131 thread->state_ = stopping;
132 }
133 return (void*)0;
134}
135
136/**
137 * POSIX Thread factory implementation
138 */
139class BoostThreadFactory::Impl {
140
141 private:
142 bool detached_;
143
144 public:
145
146 Impl(bool detached) :
147 detached_(detached) {}
148
149 /**
150 * Creates a new POSIX thread to run the runnable object
151 *
152 * @param runnable A runnable object
153 */
154 shared_ptr<Thread> newThread(shared_ptr<Runnable> runnable) const {
155 shared_ptr<BoostThread> result = shared_ptr<BoostThread>(new BoostThread(detached_, runnable));
156 result->weakRef(result);
157 runnable->thread(result);
158 return result;
159 }
160
161 bool isDetached() const { return detached_; }
162
163 void setDetached(bool value) { detached_ = value; }
164
165 Thread::id_t getCurrentThreadId() const {
166 return boost::this_thread::get_id();
167 }
168
169};
170
171BoostThreadFactory::BoostThreadFactory(bool detached) :
172 impl_(new BoostThreadFactory::Impl(detached)) {}
173
174shared_ptr<Thread> BoostThreadFactory::newThread(shared_ptr<Runnable> runnable) const { return impl_->newThread(runnable); }
175
176bool BoostThreadFactory::isDetached() const { return impl_->isDetached(); }
177
178void BoostThreadFactory::setDetached(bool value) { impl_->setDetached(value); }
179
180Thread::id_t BoostThreadFactory::getCurrentThreadId() const { return impl_->getCurrentThreadId(); }
181
182}}} // apache::thrift::concurrency