Changeset 4552 for pjproject/trunk


Ignore:
Timestamp:
Jul 5, 2013 8:14:14 AM (11 years ago)
Author:
nanang
Message:

Fix #1686: release mutex when invoking callback to avoid deadlock. Also a bit memory usage optimization, i.e: avoid bloated pool by unfreed old/expired packet in cache entry.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib-util/src/pjlib-util/resolver.c

    r4537 r4552  
    158158    pj_time_val              expiry_time;   /**< Expiration time.           */ 
    159159    pj_dns_parsed_packet    *pkt;           /**< The response packet.       */ 
     160    unsigned                 ref_cnt;       /**< Reference counter.         */ 
    160161}; 
    161162 
     
    701702    cache = PJ_POOL_ZALLOC_T(pool, struct cached_res); 
    702703    cache->pool = pool; 
     704    cache->ref_cnt = 1; 
    703705 
    704706    return cache; 
     707} 
     708 
     709/* Re-allocate cache entry, to free cached packet */ 
     710static void reset_entry(struct cached_res **p_cached) 
     711{ 
     712    pj_pool_t *pool; 
     713    struct cached_res *cache = *p_cached; 
     714    unsigned ref_cnt; 
     715 
     716    pool = cache->pool; 
     717    ref_cnt = cache->ref_cnt; 
     718 
     719    pj_pool_reset(pool); 
     720 
     721    cache = PJ_POOL_ZALLOC_T(pool, struct cached_res); 
     722    cache->pool = pool; 
     723    cache->ref_cnt = ref_cnt; 
     724    *p_cached = cache; 
    705725} 
    706726 
     
    776796            status = PJ_STATUS_FROM_DNS_RCODE(status); 
    777797 
     798            /* Workaround for deadlock problem. Need to increment the cache's 
     799             * ref counter first before releasing mutex, so the cache won't be 
     800             * destroyed by other thread while in callback. 
     801             */ 
     802            cache->ref_cnt++; 
     803            pj_mutex_unlock(resolver->mutex); 
     804 
    778805            /* This cached response is still valid. Just return this 
    779806             * response to caller. 
     
    784811 
    785812            /* Done. No host resolution is necessary */ 
     813            pj_mutex_lock(resolver->mutex); 
     814 
     815            /* Decrement the ref counter. Also check if it is time to free 
     816             * the cache (as it has been expired). 
     817             */ 
     818            cache->ref_cnt--; 
     819            if (cache->ref_cnt <= 0) 
     820                free_entry(resolver, cache); 
    786821 
    787822            /* Must return PJ_SUCCESS */ 
     
    796831        pj_hash_set(NULL, resolver->hrescache, &key, sizeof(key), 0, NULL); 
    797832 
    798         /* Store the entry into free nodes */ 
    799         free_entry(resolver, cache); 
     833        /* Also free the cache, if it is not being used (by callback). */ 
     834        cache->ref_cnt--; 
     835        if (cache->ref_cnt <= 0) 
     836            free_entry(resolver, cache); 
    800837 
    801838        /* Must continue with creating a query now */ 
     
    12081245    if (cache == NULL) { 
    12091246        cache = alloc_entry(resolver); 
     1247    } else { 
     1248        /* Reset cache to avoid bloated cache pool */ 
     1249        reset_entry(&cache); 
    12101250    } 
    12111251 
     
    12161256     * the name being requested. 
    12171257     */ 
    1218     cache->pkt = NULL; 
    12191258    pj_dns_packet_dup(cache->pool, pkt,  
    12201259                      PJ_DNS_NO_NS | PJ_DNS_NO_AR, 
Note: See TracChangeset for help on using the changeset viewer.