1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: urp_environment.cxx,v $
10 * $Revision: 1.21.20.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_bridges.hxx"
36 #include <osl/interlck.h>
37 #include <osl/diagnose.h>
38 #include <osl/conditn.h>
39 #include <osl/mutex.hxx>
40 #include <osl/process.h>
42 #include <rtl/alloc.h>
44 #include <rtl/unload.h>
46 #include <uno/environment.h>
47 #include <uno/lbnames.h>
48 #include <uno/mapping.hxx>
49 #include <uno/threadpool.h>
51 #include <com/sun/star/uno/Sequence.hxx>
53 #include <bridges/remote/proxy.hxx>
54 #include <bridges/remote/stub.hxx>
55 #include <bridges/remote/context.h>
56 #include <bridges/remote/mapping.hxx>
57 #include <bridges/remote/counter.hxx>
58 #include <bridges/remote/bridgeimpl.hxx>
59 #include <bridges/remote/helper.hxx>
61 #include "urp_bridgeimpl.hxx"
62 #include "urp_writer.hxx"
63 #include "urp_reader.hxx"
64 #include "urp_dispatch.hxx"
65 #include "urp_log.hxx"
66 #include "urp_propertyobject.hxx"
68 using namespace ::rtl
;
69 using namespace ::osl
;
70 using namespace ::com::sun::star::uno
;
74 rtl_StandardModuleCount g_moduleCount
= MODULE_COUNT_INIT
;
76 // static void dumpProperties( struct Properties *p )
78 // fprintf( stderr , "FlushBlockSize : %d\n" , p->nFlushBlockSize );
79 // fprintf( stderr , "OnewayTimeoutMUSEC : %d\n" , p->nOnewayTimeoutMUSEC );
80 // fprintf( stderr , "OidCacheSize : %d\n" , p->nOidCacheSize );
81 // fprintf( stderr , "TypeCacheSize : %d\n" , p->nTypeCacheSize );
82 // fprintf( stderr , "TidCacheSize : %d\n" , p->nTidCacheSize );
83 // OString o = OUStringToOString( p->sSupportedVersions , RTL_TEXTENCODING_ASCII_US );
84 // fprintf( stderr , "SupportedVersions : %s\n" , o.pData->buffer );
85 // o = OUStringToOString( p->sVersion , RTL_TEXTENCODING_ASCII_US );
86 // fprintf( stderr , "Version : %s\n" , o.pData->buffer );
87 // fprintf( stderr , "SupportsMultipleSynchronous : %d\n" , p->bSupportsMultipleSynchronous );
88 // fprintf( stderr , "SupportsMustReply : %d\n" , p->bSupportsMustReply );
89 // fprintf( stderr , "SupportsSynchronous : %d\n" , p->bSupportsSynchronous );
92 // PropertySetterThread
93 //------------------------------------
94 class PropertySetterThread
: public ::osl::Thread
96 urp_BridgeImpl
*m_pImpl
;
97 ::rtl::OUString m_sProps
;
98 uno_Environment
*m_pEnvRemote
;
100 PropertySetterThread( uno_Environment
*pEnvRemote
,
101 urp_BridgeImpl
*pImpl
,
102 const ::rtl::OUString
& props
)
105 , m_pEnvRemote( pEnvRemote
)
107 if (m_sProps
.getLength() > 0) {
108 m_sProps
+= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(","));
110 m_sProps
+= rtl::OUString(
111 RTL_CONSTASCII_USTRINGPARAM("CurrentContext="));
112 // hold the environment in case all references are released before this
114 m_pEnvRemote
->acquire( pEnvRemote
);
116 ~PropertySetterThread()
118 m_pEnvRemote
->release( m_pEnvRemote
);
121 virtual void SAL_CALL
run()
125 switch ( m_pImpl
->m_pPropertyObject
->localRequestChange( ) )
128 sal_Bool bExceptionThrown
;
129 m_pImpl
->m_pPropertyObject
->localCommitChange( m_sProps
, &bExceptionThrown
);
130 OSL_ENSURE( !bExceptionThrown
, "properties were not set\n" );
133 OSL_TRACE( "urp-bridge : remote-counterpart won the changing-the-protocol-race\n" );
138 m_pImpl
->m_initialized
.set();
140 virtual void SAL_CALL
onTerminated()
145 //------------------------------------
150 OUString a
= OUString( RTL_CONSTASCII_USTRINGPARAM( "a" ) );
151 OUString b
= OUString( RTL_CONSTASCII_USTRINGPARAM( "b" ) );
152 OUString c
= OUString( RTL_CONSTASCII_USTRINGPARAM( "c" ) );
153 Cache
< OUString
, equalOUString
> cache ( 2 );
155 sal_Int32 n
= cache
.put( a
);
156 if (cache
.seek( a
) != n
)
160 OSL_ASSERT( 0 == n
);
163 OSL_ASSERT( 1 == n
);
167 OSL_ASSERT( 0xffff == cache
.seek( a
) );
168 OSL_ASSERT( 1 == cache
.seek( b
) );
169 OSL_ASSERT( 0 == cache
.seek( c
) );
171 OSL_ASSERT( 1 == cache
.put( a
) );
172 OSL_ASSERT( 0xffff == cache
.seek( b
) );
173 OSL_ASSERT( 1 == cache
.seek( a
) );
174 OSL_ASSERT( 0 == cache
.seek( c
) );
178 * Are we within thread, that calls destructors of static objects ?
180 sal_Bool g_bStaticDestructorsCalled
= sal_False
;
181 struct StaticSingleton
185 ::osl::MutexGuard
guard( ::osl::Mutex::getGlobalMutex() );
186 g_bStaticDestructorsCalled
= sal_True
;
189 StaticSingleton singleton
;
191 #if OSL_DEBUG_LEVEL > 1
192 static MyCounter
thisCounter( "Remote Environment" );
195 void SAL_CALL
allThreadsAreGone( uno_Environment
* pEnvRemote
)
197 remote_Context
*pContext
= (remote_Context
*) pEnvRemote
->pContext
;
198 urp_BridgeImpl
*pImpl
= ( urp_BridgeImpl
*) pContext
->m_pBridgeImpl
;
200 // if the current thread is not the writer thread, the writer thread
201 // object is not destroyed up to now, though it may already have run out.
202 // In both cases, it must be safe to cal pImpl->m_pWriter->getIdentifier()
203 OSL_ASSERT( pImpl
->m_pWriter
);
204 if( pImpl
->m_pWriter
->getIdentifier() == osl_getThreadIdentifier(0) )
206 // This is the writer thread. It has done some release calls,
207 // and is now the last one, that was active. Because the writer
208 // thread holds the environment weakly, there may also be a thread within
209 // the dispose of the bridge ( because the enviroment may have a refcount == 0 ).
210 // However, this thread MUST wait for the writer thread, so it is perfectly ok,
211 // not to set m_cndWaitForThreads. ( The check for m_nRemoteThreads is done
212 // after the join of the writer thread ).
216 pImpl
->m_cndWaitForThreads
.set();
221 void SAL_CALL
releaseStubs( uno_Environment
*pEnvRemote
)
224 ((remote_Context
* ) pEnvRemote
->pContext
)->m_pBridgeImpl
->m_bReleaseStubsCalled
= sal_True
;
226 remote_Interface
**ppInterfaces
= 0;
228 pEnvRemote
->pExtEnv
->getRegisteredInterfaces( pEnvRemote
->pExtEnv
,
229 (void***)&ppInterfaces
,
231 rtl_allocateMemory
);
234 for( i
= 0 ; i
< nCount
; i
++ )
236 if( ppInterfaces
[i
]->acquire
== bridges_remote::acquireUno2RemoteStub
)
238 // these are freed by the environment, so no release necessary
239 pEnvRemote
->pExtEnv
->revokeInterface( pEnvRemote
->pExtEnv
, ppInterfaces
[i
] );
243 ppInterfaces
[i
]->release( ppInterfaces
[i
] );
247 rtl_freeMemory( (void*) ppInterfaces
);
250 } // end namespace bridges_urp
252 using namespace bridges_urp
;
256 static void SAL_CALL
RemoteEnvironment_thisDispose( uno_Environment
*pEnvRemote
)
258 remote_Context
*pContext
= (remote_Context
*) pEnvRemote
->pContext
;
259 urp_BridgeImpl
*pImpl
= ( urp_BridgeImpl
*) pContext
->m_pBridgeImpl
;
261 ::osl::ClearableMutexGuard
guard( pImpl
->m_disposingMutex
);
262 if( pContext
->m_pBridgeImpl
->m_bDisposed
&&
263 ( ! pImpl
->m_pReader
||
264 osl_getThreadIdentifier(0) ==
265 (oslThreadIdentifier
) pImpl
->m_pReader
->getIdentifier() ) )
269 // in case, that the static destructors already have been called, no
270 // tiding up is done.
273 ::osl::MutexGuard
guard2( ::osl::Mutex::getGlobalMutex() );
274 tidyUp
= ! g_bStaticDestructorsCalled
&&
275 ! pContext
->m_pBridgeImpl
->m_bDisposed
;
279 // TODO : not threadsafe
280 // synchronization with dispatch methods needed !
282 pImpl
->m_bDisposed
= sal_True
;
285 // close the connection
286 uno_threadpool_dispose( pImpl
->m_hThreadPool
);
287 pImpl
->m_pWriter
->abortThread();
288 pContext
->m_pConnection
->close( pContext
->m_pConnection
);
290 if( osl_getThreadIdentifier(0) ==
291 (oslThreadIdentifier
) pImpl
->m_pReader
->getIdentifier() )
293 // This is the reader thread. Let the thread destroy itself
294 // the reader thread object must also release the connection at this stage !
295 pImpl
->m_pReader
->destroyYourself();
296 pImpl
->m_pReader
= 0;
300 // wait for the reader thread
301 // the reader thread object must also release the connection,
302 // when terminating !!!!
303 pImpl
->m_pReader
->join();
306 // wait for the writer thread
307 pImpl
->m_pWriter
->join();
309 // now let the context go !
310 pContext
->dispose( pContext
);
312 if( 0 != pImpl
->m_nRemoteThreads
)
314 // Wait for all threads
316 pImpl
->m_cndWaitForThreads
.wait();
317 OSL_ASSERT( ! pImpl
->m_nRemoteThreads
);
323 #ifdef BRIDGES_URP_PROT
324 if( pImpl
->m_pLogFile
)
326 fclose( pImpl
->m_pLogFile
);
327 pImpl
->m_pLogFile
= 0;
330 #if OSL_DEBUG_LEVEL > 1
331 pImpl
->dumpErrors( stderr
);
334 // destroy the threads
335 delete pImpl
->m_pWriter
;
336 pImpl
->m_pWriter
= 0;
338 if( pImpl
->m_pReader
!= 0 )
340 // This is not the reader thread, so the thread object is deleted
341 delete pImpl
->m_pReader
;
342 pImpl
->m_pReader
= 0;
345 bool bReleaseStubs
= false;
347 ::osl::MutexGuard
guard2( ::osl::Mutex::getGlobalMutex() );
348 bReleaseStubs
= !g_bStaticDestructorsCalled
;
352 releaseStubs( pEnvRemote
);
357 static void SAL_CALL
RemoteEnvironment_thisDisposing(
358 uno_Environment
*pEnvRemote
)
360 remote_Context
*pContext
= (remote_Context
* )pEnvRemote
->pContext
;
361 urp_BridgeImpl
*pImpl
= ((urp_BridgeImpl
*) pContext
->m_pBridgeImpl
);
364 ::osl::ClearableMutexGuard
guard( pImpl
->m_disposingMutex
);
365 if( ! pImpl
->m_bDisposed
)
368 urp_sendCloseConnection( pEnvRemote
);
369 RemoteEnvironment_thisDispose( pEnvRemote
);
372 pImpl
->m_pPropertyObject
->thisRelease();
373 pImpl
->m_pPropertyObject
= 0;
375 uno_threadpool_destroy( pImpl
->m_hThreadPool
);
378 pContext
->aBase
.release( (uno_Context
* ) pContext
);
379 g_moduleCount
.modCnt
.release( &g_moduleCount
.modCnt
);
380 #if OSL_DEBUG_LEVEL > 1
381 thisCounter
.release();
385 static void SAL_CALL
RemoteEnvironment_thisComputeObjectIdentifier(
386 uno_ExtEnvironment
*, rtl_uString
**, void *)
388 OSL_ENSURE( 0, "RemoteEnvironment_thisComputeObjectIdentifier should never be called" );
391 static void SAL_CALL
RemoteEnvironment_thisAcquireInterface(
392 uno_ExtEnvironment
*, void *pInterface
)
394 ((remote_Interface
*)pInterface
)->acquire( ( remote_Interface
*) pInterface
);
397 static void SAL_CALL
RemoteEnvironment_thisReleaseInterface(
398 uno_ExtEnvironment
*, void *pInterface
)
400 ((remote_Interface
*)pInterface
)->release( ( remote_Interface
*) pInterface
);
403 //##################################################################################################
404 void SAL_CALL
uno_initEnvironment( uno_Environment
* pEnvRemote
)
406 g_moduleCount
.modCnt
.acquire( &g_moduleCount
.modCnt
);
407 // set C-virtual methods
408 pEnvRemote
->environmentDisposing
= RemoteEnvironment_thisDisposing
;
409 pEnvRemote
->pExtEnv
->computeObjectIdentifier
= RemoteEnvironment_thisComputeObjectIdentifier
;
410 pEnvRemote
->pExtEnv
->acquireInterface
= RemoteEnvironment_thisAcquireInterface
;
411 pEnvRemote
->pExtEnv
->releaseInterface
= RemoteEnvironment_thisReleaseInterface
;
412 pEnvRemote
->dispose
= RemoteEnvironment_thisDispose
;
414 remote_Context
*pContext
= ( remote_Context
* ) pEnvRemote
->pContext
;
415 pContext
->aBase
.acquire( ( uno_Context
* ) pContext
);
416 pContext
->getRemoteInstance
= ::bridges_remote::remote_sendQueryInterface
;
418 // Initialize impl struct urp_BridgeImpl
419 urp_BridgeImpl
*pImpl
= new ::bridges_urp::urp_BridgeImpl( 256, 8192 );
420 pContext
->m_pBridgeImpl
= pImpl
;
422 // Initialize threadpool
423 pImpl
->m_hThreadPool
= uno_threadpool_create();
425 // take the bridgepointer as id
426 pImpl
->m_properties
.seqBridgeID
= ByteSequence( (sal_Int8
*)&pEnvRemote
, sizeof( pEnvRemote
) );
428 pImpl
->m_allThreadsAreGone
= allThreadsAreGone
;
429 pImpl
->m_sendRequest
= urp_sendRequest
;
430 pImpl
->m_nRemoteThreads
= 0;
431 pImpl
->m_bDisposed
= sal_False
;
432 pImpl
->m_bReleaseStubsCalled
= sal_False
;
434 pImpl
->m_pPropertyObject
= new PropertyObject( &(pImpl
->m_properties
), pEnvRemote
, pImpl
);
435 pImpl
->m_pPropertyObject
->thisAcquire();
437 OUString sProtocolProperties
;
438 if( pContext
->m_pProtocol
->length
> 3 )
440 sProtocolProperties
= OUString( pContext
->m_pProtocol
).copy( 4, pContext
->m_pProtocol
->length
-4);
442 if( sProtocolProperties
.getLength() )
444 struct Properties props
= pImpl
->m_properties
;
445 assignFromStringToStruct( sProtocolProperties
, &props
);
446 if( ! props
.bNegotiate
)
448 // no negotiation takes place, the creator of the bridge knows the parameter
449 // of the other side !
450 pImpl
->applyProtocolChanges( props
);
451 sProtocolProperties
= OUString();
455 #ifdef BRIDGES_URP_PROT
456 char *p
= getenv( "PROT_REMOTE" );
457 pImpl
->m_pLogFile
= 0;
460 MutexGuard
guard( Mutex::getGlobalMutex() );
463 data
.Size
= sizeof( data
);
464 osl_getProcessInfo( 0 , osl_Process_HEAPUSAGE
| osl_Process_IDENTIFIER
, &data
);
467 s
+= OString::valueOf( (sal_Int32
) data
.Ident
);
469 s
+= OString::valueOf( (sal_Int32
) counter
);
470 pImpl
->m_sLogFileName
= s
;
472 FILE *f
= fopen( s
.getStr() , "w" );
474 if( getenv( "PROT_REMOTE_FAST") )
476 pImpl
->m_pLogFile
= f
;
486 // start reader and writer threads
487 pImpl
->m_pWriter
= new ::bridges_urp::OWriterThread( pContext
->m_pConnection
, pImpl
,
489 pImpl
->m_pWriter
->create();
491 pImpl
->m_pReader
= new ::bridges_urp::OReaderThread( pContext
->m_pConnection
,
494 pImpl
->m_pReader
->create();
496 PropertySetterThread
*pPropsSetterThread
=
497 new PropertySetterThread( pEnvRemote
, pImpl
, sProtocolProperties
);
498 pPropsSetterThread
->create();
499 #if OSL_DEBUG_LEVEL > 1
500 thisCounter
.acquire();
505 //##################################################################################################
506 void SAL_CALL
uno_ext_getMapping(
507 uno_Mapping
** ppMapping
,
508 uno_Environment
* pFrom
,
509 uno_Environment
* pTo
)
511 OSL_ASSERT( ppMapping
&& pFrom
&& pTo
);
512 if (ppMapping
&& pFrom
&& pTo
)
515 ((*ppMapping
)->release
)( *ppMapping
);
516 bridges_remote::RemoteMapping
* pMapping
= 0;
518 ::rtl::OUString sFromName
= pFrom
->pTypeName
;
519 ::rtl::OUString sToName
= pTo
->pTypeName
;
520 ::rtl::OUString sUno
= OUString::createFromAscii( UNO_LB_UNO
);
521 ::rtl::OUString sRemote
= OUString::createFromAscii( "urp" );
522 if ( sFromName
.equalsIgnoreAsciiCase( sRemote
) &&
523 sToName
.equalsIgnoreAsciiCase( sUno
) )
525 pMapping
= new bridges_remote::RemoteMapping( pTo
, /* Uno */
527 bridges_remote::remoteToUno
,
530 else if ( sFromName
.equalsIgnoreAsciiCase( sUno
) &&
531 sToName
.equalsIgnoreAsciiCase( sRemote
) )
533 pMapping
= new bridges_remote::RemoteMapping( pFrom
,
535 bridges_remote::unoToRemote
,
539 *ppMapping
= (uno_Mapping
* )pMapping
;
541 uno_registerMapping( ppMapping
,
542 bridges_remote::freeRemoteMapping
,
549 sal_Bool SAL_CALL
component_canUnload( TimeValue
*pTime
)
551 return g_moduleCount
.canUnload( &g_moduleCount
, pTime
);