Changeset 2853


Ignore:
Timestamp:
Aug 5, 2009 10:58:02 AM (12 years ago)
Author:
bennylp
Message:

Ticket #931: Logging function may infinitely recursively calls itself on Windows Mobile (thanks Emil Sturniolo for the report)

  • Added feature to temporarily suspend the logging facility while we're in the pj_log() function. The suspension will be thread specific if the platform supports it.
Location:
pjproject/trunk/pjlib
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib/include/pj/log.h

    r2842 r2853  
    221221PJ_DECL(pj_color_t) pj_log_get_color(int level); 
    222222 
     223/** 
     224 * Internal function to be called by pj_init() 
     225 */ 
     226pj_status_t pj_log_init(void); 
    223227 
    224228#else   /* #if PJ_LOG_MAX_LEVEL >= 1 */ 
     
    288292#  define pj_log_get_color(level) 0 
    289293 
     294 
     295/** 
     296 * Internal. 
     297 */ 
     298#   define pj_log_init()        PJ_SUCCESS 
    290299 
    291300#endif  /* #if PJ_LOG_MAX_LEVEL >= 1 */ 
  • pjproject/trunk/pjlib/src/pj/log.c

    r2842 r2853  
    3131static int pj_log_max_level = PJ_LOG_MAX_LEVEL; 
    3232#endif 
     33static long thread_suspended_tls_id = -1; 
    3334static pj_log_func *log_writer = &pj_log_write; 
    3435static unsigned log_decor = PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC | 
     
    6768#endif 
    6869 
     70static void logging_shutdown(void) 
     71{ 
     72#if PJ_HAS_THREADS 
     73    if (thread_suspended_tls_id != -1) { 
     74        pj_thread_local_free(thread_suspended_tls_id); 
     75        thread_suspended_tls_id = -1; 
     76    } 
     77#endif 
     78} 
     79 
     80pj_status_t pj_log_init(void) 
     81{ 
     82#if PJ_HAS_THREADS 
     83    if (thread_suspended_tls_id == -1) { 
     84        pj_thread_local_alloc(&thread_suspended_tls_id); 
     85        pj_atexit(&logging_shutdown); 
     86    } 
     87#endif 
     88    return PJ_SUCCESS; 
     89} 
     90 
    6991PJ_DEF(void) pj_log_set_decor(unsigned decor) 
    7092{ 
     
    149171} 
    150172 
     173/* Temporarily suspend logging facility for this thread. 
     174 * If thread local storage/variable is not used or not initialized, then 
     175 * we can only suspend the logging globally across all threads. This may 
     176 * happen e.g. when log function is called before PJLIB is fully initialized 
     177 * or after PJLIB is shutdown. 
     178 */ 
     179static void suspend_logging(int *saved_level) 
     180{ 
     181#if PJ_HAS_THREADS 
     182    if (thread_suspended_tls_id != -1)  
     183    { 
     184        pj_thread_local_set(thread_suspended_tls_id, (void*)PJ_TRUE); 
     185    }  
     186    else 
     187#endif 
     188    { 
     189        pj_log_max_level = 0; 
     190    } 
     191    /* Save the level regardless, just in case PJLIB is shutdown 
     192     * between suspend and resume. 
     193     */ 
     194    *saved_level = pj_log_max_level; 
     195} 
     196 
     197/* Resume logging facility for this thread */ 
     198static void resume_logging(int *saved_level) 
     199{ 
     200#if PJ_HAS_THREADS 
     201    if (thread_suspended_tls_id != -1)  
     202    { 
     203        pj_thread_local_set(thread_suspended_tls_id, (void*)PJ_FALSE); 
     204    } 
     205    else 
     206#endif 
     207    { 
     208        /* Only revert the level if application doesn't change the 
     209         * logging level between suspend and resume. 
     210         */ 
     211        if (pj_log_max_level==0 && *saved_level) 
     212            pj_log_max_level = *saved_level; 
     213    } 
     214} 
     215 
     216/* Is logging facility suspended for this thread? */ 
     217static pj_bool_t is_logging_suspended(void) 
     218{ 
     219#if PJ_HAS_THREADS 
     220    if (thread_suspended_tls_id != -1)  
     221    { 
     222        return pj_thread_local_get(thread_suspended_tls_id) != NULL; 
     223    } 
     224    else 
     225#endif 
     226    { 
     227        return pj_log_max_level != 0; 
     228    } 
     229} 
     230 
    151231PJ_DEF(void) pj_log( const char *sender, int level,  
    152232                     const char *format, va_list marker) 
     
    158238    char log_buffer[PJ_LOG_MAX_SIZE]; 
    159239#endif 
    160     int len, print_len; 
     240    int saved_level, len, print_len; 
    161241 
    162242    PJ_CHECK_STACK(); 
     
    164244    if (level > pj_log_max_level) 
    165245        return; 
     246 
     247    if (is_logging_suspended()) 
     248        return; 
     249 
     250    /* Temporarily disable logging for this thread. Some of PJLIB APIs that 
     251     * this function calls below will recursively call the logging function  
     252     * back, hence it will cause infinite recursive calls if we allow that. 
     253     */ 
     254    suspend_logging(&saved_level); 
    166255 
    167256    /* Get current date/time. */ 
     
    275364    } 
    276365 
     366    /* It should be safe to resume logging at this point. Application can 
     367     * recursively call the logging function inside the callback. 
     368     */ 
     369    resume_logging(&saved_level); 
     370 
    277371    if (log_writer) 
    278372        (*log_writer)(level, log_buffer, len); 
  • pjproject/trunk/pjlib/src/pj/os_core_symbian.cpp

    r2481 r2853  
    343343    if (err != KErrNone) 
    344344        return PJ_RETURN_OS_ERROR(err); 
    345      
     345 
     346    /* Init logging */ 
     347    pj_log_init(); 
     348 
    346349    /* Initialize exception ID for the pool.  
    347350     * Must do so after critical section is configured. 
  • pjproject/trunk/pjlib/src/pj/os_core_unix.c

    r2395 r2853  
    139139 
    140140#endif 
     141 
     142    /* Init logging */ 
     143    pj_log_init(); 
    141144 
    142145    /* Initialize exception ID for the pool.  
  • pjproject/trunk/pjlib/src/pj/os_core_win32.c

    r2843 r2853  
    153153    } 
    154154     
     155    /* Init logging */ 
     156    pj_log_init(); 
     157 
    155158    /* Init random seed. */ 
    156159    /* Or probably not. Let application in charge of this */ 
Note: See TracChangeset for help on using the changeset viewer.