Salome HOME
6f1c25a0b2b294e451dddc34119fb3177f789adb
[modules/kernel.git] / src / SALOMETraceCollector / SALOMETraceCollector.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  File   : LocalTraceCollector.cxx
24 //  Author : Paul RASCLE (EDF)
25 //  Module : KERNEL
26 //  $Header$
27 //
28 #include <SALOMEconfig.h>
29
30 #include <iostream>
31 #include <sstream>
32 #include <fstream>
33 #include <cstdlib>
34 #include <omniORB4/CORBA.h>
35
36 #include "SALOMETraceCollector.hxx"
37 #include "TraceCollector_WaitForServerReadiness.hxx"
38 #include <SALOMEconfig.h>
39 #include CORBA_CLIENT_HEADER(Logger)
40
41 // Class attributes initialisation, for class method SALOMETraceCollector::run
42
43 CORBA::ORB_ptr SALOMETraceCollector::_orb = 0;
44
45 // ============================================================================
46 /*!
47  *  This class is for use with CORBA, inside SALOME.
48  *  Type of trace (and corresponding class) is choosen in LocalTraceBufferPool.
49  *
50  *  Guarantees a unique object instance of the class (singleton thread safe)
51  *  a separate thread for loop to print traces is launched.
52  */
53 // ============================================================================
54
55 BaseTraceCollector* SALOMETraceCollector::instance()
56 {
57   if (_singleton == 0) // no need of lock when singleton already exists
58     {
59       int ret;
60       ret = pthread_mutex_lock(&_singletonMutex); // acquire lock to be alone
61       if (_singleton == 0)                     // another thread may have got
62         {                                      // the lock after the first test
63           BaseTraceCollector* myInstance = new SALOMETraceCollector();
64           int argc=0;
65           char *_argv=0;
66           char ** argv = &_argv;
67           _orb = CORBA::ORB_init (argc, argv);
68
69           sem_init(&_sem,0,0); // to wait until run thread is initialized
70           pthread_t traceThread;
71           int bid = 0;
72           pthread_create(&traceThread, NULL,
73                                    SALOMETraceCollector::run, &bid);
74           sem_wait(&_sem);
75           _singleton = myInstance; // _singleton known only when init done
76         }
77       ret = pthread_mutex_unlock(&_singletonMutex); // release lock
78     }
79   return _singleton;
80 }
81
82 // ============================================================================
83 /*!
84  *  In a separate thread, loop to print traces.
85  *  Mutex garantees intialisation on instance method is done and only one run
86  *  allowed (double check ...)
87  *  Loop until there is no more buffer to print,
88  *  and no ask for end from destructor.
89  *  Get a buffer. If type = ABORT then exit application with message.
90  */
91 // ============================================================================
92
93 void* SALOMETraceCollector::run(void *bid)
94 {
95   _threadId = new pthread_t;
96   *_threadId = pthread_self();
97   sem_post(&_sem); // unlock instance
98
99   LocalTraceBufferPool* myTraceBuffer = LocalTraceBufferPool::instance();
100   LocalTrace_TraceInfo myTrace;
101
102   SALOME_Logger::Logger_var m_pInterfaceLogger;
103   CORBA::Object_var obj;
104
105   obj = TraceCollector_WaitForServerReadiness(_orb,"Logger");
106   if (!CORBA::is_nil(obj))
107     m_pInterfaceLogger = SALOME_Logger::Logger::_narrow(obj);
108   if (CORBA::is_nil(m_pInterfaceLogger))
109     {
110       std::cerr << "Logger server not found ! Abort" << std::endl;
111       std::cerr << std::flush ; 
112       exit(1);
113     } 
114   else
115     {
116       CORBA::String_var LogMsg =
117         CORBA::string_dup("\n---Init logger trace---\n");
118       m_pInterfaceLogger->putMessage(LogMsg);
119       DEVTRACE("Logger server found");
120     }
121
122   // --- Loop until there is no more buffer to print,
123   //     and no ask for end from destructor.
124
125   while ((!_threadToClose) || myTraceBuffer->toCollect() )
126     {
127       if (_threadToClose)
128         {
129           DEVTRACE("SALOMETraceCollector _threadToClose");
130           //break;
131         }
132
133       myTraceBuffer->retrieve(myTrace);
134       if (!CORBA::is_nil(_orb))
135         {
136           if (myTrace.traceType == ABORT_MESS)
137             {
138               std::stringstream abortMessage("");
139 #ifndef WIN32
140               abortMessage << "INTERRUPTION from thread "
141                            << myTrace.threadId << " : " << myTrace.trace;
142 #else
143               abortMessage << "INTERRUPTION from thread "
144                            << (void*)&myTrace.threadId 
145                            << " : " << myTrace.trace;
146 #endif
147               CORBA::String_var LogMsg =
148                 CORBA::string_dup(abortMessage.str().c_str());
149               m_pInterfaceLogger->putMessage(LogMsg);
150               exit(1);
151             }
152           else
153             {
154               std::stringstream aMessage("");
155 #ifndef WIN32
156               aMessage << "th. " << myTrace.threadId
157 #else
158                 aMessage << "th. " << (void*)&myTrace.threadId
159 #endif
160                        << " " << myTrace.trace;
161               CORBA::String_var LogMsg =
162                 CORBA::string_dup(aMessage.str().c_str());
163               m_pInterfaceLogger->putMessage(LogMsg);
164             }
165         }
166     }
167   pthread_exit(NULL);
168   return NULL;
169 }
170
171 // ============================================================================
172 /*!
173  *  Destructor: wait until printing thread ends (SALOMETraceCollector::run)
174  */
175 // ============================================================================
176
177 SALOMETraceCollector:: ~SALOMETraceCollector()
178 {
179   int ret;
180   ret = pthread_mutex_lock(&_singletonMutex); // acquire lock to be alone
181   if (_singleton)
182     {
183       DEVTRACE("SALOMETraceCollector:: ~SALOMETraceCollector()");
184       LocalTraceBufferPool* myTraceBuffer = LocalTraceBufferPool::instance();
185       _threadToClose = 1;
186       myTraceBuffer->insert(NORMAL_MESS,"end of trace\n"); // to wake up thread
187       if (_threadId)
188         {
189           int ret = pthread_join(*_threadId, NULL);
190           if (ret) std::cerr << "error close SALOMETraceCollector : "<< ret << std::endl;
191           else DEVTRACE("SALOMETraceCollector destruction OK");
192           delete _threadId;
193           _threadId = 0;
194           _threadToClose = 0;
195         }
196       _singleton = 0;
197     }
198   ret = pthread_mutex_unlock(&_singletonMutex); // release lock
199 }
200
201 // ============================================================================
202 /*!
203  * Constructor: no need of LocalTraceBufferPool object initialization here,
204  * thread safe singleton used in LocalTraceBufferPool::instance()
205  */
206 // ============================================================================
207
208 SALOMETraceCollector::SALOMETraceCollector()
209 {
210   _threadId=0;
211   _threadToClose = 0;
212 }
213
214 // ============================================================================
215 /*!
216  * 
217  */
218 // ============================================================================
219
220 extern "C"
221 {
222  SALOMETRACECOLLECTOR_EXPORT
223   BaseTraceCollector *SingletonInstance(void)
224   {
225     BaseTraceCollector *instance = SALOMETraceCollector::instance();
226     return instance;
227   }
228 }