/* -*- 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. * ************************************************************************/ #ifndef _URP_JOB_HXX_ #define _URP_JOB_HXX_ #include #include #include #include #include #include "urp_threadid.hxx" #include "urp_unmarshal.hxx" #include "urp_bridgeimpl.hxx" namespace bridges_urp { const sal_Int32 MULTIJOB_STANDARD_MEMORY_SIZE = 1024; const sal_Int32 MULTIJOB_PER_CALL_MEMORY_SIZE = 96; class Unmarshal; struct urp_BridgeImpl; template < class t > inline t mymax( const t &t1 , const t &t2 ) { return t1 > t2 ? t1 : t2; } class Job { public: Job( uno_Environment *pEnvRemote, remote_Context *pContext, sal_Sequence *pTid, struct urp_BridgeImpl *pBridgeImpl, Unmarshal *pUnmarshal ); Job( uno_Environment *pEnvRemote, remote_Context *pContext, struct urp_BridgeImpl *pBridgeImpl, ::bridges_remote::RemoteThreadCounter_HoldEnvWeak value ) : m_pContext( pContext ) , m_pBridgeImpl( pBridgeImpl ) , m_pTid( 0 ) , m_counter( pEnvRemote , value ) { if ( m_pContext ) { m_pContext->aBase.acquire( &m_pContext->aBase ); } } ~Job(); public: remote_Context *m_pContext; Unmarshal *m_pUnmarshal; struct urp_BridgeImpl *m_pBridgeImpl; sal_Sequence *m_pTid; ::bridges_remote::RemoteThreadCounter m_counter; }; class ClientJob : private Job { public: // pContext is null for bridge-internal UrpProtocolProperties requests inline ClientJob( uno_Environment *pEnvRemote, // weak ! remote_Context *pContext, struct urp_BridgeImpl *pBridgeImpl, rtl_uString *pOid, // weak typelib_TypeDescription const * pMemberType, // weak typelib_InterfaceTypeDescription *pInterfaceType, // weak void *pReturn, void *ppArgs[], uno_Any **ppException ); // ~ClientJob // no release for method type and attribute type necessary, because // it was acquired by the caller of urp_sendRequest. The lifetime // of the ClientJob object is always shorter than the urp_sendRequest call. inline ~ClientJob() { if( m_bReleaseForTypeDescriptionNecessary ) typelib_typedescription_release( (typelib_TypeDescription*) m_pInterfaceType ); uno_releaseIdFromCurrentThread(); } sal_Bool pack(); void wait(); sal_Bool extract( ); void initiate(); inline void setBridgePropertyCall() { m_bBridgePropertyCall = sal_True; } inline sal_Bool isBridgePropertyCall() const { return m_bBridgePropertyCall; } inline sal_Bool isOneway() const { return m_bOneway; } inline void setUnmarshal( Unmarshal *p ) { m_pUnmarshal = p; } public: typelib_InterfaceMethodTypeDescription *m_pMethodType; typelib_InterfaceAttributeTypeDescription *m_pAttributeType; sal_Bool m_bExceptionOccurred; private: void **m_ppArgs; void *m_pReturn; typelib_InterfaceTypeDescription *m_pInterfaceType; sal_Bool m_bReleaseForTypeDescriptionNecessary; uno_Any **m_ppException; sal_Bool m_bOneway; sal_Bool m_bBridgePropertyCall; sal_uInt16 m_nMethodIndex; uno_Environment *m_pEnvRemote; rtl_uString *m_pOid; sal_Bool m_bCallingConventionForced; }; struct MemberTypeInfo { typelib_InterfaceTypeDescription *m_pInterfaceType; typelib_InterfaceMethodTypeDescription *m_pMethodType; typelib_InterfaceAttributeTypeDescription *m_pAttributeType; sal_Int32 m_nArgCount; sal_Bool m_bIsReleaseCall; sal_Bool *m_pbIsIn; sal_Bool *m_pbIsOut; sal_Bool m_bIsOneway; typelib_TypeDescription *m_pReturnType; typelib_TypeDescription **m_ppArgType; }; struct ServerJobEntry { rtl_uString *m_pOid; remote_Interface *m_pRemoteI; typelib_TypeDescriptionReference *m_pInterfaceTypeRef; void **m_ppArgs; void *m_pReturn; uno_Any m_exception; uno_Any *m_pException; remote_Interface *m_pCurrentContext; sal_Bool m_bHasCurrentContext; sal_Bool m_bIgnoreCache; }; class ServerMultiJob : private Job { public: ServerMultiJob( uno_Environment *pEnvRemote, remote_Context *pContext, sal_Sequence *pTid, struct urp_BridgeImpl *pBridgeImpl, Unmarshal *pUnmarshal, sal_Int32 nMaxMessages ); ~ServerMultiJob(); public: sal_Bool extract( ); void initiate(); void execute(); public: // setMethodType or setAttributeType MUST be called before extract inline void setMethodType( typelib_InterfaceMethodTypeDescription *pMethodType, sal_Bool bIsReleaseCall, sal_Bool bIsOneway ) { m_aTypeInfo[m_nCalls].m_pMethodType = pMethodType; m_aTypeInfo[m_nCalls].m_pAttributeType = 0; m_aTypeInfo[m_nCalls].m_nArgCount = pMethodType->nParams; m_aTypeInfo[m_nCalls].m_bIsReleaseCall = bIsReleaseCall; m_aTypeInfo[m_nCalls].m_bIsOneway = bIsOneway; } inline void setAttributeType( typelib_InterfaceAttributeTypeDescription *pAttributeType, sal_Bool bIsSetter, sal_Bool bIsOneway ) { m_aTypeInfo[m_nCalls].m_pAttributeType = pAttributeType; m_aTypeInfo[m_nCalls].m_pMethodType = 0; m_aTypeInfo[m_nCalls].m_nArgCount = bIsSetter ? 1 : 0; m_aTypeInfo[m_nCalls].m_bIsReleaseCall = sal_False; m_aTypeInfo[m_nCalls].m_bIsOneway = bIsOneway; } inline void setType( typelib_TypeDescriptionReference *pTypeRef ) { m_aEntries[m_nCalls].m_pInterfaceTypeRef = pTypeRef; typelib_typedescriptionreference_acquire( m_aEntries[m_nCalls].m_pInterfaceTypeRef ); TYPELIB_DANGER_GET( (typelib_TypeDescription ** )&(m_aTypeInfo[m_nCalls].m_pInterfaceType) , pTypeRef ); } // setOid or setInterface MUST be called before extract inline void setOid( rtl_uString *pOid ) { m_aEntries[m_nCalls].m_pOid = pOid; rtl_uString_acquire( m_aEntries[m_nCalls].m_pOid ); m_aEntries[m_nCalls].m_pRemoteI = 0; } // setOid or setInterface MUST be called inline void setInterface( remote_Interface *pRemoteI ) { m_aEntries[m_nCalls].m_pRemoteI = pRemoteI; pRemoteI->acquire( pRemoteI ); m_aEntries[m_nCalls].m_pOid = 0; } inline void setCurrentContext( bool bHasCurrentContext, remote_Interface *pCurrentContext ) { m_aEntries[m_nCalls].m_pCurrentContext = pCurrentContext; m_aEntries[m_nCalls].m_bHasCurrentContext = bHasCurrentContext; } inline void setIgnoreCache( sal_Bool bIgnoreCache ) { m_aEntries[m_nCalls].m_bIgnoreCache = bIgnoreCache; } inline sal_Bool isFull() const { return m_nCalls >= m_nMaxMessages; } inline sal_Int8 *getHeap( sal_Int32 nSizeToAlloc ) { if( nSizeToAlloc + m_nCurrentMemPosition > m_nCurrentMemSize ) { m_lstMem.push_back( m_pCurrentMem ); m_nCurrentMemSize = mymax( nSizeToAlloc , MULTIJOB_STANDARD_MEMORY_SIZE ) + (m_nMaxMessages -m_nCalls)*MULTIJOB_PER_CALL_MEMORY_SIZE; m_pCurrentMem = (sal_Int8*) rtl_allocateMemory( m_nCurrentMemSize ); m_nCurrentMemPosition = 0; } sal_Int8 *pHeap = m_pCurrentMem + m_nCurrentMemPosition; m_nCurrentMemPosition += nSizeToAlloc; // care for alignment if( m_nCurrentMemPosition & 0x7 ) { m_nCurrentMemPosition = ( ((sal_uInt32)m_nCurrentMemPosition) & ( 0xffffffff - 0x7 )) + 8; } return pHeap; } void prepareRuntimeException( const ::rtl::OUString &sMessage, sal_Int32 nCall ); private: uno_Environment *m_pEnvRemote; sal_Int32 m_nCalls; sal_Int32 m_nMaxMessages; ServerJobEntry *m_aEntries; MemberTypeInfo *m_aTypeInfo; sal_Int8 *m_pCurrentMem; sal_Int32 m_nCurrentMemSize; sal_Int32 m_nCurrentMemPosition; // list of memory pointers, that must be freed ::std::list< sal_Int8 * > m_lstMem; }; //--------------------------------------------------------------------------------------------- inline ClientJob::ClientJob( uno_Environment *pEnvRemote, remote_Context *pContext, struct urp_BridgeImpl *pBridgeImpl, rtl_uString *pOid, typelib_TypeDescription const * pMemberType, typelib_InterfaceTypeDescription *pInterfaceType, void *pReturn, void *ppArgs[], uno_Any **ppException ) : Job( pEnvRemote, pContext, pBridgeImpl, ::bridges_remote::RTC_HOLDENVWEAK ) , m_ppArgs( ppArgs ) , m_pReturn( pReturn ) , m_pInterfaceType( pInterfaceType ) // weak , m_bReleaseForTypeDescriptionNecessary( sal_False ) , m_ppException( ppException ) , m_bBridgePropertyCall( sal_False ) , m_pEnvRemote( pEnvRemote ) // weak , m_pOid( pOid ) // weak , m_bCallingConventionForced( sal_False ) { uno_getIdOfCurrentThread( &m_pTid ); if( typelib_TypeClass_INTERFACE_METHOD == pMemberType->eTypeClass ) { m_pMethodType = ( typelib_InterfaceMethodTypeDescription * ) pMemberType; m_pAttributeType = 0; } else if( typelib_TypeClass_INTERFACE_ATTRIBUTE == pMemberType->eTypeClass ) { m_pAttributeType = ( typelib_InterfaceAttributeTypeDescription * ) pMemberType; m_pMethodType = 0; } else { OSL_ASSERT( ! "wrong member type" ); } // calculate method index if( ! m_pInterfaceType->aBase.bComplete ) { // must be acquired because typedescription may be exchanged typelib_typedescription_acquire((typelib_TypeDescription*) m_pInterfaceType ); m_bReleaseForTypeDescriptionNecessary = sal_True; typelib_typedescription_complete( (typelib_TypeDescription ** ) &m_pInterfaceType ); } m_nMethodIndex = (sal_uInt16) m_pInterfaceType->pMapMemberIndexToFunctionIndex[ ((typelib_InterfaceMemberTypeDescription*)pMemberType)->nPosition ]; if( m_pAttributeType && m_ppArgs ) { // setter m_nMethodIndex ++; } if( typelib_TypeClass_INTERFACE_METHOD == pMemberType->eTypeClass ) { // if( (( typelib_InterfaceMemberTypeDescription * ) pMemberType)->nPosition // == REMOTE_RELEASE_METHOD_INDEX ) // { // m_bOneway = sal_True; // } // else if( pBridgeImpl->m_properties.bForceSynchronous ) { m_bOneway = sal_False; if( (( typelib_InterfaceMethodTypeDescription * ) pMemberType)->bOneWay ) { m_bCallingConventionForced = sal_True; } } else { m_bOneway = (( typelib_InterfaceMethodTypeDescription * ) pMemberType)->bOneWay; } } else { m_bOneway = sal_False; } } } #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */