| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| #include "BoostThreadFactory.h" |
| #include "Exception.h" |
| |
| #include <cassert> |
| |
| #include <boost/weak_ptr.hpp> |
| #include <boost/thread.hpp> |
| |
| namespace apache { namespace thrift { namespace concurrency { |
| |
| using boost::shared_ptr; |
| using boost::weak_ptr; |
| |
| /** |
| * The boost thread class. |
| * |
| * @version $Id:$ |
| */ |
| class BoostThread: public Thread { |
| public: |
| |
| enum STATE { |
| uninitialized, |
| starting, |
| started, |
| stopping, |
| stopped |
| }; |
| |
| static void* threadMain(void* arg); |
| |
| private: |
| std::auto_ptr<boost::thread> thread_; |
| STATE state_; |
| weak_ptr<BoostThread> self_; |
| bool detached_; |
| |
| public: |
| |
| BoostThread(bool detached, shared_ptr<Runnable> runnable) : |
| state_(uninitialized), |
| detached_(detached) { |
| this->Thread::runnable(runnable); |
| } |
| |
| ~BoostThread() { |
| if(!detached_) { |
| try { |
| join(); |
| } catch(...) { |
| // We're really hosed. |
| } |
| } |
| } |
| |
| void start() { |
| if (state_ != uninitialized) { |
| return; |
| } |
| |
| // Create reference |
| shared_ptr<BoostThread>* selfRef = new shared_ptr<BoostThread>(); |
| *selfRef = self_.lock(); |
| |
| thread_ = std::auto_ptr<boost::thread>(new boost::thread(boost::bind(threadMain, (void*)selfRef))); |
| |
| if(detached_) |
| thread_->detach(); |
| |
| state_ = starting; |
| } |
| |
| void join() { |
| if (!detached_ && state_ != uninitialized) { |
| thread_->join(); |
| } |
| } |
| |
| Thread::id_t getId() { |
| return thread_.get() ? thread_->get_id() : boost::thread::id(); |
| } |
| |
| shared_ptr<Runnable> runnable() const { return Thread::runnable(); } |
| |
| void runnable(shared_ptr<Runnable> value) { Thread::runnable(value); } |
| |
| void weakRef(shared_ptr<BoostThread> self) { |
| assert(self.get() == this); |
| self_ = weak_ptr<BoostThread>(self); |
| } |
| }; |
| |
| void* BoostThread::threadMain(void* arg) { |
| shared_ptr<BoostThread> thread = *(shared_ptr<BoostThread>*)arg; |
| delete reinterpret_cast<shared_ptr<BoostThread>*>(arg); |
| |
| if (thread == NULL) { |
| return (void*)0; |
| } |
| |
| if (thread->state_ != starting) { |
| return (void*)0; |
| } |
| |
| thread->state_ = started; |
| thread->runnable()->run(); |
| |
| if (thread->state_ != stopping && thread->state_ != stopped) { |
| thread->state_ = stopping; |
| } |
| return (void*)0; |
| } |
| |
| /** |
| * POSIX Thread factory implementation |
| */ |
| class BoostThreadFactory::Impl { |
| |
| private: |
| bool detached_; |
| |
| public: |
| |
| Impl(bool detached) : |
| detached_(detached) {} |
| |
| /** |
| * Creates a new POSIX thread to run the runnable object |
| * |
| * @param runnable A runnable object |
| */ |
| shared_ptr<Thread> newThread(shared_ptr<Runnable> runnable) const { |
| shared_ptr<BoostThread> result = shared_ptr<BoostThread>(new BoostThread(detached_, runnable)); |
| result->weakRef(result); |
| runnable->thread(result); |
| return result; |
| } |
| |
| bool isDetached() const { return detached_; } |
| |
| void setDetached(bool value) { detached_ = value; } |
| |
| Thread::id_t getCurrentThreadId() const { |
| return boost::this_thread::get_id(); |
| } |
| |
| }; |
| |
| BoostThreadFactory::BoostThreadFactory(bool detached) : |
| impl_(new BoostThreadFactory::Impl(detached)) {} |
| |
| shared_ptr<Thread> BoostThreadFactory::newThread(shared_ptr<Runnable> runnable) const { return impl_->newThread(runnable); } |
| |
| bool BoostThreadFactory::isDetached() const { return impl_->isDetached(); } |
| |
| void BoostThreadFactory::setDetached(bool value) { impl_->setDetached(value); } |
| |
| Thread::id_t BoostThreadFactory::getCurrentThreadId() const { return impl_->getCurrentThreadId(); } |
| |
| }}} // apache::thrift::concurrency |