Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "trace_impl.h"
     12 
     13 #include <cassert>
     14 #include <string.h> // memset
     15 
     16 #ifdef _WIN32
     17 #include "trace_windows.h"
     18 #include "fix_interlocked_exchange_pointer_windows.h"
     19 #else
     20 #include <stdio.h>
     21 #include <time.h>
     22 #include <stdarg.h>
     23 #include "trace_linux.h"
     24 #endif // _WIN32
     25 
     26 #define KEY_LEN_CHARS 31
     27 
     28 #ifdef _WIN32
     29     #pragma warning(disable:4355)
     30 // VS 2005: Disable warnings for default initialized arrays.
     31     #pragma warning(disable:4351)
     32 #endif // _WIN32
     33 
     34 namespace webrtc {
     35 static WebRtc_UWord32 levelFilter = kTraceDefault;
     36 
     37 // Construct On First Use idiom. Avoids "static initialization order fiasco".
     38 Trace* TraceImpl::StaticInstance(TraceCount inc, const TraceLevel level)
     39 {
     40     // TODO (hellner): use atomic wrapper instead.
     41     static volatile long theTraceCount = 0;
     42     static Trace* volatile theTrace = NULL;
     43 
     44     TraceCreate state = WEBRTC_TRACE_EXIST;
     45 
     46     // Sanitys to avoid taking lock unless absolutely necessary (for
     47     // performance reasons). inc == WEBRTC_TRACE_INC_NO_CREATE) implies that
     48     // a message will be written to file.
     49     if(level != kTraceAll && inc == WEBRTC_TRACE_INC_NO_CREATE)
     50     {
     51         if(!(level & levelFilter))
     52         {
     53             return NULL;
     54         }
     55     }
     56 
     57 #ifndef _WIN32
     58     // TODO (pwestin): crtiSect is never reclaimed. Fix memory leak.
     59     static CriticalSectionWrapper* crtiSect(
     60         CriticalSectionWrapper::CreateCriticalSection());
     61     CriticalSectionScoped lock(*crtiSect);
     62 
     63     if(inc == WEBRTC_TRACE_INC_NO_CREATE && theTraceCount == 0)
     64     {
     65         return NULL;
     66     }
     67 
     68     if(inc == WEBRTC_TRACE_INC || inc == WEBRTC_TRACE_INC_NO_CREATE)
     69     {
     70         theTraceCount++;
     71         if(theTraceCount == 1)
     72         {
     73             state = WEBRTC_TRACE_CREATE;
     74         }
     75     } else {
     76         theTraceCount--;
     77         if(theTraceCount == 0)
     78         {
     79             state = WEBRTC_TRACE_DESTROY;
     80         }
     81     }
     82     if(state == WEBRTC_TRACE_CREATE)
     83     {
     84         theTrace = TraceImpl::CreateTrace();
     85 
     86     } else if(state == WEBRTC_TRACE_DESTROY) {
     87         Trace* oldValue = theTrace;
     88         theTrace = NULL;
     89         // The lock is held by the scoped critical section. Release the lock
     90         // temporarily so that the trace can be safely deleted. If the lock
     91         // was kept during the delete, e.g. creating and destroying the trace
     92         // too quickly may lead to a deadlock.
     93         // This is due to the fact that starting and stopping a ThreadWrapper
     94         // thread will trigger writing of trace messages.
     95         // TODO (hellner): remove the tight coupling with the thread
     96         //                 implementation.
     97         crtiSect->Leave();
     98         if(oldValue)
     99         {
    100             delete static_cast<TraceImpl*>(oldValue);
    101         }
    102         // Re-aqcuire the lock.
    103         crtiSect->Enter();
    104         return NULL;
    105     }
    106 #else  // _WIN32
    107     if(inc == WEBRTC_TRACE_INC_NO_CREATE && theTraceCount == 0)
    108     {
    109         return NULL;
    110     }
    111     if(inc == WEBRTC_TRACE_INC_NO_CREATE)
    112     {
    113         if(1 == InterlockedIncrement(&theTraceCount))
    114         {
    115             // The trace has been destroyed by some other thread. Rollback.
    116             InterlockedDecrement(&theTraceCount);
    117             assert(false);
    118             return NULL;
    119         }
    120         // Sanity to catch corrupt state.
    121         if(theTrace == NULL)
    122         {
    123             assert(false);
    124             InterlockedDecrement(&theTraceCount);
    125             return NULL;
    126         }
    127     } else if(inc == WEBRTC_TRACE_INC) {
    128         if(theTraceCount == 0)
    129         {
    130             state = WEBRTC_TRACE_CREATE;
    131         } else {
    132             if(1 == InterlockedIncrement(&theTraceCount))
    133             {
    134                 // InterlockedDecrement because reference count should not be
    135                 // updated just yet (that's done when the trace is created).
    136                 InterlockedDecrement(&theTraceCount);
    137                 state = WEBRTC_TRACE_CREATE;
    138             }
    139         }
    140     } else {
    141         int newValue = InterlockedDecrement(&theTraceCount);
    142         if(newValue == 0)
    143         {
    144             state = WEBRTC_TRACE_DESTROY;
    145         }
    146     }
    147 
    148     if(state == WEBRTC_TRACE_CREATE)
    149     {
    150         // Create trace and let whichever thread finishes first assign its local
    151         // copy to the global instance. All other threads reclaim their local
    152         // copy.
    153         Trace* newTrace = TraceImpl::CreateTrace();
    154         if(1 == InterlockedIncrement(&theTraceCount))
    155         {
    156             Trace* oldValue = (Trace*)InterlockedExchangePointer(
    157                 reinterpret_cast<void* volatile*>(&theTrace), newTrace);
    158             assert(oldValue == NULL);
    159             assert(theTrace);
    160         } else {
    161             InterlockedDecrement(&theTraceCount);
    162             if(newTrace)
    163             {
    164                 delete static_cast<TraceImpl*>(newTrace);
    165             }
    166         }
    167         return NULL;
    168     } else if(state == WEBRTC_TRACE_DESTROY)
    169     {
    170         Trace* oldValue = (Trace*)InterlockedExchangePointer(
    171             reinterpret_cast<void* volatile*>(&theTrace), NULL);
    172         if(oldValue)
    173         {
    174             delete static_cast<TraceImpl*>(oldValue);
    175         }
    176         return NULL;
    177     }
    178 #endif // #ifndef _WIN32
    179     return theTrace;
    180 }
    181 
    182 void Trace::CreateTrace()
    183 {
    184     TraceImpl::StaticInstance(WEBRTC_TRACE_INC);
    185 }
    186 
    187 void Trace::ReturnTrace()
    188 {
    189     TraceImpl::StaticInstance(WEBRTC_TRACE_DEC);
    190 }
    191 
    192 TraceImpl* TraceImpl::GetTrace(const TraceLevel level)
    193 {
    194     return (TraceImpl*)StaticInstance(WEBRTC_TRACE_INC_NO_CREATE, level);
    195 }
    196 
    197 Trace* TraceImpl::CreateTrace()
    198 {
    199 #if defined(_WIN32)
    200     return new TraceWindows();
    201 #else
    202     return new TraceLinux();
    203 #endif
    204 }
    205 
    206 TraceImpl::TraceImpl()
    207     : _critsectInterface(*CriticalSectionWrapper::CreateCriticalSection()),
    208       _callback(NULL),
    209       _rowCountText(0),
    210       _fileCountText(0),
    211       _traceFile(*FileWrapper::Create()),
    212       _thread(*ThreadWrapper::CreateThread(TraceImpl::Run, this,
    213                                            kHighestPriority, "Trace")),
    214       _event(*EventWrapper::Create()),
    215       _critsectArray(*CriticalSectionWrapper::CreateCriticalSection()),
    216       _nextFreeIdx(),
    217       _level(),
    218       _length(),
    219       _messageQueue(),
    220       _activeQueue(0)
    221 {
    222     _nextFreeIdx[0] = 0;
    223     _nextFreeIdx[1] = 0;
    224 
    225     unsigned int tid = 0;
    226     _thread.Start(tid);
    227 
    228     for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++)
    229     {
    230         for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++)
    231         {
    232             _messageQueue[m][n] = new
    233                 WebRtc_Word8[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
    234         }
    235     }
    236 }
    237 
    238 bool TraceImpl::StopThread()
    239 {
    240     // Release the worker thread so that it can flush any lingering messages.
    241     _event.Set();
    242 
    243     // Allow 10 ms for pending messages to be flushed out.
    244     // TODO (hellner): why not use condition variables to do this? Or let the
    245     //                 worker thread die and let this thread flush remaining
    246     //                 messages?
    247 #ifdef _WIN32
    248     Sleep(10);
    249 #else
    250     timespec t;
    251     t.tv_sec = 0;
    252     t.tv_nsec = 10*1000000;
    253     nanosleep(&t,NULL);
    254 #endif
    255 
    256     _thread.SetNotAlive();
    257     // Make sure the thread finishes as quickly as possible (instead of having
    258     // to wait for the timeout).
    259     _event.Set();
    260     bool stopped = _thread.Stop();
    261 
    262     CriticalSectionScoped lock(_critsectInterface);
    263     _traceFile.Flush();
    264     _traceFile.CloseFile();
    265     return stopped;
    266 }
    267 
    268 TraceImpl::~TraceImpl()
    269 {
    270     StopThread();
    271     delete &_event;
    272     delete &_traceFile;
    273     delete &_thread;
    274     delete &_critsectInterface;
    275     delete &_critsectArray;
    276 
    277     for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++)
    278     {
    279         for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++)
    280         {
    281             delete [] _messageQueue[m][n];
    282         }
    283     }
    284 }
    285 
    286 WebRtc_Word32 TraceImpl::AddLevel(char* szMessage, const TraceLevel level) const
    287 {
    288     switch (level)
    289     {
    290         case kTraceStateInfo:
    291             sprintf (szMessage, "STATEINFO ; ");
    292             break;
    293         case kTraceWarning:
    294             sprintf (szMessage, "WARNING   ; ");
    295             break;
    296         case kTraceError:
    297             sprintf (szMessage, "ERROR     ; ");
    298             break;
    299         case kTraceCritical:
    300             sprintf (szMessage, "CRITICAL  ; ");
    301             break;
    302         case kTraceInfo:
    303             sprintf (szMessage, "DEBUGINFO ; ");
    304             break;
    305         case kTraceModuleCall:
    306             sprintf (szMessage, "MODULECALL; ");
    307             break;
    308         case kTraceMemory:
    309             sprintf (szMessage, "MEMORY    ; ");
    310             break;
    311         case kTraceTimer:
    312             sprintf (szMessage, "TIMER     ; ");
    313             break;
    314         case kTraceStream:
    315             sprintf (szMessage, "STREAM    ; ");
    316             break;
    317         case kTraceApiCall:
    318             sprintf (szMessage, "APICALL   ; ");
    319             break;
    320         case kTraceDebug:
    321             sprintf (szMessage, "DEBUG     ; ");
    322             break;
    323         default:
    324             assert(false);
    325             return 0;
    326     }
    327     // All messages are 12 characters.
    328     return 12;
    329 }
    330 
    331 WebRtc_Word32 TraceImpl::AddModuleAndId(char* traceMessage,
    332                                         const TraceModule module,
    333                                         const WebRtc_Word32 id) const
    334 {
    335     // Use long int to prevent problems with different definitions of
    336     // WebRtc_Word32.
    337     // TODO (hellner): is this actually a problem? If so, it should be better to
    338     //                 clean up WebRtc_Word32
    339     const long int idl = id;
    340     if(idl != -1)
    341     {
    342         const unsigned long int idEngine = id>>16;
    343         const unsigned long int idChannel = id & 0xffff;
    344 
    345         switch (module)
    346         {
    347             case kTraceVoice:
    348                 sprintf(traceMessage, "       VOICE:%5ld %5ld;", idEngine,
    349                         idChannel);
    350                 break;
    351             case kTraceVideo:
    352                 sprintf(traceMessage, "       VIDEO:%5ld %5ld;", idEngine,
    353                         idChannel);
    354                 break;
    355             case kTraceUtility:
    356                 sprintf(traceMessage, "     UTILITY:%5ld %5ld;", idEngine,
    357                         idChannel);
    358                 break;
    359             case kTraceRtpRtcp:
    360                 sprintf(traceMessage, "    RTP/RTCP:%5ld %5ld;", idEngine,
    361                         idChannel);
    362                 break;
    363             case kTraceTransport:
    364                 sprintf(traceMessage, "   TRANSPORT:%5ld %5ld;", idEngine,
    365                         idChannel);
    366                 break;
    367             case kTraceAudioCoding:
    368                 sprintf(traceMessage, "AUDIO CODING:%5ld %5ld;", idEngine,
    369                         idChannel);
    370                 break;
    371             case kTraceSrtp:
    372                 sprintf(traceMessage, "        SRTP:%5ld %5ld;", idEngine,
    373                         idChannel);
    374                 break;
    375             case kTraceAudioMixerServer:
    376                 sprintf(traceMessage, " AUDIO MIX/S:%5ld %5ld;", idEngine,
    377                         idChannel);
    378                 break;
    379             case kTraceAudioMixerClient:
    380                 sprintf(traceMessage, " AUDIO MIX/C:%5ld %5ld;", idEngine,
    381                         idChannel);
    382                 break;
    383             case kTraceVideoCoding:
    384                 sprintf(traceMessage, "VIDEO CODING:%5ld %5ld;", idEngine,
    385                         idChannel);
    386                 break;
    387             case kTraceVideoMixer:
    388                 // Print sleep time and API call
    389                 sprintf(traceMessage, "   VIDEO MIX:%5ld %5ld;", idEngine,
    390                         idChannel);
    391                 break;
    392             case kTraceFile:
    393                 sprintf(traceMessage, "        FILE:%5ld %5ld;", idEngine,
    394                         idChannel);
    395                 break;
    396             case kTraceAudioProcessing:
    397                 sprintf(traceMessage, "  AUDIO PROC:%5ld %5ld;", idEngine,
    398                         idChannel);
    399                 break;
    400             case kTraceAudioDevice:
    401                 sprintf(traceMessage, "AUDIO DEVICE:%5ld %5ld;", idEngine,
    402                         idChannel);
    403                 break;
    404             case kTraceVideoRenderer:
    405                 sprintf(traceMessage, "VIDEO RENDER:%5ld %5ld;", idEngine,
    406                         idChannel);
    407                 break;
    408             case kTraceVideoCapture:
    409                 sprintf(traceMessage, "VIDEO CAPTUR:%5ld %5ld;", idEngine,
    410                         idChannel);
    411                 break;
    412             case kTraceVideoPreocessing:
    413                 sprintf(traceMessage, "  VIDEO PROC:%5ld %5ld;", idEngine,
    414                         idChannel);
    415                 break;
    416             default:
    417                 assert(false);
    418                 return 0;
    419         }
    420     } else {
    421         switch (module)
    422         {
    423             case kTraceVoice:
    424                 sprintf (traceMessage, "       VOICE:%11ld;", idl);
    425                 break;
    426             case kTraceVideo:
    427                 sprintf (traceMessage, "       VIDEO:%11ld;", idl);
    428                 break;
    429             case kTraceUtility:
    430                 sprintf (traceMessage, "     UTILITY:%11ld;", idl);
    431                 break;
    432             case kTraceRtpRtcp:
    433                 sprintf (traceMessage, "    RTP/RTCP:%11ld;", idl);
    434                 break;
    435             case kTraceTransport:
    436                 sprintf (traceMessage, "   TRANSPORT:%11ld;", idl);
    437                 break;
    438             case kTraceAudioCoding:
    439                 sprintf (traceMessage, "AUDIO CODING:%11ld;", idl);
    440                 break;
    441             case kTraceSrtp:
    442                 sprintf (traceMessage, "        SRTP:%11ld;", idl);
    443                 break;
    444             case kTraceAudioMixerServer:
    445                 sprintf (traceMessage, " AUDIO MIX/S:%11ld;", idl);
    446                 break;
    447             case kTraceAudioMixerClient:
    448                 sprintf (traceMessage, " AUDIO MIX/C:%11ld;", idl);
    449                 break;
    450             case kTraceVideoCoding:
    451                 sprintf (traceMessage, "VIDEO CODING:%11ld;", idl);
    452                 break;
    453             case kTraceVideoMixer:
    454                 sprintf (traceMessage, "   VIDEO MIX:%11ld;", idl);
    455                 break;
    456             case kTraceFile:
    457                 sprintf (traceMessage, "        FILE:%11ld;", idl);
    458                 break;
    459             case kTraceAudioProcessing:
    460                 sprintf (traceMessage, "  AUDIO PROC:%11ld;", idl);
    461                 break;
    462             case kTraceAudioDevice:
    463                 sprintf (traceMessage, "AUDIO DEVICE:%11ld;", idl);
    464                 break;
    465             case kTraceVideoRenderer:
    466                 sprintf (traceMessage, "VIDEO RENDER:%11ld;", idl);
    467                 break;
    468             case kTraceVideoCapture:
    469                 sprintf (traceMessage, "VIDEO CAPTUR:%11ld;", idl);
    470                 break;
    471             case kTraceVideoPreocessing:
    472                 sprintf (traceMessage, "  VIDEO PROC:%11ld;", idl);
    473                 break;
    474             default:
    475                 assert(false);
    476                 return 0;
    477         }
    478     }
    479     // All messages are 25 characters.
    480     return 25;
    481 }
    482 
    483 WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8,
    484                                           const bool addFileCounter)
    485 {
    486     CriticalSectionScoped lock(_critsectInterface);
    487 
    488     _traceFile.Flush();
    489     _traceFile.CloseFile();
    490 
    491     if(fileNameUTF8)
    492     {
    493         if(addFileCounter)
    494         {
    495             _fileCountText = 1;
    496 
    497             WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize];
    498             CreateFileName(fileNameUTF8, fileNameWithCounterUTF8,
    499                            _fileCountText);
    500             if(_traceFile.OpenFile(fileNameWithCounterUTF8, false, false,
    501                                    true) == -1)
    502             {
    503                 return -1;
    504             }
    505         }else {
    506             _fileCountText = 0;
    507             if(_traceFile.OpenFile(fileNameUTF8, false, false, true) == -1)
    508             {
    509                 return -1;
    510             }
    511         }
    512     }
    513     _rowCountText = 0;
    514     return 0;
    515 }
    516 
    517 WebRtc_Word32 TraceImpl::TraceFileImpl(
    518     WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize])
    519 {
    520     CriticalSectionScoped lock(_critsectInterface);
    521     return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize);
    522 }
    523 
    524 WebRtc_Word32 TraceImpl::SetTraceCallbackImpl(TraceCallback* callback)
    525 {
    526     CriticalSectionScoped lock(_critsectInterface);
    527     _callback = callback;
    528     return 0;
    529 }
    530 
    531 WebRtc_Word32 TraceImpl::AddMessage(
    532     char* traceMessage,
    533     const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
    534     const WebRtc_UWord16 writtenSoFar) const
    535 
    536 {
    537     int length = 0;
    538     if(writtenSoFar >= WEBRTC_TRACE_MAX_MESSAGE_SIZE)
    539     {
    540         return -1;
    541     }
    542     // - 2 to leave room for newline and NULL termination
    543 #ifdef _WIN32
    544     length = _snprintf(traceMessage,
    545                        WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2,
    546                        "%s",msg);
    547     if(length < 0)
    548     {
    549         length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2;
    550         traceMessage[length] = 0;
    551     }
    552 #else
    553     length = snprintf(traceMessage,
    554                       WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar-2, "%s",msg);
    555     if(length < 0 || length > WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar - 2)
    556     {
    557         length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2;
    558         traceMessage[length] = 0;
    559     }
    560 #endif
    561     // Length with NULL termination.
    562     return length+1;
    563 }
    564 
    565 void TraceImpl::AddMessageToList(
    566     const char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
    567     const WebRtc_UWord16 length,
    568     const TraceLevel level)
    569 {
    570     CriticalSectionScoped lock(_critsectArray);
    571 
    572     if(_nextFreeIdx[_activeQueue] >= WEBRTC_TRACE_MAX_QUEUE)
    573     {
    574         if( ! _traceFile.Open() &&
    575             !_callback)
    576         {
    577             // Keep at least the last 1/4 of old messages when not logging.
    578             // TODO (hellner): isn't this redundant. The user will make it known
    579             //                 when to start logging. Why keep messages before
    580             //                 that?
    581             for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE/4; n++)
    582             {
    583                 const int lastQuarterOffset = (3*WEBRTC_TRACE_MAX_QUEUE/4);
    584                 memcpy(_messageQueue[_activeQueue][n],
    585                        _messageQueue[_activeQueue][n + lastQuarterOffset],
    586                        WEBRTC_TRACE_MAX_MESSAGE_SIZE);
    587             }
    588             _nextFreeIdx[_activeQueue] = WEBRTC_TRACE_MAX_QUEUE/4;
    589         } else {
    590             // More messages are being written than there is room for in the
    591             // buffer. Drop any new messages.
    592             // TODO (hellner): its probably better to drop old messages instead
    593             //                 of new ones. One step further: if this happens
    594             //                 it's due to writing faster than what can be
    595             //                 processed. Maybe modify the filter at this point.
    596             //                 E.g. turn of STREAM.
    597             return;
    598         }
    599     }
    600 
    601     WebRtc_UWord16 idx = _nextFreeIdx[_activeQueue];
    602     _nextFreeIdx[_activeQueue]++;
    603 
    604     _level[_activeQueue][idx] = level;
    605     _length[_activeQueue][idx] = length;
    606     memcpy(_messageQueue[_activeQueue][idx], traceMessage, length);
    607 
    608     if(_nextFreeIdx[_activeQueue] == WEBRTC_TRACE_MAX_QUEUE-1)
    609     {
    610         // Loggin more messages than can be worked off. Log a warning.
    611         memcpy(_messageQueue[_activeQueue][_nextFreeIdx[_activeQueue]],
    612                "WARNING MISSING TRACE MESSAGES\n", 32);
    613         _nextFreeIdx[_activeQueue]++;
    614     }
    615 }
    616 
    617 bool TraceImpl::Run(void* obj)
    618 {
    619     return static_cast<TraceImpl*>(obj)->Process();
    620 }
    621 
    622 bool TraceImpl::Process()
    623 {
    624     if(_event.Wait(1000) == kEventSignaled)
    625     {
    626         if(_traceFile.Open() || _callback)
    627         {
    628             // File mode (not calback mode).
    629             WriteToFile();
    630         }
    631     } else {
    632         _traceFile.Flush();
    633     }
    634     return true;
    635 }
    636 
    637 void TraceImpl::WriteToFile()
    638 {
    639     WebRtc_UWord8 localQueueActive = 0;
    640     WebRtc_UWord16 localNextFreeIdx = 0;
    641 
    642     // There are two buffer. One for reading (for writing to file) and one for
    643     // writing (for storing new messages). Let new messages be posted to the
    644     // unused buffer so that the current buffer can be flushed safely.
    645     {
    646         CriticalSectionScoped lock(_critsectArray);
    647         localNextFreeIdx = _nextFreeIdx[_activeQueue];
    648         _nextFreeIdx[_activeQueue] = 0;
    649         localQueueActive = _activeQueue;
    650         if(_activeQueue == 0)
    651         {
    652             _activeQueue = 1;
    653         } else
    654         {
    655             _activeQueue = 0;
    656         }
    657     }
    658     if(localNextFreeIdx == 0)
    659     {
    660         return;
    661     }
    662 
    663     CriticalSectionScoped lock(_critsectInterface);
    664 
    665     for(WebRtc_UWord16 idx = 0; idx <localNextFreeIdx; idx++)
    666     {
    667         TraceLevel localLevel = _level[localQueueActive][idx];
    668         if(_callback)
    669         {
    670             _callback->Print(localLevel, _messageQueue[localQueueActive][idx],
    671                              _length[localQueueActive][idx]);
    672         }
    673         if(_traceFile.Open())
    674         {
    675             if(_rowCountText > WEBRTC_TRACE_MAX_FILE_SIZE)
    676             {
    677                 // wrap file
    678                 _rowCountText = 0;
    679                 _traceFile.Flush();
    680 
    681                 if(_fileCountText == 0)
    682                 {
    683                     _traceFile.Rewind();
    684                 } else
    685                 {
    686                     WebRtc_Word8 oldFileName[FileWrapper::kMaxFileNameSize];
    687                     WebRtc_Word8 newFileName[FileWrapper::kMaxFileNameSize];
    688 
    689                     // get current name
    690                     _traceFile.FileName(oldFileName,
    691                                         FileWrapper::kMaxFileNameSize);
    692                     _traceFile.CloseFile();
    693 
    694                     _fileCountText++;
    695 
    696                     UpdateFileName(oldFileName, newFileName, _fileCountText);
    697 
    698                     if(_traceFile.OpenFile(newFileName, false, false,
    699                                            true) == -1)
    700                     {
    701                         return;
    702                     }
    703                 }
    704             }
    705             if(_rowCountText ==  0)
    706             {
    707                 WebRtc_Word8 message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1];
    708                 WebRtc_Word32 length = AddDateTimeInfo(message);
    709                 if(length != -1)
    710                 {
    711                     message[length] = 0;
    712                     message[length-1] = '\n';
    713                     _traceFile.Write(message, length);
    714                     _rowCountText++;
    715                 }
    716                 length = AddBuildInfo(message);
    717                 if(length != -1)
    718                 {
    719                     message[length+1] = 0;
    720                     message[length] = '\n';
    721                     message[length-1] = '\n';
    722                     _traceFile.Write(message, length+1);
    723                     _rowCountText++;
    724                     _rowCountText++;
    725                 }
    726             }
    727             WebRtc_UWord16 length = _length[localQueueActive][idx];
    728             _messageQueue[localQueueActive][idx][length] = 0;
    729             _messageQueue[localQueueActive][idx][length-1] = '\n';
    730             _traceFile.Write(_messageQueue[localQueueActive][idx], length);
    731             _rowCountText++;
    732         }
    733     }
    734 }
    735 
    736 void TraceImpl::AddImpl(const TraceLevel level, const TraceModule module,
    737                         const WebRtc_Word32 id,
    738                         const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE])
    739 {
    740     if (TraceCheck(level))
    741     {
    742         char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
    743         char* meassagePtr = traceMessage;
    744 
    745         WebRtc_Word32 len = 0;
    746         WebRtc_Word32 ackLen = 0;
    747 
    748         len = AddLevel(meassagePtr, level);
    749         if(len == -1)
    750         {
    751             return;
    752         }
    753         meassagePtr += len;
    754         ackLen += len;
    755 
    756         len = AddTime(meassagePtr, level);
    757         if(len == -1)
    758         {
    759             return;
    760         }
    761         meassagePtr += len;
    762         ackLen += len;
    763 
    764         len = AddModuleAndId(meassagePtr, module, id);
    765         if(len == -1)
    766         {
    767             return;
    768         }
    769         meassagePtr += len;
    770         ackLen += len;
    771 
    772         len = AddThreadId(meassagePtr);
    773         if(len == -1)
    774         {
    775             return;
    776         }
    777         meassagePtr += len;
    778         ackLen += len;
    779 
    780         len = AddMessage(meassagePtr, msg, (WebRtc_UWord16)ackLen);
    781         if(len == -1)
    782         {
    783             return;
    784         }
    785         ackLen += len;
    786         AddMessageToList(traceMessage,(WebRtc_UWord16)ackLen, level);
    787 
    788         // Make sure that messages are written as soon as possible.
    789         _event.Set();
    790     }
    791 }
    792 
    793 bool TraceImpl::TraceCheck(const TraceLevel level) const
    794 {
    795     return (level & levelFilter)? true:false;
    796 }
    797 
    798 bool TraceImpl::UpdateFileName(
    799     const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize],
    800     WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],
    801     const WebRtc_UWord32 newCount) const
    802 {
    803     WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
    804     if(length < 0)
    805     {
    806         return false;
    807     }
    808 
    809     WebRtc_Word32 lengthWithoutFileEnding = length-1;
    810     while(lengthWithoutFileEnding > 0)
    811     {
    812         if(fileNameUTF8[lengthWithoutFileEnding] == '.')
    813         {
    814             break;
    815         } else {
    816             lengthWithoutFileEnding--;
    817         }
    818     }
    819     if(lengthWithoutFileEnding == 0)
    820     {
    821         lengthWithoutFileEnding = length;
    822     }
    823     WebRtc_Word32 lengthTo_ = lengthWithoutFileEnding - 1;
    824     while(lengthTo_ > 0)
    825     {
    826         if(fileNameUTF8[lengthTo_] == '_')
    827         {
    828             break;
    829         } else {
    830             lengthTo_--;
    831         }
    832     }
    833 
    834     memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthTo_);
    835     sprintf(fileNameWithCounterUTF8+lengthTo_, "_%lu%s", newCount,
    836             fileNameUTF8+lengthWithoutFileEnding);
    837     return true;
    838 }
    839 
    840 bool TraceImpl::CreateFileName(
    841     const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize],
    842     WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],
    843     const WebRtc_UWord32 newCount) const
    844 {
    845     WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
    846     if(length < 0)
    847     {
    848         return false;
    849     }
    850 
    851     WebRtc_Word32 lengthWithoutFileEnding = length-1;
    852     while(lengthWithoutFileEnding > 0)
    853     {
    854         if(fileNameUTF8[lengthWithoutFileEnding] == '.')
    855         {
    856             break;
    857         }else
    858         {
    859             lengthWithoutFileEnding--;
    860         }
    861     }
    862     if(lengthWithoutFileEnding == 0)
    863     {
    864         lengthWithoutFileEnding = length;
    865     }
    866     memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthWithoutFileEnding);
    867     sprintf(fileNameWithCounterUTF8+lengthWithoutFileEnding, "_%lu%s",
    868             newCount, fileNameUTF8+lengthWithoutFileEnding);
    869     return true;
    870 }
    871 
    872 WebRtc_Word32 Trace::SetLevelFilter(WebRtc_UWord32 filter)
    873 {
    874     levelFilter = filter;
    875     return 0;
    876 };
    877 
    878 WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter)
    879 {
    880     filter = levelFilter;
    881     return 0;
    882 };
    883 
    884 WebRtc_Word32 Trace::TraceFile(WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize])
    885 {
    886     TraceImpl* trace = TraceImpl::GetTrace();
    887     if(trace)
    888     {
    889         int retVal = trace->TraceFileImpl(fileName);
    890         ReturnTrace();
    891         return retVal;
    892     }
    893     return -1;
    894 }
    895 
    896 WebRtc_Word32 Trace::SetTraceFile(const WebRtc_Word8* fileName,
    897                                   const bool addFileCounter)
    898 {
    899     TraceImpl* trace = TraceImpl::GetTrace();
    900     if(trace)
    901     {
    902         int retVal = trace->SetTraceFileImpl(fileName, addFileCounter);
    903         ReturnTrace();
    904         return retVal;
    905     }
    906     return -1;
    907 }
    908 
    909 WebRtc_Word32 Trace::SetTraceCallback(TraceCallback* callback)
    910 {
    911     TraceImpl* trace = TraceImpl::GetTrace();
    912     if(trace)
    913     {
    914         int retVal = trace->SetTraceCallbackImpl(callback);
    915         ReturnTrace();
    916         return retVal;
    917     }
    918     return -1;
    919 }
    920 
    921 void Trace::Add(const TraceLevel level, const TraceModule module,
    922                 const WebRtc_Word32 id, const char* msg, ...)
    923 
    924 {
    925     TraceImpl* trace = TraceImpl::GetTrace(level);
    926     if(trace)
    927     {
    928         if(trace->TraceCheck(level))
    929         {
    930             char tempBuff[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
    931             char* buff = 0;
    932             if(msg)
    933             {
    934                 va_list args;
    935                 va_start(args, msg);
    936 #ifdef _WIN32
    937                 _vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args);
    938 #else
    939                 vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args);
    940 #endif
    941                 va_end(args);
    942                 buff = tempBuff;
    943             }
    944             trace->AddImpl(level, module, id, buff);
    945         }
    946         ReturnTrace();
    947     }
    948 }
    949 } // namespace webrtc
    950