/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ #include #include #include #include #include #include #include #include #include "thread.hxx" #include "jobqueue.hxx" #include "threadpool.hxx" namespace { namespace css = com::sun::star; } using namespace osl; namespace cppu_threadpool { // ---------------------------------------------------------------------------------- ThreadAdmin::ThreadAdmin(): m_disposed(false) {} ThreadAdmin::~ThreadAdmin() { #if OSL_DEBUG_LEVEL > 1 if( m_lst.size() ) { fprintf( stderr, "%lu Threads left\n" , static_cast(m_lst.size()) ); } #endif } void ThreadAdmin::add( rtl::Reference< ORequestThread > const & p ) { MutexGuard aGuard( m_mutex ); if( m_disposed ) { throw css::lang::DisposedException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cppu_threadpool::ORequestThread created after" " cppu_threadpool::ThreadAdmin has been disposed")), css::uno::Reference< css::uno::XInterface >()); } m_lst.push_back( p ); } void ThreadAdmin::remove_locked( rtl::Reference< ORequestThread > const & p ) { ::std::list< rtl::Reference< ORequestThread > >::iterator ii = ::std::find( m_lst.begin(), m_lst.end(), p ); if( ii != m_lst.end() ) { m_lst.erase( ii ); } } void ThreadAdmin::remove( rtl::Reference< ORequestThread > const & p ) { MutexGuard aGuard( m_mutex ); remove_locked( p ); } void ThreadAdmin::join() { { MutexGuard aGuard( m_mutex ); m_disposed = true; } for (;;) { rtl::Reference< ORequestThread > pCurrent; { MutexGuard aGuard( m_mutex ); if( m_lst.empty() ) { break; } pCurrent = m_lst.front(); m_lst.pop_front(); } pCurrent->join(); } } // ---------------------------------------------------------------------------------- ORequestThread::ORequestThread( ThreadPoolHolder const &aThreadPool, JobQueue *pQueue, const ByteSequence &aThreadId, sal_Bool bAsynchron ) : m_aThreadPool( aThreadPool ) , m_pQueue( pQueue ) , m_aThreadId( aThreadId ) , m_bAsynchron( bAsynchron ) {} ORequestThread::~ORequestThread() {} void ORequestThread::setTask( JobQueue *pQueue, const ByteSequence &aThreadId, sal_Bool bAsynchron ) { m_pQueue = pQueue; m_aThreadId = aThreadId; m_bAsynchron = bAsynchron; } void ORequestThread::launch() { // Assumption is that osl::Thread::create returns normally with a true // return value iff it causes osl::Thread::run to start executing: acquire(); ThreadAdmin & rThreadAdmin = m_aThreadPool->getThreadAdmin(); osl::ClearableMutexGuard g(rThreadAdmin.m_mutex); rThreadAdmin.add( this ); try { if (!create()) { throw std::runtime_error("osl::Thread::create failed"); } } catch (...) { rThreadAdmin.remove_locked( this ); g.clear(); release(); throw; } } void ORequestThread::onTerminated() { m_aThreadPool->getThreadAdmin().remove( this ); release(); } void ORequestThread::run() { try { while ( m_pQueue ) { if( ! m_bAsynchron ) { if ( !uno_bindIdToCurrentThread( m_aThreadId.getHandle() ) ) { OSL_ASSERT( false ); } } while( ! m_pQueue->isEmpty() ) { // Note : Oneways should not get a disposable disposeid, // It does not make sense to dispose a call in this state. // That's way we put it an disposeid, that can't be used otherwise. m_pQueue->enter( sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this)), sal_True ); if( m_pQueue->isEmpty() ) { m_aThreadPool->revokeQueue( m_aThreadId , m_bAsynchron ); // Note : revokeQueue might have failed because m_pQueue.isEmpty() // may be false (race). } } delete m_pQueue; m_pQueue = 0; if( ! m_bAsynchron ) { uno_releaseIdFromCurrentThread(); } m_aThreadPool->waitInPool( this ); } } catch (...) { // Work around the problem that onTerminated is not called if run // throws an exception: onTerminated(); throw; } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */