Salome HOME
PR: merge from tag mergeto_trunk_16Jan05
[modules/kernel.git] / src / SALOMELocalTrace / LocalTraceCollector.cxx
1 //  Copyright (C) 2004  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
3 // 
4 //  This library is free software; you can redistribute it and/or 
5 //  modify it under the terms of the GNU Lesser General Public 
6 //  License as published by the Free Software Foundation; either 
7 //  version 2.1 of the License. 
8 // 
9 //  This library is distributed in the hope that it will be useful, 
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 //  Lesser General Public License for more details. 
13 // 
14 //  You should have received a copy of the GNU Lesser General Public 
15 //  License along with this library; if not, write to the Free Software 
16 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
17 // 
18 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
19 //
20 //
21 //
22 //  File   : LocalTraceCollector.cxx
23 //  Author : Paul RASCLE (EDF)
24 //  Module : KERNEL
25 //  $Header$
26
27 #include <iostream>
28 #include <sstream>
29 #include <fstream>
30 #include <cstdlib>
31
32 using namespace std;
33
34 #include "LocalTraceCollector.hxx"
35
36 // Class attributes initialisation, for class method LocalTraceCollector::run
37
38 LocalTraceCollector* LocalTraceCollector::_singleton = 0;
39 pthread_mutex_t LocalTraceCollector::_singletonMutex;
40 int LocalTraceCollector::_threadToClose = 0;
41 pthread_t LocalTraceCollector::_threadId = 0; // used to control single run
42 int LocalTraceCollector::_toFile = 0;
43 std::string LocalTraceCollector::_fileName = "";
44
45 // ============================================================================
46 /*!
47  *  guarantees a unique object instance of the class (singleton thread safe)
48  *  a separate thread for loop to print traces is launched.
49  *  \param typeTrace 0=standard out, 1=file(/tmp/tracetest.log)
50  *  If typeTrace=0, checks environment for "SALOME_trace". Test values in
51  *  the following order:
52  *  - "local"  standard out
53  *  - anything else is kept as a file name
54  */
55 // ============================================================================
56
57 LocalTraceCollector* LocalTraceCollector::instance(int typeTrace)
58 {
59   if (_singleton == 0) // no need of lock when singleton already exists
60     {
61       int ret;
62       ret = pthread_mutex_lock(&_singletonMutex); // acquire lock to be alone
63       if (_singleton == 0)                     // another thread may have got
64         {                                      // the lock after the first test
65           _singleton = new LocalTraceCollector();
66
67           _fileName = "/tmp/tracetest.log";
68           _toFile=0;
69
70           if (typeTrace)       // caller sets a value different from default=0
71             _toFile = typeTrace; 
72           else                 // check environment
73             {
74               char* traceKind = getenv("SALOME_trace");
75               //cout<<"SALOME_trace="<<traceKind<<endl;
76               if (traceKind)
77                 {
78                   if (strcmp(traceKind,"local")==0) _toFile=0;
79
80                   else
81                     {
82                       _toFile=1;
83                       _fileName = traceKind;
84                     }       
85                 }
86             }
87           //cout <<"_toFile: "<<_toFile<<" _fileName: "<<_fileName<<endl;
88
89           pthread_t traceThread;
90           int bid;
91           int re2 = pthread_create(&traceThread, NULL,
92                                    LocalTraceCollector::run, (void *)bid);
93         }
94       ret = pthread_mutex_unlock(&_singletonMutex); // release lock
95     }
96   return _singleton;
97 }
98
99 // ============================================================================
100 /*!
101  *  In a separate thread, loop to print traces.
102  *  Mutex garantees intialisation on instance method is done and only one run
103  *  allowed (double check ...)
104  *  Loop until there is no more buffer to print,
105  *  and no ask for end from destructor.
106  *  Get a buffer. If type = ABORT then exit application with message.
107  */
108 // ============================================================================
109
110 void* LocalTraceCollector::run(void *bid)
111 {
112   int isOKtoRun = 0;
113   int ret = pthread_mutex_lock(&_singletonMutex); // acquire lock to be alone
114   if (! _threadId)  // only one run
115     {
116       isOKtoRun = 1;
117       _threadId = pthread_self();
118     }
119   else cout << "----- Comment est-ce possible de passer la ? -------" <<endl;
120   ret = pthread_mutex_unlock(&_singletonMutex); // release lock
121
122   if (isOKtoRun)
123     { 
124       _threadId = pthread_self();
125       LocalTraceBufferPool* myTraceBuffer = LocalTraceBufferPool::instance();
126       LocalTrace_TraceInfo myTrace;
127
128       // if trace in file requested, opens a file with append mode
129       // so, several processes can share the same file
130
131
132       ofstream traceFile;
133
134       switch (_toFile)
135         {
136         case 1 :  // --- trace to file
137           {
138             const char *fileName = _fileName.c_str();
139             traceFile.open(fileName, ios::out | ios::app);
140             if (!traceFile)
141               {
142                 cerr << "impossible to open trace file "<< fileName << endl;
143                 exit (1);
144               }
145           }
146           break;
147
148         case 0 : ; // --- trace to standard output
149         default :  // --- on standard output, too
150           break;
151         }
152
153       // Loop until there is no more buffer to print,
154       // and no ask for end from destructor.
155
156       while ((!_threadToClose) || myTraceBuffer->toCollect() )
157         {
158           int fullBuf = myTraceBuffer->retrieve(myTrace);
159           if (myTrace.traceType == ABORT_MESS)
160             {
161               switch (_toFile)
162                 {
163                 case 1 :  // --- trace to file
164                   traceFile << "INTERRUPTION from thread " << myTrace.threadId
165                             << " : " <<  myTrace.trace;
166                   traceFile.close();
167                   // no break here !
168                 case 0 :  // --- trace to standard output
169                 default : // --- on standard output, too
170                   cout << flush ;
171                   cerr << "INTERRUPTION from thread " << myTrace.threadId
172                        << " : " <<  myTrace.trace;
173                   cerr << flush ; 
174                   exit(1);     
175                   break;
176                 }
177             }
178           else
179             {
180               switch (_toFile)
181                 {
182                 case 1 :  // --- trace to file
183                   traceFile << "th. " << myTrace.threadId
184                             << " " << myTrace.trace;
185                   break;
186                 case 0 :  // --- trace to standard output
187                 default : // --- on standard output, too
188                   cout << "th. " << myTrace.threadId << " " << myTrace.trace;
189                   break;
190                 }
191             }
192         }
193
194       if (_toFile==1) traceFile.close();
195     }
196   pthread_exit(NULL);
197 }
198
199 // ============================================================================
200 /*!
201  *  Destructor: wait until printing thread ends (LocalTraceCollector::run)
202  */
203 // ============================================================================
204
205 LocalTraceCollector:: ~LocalTraceCollector()
206 {
207   LocalTraceBufferPool* myTraceBuffer = LocalTraceBufferPool::instance();
208   _threadToClose = 1;
209   myTraceBuffer->insert(NORMAL_MESS,"end of trace "); //needed to wake up thread
210   if (_threadId)
211     {
212       int ret = pthread_join(_threadId, NULL);
213       if (ret) cout << "error close LocalTraceCollector : "<< ret << endl;
214       else cout << "LocalTraceCollector destruction OK" << endl;
215     }
216   delete myTraceBuffer;
217 }
218
219 // ============================================================================
220 /*!
221  * Constructor: no need of LocalTraceBufferPool object initialization here,
222  * thread safe singleton used in LocalTraceBufferPool::instance()
223  */
224 // ============================================================================
225
226 LocalTraceCollector::LocalTraceCollector()
227 {
228   _threadId=0;
229 }
230
231