xref: /trunk/main/framework/test/threadtest/threadtest.cxx (revision cf6516809c57e1bb0a940545cca99cdad54d4ce2)
16d739b60SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
36d739b60SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
46d739b60SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
56d739b60SAndrew Rist  * distributed with this work for additional information
66d739b60SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
76d739b60SAndrew Rist  * to you under the Apache License, Version 2.0 (the
86d739b60SAndrew Rist  * "License"); you may not use this file except in compliance
96d739b60SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
116d739b60SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
136d739b60SAndrew Rist  * Unless required by applicable law or agreed to in writing,
146d739b60SAndrew Rist  * software distributed under the License is distributed on an
156d739b60SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
166d739b60SAndrew Rist  * KIND, either express or implied.  See the License for the
176d739b60SAndrew Rist  * specific language governing permissions and limitations
186d739b60SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
206d739b60SAndrew Rist  *************************************************************/
216d739b60SAndrew Rist 
226d739b60SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_framework.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir //_________________________________________________________________________________________________________________
28cdf0e10cSrcweir //  my own includes
29cdf0e10cSrcweir //_________________________________________________________________________________________________________________
30cdf0e10cSrcweir #include <threadhelp/threadhelpbase.hxx>
31cdf0e10cSrcweir 
32cdf0e10cSrcweir #ifndef __FRAMEWORK_THREADHELP_TRANSACTIONBASE_HXX_
33cdf0e10cSrcweir #include <threadhelp/transactionbase.hxx>
34cdf0e10cSrcweir #endif
35cdf0e10cSrcweir #include <threadhelp/resetableguard.hxx>
36cdf0e10cSrcweir #include <threadhelp/readguard.hxx>
37cdf0e10cSrcweir #include <threadhelp/writeguard.hxx>
38cdf0e10cSrcweir #include <threadhelp/transactionguard.hxx>
39cdf0e10cSrcweir #include <macros/generic.hxx>
40cdf0e10cSrcweir #include <macros/debug.hxx>
41cdf0e10cSrcweir 
42cdf0e10cSrcweir //_________________________________________________________________________________________________________________
43cdf0e10cSrcweir //  interface includes
44cdf0e10cSrcweir //_________________________________________________________________________________________________________________
45cdf0e10cSrcweir 
46cdf0e10cSrcweir //_________________________________________________________________________________________________________________
47cdf0e10cSrcweir //  other includes
48cdf0e10cSrcweir //_________________________________________________________________________________________________________________
49cdf0e10cSrcweir #include <rtl/random.h>
50cdf0e10cSrcweir #include <vos/process.hxx>
51cdf0e10cSrcweir #include <vos/thread.hxx>
52cdf0e10cSrcweir #include <rtl/ustring.hxx>
53cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
54cdf0e10cSrcweir #include <osl/time.h>
55cdf0e10cSrcweir 
56cdf0e10cSrcweir #ifndef _OSL_INTERLOCK_H_
57cdf0e10cSrcweir #include <osl/interlock.h>
58cdf0e10cSrcweir #endif
59cdf0e10cSrcweir 
60cdf0e10cSrcweir #include <vcl/event.hxx>
61cdf0e10cSrcweir #include <vcl/svapp.hxx>
62cdf0e10cSrcweir #include <vcl/wrkwin.hxx>
63cdf0e10cSrcweir #include <vcl/msgbox.hxx>
64cdf0e10cSrcweir #include <stdio.h>
65cdf0e10cSrcweir 
66cdf0e10cSrcweir //_________________________________________________________________________________________________________________
67cdf0e10cSrcweir //  const
68cdf0e10cSrcweir //_________________________________________________________________________________________________________________
69cdf0e10cSrcweir 
70cdf0e10cSrcweir #define LOGFILE             "threadtest.log"
71cdf0e10cSrcweir #define STATISTICS_FILE     "threadtest_statistic.csv"
72cdf0e10cSrcweir 
73cdf0e10cSrcweir //_________________________________________________________________________________________________________________
74cdf0e10cSrcweir //  namespace
75cdf0e10cSrcweir //_________________________________________________________________________________________________________________
76cdf0e10cSrcweir 
77cdf0e10cSrcweir using namespace ::rtl       ;
78cdf0e10cSrcweir using namespace ::osl       ;
79cdf0e10cSrcweir using namespace ::vos       ;
80cdf0e10cSrcweir using namespace ::framework ;
81cdf0e10cSrcweir 
82cdf0e10cSrcweir //_________________________________________________________________________________________________________________
83cdf0e10cSrcweir //  defines
84cdf0e10cSrcweir //_________________________________________________________________________________________________________________
85cdf0e10cSrcweir 
86cdf0e10cSrcweir /*---------------- Use follow defines to enable/disable some special features of this little test program! -------*/
87cdf0e10cSrcweir 
88cdf0e10cSrcweir #define ENABLE_LOG
89cdf0e10cSrcweir //#define ENABLE_THREADDELAY
90cdf0e10cSrcweir #define ENABLE_REQUESTCOUNT
91cdf0e10cSrcweir 
92cdf0e10cSrcweir /*----------------------------------------------------------------------------------------------------------------*/
93cdf0e10cSrcweir 
94cdf0e10cSrcweir #ifdef ENABLE_LOG
95cdf0e10cSrcweir     #define LOG_SETA_START( NA, NID )                                           \
96cdf0e10cSrcweir         {                                                                       \
97cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
98cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
99cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
100cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp  );                              \
101cdf0e10cSrcweir             sLog.append( ": Thread[ "           );                              \
102cdf0e10cSrcweir             sLog.append( NID                    );                              \
103cdf0e10cSrcweir             sLog.append( " ] call setA( "       );                              \
104cdf0e10cSrcweir             sLog.append( NA                     );                              \
105cdf0e10cSrcweir             sLog.append( " )\n"                 );                              \
106cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
107cdf0e10cSrcweir         }
108cdf0e10cSrcweir 
109cdf0e10cSrcweir     #define LOG_SETA_END( NA, EREASON, NID )                                    \
110cdf0e10cSrcweir         {                                                                       \
111cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
112cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
113cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
114cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp  );                              \
115cdf0e10cSrcweir             sLog.append( ": Thread[ "           );                              \
116cdf0e10cSrcweir             sLog.append( NID                    );                              \
117cdf0e10cSrcweir             if( EREASON == E_NOREASON )                                         \
118cdf0e10cSrcweir                 sLog.append( " ] finish setA( "         );                      \
119cdf0e10cSrcweir             else                                                                \
120cdf0e10cSrcweir                 sLog.append( " ] was refused at setA( ");                       \
121cdf0e10cSrcweir             sLog.append( NA     );                                              \
122cdf0e10cSrcweir             sLog.append( " )\n" );                                              \
123cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
124cdf0e10cSrcweir         }
125cdf0e10cSrcweir 
126cdf0e10cSrcweir     #define LOG_GETA_START( NID )                                               \
127cdf0e10cSrcweir         {                                                                       \
128cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
129cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
130cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
131cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp  );                              \
132cdf0e10cSrcweir             sLog.append( ": Thread[ "           );                              \
133cdf0e10cSrcweir             sLog.append( NID                    );                              \
134cdf0e10cSrcweir             sLog.append( " ] call getA()\n"     );                              \
135cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
136cdf0e10cSrcweir         }
137cdf0e10cSrcweir 
138cdf0e10cSrcweir     #define LOG_GETA_END( NRETURN, EREASON, NID )                               \
139cdf0e10cSrcweir         {                                                                       \
140cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
141cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
142cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
143cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp  );                              \
144cdf0e10cSrcweir             sLog.append( ": Thread[ "           );                              \
145cdf0e10cSrcweir             sLog.append( NID                    );                              \
146cdf0e10cSrcweir             if( EREASON == E_NOREASON )                                         \
147cdf0e10cSrcweir                 sLog.append( " ] finish getA() with "           );              \
148cdf0e10cSrcweir             else                                                                \
149cdf0e10cSrcweir                 sLog.append( " ] was refused at getA() with "   );              \
150cdf0e10cSrcweir             sLog.append( NRETURN    );                                          \
151cdf0e10cSrcweir             sLog.append( "\n"       );                                          \
152cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
153cdf0e10cSrcweir         }
154cdf0e10cSrcweir 
155cdf0e10cSrcweir     #define LOG_WORKA_START( NA, NID )                                          \
156cdf0e10cSrcweir         {                                                                       \
157cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
158cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
159cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
160cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp  );                              \
161cdf0e10cSrcweir             sLog.append( ": Thread[ "           );                              \
162cdf0e10cSrcweir             sLog.append( NID                    );                              \
163cdf0e10cSrcweir             sLog.append( " ] call workA( "      );                              \
164cdf0e10cSrcweir             sLog.append( NA                     );                              \
165cdf0e10cSrcweir             sLog.append( " )\n"                 );                              \
166cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
167cdf0e10cSrcweir         }
168cdf0e10cSrcweir 
169cdf0e10cSrcweir     #define LOG_WORKA_END( NRETURN, EREASON, NID )                              \
170cdf0e10cSrcweir         {                                                                       \
171cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
172cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
173cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
174cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp  );                              \
175cdf0e10cSrcweir             sLog.append( ": Thread[ "           );                              \
176cdf0e10cSrcweir             sLog.append( NID                    );                              \
177cdf0e10cSrcweir             if( EREASON == E_NOREASON )                                         \
178cdf0e10cSrcweir                 sLog.append( " ] finish workA() with "          );              \
179cdf0e10cSrcweir             else                                                                \
180cdf0e10cSrcweir                 sLog.append( " ] was refused at workA() with "  );              \
181cdf0e10cSrcweir             sLog.append( NRETURN    );                                          \
182cdf0e10cSrcweir             sLog.append( "\n"       );                                          \
183cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
184cdf0e10cSrcweir         }
185cdf0e10cSrcweir 
186cdf0e10cSrcweir     #define LOG_INITEXCEPTION( SMETHOD, NID )                                   \
187cdf0e10cSrcweir         {                                                                       \
188cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
189cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
190cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
191cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp              );                  \
192cdf0e10cSrcweir             sLog.append( ": Thread[ "                       );                  \
193cdf0e10cSrcweir             sLog.append( NID                                );                  \
194cdf0e10cSrcweir             sLog.append( " ] get EInitException from \""    );                  \
195cdf0e10cSrcweir             sLog.append( SMETHOD                            );                  \
196cdf0e10cSrcweir             sLog.append( "\"\n"                             );                  \
197cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
198cdf0e10cSrcweir         }
199cdf0e10cSrcweir 
200cdf0e10cSrcweir     #define LOG_CLOSEEXCEPTION( SMETHOD, NID )                                  \
201cdf0e10cSrcweir         {                                                                       \
202cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
203cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
204cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
205cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp              );                  \
206cdf0e10cSrcweir             sLog.append( ": Thread[ "                       );                  \
207cdf0e10cSrcweir             sLog.append( NID                                );                  \
208cdf0e10cSrcweir             sLog.append( " ] get ECloseException from \""   );                  \
209cdf0e10cSrcweir             sLog.append( SMETHOD                            );                  \
210cdf0e10cSrcweir             sLog.append( "\"\n"                             );                  \
211cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
212cdf0e10cSrcweir         }
213cdf0e10cSrcweir 
214cdf0e10cSrcweir     #define LOG_INIT( NA, NID )                                                 \
215cdf0e10cSrcweir         {                                                                       \
216cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
217cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
218cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
219cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp      );                          \
220cdf0e10cSrcweir             sLog.append( ": Thread[ "               );                          \
221cdf0e10cSrcweir             sLog.append( NID                        );                          \
222cdf0e10cSrcweir             sLog.append( " ] initialize me with "   );                          \
223cdf0e10cSrcweir             sLog.append( NA                         );                          \
224cdf0e10cSrcweir             sLog.append( "\n"                       );                          \
225cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
226cdf0e10cSrcweir         }
227cdf0e10cSrcweir 
228cdf0e10cSrcweir     #define LOG_CLOSE( NID )                                                    \
229cdf0e10cSrcweir         {                                                                       \
230cdf0e10cSrcweir             sal_uInt32 nTimeStamp = osl_getGlobalTimer();                       \
231cdf0e10cSrcweir             ::osl::MutexGuard aLogGuard( m_aLogMutex );                            \
232cdf0e10cSrcweir             OStringBuffer sLog(256);                                            \
233cdf0e10cSrcweir             sLog.append( (sal_Int32)nTimeStamp  );                              \
234cdf0e10cSrcweir             sLog.append( ": Thread[ "           );                              \
235cdf0e10cSrcweir             sLog.append( NID                    );                              \
236cdf0e10cSrcweir             sLog.append( " ] close me\n"        );                              \
237cdf0e10cSrcweir             WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() )                 \
238cdf0e10cSrcweir         }
239cdf0e10cSrcweir #else
240cdf0e10cSrcweir     #define LOG_SETA_START( NA, NID )
241cdf0e10cSrcweir     #define LOG_SETA_END( NA, EREASON, NID )
242cdf0e10cSrcweir     #define LOG_GETA_START( NID )
243cdf0e10cSrcweir     #define LOG_GETA_END( NRETURN, EREASON, NID )
244cdf0e10cSrcweir     #define LOG_WORKA_START( NA, NID )
245cdf0e10cSrcweir     #define LOG_WORKA_END( NRETURN, EREASON, NID )
246cdf0e10cSrcweir     #define LOG_INITEXCEPTION( SMETHOD, NID )
247cdf0e10cSrcweir     #define LOG_CLOSEEXCEPTION( SMETHOD, NID )
248cdf0e10cSrcweir     #define LOG_INIT( NA, NID )
249cdf0e10cSrcweir     #define LOG_CLOSE( NID )
250cdf0e10cSrcweir #endif
251cdf0e10cSrcweir 
252cdf0e10cSrcweir //_________________________________________________________________________________________________________________
253cdf0e10cSrcweir //  declarations
254cdf0e10cSrcweir //_________________________________________________________________________________________________________________
255cdf0e10cSrcweir 
getRandomValue()256cdf0e10cSrcweir sal_uInt16 getRandomValue()
257cdf0e10cSrcweir {
258cdf0e10cSrcweir     // Get new random value for thread-sleep!
259cdf0e10cSrcweir     // See run() for further informations.
260cdf0e10cSrcweir     // Always calculate a new random number.
261cdf0e10cSrcweir     sal_uInt16      nValue;
262cdf0e10cSrcweir     rtlRandomPool   aPool = rtl_random_createPool();
263cdf0e10cSrcweir     rtl_random_getBytes     ( aPool, &nValue, 2 );
264cdf0e10cSrcweir     rtl_random_destroyPool  ( aPool             );
265cdf0e10cSrcweir     return nValue;
266cdf0e10cSrcweir }
267cdf0e10cSrcweir 
268cdf0e10cSrcweir /*-************************************************************************************************************//**
269cdf0e10cSrcweir     @descr          This class is used from different threads at the same time.
270cdf0e10cSrcweir                     We start working after calling init() first(!) ...
271cdf0e10cSrcweir                     and finish it by calling close(). It exist two methods for reading/writing an
272cdf0e10cSrcweir                     internal variable "A". Another function workA() do both things at the same time.
273cdf0e10cSrcweir                     All public methods log information in a file if DO_LOG is defined.
274cdf0e10cSrcweir 
275cdf0e10cSrcweir     @attention      Our public base class FaiRWLockBase is a struct with a RWLock as member.
276cdf0e10cSrcweir                     This member can be used by guards to safe access at internal variables
277cdf0e10cSrcweir                     in interface methods.
278cdf0e10cSrcweir                     Another baseclass is the TransactionBase. They support rejection of wrong calls at wrong time.
279cdf0e10cSrcweir                     e.g. calls after closing object!
280cdf0e10cSrcweir *//*-*************************************************************************************************************/
281cdf0e10cSrcweir 
282cdf0e10cSrcweir class ThreadSafeClass : private ThreadHelpBase
283cdf0e10cSrcweir                       , private TransactionBase
284cdf0e10cSrcweir 
285cdf0e10cSrcweir {
286cdf0e10cSrcweir     public:
287cdf0e10cSrcweir 
288cdf0e10cSrcweir         ThreadSafeClass ();
289cdf0e10cSrcweir         ~ThreadSafeClass();
290cdf0e10cSrcweir 
291*07a3d7f1SPedro Giffuni         // This methods are used from different threads
292cdf0e10cSrcweir         // to test this class.
293cdf0e10cSrcweir         void        init    (   sal_Int32   nA          ,
294cdf0e10cSrcweir                                 sal_Int32   nThreadID   );
295cdf0e10cSrcweir         void        close   (   sal_Int32   nThreadID   );
296cdf0e10cSrcweir         void        setA    (   sal_Int32   nA          ,
297cdf0e10cSrcweir                                 sal_Int32   nThreadID   );
298cdf0e10cSrcweir         sal_Int32   getA    (   sal_Int32   nThreadID   );
299cdf0e10cSrcweir         sal_Int32   workA   (   sal_Int32   nA          ,
300cdf0e10cSrcweir                                 sal_Int32   nThreadID   );
301cdf0e10cSrcweir 
302cdf0e10cSrcweir         #ifdef ENABLE_REQUESTCOUNT
303cdf0e10cSrcweir         // This methods are used for statistics only!
getReadCount()304cdf0e10cSrcweir         sal_Int32 getReadCount () { return m_nReadCount;    }
getWriteCount()305cdf0e10cSrcweir         sal_Int32 getWriteCount() { return m_nWriteCount;   }
306cdf0e10cSrcweir         #endif
307cdf0e10cSrcweir 
308cdf0e10cSrcweir     private:
309cdf0e10cSrcweir 
310cdf0e10cSrcweir         sal_Int32               m_nA            ;   /// test member fro reading/writing
311cdf0e10cSrcweir 
312cdf0e10cSrcweir         #ifdef ENABLE_LOG
313cdf0e10cSrcweir         ::osl::Mutex            m_aLogMutex     ;   /// mutex to serialize writing log file!
314cdf0e10cSrcweir         #endif
315cdf0e10cSrcweir 
316cdf0e10cSrcweir         #ifdef ENABLE_REQUESTCOUNT
317cdf0e10cSrcweir         oslInterlockedCount     m_nReadCount    ;   /// statistic variables to count read/write requests
318cdf0e10cSrcweir         oslInterlockedCount     m_nWriteCount   ;
319cdf0e10cSrcweir         #endif
320cdf0e10cSrcweir };
321cdf0e10cSrcweir 
322cdf0e10cSrcweir //_________________________________________________________________________________________________________________
ThreadSafeClass()323cdf0e10cSrcweir ThreadSafeClass::ThreadSafeClass()
324cdf0e10cSrcweir     :   ThreadHelpBase  (   )
325cdf0e10cSrcweir     ,   TransactionBase (   )
326cdf0e10cSrcweir     ,   m_nA            ( 0 )
327cdf0e10cSrcweir     #ifdef ENABLE_REQUESTCOUNT
328cdf0e10cSrcweir     ,   m_nReadCount    ( 0 )
329cdf0e10cSrcweir     ,   m_nWriteCount   ( 0 )
330cdf0e10cSrcweir     #endif
331cdf0e10cSrcweir {
332cdf0e10cSrcweir }
333cdf0e10cSrcweir 
334cdf0e10cSrcweir //_________________________________________________________________________________________________________________
~ThreadSafeClass()335cdf0e10cSrcweir ThreadSafeClass::~ThreadSafeClass()
336cdf0e10cSrcweir {
337cdf0e10cSrcweir }
338cdf0e10cSrcweir 
339cdf0e10cSrcweir //_________________________________________________________________________________________________________________
init(sal_Int32 nA,sal_Int32 nThreadID)340cdf0e10cSrcweir void ThreadSafeClass::init( sal_Int32 nA, sal_Int32 nThreadID )
341cdf0e10cSrcweir {
342cdf0e10cSrcweir     // Look for multiple calls of this method first!
343*07a3d7f1SPedro Giffuni     // Use E_SOFTEXCEPTIONS to disable automatically throwing of exceptions for some working modes.
344cdf0e10cSrcweir     TransactionGuard aTransaction( m_aTransactionManager, E_SOFTEXCEPTIONS );
345cdf0e10cSrcweir 
346cdf0e10cSrcweir     // Set write lock for setting internal member AND
347cdf0e10cSrcweir     // protect changing of working mode!
348cdf0e10cSrcweir     WriteGuard aWriteLock( m_aLock );
349cdf0e10cSrcweir     LOG_INIT( nA, nThreadID )
350cdf0e10cSrcweir 
351cdf0e10cSrcweir     // OK, it must be the first call and we are synchronized with all other threads by using the write lock!
352cdf0e10cSrcweir     // Otherwise (e.g. if working mode == E_WORK) we get a exception and follow lines are never called.
353cdf0e10cSrcweir 
354cdf0e10cSrcweir     // We can set our member and change the working mode now.
355cdf0e10cSrcweir     m_nA = nA;
356cdf0e10cSrcweir 
357cdf0e10cSrcweir     aWriteLock.unlock();
358cdf0e10cSrcweir 
359cdf0e10cSrcweir     m_aTransactionManager.setWorkingMode( E_WORK );
360cdf0e10cSrcweir }
361cdf0e10cSrcweir 
362cdf0e10cSrcweir //_________________________________________________________________________________________________________________
close(sal_Int32 nThreadID)363cdf0e10cSrcweir void ThreadSafeClass::close( sal_Int32 nThreadID )
364cdf0e10cSrcweir {
365cdf0e10cSrcweir     // We must look for multiple calls of this method.
366cdf0e10cSrcweir     // Try to register this method as a transaction.
367cdf0e10cSrcweir     // In combination with E_HARDEXCEPTIONS only working mode E_WORK pass this barrier.
368cdf0e10cSrcweir     TransactionGuard aTransaction( m_aTransactionManager, E_HARDEXCEPTIONS );
369cdf0e10cSrcweir     aTransaction.stop();
370cdf0e10cSrcweir 
371cdf0e10cSrcweir     // Change working mode to BEFORECLOSE to enable rejection of normal interface calls
372cdf0e10cSrcweir     // and enable SOFTEXCEPTION mode for some impl- or helper methods!
373cdf0e10cSrcweir     // Attention: We must stop successful registered transaction first ...
374cdf0e10cSrcweir     // because setWorkingMode() blocks and wait for all current existing ones!
375cdf0e10cSrcweir     m_aTransactionManager.setWorkingMode( E_BEFORECLOSE );
376cdf0e10cSrcweir 
377cdf0e10cSrcweir     // Make it threadsafe.
378cdf0e10cSrcweir     // It must be an exclusiv access! => WriteLock!
379cdf0e10cSrcweir     WriteGuard aWriteLock( m_aLock );
380cdf0e10cSrcweir 
381cdf0e10cSrcweir     LOG_CLOSE( nThreadID )
382cdf0e10cSrcweir 
383cdf0e10cSrcweir     // Now we are alone ...
384cdf0e10cSrcweir     // All further calls to this object are rejected ...
385cdf0e10cSrcweir     // (not all ... some special ones can work by using E_SOFTEXCEPTIONS!)
386cdf0e10cSrcweir 
387cdf0e10cSrcweir     // Deinitialize all member and set working mode to E_CLOSE.
388cdf0e10cSrcweir     m_nA = 0;
389cdf0e10cSrcweir 
390cdf0e10cSrcweir     aWriteLock.unlock();
391cdf0e10cSrcweir 
392cdf0e10cSrcweir     m_aTransactionManager.setWorkingMode( E_CLOSE );
393cdf0e10cSrcweir }
394cdf0e10cSrcweir 
395cdf0e10cSrcweir //_________________________________________________________________________________________________________________
setA(sal_Int32 nA,sal_Int32 nThreadID)396cdf0e10cSrcweir void ThreadSafeClass::setA( sal_Int32 nA, sal_Int32 nThreadID   )
397cdf0e10cSrcweir {
398cdf0e10cSrcweir     // Register this method as a transaction to prevent code against wrong calls
399cdf0e10cSrcweir     // after close() or before init()!
400cdf0e10cSrcweir     ERejectReason eReason;
401cdf0e10cSrcweir     TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, &eReason );
402cdf0e10cSrcweir     if( eReason == E_NOREASON )
403cdf0e10cSrcweir     {
404cdf0e10cSrcweir         // Make it threadsafe.
405cdf0e10cSrcweir         WriteGuard aWriteLock( m_aLock );
406cdf0e10cSrcweir 
407cdf0e10cSrcweir         LOG_SETA_START( nA, nThreadID )
408cdf0e10cSrcweir 
409cdf0e10cSrcweir         // This object is ready for working and we have full write access.
410cdf0e10cSrcweir         // We can work with our member.
411cdf0e10cSrcweir         m_nA = nA;
412cdf0e10cSrcweir         #ifdef ENABLE_REQUESTCOUNT
413cdf0e10cSrcweir         osl_incrementInterlockedCount( &m_nWriteCount );
414cdf0e10cSrcweir         #endif
415cdf0e10cSrcweir         LOG_SETA_END( nA, eReason, nThreadID )
416cdf0e10cSrcweir     }
417cdf0e10cSrcweir }
418cdf0e10cSrcweir 
419cdf0e10cSrcweir //_________________________________________________________________________________________________________________
getA(sal_Int32 nThreadID)420cdf0e10cSrcweir sal_Int32 ThreadSafeClass::getA( sal_Int32 nThreadID )
421cdf0e10cSrcweir {
422cdf0e10cSrcweir     // Register this method as a transaction to prevent code against wrong calls
423cdf0e10cSrcweir     // after close() or before init()!
424cdf0e10cSrcweir     sal_Int32           nReturn = 0;
425cdf0e10cSrcweir     ERejectReason       eReason;
426cdf0e10cSrcweir     TransactionGuard    aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, &eReason );
427cdf0e10cSrcweir     if( eReason == E_NOREASON )
428cdf0e10cSrcweir     {
429cdf0e10cSrcweir         // Make it threadsafe.
430cdf0e10cSrcweir         ReadGuard aReadLock( m_aLock );
431cdf0e10cSrcweir 
432cdf0e10cSrcweir         LOG_GETA_START( nThreadID )
433cdf0e10cSrcweir 
434cdf0e10cSrcweir         // This object is ready for working and we have a read access.
435cdf0e10cSrcweir         // We can work with our member.
436cdf0e10cSrcweir         nReturn = m_nA;
437cdf0e10cSrcweir         #ifdef ENABLE_REQUESTCOUNT
438cdf0e10cSrcweir         osl_incrementInterlockedCount( &m_nReadCount );
439cdf0e10cSrcweir         #endif
440cdf0e10cSrcweir         LOG_GETA_END( nReturn, eReason, nThreadID )
441cdf0e10cSrcweir     }
442cdf0e10cSrcweir     return nReturn;
443cdf0e10cSrcweir }
444cdf0e10cSrcweir 
445cdf0e10cSrcweir //_________________________________________________________________________________________________________________
workA(sal_Int32 nA,sal_Int32 nThreadID)446cdf0e10cSrcweir sal_Int32 ThreadSafeClass::workA(   sal_Int32   nA          ,
447cdf0e10cSrcweir                                     sal_Int32   nThreadID   )
448cdf0e10cSrcweir {
449cdf0e10cSrcweir     // Register this method as a transaction to prevent code against wrong calls
450cdf0e10cSrcweir     // after close() or before init()!
451cdf0e10cSrcweir     sal_Int32           nReturn = 0;
452cdf0e10cSrcweir     ERejectReason       eReason;
453cdf0e10cSrcweir     TransactionGuard    aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, &eReason );
454cdf0e10cSrcweir     if( eReason == E_NOREASON )
455cdf0e10cSrcweir     {
456cdf0e10cSrcweir         // This method test the downgrade-mechanism of used lock implementation!
457cdf0e10cSrcweir         // Make it threadsafe.
458cdf0e10cSrcweir         WriteGuard aWriteLock( m_aLock );
459cdf0e10cSrcweir 
460cdf0e10cSrcweir         LOG_WORKA_START( nA, nThreadID )
461cdf0e10cSrcweir         // We have write access to our member.
462cdf0e10cSrcweir         // Set new value.
463cdf0e10cSrcweir         m_nA = nA;
464cdf0e10cSrcweir         #ifdef ENABLE_REQUESTCOUNT
465cdf0e10cSrcweir         osl_incrementInterlockedCount( &m_nWriteCount );
466cdf0e10cSrcweir         #endif
467cdf0e10cSrcweir 
468cdf0e10cSrcweir         // Downgrade write access to read access and read the set value again.
469cdf0e10cSrcweir         // This call can't be rejected - but it can fail!
470cdf0e10cSrcweir         aWriteLock.downgrade();
471cdf0e10cSrcweir         nReturn = m_nA;
472cdf0e10cSrcweir         #ifdef ENABLE_REQUESTCOUNT
473cdf0e10cSrcweir         osl_incrementInterlockedCount( &m_nReadCount );
474cdf0e10cSrcweir         #endif
475cdf0e10cSrcweir 
476cdf0e10cSrcweir         LOG_WORKA_END( nReturn, eReason, nThreadID )
477cdf0e10cSrcweir     }
478cdf0e10cSrcweir     return nReturn;
479cdf0e10cSrcweir }
480cdf0e10cSrcweir 
481cdf0e10cSrcweir /*-****************************************************************************************************//**
482cdf0e10cSrcweir     @descr  Every thread instance of these class lopp from 0 up to "nLoops".
483cdf0e10cSrcweir             He sleep for a random time and work with given test class "pClass" then.
484cdf0e10cSrcweir             We use random values for waiting for better results!
485cdf0e10cSrcweir             Otherwise all threads are sychron after first 2,3...5 calls - I think!
486cdf0e10cSrcweir *//*-*****************************************************************************************************/
487cdf0e10cSrcweir 
488cdf0e10cSrcweir class TestThread : public OThread
489cdf0e10cSrcweir {
490cdf0e10cSrcweir     public:
491cdf0e10cSrcweir 
492cdf0e10cSrcweir         TestThread( ThreadSafeClass*    pClass                      ,
493cdf0e10cSrcweir                     sal_Int32           nLoops                      ,
494cdf0e10cSrcweir                     Condition*          pListener                   ,
495cdf0e10cSrcweir                     sal_Bool            bOwner      =   sal_False   );
496cdf0e10cSrcweir 
497cdf0e10cSrcweir     private:
498cdf0e10cSrcweir 
499cdf0e10cSrcweir         virtual void SAL_CALL   run             ();
500cdf0e10cSrcweir         virtual void SAL_CALL   onTerminated    ();
501cdf0e10cSrcweir 
502cdf0e10cSrcweir     private:
503cdf0e10cSrcweir 
504cdf0e10cSrcweir         ThreadSafeClass*    m_pClass        ;
505cdf0e10cSrcweir         sal_Int32           m_nLoops        ;
506cdf0e10cSrcweir         sal_Int32           m_nThreadID     ;
507cdf0e10cSrcweir         Condition*          m_pListener     ;
508cdf0e10cSrcweir         sal_Bool            m_bOwner        ;
509cdf0e10cSrcweir };
510cdf0e10cSrcweir 
511cdf0e10cSrcweir //_________________________________________________________________________________________________________________
TestThread(ThreadSafeClass * pClass,sal_Int32 nLoops,Condition * pListener,sal_Bool bOwner)512cdf0e10cSrcweir TestThread::TestThread( ThreadSafeClass*    pClass      ,
513cdf0e10cSrcweir                         sal_Int32           nLoops      ,
514cdf0e10cSrcweir                         Condition*          pListener   ,
515cdf0e10cSrcweir                         sal_Bool            bOwner      )
516cdf0e10cSrcweir     :   m_pClass    ( pClass    )
517cdf0e10cSrcweir     ,   m_nLoops    ( nLoops    )
518cdf0e10cSrcweir     ,   m_pListener ( pListener )
519cdf0e10cSrcweir     ,   m_bOwner    ( bOwner    )
520cdf0e10cSrcweir {
521cdf0e10cSrcweir }
522cdf0e10cSrcweir 
523cdf0e10cSrcweir //_________________________________________________________________________________________________________________
run()524cdf0e10cSrcweir void SAL_CALL TestThread::run()
525cdf0e10cSrcweir {
526cdf0e10cSrcweir     // Get ID of this thread.
527cdf0e10cSrcweir     // Is used for logging information ...
528cdf0e10cSrcweir     m_nThreadID = getCurrentIdentifier();
529cdf0e10cSrcweir 
530cdf0e10cSrcweir     // If we are the owner of given pClass
531cdf0e10cSrcweir     // we must initialize ... and close
532cdf0e10cSrcweir     // it. See at the end of this method too.
533cdf0e10cSrcweir     if( m_bOwner == sal_True )
534cdf0e10cSrcweir     {
535cdf0e10cSrcweir         m_pClass->init( 0, m_nThreadID );
536cdf0e10cSrcweir     }
537cdf0e10cSrcweir 
538cdf0e10cSrcweir     #ifdef ENABLE_THREADDELAY
539cdf0e10cSrcweir     TimeValue   nDelay  ;
540cdf0e10cSrcweir     #endif
541cdf0e10cSrcweir 
542cdf0e10cSrcweir     sal_Int32   nA      ;
543cdf0e10cSrcweir 
544cdf0e10cSrcweir     for( sal_Int32 nCount=0; nCount<m_nLoops; ++nCount )
545cdf0e10cSrcweir     {
546cdf0e10cSrcweir         // Work with class.
547cdf0e10cSrcweir         // Use random to select called method.
548cdf0e10cSrcweir         nA = (sal_Int32)getRandomValue();
549cdf0e10cSrcweir         if( nA % 5 == 0 )
550cdf0e10cSrcweir         {
551cdf0e10cSrcweir             //nA = m_pClass->workA( nA, m_nThreadID );
552cdf0e10cSrcweir         }
553cdf0e10cSrcweir         else
554cdf0e10cSrcweir         if( nA % 3 == 0 )
555cdf0e10cSrcweir         {
556cdf0e10cSrcweir             m_pClass->setA( nA, m_nThreadID );
557cdf0e10cSrcweir         }
558cdf0e10cSrcweir         else
559cdf0e10cSrcweir         {
560cdf0e10cSrcweir             nA = m_pClass->getA( m_nThreadID );
561cdf0e10cSrcweir         }
562cdf0e10cSrcweir         #ifdef ENABLE_THREADDELAY
563cdf0e10cSrcweir         // Sleep - use random value to do that too!
564cdf0e10cSrcweir         nDelay.Seconds = 0;
565cdf0e10cSrcweir         nDelay.Nanosec = getRandomValue();
566cdf0e10cSrcweir         sleep( nDelay );
567cdf0e10cSrcweir         #endif
568cdf0e10cSrcweir     }
569cdf0e10cSrcweir 
570cdf0e10cSrcweir     // Don't forget to "close" teset object if you are the owner!
571cdf0e10cSrcweir     if( m_bOwner == sal_True )
572cdf0e10cSrcweir     {
573cdf0e10cSrcweir         m_pClass->close( m_nThreadID );
574cdf0e10cSrcweir     }
575cdf0e10cSrcweir }
576cdf0e10cSrcweir 
577cdf0e10cSrcweir //_________________________________________________________________________________________________________________
onTerminated()578cdf0e10cSrcweir void SAL_CALL TestThread::onTerminated()
579cdf0e10cSrcweir {
580cdf0e10cSrcweir     // Destroy yourself if you finished.
581cdf0e10cSrcweir     // But don't forget to call listener before.
582cdf0e10cSrcweir     m_pListener->set();
583cdf0e10cSrcweir 
584cdf0e10cSrcweir     m_pClass    = NULL;
585cdf0e10cSrcweir     m_pListener = NULL;
586cdf0e10cSrcweir 
587cdf0e10cSrcweir     delete this;
588cdf0e10cSrcweir }
589cdf0e10cSrcweir 
590cdf0e10cSrcweir /*-****************************************************************************************************//**
591cdf0e10cSrcweir     @descr  This is our test application.
592cdf0e10cSrcweir             We create one ThreadSafeClass object and a lot of threads
593cdf0e10cSrcweir             which use it at different times.
594cdf0e10cSrcweir *//*-*****************************************************************************************************/
595cdf0e10cSrcweir 
596cdf0e10cSrcweir struct ThreadInfo
597cdf0e10cSrcweir {
598cdf0e10cSrcweir     Condition*  pCondition  ;
599cdf0e10cSrcweir     TestThread* pThread     ;
600cdf0e10cSrcweir };
601cdf0e10cSrcweir 
602cdf0e10cSrcweir class TestApplication : public Application
603cdf0e10cSrcweir {
604cdf0e10cSrcweir     public:
605cdf0e10cSrcweir         void        Main        (                               );
606cdf0e10cSrcweir         sal_Int32   measureTime (   sal_Int32   nThreadCount    ,
607cdf0e10cSrcweir                                     sal_Int32   nOwner          ,
608cdf0e10cSrcweir                                     sal_Int32   nLoops=0        );
609cdf0e10cSrcweir };
610cdf0e10cSrcweir 
611cdf0e10cSrcweir //_________________________________________________________________________________________________________________
612cdf0e10cSrcweir //  definition
613cdf0e10cSrcweir //_________________________________________________________________________________________________________________
614cdf0e10cSrcweir 
615cdf0e10cSrcweir TestApplication aApplication;
616cdf0e10cSrcweir 
617cdf0e10cSrcweir //_________________________________________________________________________________________________________________
618cdf0e10cSrcweir // This function start "nThreadCount" threads to use same test class.
619cdf0e10cSrcweir // You can specify the owner thread of this test class which start/stop it by using "nOwner". [1..nThreadcount]!
620cdf0e10cSrcweir // If you specify "nLoops" different from 0 we use it as loop count for every started thread.
621cdf0e10cSrcweir // Otherwise we work with random values.
measureTime(sal_Int32 nThreadCount,sal_Int32 nOwner,sal_Int32 nLoops)622cdf0e10cSrcweir sal_Int32 TestApplication::measureTime( sal_Int32   nThreadCount    ,
623cdf0e10cSrcweir                                         sal_Int32   nOwner          ,
624cdf0e10cSrcweir                                         sal_Int32   nLoops          )
625cdf0e10cSrcweir {
626cdf0e10cSrcweir     // This is the class which should be tested.
627cdf0e10cSrcweir     ThreadSafeClass aClass;
628cdf0e10cSrcweir 
629cdf0e10cSrcweir     // Create list of threads.
630cdf0e10cSrcweir     ThreadInfo* pThreads    =   new ThreadInfo[nThreadCount];
631cdf0e10cSrcweir     sal_Int32   nLoopCount  =   nLoops                      ;
632cdf0e10cSrcweir     sal_Bool    bOwner      =   sal_False                   ;
633cdf0e10cSrcweir     for( sal_Int32 nI=0; nI<nThreadCount; ++nI )
634cdf0e10cSrcweir     {
635cdf0e10cSrcweir         // If nLoops==0 => we must use random value; otherwise we must use given count ...
636cdf0e10cSrcweir         if( nLoops == 0 )
637cdf0e10cSrcweir         {
638cdf0e10cSrcweir             nLoopCount = getRandomValue();
639cdf0e10cSrcweir         }
640cdf0e10cSrcweir         // Search owner of class.
641cdf0e10cSrcweir         bOwner = sal_False;
642cdf0e10cSrcweir         if( nOwner == nI )
643cdf0e10cSrcweir         {
644cdf0e10cSrcweir             bOwner = sal_True;
645cdf0e10cSrcweir         }
646cdf0e10cSrcweir         // initialize condition.
647cdf0e10cSrcweir         pThreads[nI].pCondition = new Condition;
648cdf0e10cSrcweir         // Initialize thread.
649cdf0e10cSrcweir         pThreads[nI].pThread = new TestThread( &aClass, nLoopCount, pThreads[nI].pCondition, bOwner );
650cdf0e10cSrcweir     }
651cdf0e10cSrcweir 
652cdf0e10cSrcweir     // Start clock to get information about used time.
653cdf0e10cSrcweir     sal_uInt32  nStartTime  ;
654cdf0e10cSrcweir     sal_uInt32  nEndTime    ;
655cdf0e10cSrcweir 
656cdf0e10cSrcweir     nStartTime = osl_getGlobalTimer();
657cdf0e10cSrcweir 
658cdf0e10cSrcweir     // Start threads ...
659cdf0e10cSrcweir     for( nI=0; nI<nThreadCount; ++nI )
660cdf0e10cSrcweir     {
661cdf0e10cSrcweir         pThreads[nI].pThread->create();
662cdf0e10cSrcweir     }
663cdf0e10cSrcweir 
664cdf0e10cSrcweir     // Wait for threads ...
665cdf0e10cSrcweir     for( nI=0; nI<nThreadCount; ++nI )
666cdf0e10cSrcweir     {
667cdf0e10cSrcweir         pThreads[nI].pCondition->wait();
668cdf0e10cSrcweir         delete pThreads[nI].pCondition;
669cdf0e10cSrcweir         pThreads[nI].pCondition = NULL;
670cdf0e10cSrcweir         pThreads[nI].pThread    = NULL;
671cdf0e10cSrcweir     }
672cdf0e10cSrcweir 
673cdf0e10cSrcweir     delete[] pThreads;
674cdf0e10cSrcweir     pThreads = NULL;
675cdf0e10cSrcweir 
676cdf0e10cSrcweir     nEndTime = osl_getGlobalTimer();
677cdf0e10cSrcweir 
678cdf0e10cSrcweir     // Calc used time and return it. [ms]
679cdf0e10cSrcweir     return( nEndTime-nStartTime );
680cdf0e10cSrcweir }
681cdf0e10cSrcweir 
682cdf0e10cSrcweir //_________________________________________________________________________________________________________________
Main()683cdf0e10cSrcweir void TestApplication::Main()
684cdf0e10cSrcweir {
685cdf0e10cSrcweir     sal_Int32 nTestCount    = 0;    /// count of calling "measureTime()"
686cdf0e10cSrcweir     sal_Int32 nThreadCount  = 0;    /// count of used threads by "measure..."
687cdf0e10cSrcweir     sal_Int32 nLoops        = 0;    /// loop count for every thread
688cdf0e10cSrcweir     sal_Int32 nOwner        = 0;    /// number of owner thread
689cdf0e10cSrcweir 
690cdf0e10cSrcweir     // Parse command line.
691cdf0e10cSrcweir     // Attention: All parameter are required and must exist!
692cdf0e10cSrcweir     // syntax: "threadtest.exe <testcount> <threadcount> <loops> <owner>"
693cdf0e10cSrcweir     OStartupInfo    aInfo       ;
694cdf0e10cSrcweir     OUString        sArgument   ;
695cdf0e10cSrcweir     sal_Int32       nArgument   ;
696cdf0e10cSrcweir     sal_Int32       nCount      = aInfo.getCommandArgCount();
697cdf0e10cSrcweir 
698cdf0e10cSrcweir     LOG_ASSERT2( nCount!=4 ,"TestApplication::Main()" , "Wrong argument line detected!")
699cdf0e10cSrcweir 
700cdf0e10cSrcweir     for( nArgument=0; nArgument<nCount; ++nArgument )
701cdf0e10cSrcweir     {
702cdf0e10cSrcweir         aInfo.getCommandArg( nArgument, sArgument );
703cdf0e10cSrcweir         if( nArgument== 0 ) nTestCount  =sArgument.toInt32();
704cdf0e10cSrcweir         if( nArgument== 1 ) nThreadCount=sArgument.toInt32();
705cdf0e10cSrcweir         if( nArgument== 2 ) nLoops      =sArgument.toInt32();
706cdf0e10cSrcweir         if( nArgument== 3 ) nOwner      =sArgument.toInt32();
707cdf0e10cSrcweir     }
708cdf0e10cSrcweir 
709cdf0e10cSrcweir     LOG_ASSERT2( nTestCount==0||nThreadCount==0||nLoops==0||nOwner==0,"TestApplication::Main()", "Wrong argument value detected!" )
710cdf0e10cSrcweir 
711cdf0e10cSrcweir     // Start test.
712cdf0e10cSrcweir     OStringBuffer   sBuf(256);
713cdf0e10cSrcweir     sal_Int32       nTime=0;
714cdf0e10cSrcweir     sBuf.append( "Nr.\tTime\tThreadCount\tLoops\tOwner\n" );
715cdf0e10cSrcweir     for( sal_Int32 nI=1; nI<=nTestCount; ++nI )
716cdf0e10cSrcweir     {
717cdf0e10cSrcweir         nTime = measureTime( nThreadCount, nOwner, nLoops );
718cdf0e10cSrcweir         sBuf.append( nI             );
719cdf0e10cSrcweir         sBuf.append( "\t"           );
720cdf0e10cSrcweir         sBuf.append( nTime          );
721cdf0e10cSrcweir         sBuf.append( "\t"           );
722cdf0e10cSrcweir         sBuf.append( nThreadCount   );
723cdf0e10cSrcweir         sBuf.append( "\t"           );
724cdf0e10cSrcweir         sBuf.append( nLoops         );
725cdf0e10cSrcweir         sBuf.append( "\t"           );
726cdf0e10cSrcweir         sBuf.append( nOwner         );
727cdf0e10cSrcweir         sBuf.append( "\n"           );
728cdf0e10cSrcweir     }
729cdf0e10cSrcweir 
730cdf0e10cSrcweir     WRITE_LOGFILE( STATISTICS_FILE, sBuf.makeStringAndClear() );
731cdf0e10cSrcweir     LOG_ERROR( "TApplication::Main()", "Test finish successful!" )
732cdf0e10cSrcweir }
733