Changeset 4420


Ignore:
Timestamp:
Mar 5, 2013 11:59:54 AM (8 years ago)
Author:
bennylp
Message:

Implementation of Re #1628: Modify SIP transaction to use group lock to avoid deadlock etc.

Location:
pjproject/trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/samples/stateful_proxy.c

    r3553 r4420  
    274274            pjsip_tx_data *cancel; 
    275275 
    276             pj_mutex_lock(uas_data->uac_tsx->mutex); 
     276            pj_grp_lock_acquire(uas_data->uac_tsx->grp_lock); 
    277277 
    278278            pjsip_endpt_create_cancel(global.endpt, uas_data->uac_tsx->last_tx, 
     
    280280            pjsip_endpt_send_request(global.endpt, cancel, -1, NULL, NULL); 
    281281 
    282             pj_mutex_unlock(uas_data->uac_tsx->mutex); 
     282            pj_grp_lock_release(uas_data->uac_tsx->grp_lock); 
    283283        } 
    284284 
    285285        /* Unlock UAS tsx because it is locked in find_tsx() */ 
    286         pj_mutex_unlock(invite_uas->mutex); 
     286        pj_grp_lock_release(invite_uas->grp_lock); 
    287287    } 
    288288 
  • pjproject/trunk/pjsip/include/pjsip/sip_transaction.h

    r3553 r4420  
    8686    pjsip_module               *tsx_user;       /**< Transaction user.      */ 
    8787    pjsip_endpoint             *endpt;          /**< Endpoint instance.     */ 
    88     pj_mutex_t                 *mutex;          /**< Mutex for this tsx.    */ 
     88    pj_bool_t                   terminating;    /**< terminate() was called */ 
     89    pj_grp_lock_t              *grp_lock;       /**< Transaction grp lock.  */ 
    8990    pj_mutex_t                 *mutex_b;        /**< Second mutex to avoid 
    9091                                                     deadlock. It is used to 
     
    214215 
    215216/** 
     217 * Variant of pjsip_tsx_create_uac() with additional parameter to specify 
     218 * the group lock to use. Group lock can be used to synchronize locking 
     219 * among several objects to prevent deadlock, and to synchronize the 
     220 * lifetime of objects sharing the same group lock. 
     221 * 
     222 * See pjsip_tsx_create_uac() for general info about this function. 
     223 * 
     224 * @param tsx_user  Module to be registered as transaction user of the new 
     225 *                  transaction, which will receive notification from the 
     226 *                  transaction via on_tsx_state() callback. 
     227 * @param tdata     The outgoing request message. 
     228 * @param grp_lock  Optional group lock to use by this transaction. If 
     229 *                  the value is NULL, the transaction will create its 
     230 *                  own group lock. 
     231 * @param p_tsx     On return will contain the new transaction instance. 
     232 * 
     233 * @return          PJ_SUCCESS if successfull. 
     234 */ 
     235PJ_DECL(pj_status_t) pjsip_tsx_create_uac2(pjsip_module *tsx_user, 
     236                                           pjsip_tx_data *tdata, 
     237                                           pj_grp_lock_t *grp_lock, 
     238                                           pjsip_transaction **p_tsx); 
     239 
     240/** 
    216241 * Create, initialize, and register a new transaction as UAS from the 
    217242 * specified incoming request in \c rdata. After calling this function, 
     
    231256                                           pjsip_transaction **p_tsx ); 
    232257 
     258/** 
     259 * Variant of pjsip_tsx_create_uas() with additional parameter to specify 
     260 * the group lock to use. Group lock can be used to synchronize locking 
     261 * among several objects to prevent deadlock, and to synchronize the 
     262 * lifetime of objects sharing the same group lock. 
     263 * 
     264 * See pjsip_tsx_create_uas() for general info about this function. 
     265 * 
     266 * @param tsx_user  Module to be registered as transaction user of the new 
     267 *                  transaction, which will receive notification from the 
     268 *                  transaction via on_tsx_state() callback. 
     269 * @param rdata     The received incoming request. 
     270 * @param grp_lock  Optional group lock to use by this transaction. If 
     271 *                  the value is NULL, the transaction will create its 
     272 *                  own group lock. 
     273 * @param p_tsx     On return will contain the new transaction instance. 
     274 * 
     275 * @return          PJ_SUCCESS if successfull. 
     276 */ 
     277PJ_DECL(pj_status_t) pjsip_tsx_create_uas2(pjsip_module *tsx_user, 
     278                                           pjsip_rx_data *rdata, 
     279                                           pj_grp_lock_t *grp_lock, 
     280                                           pjsip_transaction **p_tsx ); 
    233281 
    234282/** 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c

    r4367 r4420  
    29112911 
    29122912    if (invite_tsx) 
    2913         pj_mutex_unlock(invite_tsx->mutex); 
     2913        pj_grp_lock_release(invite_tsx->grp_lock); 
    29142914} 
    29152915 
  • pjproject/trunk/pjsip/src/pjsip/sip_transaction.c

    r4208 r4420  
    2828#include <pj/pool.h> 
    2929#include <pj/os.h> 
     30#include <pj/rand.h> 
    3031#include <pj/string.h> 
    3132#include <pj/assert.h> 
     
    9192}; 
    9293 
    93 /* Thread Local Storage ID for transaction lock */ 
    94 static long pjsip_tsx_lock_tls_id; 
    95  
    9694/* Transaction state names */ 
    9795static const char *state_str[] =  
     
    123121    TSX_HAS_RESOLVED_SERVER     = 16, 
    124122}; 
    125  
    126 /* Transaction lock. */ 
    127 typedef struct tsx_lock_data { 
    128     struct tsx_lock_data *prev; 
    129     pjsip_transaction    *tsx; 
    130     int                   is_alive; 
    131 } tsx_lock_data; 
    132  
    133123 
    134124/* Timer timeout value constants */ 
     
    149139 
    150140/* Prototypes. */ 
    151 static void        lock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck); 
    152 static pj_status_t unlock_tsx( pjsip_transaction *tsx,  
    153                                struct tsx_lock_data *lck); 
    154141static pj_status_t tsx_on_state_null(           pjsip_transaction *tsx,  
    155142                                                pjsip_event *event); 
     
    179166                                       const pjsip_transport_state_info *info); 
    180167static pj_status_t tsx_create( pjsip_module *tsx_user, 
     168                               pj_grp_lock_t *grp_lock, 
    181169                               pjsip_transaction **p_tsx); 
    182 static pj_status_t tsx_destroy( pjsip_transaction *tsx ); 
     170static void        tsx_on_destroy(void *arg); 
     171static pj_status_t tsx_shutdown( pjsip_transaction *tsx ); 
    183172static void        tsx_resched_retransmission( pjsip_transaction *tsx ); 
    184173static pj_status_t tsx_retransmit( pjsip_transaction *tsx, int resched); 
     
    271260{ 
    272261#define SEPARATOR   '$' 
    273     char *key, *p, *end; 
     262    char *key, *p; 
    274263    int len; 
    275264    pj_size_t len_required; 
    276     pjsip_uri *req_uri; 
    277265    pj_str_t *host; 
    278266 
     
    284272 
    285273    host = &rdata->msg_info.via->sent_by.host; 
    286     req_uri = (pjsip_uri*)rdata->msg_info.msg->line.req.uri; 
    287274 
    288275    /* Calculate length required. */ 
     
    294281                   16;                      /* Separator+Allowance. */ 
    295282    key = p = (char*) pj_pool_alloc(pool, len_required); 
    296     end = p + len_required; 
    297283 
    298284    /* Add role. */ 
     
    452438    timeout_timer_val = td_timer_val; 
    453439 
    454     /* Initialize TLS ID for transaction lock. */ 
    455     status = pj_thread_local_alloc(&pjsip_tsx_lock_tls_id); 
    456     if (status != PJ_SUCCESS) 
    457         return status; 
    458  
    459     pj_thread_local_set(pjsip_tsx_lock_tls_id, NULL); 
    460  
    461440    /* 
    462441     * Initialize transaction layer structure. 
     
    483462    } 
    484463 
    485     /* Create mutex. */ 
     464    /* Create group lock. */ 
    486465    status = pj_mutex_create_recursive(pool, "tsxlayer", &mod_tsx_layer.mutex); 
    487466    if (status != PJ_SUCCESS) { 
     
    666645     */ 
    667646    PJ_TODO(FIX_RACE_CONDITION_HERE); 
     647    PJ_RACE_ME(5); 
     648 
    668649    if (tsx && lock) 
    669         pj_mutex_lock(tsx->mutex); 
     650        pj_grp_lock_acquire(tsx->grp_lock); 
    670651 
    671652    return tsx; 
     
    712693            pjsip_tsx_terminate(tsx, PJSIP_SC_SERVICE_UNAVAILABLE); 
    713694            mod_tsx_layer_unregister_tsx(tsx); 
    714             tsx_destroy(tsx); 
     695            tsx_shutdown(tsx); 
    715696        } 
    716697        it = next; 
     
    735716    /* Release pool. */ 
    736717    pjsip_endpt_release_pool(mod_tsx_layer.endpt, mod_tsx_layer.pool); 
    737  
    738     /* Free TLS */ 
    739     pj_thread_local_free(pjsip_tsx_lock_tls_id); 
    740718 
    741719    /* Mark as unregistered. */ 
     
    814792     */ 
    815793    PJ_TODO(FIX_RACE_CONDITION_HERE); 
     794    PJ_RACE_ME(5); 
    816795 
    817796    /* Pass the message to the transaction. */ 
     
    863842     */ 
    864843    PJ_TODO(FIX_RACE_CONDITION_HERE); 
     844    PJ_RACE_ME(5); 
    865845 
    866846    /* Pass the message to the transaction. */ 
     
    929909 ***************************************************************************** 
    930910 **/ 
    931 /* 
    932  * Lock transaction and set the value of Thread Local Storage. 
    933  */ 
    934 static void lock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck) 
    935 { 
    936     struct tsx_lock_data *prev_data; 
    937  
    938     pj_mutex_lock(tsx->mutex); 
    939     prev_data = (struct tsx_lock_data *)  
    940                     pj_thread_local_get(pjsip_tsx_lock_tls_id); 
    941     lck->prev = prev_data; 
    942     lck->tsx = tsx; 
    943     lck->is_alive = 1; 
    944     pj_thread_local_set(pjsip_tsx_lock_tls_id, lck); 
    945 } 
    946  
    947  
    948 /* 
    949  * Unlock transaction. 
    950  * This will selectively unlock the mutex ONLY IF the transaction has not been  
    951  * destroyed. The function knows whether the transaction has been destroyed 
    952  * because when transaction is destroyed the is_alive flag for the transaction 
    953  * will be set to zero. 
    954  */ 
    955 static pj_status_t unlock_tsx( pjsip_transaction *tsx,  
    956                                struct tsx_lock_data *lck) 
    957 { 
    958     pj_assert( (void*)pj_thread_local_get(pjsip_tsx_lock_tls_id) == lck); 
    959     pj_assert( lck->tsx == tsx ); 
    960     pj_thread_local_set(pjsip_tsx_lock_tls_id, lck->prev); 
    961     if (lck->is_alive) 
    962         pj_mutex_unlock(tsx->mutex); 
    963  
    964     return lck->is_alive ? PJ_SUCCESS : PJSIP_ETSXDESTROYED; 
    965 } 
    966  
    967  
    968911/* Lock transaction for accessing the timeout timer only. */ 
    969912static void lock_timer(pjsip_transaction *tsx) 
     
    982925 */ 
    983926static pj_status_t tsx_create( pjsip_module *tsx_user, 
     927                               pj_grp_lock_t *grp_lock, 
    984928                               pjsip_transaction **p_tsx) 
    985929{ 
     
    1010954    tsx->timeout_timer.cb = &tsx_timer_callback; 
    1011955     
    1012     status = pj_mutex_create_recursive(pool, tsx->obj_name, &tsx->mutex); 
    1013     if (status != PJ_SUCCESS) { 
    1014         pjsip_endpt_release_pool(mod_tsx_layer.endpt, pool); 
    1015         return status; 
    1016     } 
     956    if (grp_lock) { 
     957        tsx->grp_lock = grp_lock; 
     958    } else { 
     959        status = pj_grp_lock_create(pool, NULL, &tsx->grp_lock); 
     960        if (status != PJ_SUCCESS) { 
     961            pjsip_endpt_release_pool(mod_tsx_layer.endpt, pool); 
     962            return status; 
     963        } 
     964    } 
     965 
     966    pj_grp_lock_add_ref(tsx->grp_lock); 
     967    pj_grp_lock_add_handler(tsx->grp_lock, tsx->pool, tsx, &tsx_on_destroy); 
    1017968 
    1018969    status = pj_mutex_create_simple(pool, tsx->obj_name, &tsx->mutex_b); 
    1019970    if (status != PJ_SUCCESS) { 
    1020         pj_mutex_destroy(tsx->mutex); 
    1021         pjsip_endpt_release_pool(mod_tsx_layer.endpt, pool); 
     971        tsx_shutdown(tsx); 
    1022972        return status; 
    1023973    } 
     
    1027977} 
    1028978 
    1029  
    1030 /* Destroy transaction. */ 
    1031 static pj_status_t tsx_destroy( pjsip_transaction *tsx ) 
    1032 { 
    1033     struct tsx_lock_data *lck; 
    1034  
     979/* Really destroy transaction, when grp_lock reference is zero */ 
     980static void tsx_on_destroy( void *arg ) 
     981{ 
     982    pjsip_transaction *tsx = (pjsip_transaction*)arg; 
     983 
     984    PJ_LOG(5,(tsx->obj_name, "Transaction destroyed!")); 
     985 
     986    pj_mutex_destroy(tsx->mutex_b); 
     987    pjsip_endpt_release_pool(tsx->endpt, tsx->pool); 
     988} 
     989 
     990/* Shutdown transaction. */ 
     991static pj_status_t tsx_shutdown( pjsip_transaction *tsx ) 
     992{ 
    1035993    /* Release the transport */ 
    1036994    tsx_update_transport(tsx, NULL); 
    1037995 
    1038     /* Decrement reference counter in transport selector */ 
    1039     pjsip_tpselector_dec_ref(&tsx->tp_sel); 
     996    /* Decrement reference counter in transport selector, only if 
     997     * we haven't been called before */ 
     998    if (!tsx->terminating) { 
     999        pjsip_tpselector_dec_ref(&tsx->tp_sel); 
     1000    } 
    10401001 
    10411002    /* Free last transmitted message. */ 
     
    10571018    /* Clear some pending flags. */ 
    10581019    tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED | TSX_HAS_PENDING_SEND); 
     1020 
    10591021 
    10601022    /* Refuse to destroy transaction if it has pending resolving. */ 
     
    10641026        PJ_LOG(4,(tsx->obj_name, "Will destroy later because transport is " 
    10651027                                 "in progress")); 
    1066         return PJ_EBUSY; 
    1067     } 
    1068  
    1069     /* Clear TLS, so that mutex will not be unlocked */ 
    1070     lck = (struct tsx_lock_data*) pj_thread_local_get(pjsip_tsx_lock_tls_id); 
    1071     while (lck) { 
    1072         if (lck->tsx == tsx) { 
    1073             lck->is_alive = 0; 
    1074         } 
    1075         lck = lck->prev; 
    1076     } 
    1077  
    1078     pj_mutex_destroy(tsx->mutex_b); 
    1079     pj_mutex_destroy(tsx->mutex); 
    1080  
    1081     PJ_LOG(5,(tsx->obj_name, "Transaction destroyed!")); 
    1082  
    1083     pjsip_endpt_release_pool(tsx->endpt, tsx->pool); 
     1028    } 
     1029 
     1030    if (!tsx->terminating) { 
     1031        tsx->terminating = PJ_TRUE; 
     1032        pj_grp_lock_dec_ref(tsx->grp_lock); 
     1033    } 
     1034 
     1035    /* No acccess to tsx after this, it may have been destroyed */ 
    10841036 
    10851037    return PJ_SUCCESS; 
     
    10941046    pjsip_event event; 
    10951047    pjsip_transaction *tsx = (pjsip_transaction*) entry->user_data; 
    1096     struct tsx_lock_data lck; 
    10971048 
    10981049    PJ_UNUSED_ARG(theap); 
     
    11081059 
    11091060    /* Dispatch event to transaction. */ 
    1110     lock_tsx(tsx, &lck); 
     1061    pj_grp_lock_acquire(tsx->grp_lock); 
    11111062    (*tsx->state_handler)(tsx, &event); 
    1112     unlock_tsx(tsx, &lck); 
     1063    pj_grp_lock_release(tsx->grp_lock); 
    11131064 
    11141065    pj_log_pop_indent(); 
     
    12091160 
    12101161        /* Destroy transaction. */ 
    1211         tsx_destroy(tsx); 
     1162        tsx_shutdown(tsx); 
    12121163    } 
    12131164 
     
    12211172PJ_DEF(pj_status_t) pjsip_tsx_create_uac( pjsip_module *tsx_user, 
    12221173                                          pjsip_tx_data *tdata, 
     1174                                          pjsip_transaction **p_tsx) 
     1175{ 
     1176    return pjsip_tsx_create_uac2(tsx_user, tdata, NULL, p_tsx); 
     1177} 
     1178 
     1179PJ_DEF(pj_status_t) pjsip_tsx_create_uac2(pjsip_module *tsx_user, 
     1180                                          pjsip_tx_data *tdata, 
     1181                                          pj_grp_lock_t *grp_lock, 
    12231182                                          pjsip_transaction **p_tsx) 
    12241183{ 
     
    12281187    pjsip_via_hdr *via; 
    12291188    pjsip_host_info dst_info; 
    1230     struct tsx_lock_data lck; 
    12311189    pj_status_t status; 
    12321190 
     
    12521210 
    12531211    /* Create transaction instance. */ 
    1254     status = tsx_create( tsx_user, &tsx); 
     1212    status = tsx_create( tsx_user, grp_lock, &tsx); 
    12551213    if (status != PJ_SUCCESS) 
    12561214        return status; 
     
    12581216 
    12591217    /* Lock transaction. */ 
    1260     lock_tsx(tsx, &lck); 
     1218    pj_grp_lock_acquire(tsx->grp_lock); 
    12611219 
    12621220    /* Role is UAC. */ 
     
    13241282    status = pjsip_get_request_dest(tdata, &dst_info); 
    13251283    if (status != PJ_SUCCESS) { 
    1326         unlock_tsx(tsx, &lck); 
    1327         tsx_destroy(tsx); 
     1284        pj_grp_lock_release(tsx->grp_lock); 
     1285        tsx_shutdown(tsx); 
    13281286        return status; 
    13291287    } 
     
    13361294        pj_assert(!"Bug in branch_param generator (i.e. not unique)"); 
    13371295        */ 
    1338         unlock_tsx(tsx, &lck); 
    1339         tsx_destroy(tsx); 
     1296        pj_grp_lock_release(tsx->grp_lock); 
     1297        tsx_shutdown(tsx); 
    13401298        return status; 
    13411299    } 
     
    13431301 
    13441302    /* Unlock transaction and return. */ 
    1345     unlock_tsx(tsx, &lck); 
     1303    pj_grp_lock_release(tsx->grp_lock); 
    13461304 
    13471305    pj_log_push_indent(); 
     
    13601318PJ_DEF(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user, 
    13611319                                          pjsip_rx_data *rdata, 
     1320                                          pjsip_transaction **p_tsx) 
     1321{ 
     1322    return pjsip_tsx_create_uas2(tsx_user, rdata, NULL, p_tsx); 
     1323} 
     1324 
     1325PJ_DEF(pj_status_t) pjsip_tsx_create_uas2(pjsip_module *tsx_user, 
     1326                                          pjsip_rx_data *rdata, 
     1327                                          pj_grp_lock_t *grp_lock, 
    13621328                                          pjsip_transaction **p_tsx) 
    13631329{ 
     
    13671333    pjsip_cseq_hdr *cseq; 
    13681334    pj_status_t status; 
    1369     struct tsx_lock_data lck; 
    13701335 
    13711336    /* Validate arguments. */ 
     
    14051370     * Create transaction instance.  
    14061371     */ 
    1407     status = tsx_create( tsx_user, &tsx); 
     1372    status = tsx_create( tsx_user, grp_lock, &tsx); 
    14081373    if (status != PJ_SUCCESS) 
    14091374        return status; 
     
    14111376 
    14121377    /* Lock transaction. */ 
    1413     lock_tsx(tsx, &lck); 
     1378    pj_grp_lock_acquire(tsx->grp_lock); 
    14141379 
    14151380    /* Role is UAS */ 
     
    14281393                                  PJSIP_ROLE_UAS, &tsx->method, rdata); 
    14291394    if (status != PJ_SUCCESS) { 
    1430         unlock_tsx(tsx, &lck); 
    1431         tsx_destroy(tsx); 
     1395        pj_grp_lock_release(tsx->grp_lock); 
     1396        tsx_shutdown(tsx); 
    14321397        return status; 
    14331398    } 
     
    14551420    status = pjsip_get_response_addr( tsx->pool, rdata, &tsx->res_addr ); 
    14561421    if (status != PJ_SUCCESS) { 
    1457         unlock_tsx(tsx, &lck); 
    1458         tsx_destroy(tsx); 
     1422        pj_grp_lock_release(tsx->grp_lock); 
     1423        tsx_shutdown(tsx); 
    14591424        return status; 
    14601425    } 
     
    14771442    status = mod_tsx_layer_register_tsx(tsx); 
    14781443    if (status != PJ_SUCCESS) { 
    1479         unlock_tsx(tsx, &lck); 
    1480         tsx_destroy(tsx); 
     1444        pj_grp_lock_release(tsx->grp_lock); 
     1445        tsx_shutdown(tsx); 
    14811446        return status; 
    14821447    } 
     
    14861451 
    14871452    /* Unlock transaction and return. */ 
    1488     unlock_tsx(tsx, &lck); 
     1453    pj_grp_lock_release(tsx->grp_lock); 
    14891454 
    14901455    pj_log_push_indent(); 
     
    15051470                                            const pjsip_tpselector *sel) 
    15061471{ 
    1507     struct tsx_lock_data lck; 
    1508  
    15091472    /* Must be UAC transaction */ 
    15101473    PJ_ASSERT_RETURN(tsx && sel, PJ_EINVAL); 
    15111474 
    15121475    /* Start locking the transaction. */ 
    1513     lock_tsx(tsx, &lck); 
     1476    pj_grp_lock_acquire(tsx->grp_lock); 
    15141477 
    15151478    /* Decrement reference counter of previous transport selector */ 
     
    15231486 
    15241487    /* Unlock transaction. */ 
    1525     unlock_tsx(tsx, &lck); 
     1488    pj_grp_lock_release(tsx->grp_lock); 
    15261489 
    15271490    return PJ_SUCCESS; 
     
    15481511PJ_DEF(pj_status_t) pjsip_tsx_terminate( pjsip_transaction *tsx, int code ) 
    15491512{ 
    1550     struct tsx_lock_data lck; 
    1551  
    15521513    PJ_ASSERT_RETURN(tsx != NULL, PJ_EINVAL); 
    15531514 
     
    15611522    pj_log_push_indent(); 
    15621523 
    1563     lock_tsx(tsx, &lck); 
     1524    pj_grp_lock_acquire(tsx->grp_lock); 
    15641525    tsx_set_status_code(tsx, code, NULL); 
    15651526    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, PJSIP_EVENT_USER, NULL); 
    1566     unlock_tsx(tsx, &lck); 
     1527    pj_grp_lock_release(tsx->grp_lock); 
    15671528 
    15681529    pj_log_pop_indent(); 
     
    15791540PJ_DEF(pj_status_t) pjsip_tsx_stop_retransmit(pjsip_transaction *tsx) 
    15801541{ 
    1581     struct tsx_lock_data lck; 
    1582  
    15831542    PJ_ASSERT_RETURN(tsx != NULL, PJ_EINVAL); 
    15841543    PJ_ASSERT_RETURN(tsx->role == PJSIP_ROLE_UAC && 
     
    15901549    pj_log_push_indent(); 
    15911550 
    1592     lock_tsx(tsx, &lck); 
     1551    pj_grp_lock_acquire(tsx->grp_lock); 
    15931552    /* Cancel retransmission timer. */ 
    15941553    if (tsx->retransmit_timer.id != 0) { 
     
    15961555        tsx->retransmit_timer.id = 0; 
    15971556    } 
    1598     unlock_tsx(tsx, &lck); 
     1557    pj_grp_lock_release(tsx->grp_lock); 
    15991558 
    16001559    pj_log_pop_indent(); 
     
    16181577                     PJ_EINVALIDOP); 
    16191578 
    1620     /* Note: must not call lock_tsx() as that would introduce deadlock. 
    1621      * See #1121. 
     1579    /* Note: must not call pj_grp_lock_acquire(tsx->grp_lock) as 
     1580     * that would introduce deadlock. See #1121. 
    16221581     */ 
    16231582    lock_timer(tsx); 
     
    16601619{ 
    16611620    pjsip_event event; 
    1662     struct tsx_lock_data lck; 
    16631621    pj_status_t status; 
    16641622 
     
    16761634 
    16771635    /* Dispatch to transaction. */ 
    1678     lock_tsx(tsx, &lck); 
     1636    pj_grp_lock_acquire(tsx->grp_lock); 
    16791637 
    16801638    /* Set transport selector to tdata */ 
     
    16841642    status = (*tsx->state_handler)(tsx, &event); 
    16851643 
    1686     unlock_tsx(tsx, &lck); 
     1644    pj_grp_lock_release(tsx->grp_lock); 
    16871645 
    16881646    /* Only decrement reference counter when it returns success. 
     
    17071665{ 
    17081666    pjsip_event event; 
    1709     struct tsx_lock_data lck; 
    1710     pj_status_t status; 
    17111667 
    17121668    PJ_LOG(5,(tsx->obj_name, "Incoming %s in state %s",  
     
    17211677 
    17221678    /* Dispatch to transaction. */ 
    1723     lock_tsx(tsx, &lck); 
    1724     status = (*tsx->state_handler)(tsx, &event); 
    1725     unlock_tsx(tsx, &lck); 
     1679    pj_grp_lock_acquire(tsx->grp_lock); 
     1680    (*tsx->state_handler)(tsx, &event); 
     1681    pj_grp_lock_release(tsx->grp_lock); 
    17261682 
    17271683    pj_log_pop_indent(); 
     
    17351691    pjsip_transaction *tsx = (pjsip_transaction*) send_state->token; 
    17361692    pjsip_tx_data *tdata = send_state->tdata; 
    1737     struct tsx_lock_data lck; 
    17381693 
    17391694    /* Check if transaction has cancelled itself from this transmit 
     
    17491704    } 
    17501705 
     1706    pj_grp_lock_acquire(tsx->grp_lock); 
     1707 
    17511708    /* Reset */ 
    17521709    tdata->mod_data[mod_tsx_layer.mod.id] = NULL; 
    17531710    tsx->pending_tx = NULL; 
    1754  
    1755     lock_tsx(tsx, &lck); 
    17561711 
    17571712    if (sent > 0) { 
     
    17831738            tsx_set_state( tsx, PJSIP_TSX_STATE_DESTROYED,  
    17841739                           PJSIP_EVENT_UNKNOWN, NULL ); 
    1785             unlock_tsx(tsx, &lck); 
     1740            pj_grp_lock_release(tsx->grp_lock); 
    17861741            return; 
    17871742        } 
     
    18251780            err =pj_strerror(-sent, errmsg, sizeof(errmsg)); 
    18261781 
    1827             PJ_LOG(2,(tsx->obj_name,  
     1782            PJ_LOG(2,(tsx->obj_name, 
    18281783                      "Failed to send %s! err=%d (%s)", 
    18291784                      pjsip_tx_data_get_info(send_state->tdata), -sent, 
     
    18631818 
    18641819        } else { 
    1865             char errmsg[PJ_ERR_MSG_SIZE]; 
    1866  
    1867             PJ_LOG(2,(tsx->obj_name,  
    1868                       "Temporary failure in sending %s, " 
    1869                       "will try next server. Err=%d (%s)", 
    1870                       pjsip_tx_data_get_info(send_state->tdata), -sent, 
    1871                       pj_strerror(-sent, errmsg, sizeof(errmsg)).ptr)); 
     1820            PJ_PERROR(2,(tsx->obj_name, -sent, 
     1821                         "Temporary failure in sending %s, " 
     1822                         "will try next server", 
     1823                         pjsip_tx_data_get_info(send_state->tdata))); 
    18721824 
    18731825            /* Reset retransmission count */ 
     
    18941846    } 
    18951847 
    1896     unlock_tsx(tsx, &lck); 
     1848    pj_grp_lock_release(tsx->grp_lock); 
    18971849} 
    18981850 
     
    19041856    if (sent < 0) { 
    19051857        pjsip_transaction *tsx = (pjsip_transaction*) token; 
    1906         struct tsx_lock_data lck; 
    19071858        char errmsg[PJ_ERR_MSG_SIZE]; 
    19081859        pj_str_t err; 
     
    19131864 
    19141865        PJ_LOG(2,(tsx->obj_name, "Transport failed to send %s! Err=%d (%s)", 
    1915                   pjsip_tx_data_get_info(tdata), -sent, errmsg)); 
    1916  
    1917         lock_tsx(tsx, &lck); 
     1866                pjsip_tx_data_get_info(tdata), -sent, errmsg)); 
     1867 
     1868        pj_grp_lock_acquire(tsx->grp_lock); 
    19181869 
    19191870        /* Release transport. */ 
     
    19251876                       PJSIP_EVENT_TRANSPORT_ERROR, tdata ); 
    19261877 
    1927         unlock_tsx(tsx, &lck); 
     1878        pj_grp_lock_release(tsx->grp_lock); 
    19281879   } 
    19291880} 
     
    19411892    if (state == PJSIP_TP_STATE_DISCONNECTED) { 
    19421893        pjsip_transaction *tsx; 
    1943         struct tsx_lock_data lck; 
    19441894 
    19451895        pj_assert(tp && info && info->user_data); 
     
    19471897        tsx = (pjsip_transaction*)info->user_data; 
    19481898 
    1949         lock_tsx(tsx, &lck); 
     1899        pj_grp_lock_acquire(tsx->grp_lock); 
    19501900 
    19511901        /* Terminate transaction when transport disconnected */ 
     
    19601910        } 
    19611911 
    1962         unlock_tsx(tsx, &lck); 
     1912        pj_grp_lock_release(tsx->grp_lock); 
    19631913    } 
    19641914} 
     
    19921942 
    19931943        if (status != PJ_SUCCESS) { 
    1994             char errmsg[PJ_ERR_MSG_SIZE]; 
    1995  
    1996             PJ_LOG(2,(tsx->obj_name,  
    1997                       "Error sending %s: Err=%d (%s)", 
    1998                       pjsip_tx_data_get_info(tdata), status,  
    1999                       pj_strerror(status, errmsg, sizeof(errmsg)).ptr)); 
     1944            PJ_PERROR(2,(tsx->obj_name, status, 
     1945                         "Error sending %s", 
     1946                         pjsip_tx_data_get_info(tdata))); 
    20001947 
    20011948            /* On error, release transport to force using full transport 
     
    21102057                                                  pjsip_tx_data *tdata) 
    21112058{ 
    2112     struct tsx_lock_data lck; 
    21132059    pj_status_t status; 
    21142060 
    2115     lock_tsx(tsx, &lck); 
     2061    pj_grp_lock_acquire(tsx->grp_lock); 
    21162062    if (tdata == NULL) { 
    21172063        tdata = tsx->last_tx; 
    21182064    } 
    21192065    status = tsx_send_msg(tsx, tdata); 
    2120     unlock_tsx(tsx, &lck); 
     2066    pj_grp_lock_release(tsx->grp_lock); 
    21212067 
    21222068    /* Only decrement reference counter when it returns success. 
  • pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c

    r4208 r4420  
    546546        if (tsx) { 
    547547            dlg = (pjsip_dialog*) tsx->mod_data[mod_ua.mod.id]; 
    548             pj_mutex_unlock(tsx->mutex); 
     548            pj_grp_lock_release(tsx->grp_lock); 
    549549 
    550550            /* Dlg may be NULL on some extreme condition 
  • pjproject/trunk/pjsip/src/test/regc_test.c

    r4094 r4420  
    348348        return -210; 
    349349    } 
    350     if (client_result.code != client_cfg->code) { 
     350    if (client_result.code != client_cfg->code && 
     351        client_cfg->code != 502 && client_cfg->code != 503 && 
     352        client_result.code != 502 && client_result.code != 503) 
     353    { 
    351354        PJ_LOG(3,(THIS_FILE, "    error: expecting code=%d, got code=%d", 
    352355                  client_cfg->code, client_result.code)); 
  • pjproject/trunk/pjsip/src/test/test.c

    r3553 r4420  
    4848 
    4949pjsip_endpoint *endpt; 
     50pj_caching_pool caching_pool; 
    5051int log_level = 3; 
    5152int param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME |  
    52                       PJ_LOG_HAS_MICRO_SEC; 
     53                      PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_INDENT; 
    5354 
    5455static pj_oshandle_t fd_report; 
     
    224225{ 
    225226    pj_status_t rc; 
    226     pj_caching_pool caching_pool; 
    227227    const char *filename; 
    228228    unsigned tsx_test_cnt=0; 
     
    370370#endif 
    371371 
     372    /* 
     373     * Better be last because it recreates the endpt 
     374     */ 
     375#if INCLUDE_TSX_DESTROY_TEST 
     376    DO_TEST(tsx_destroy_test()); 
     377#endif 
    372378 
    373379on_return: 
  • pjproject/trunk/pjsip/src/test/test.h

    r3553 r4420  
    2424 
    2525extern pjsip_endpoint *endpt; 
     26extern pj_caching_pool caching_pool; 
    2627 
    2728#define TEST_UDP_PORT       15060 
     
    6566#define INCLUDE_RESOLVE_TEST    INCLUDE_TRANSPORT_GROUP 
    6667#define INCLUDE_TSX_TEST        INCLUDE_TSX_GROUP 
     68#define INCLUDE_TSX_DESTROY_TEST INCLUDE_TSX_GROUP 
    6769#define INCLUDE_INV_OA_TEST     INCLUDE_INV_GROUP 
    6870#define INCLUDE_REGC_TEST       INCLUDE_REGC_GROUP 
     
    7678int txdata_test(void); 
    7779int tsx_bench(void); 
     80int tsx_destroy_test(void); 
    7881int transport_udp_test(void); 
    7982int transport_loop_test(void); 
  • pjproject/trunk/pjsip/src/test/tsx_basic_test.c

    r3553 r4420  
    126126            return -40; 
    127127        } 
    128         pj_mutex_unlock(tsx->mutex); 
     128        pj_grp_lock_release(tsx->grp_lock); 
    129129    } 
    130130 
     
    156156    return 0; 
    157157} 
     158 
     159/**************************************************************************/ 
     160 
     161struct tsx_test_state 
     162{ 
     163    int pool_cnt; 
     164}; 
     165 
     166static void save_tsx_test_state(struct tsx_test_state *st) 
     167{ 
     168    st->pool_cnt = caching_pool.used_count; 
     169} 
     170 
     171static pj_status_t check_tsx_test_state(struct tsx_test_state *st) 
     172{ 
     173    if (caching_pool.used_count > st->pool_cnt) 
     174        return -1; 
     175 
     176    return 0; 
     177} 
     178 
     179static void destroy_endpt() 
     180{ 
     181    pjsip_endpt_destroy(endpt); 
     182    endpt = NULL; 
     183} 
     184 
     185static pj_status_t init_endpt() 
     186{ 
     187    pj_str_t ns = { "10.187.27.172", 13};       /* just a random, unreachable IP */ 
     188    pj_dns_resolver *resolver; 
     189    pj_status_t rc; 
     190 
     191    rc = pjsip_endpt_create(&caching_pool.factory, "endpt", &endpt); 
     192    if (rc != PJ_SUCCESS) { 
     193        app_perror("pjsip_endpt_create", rc); 
     194        return rc; 
     195    } 
     196 
     197    /* Start transaction layer module. */ 
     198    rc = pjsip_tsx_layer_init_module(endpt); 
     199    if (rc != PJ_SUCCESS) { 
     200        app_perror("tsx_layer_init", rc); 
     201        return rc; 
     202    } 
     203 
     204    rc = pjsip_udp_transport_start(endpt, NULL, NULL, 1,  NULL); 
     205    if (rc != PJ_SUCCESS) { 
     206        app_perror("udp init", rc); 
     207        return rc; 
     208    } 
     209 
     210    rc = pjsip_tcp_transport_start(endpt, NULL, 1, NULL); 
     211    if (rc != PJ_SUCCESS) { 
     212        app_perror("tcp init", rc); 
     213        return rc; 
     214    } 
     215 
     216    rc = pjsip_endpt_create_resolver(endpt, &resolver); 
     217    if (rc != PJ_SUCCESS) { 
     218        app_perror("create resolver", rc); 
     219        return rc; 
     220    } 
     221 
     222    pj_dns_resolver_set_ns(resolver, 1, &ns, NULL); 
     223 
     224    rc = pjsip_endpt_set_resolver(endpt, resolver); 
     225    if (rc != PJ_SUCCESS) { 
     226        app_perror("set resolver", rc); 
     227        return rc; 
     228    } 
     229 
     230    return PJ_SUCCESS; 
     231} 
     232 
     233static int tsx_create_and_send_req(void *arg) 
     234{ 
     235    pj_str_t dst_uri = pj_str((char*)arg); 
     236    pj_str_t from_uri = pj_str((char*)"<sip:user@host>"); 
     237    pjsip_tx_data *tdata; 
     238    pj_status_t status; 
     239 
     240    status = pjsip_endpt_create_request(endpt, &pjsip_options_method, 
     241                                        &dst_uri, &from_uri, &dst_uri, 
     242                                        NULL, NULL, -1, NULL, 
     243                                        &tdata); 
     244    if (status != PJ_SUCCESS) 
     245        return status; 
     246 
     247    status = pjsip_endpt_send_request(endpt, tdata, -1, NULL, NULL); 
     248    if (status != PJ_SUCCESS) 
     249        return status; 
     250 
     251    return PJ_SUCCESS; 
     252} 
     253 
     254int tsx_destroy_test() 
     255{ 
     256    struct tsx_test_state state; 
     257    struct test_desc 
     258    { 
     259        const char *title; 
     260        int (*func)(void*); 
     261        void *arg; 
     262        int sleep_before_unload; 
     263        int sleep_after_unload; 
     264    } test_entries[] = 
     265    { 
     266        { 
     267            "normal unable to resolve", 
     268            &tsx_create_and_send_req, 
     269            "sip:user@somehost", 
     270            10000, 
     271            1 
     272        }, 
     273        { 
     274            "resolve and destroy, wait", 
     275            &tsx_create_and_send_req, 
     276            "sip:user@somehost", 
     277            1, 
     278            10000 
     279        }, 
     280        { 
     281            "tcp connect and destroy", 
     282            &tsx_create_and_send_req, 
     283            "sip:user@10.125.36.63:58517;transport=tcp", 
     284            60000, 
     285            1000 
     286        }, 
     287        { 
     288            "tcp connect and destroy", 
     289            &tsx_create_and_send_req, 
     290            "sip:user@10.125.36.63:58517;transport=tcp", 
     291            1, 
     292            60000 
     293        }, 
     294 
     295    }; 
     296    int rc; 
     297    unsigned i; 
     298    const int INDENT = 2; 
     299 
     300    pj_log_add_indent(INDENT); 
     301    destroy_endpt(); 
     302 
     303    for (i=0; i<PJ_ARRAY_SIZE(test_entries); ++i) { 
     304        struct test_desc *td = &test_entries[i]; 
     305 
     306        PJ_LOG(3,(THIS_FILE, "%s", td->title)); 
     307 
     308        pj_log_add_indent(INDENT); 
     309        save_tsx_test_state(&state); 
     310 
     311        rc = init_endpt(); 
     312        if (rc != PJ_SUCCESS) { 
     313            pj_log_add_indent(-INDENT*2); 
     314            return -10; 
     315        } 
     316 
     317        rc = td->func(td->arg); 
     318        if (rc != PJ_SUCCESS) { 
     319            pj_log_add_indent(-INDENT*2); 
     320            return -20; 
     321        } 
     322 
     323        flush_events(td->sleep_before_unload); 
     324        pjsip_tsx_layer_destroy(); 
     325        flush_events(td->sleep_after_unload); 
     326        destroy_endpt(); 
     327 
     328        rc = check_tsx_test_state(&state); 
     329        if (rc != PJ_SUCCESS) { 
     330            init_endpt(); 
     331            pj_log_add_indent(-INDENT*2); 
     332            return -30; 
     333        } 
     334 
     335        pj_log_add_indent(-INDENT); 
     336    } 
     337 
     338    init_endpt(); 
     339 
     340    pj_log_add_indent(-INDENT); 
     341    return 0; 
     342} 
     343 
  • pjproject/trunk/pjsip/src/test/tsx_bench.c

    r3553 r4420  
    8080    for (i=0; i<working_set; ++i) { 
    8181        if (tsx[i]) { 
     82            pj_timer_heap_t *th; 
     83 
    8284            pjsip_tsx_terminate(tsx[i], 601); 
    8385            tsx[i] = NULL; 
     86 
     87            th = pjsip_endpt_get_timer_heap(endpt); 
     88            pj_timer_heap_poll(th, NULL); 
    8489        } 
    8590    } 
     
    178183    for (i=0; i<working_set; ++i) { 
    179184        if (tsx[i]) { 
     185            pj_timer_heap_t *th; 
     186 
    180187            pjsip_tsx_terminate(tsx[i], 601); 
    181188            tsx[i] = NULL; 
     189 
     190            th = pjsip_endpt_get_timer_heap(endpt); 
     191            pj_timer_heap_poll(th, NULL); 
     192 
    182193        } 
    183194    } 
     
    209220        PJ_LOG(3,(THIS_FILE, "    test %d of %d..", 
    210221                  i+1, REPEAT)); 
     222        PJ_LOG(3,(THIS_FILE, "    number of current tsx: %d", 
     223                  pjsip_tsx_layer_get_tsx_count())); 
    211224        status = uac_tsx_bench(WORKING_SET, &usec[i]); 
    212225        if (status != PJ_SUCCESS) 
     
    247260        PJ_LOG(3,(THIS_FILE, "    test %d of %d..", 
    248261                  i+1, REPEAT)); 
     262        PJ_LOG(3,(THIS_FILE, "    number of current tsx: %d", 
     263                  pjsip_tsx_layer_get_tsx_count())); 
    249264        status = uas_tsx_bench(WORKING_SET, &usec[i]); 
    250265        if (status != PJ_SUCCESS) 
  • pjproject/trunk/pjsip/src/test/tsx_uac_test.c

    r4208 r4420  
    221221 
    222222            /* Test the status code. */ 
    223             if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) { 
    224                 PJ_LOG(3,(THIS_FILE,  
    225                           "    error: status code is %d instead of %d", 
    226                           tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR)); 
     223            if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR && 
     224                tsx->status_code != PJSIP_SC_BAD_GATEWAY) 
     225            { 
     226                PJ_LOG(3,(THIS_FILE,  
     227                          "    error: status code is %d instead of %d or %d", 
     228                          tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR, 
     229                          PJSIP_SC_BAD_GATEWAY)); 
    227230                test_complete = -720; 
    228231            } 
     
    689692            if (tsx) { 
    690693                pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); 
    691                 pj_mutex_unlock(tsx->mutex); 
     694                pj_grp_lock_release(tsx->grp_lock); 
    692695            } else { 
    693696                PJ_LOG(3,(THIS_FILE, "    error: uac transaction not found!")); 
     
    10281031        if (tsx) { 
    10291032            pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); 
    1030             pj_mutex_unlock(tsx->mutex); 
     1033            pj_grp_lock_release(tsx->grp_lock); 
    10311034            flush_events(1000); 
    10321035        } 
  • pjproject/trunk/pjsip/src/test/tsx_uas_test.c

    r4208 r4420  
    226226        // Some tests do expect failure! 
    227227        //PJ_LOG(3,(THIS_FILE,"    error: timer unable to send response")); 
    228         pj_mutex_unlock(tsx->mutex); 
     228        pj_grp_lock_release(tsx->grp_lock); 
    229229        pjsip_tx_data_dec_ref(r->tdata); 
    230230        return; 
    231231    } 
    232232 
    233     pj_mutex_unlock(tsx->mutex); 
     233    pj_grp_lock_release(tsx->grp_lock); 
    234234} 
    235235 
     
    314314 
    315315    pjsip_tsx_terminate(tsx, status_code); 
    316     pj_mutex_unlock(tsx->mutex); 
     316    pj_grp_lock_release(tsx->grp_lock); 
    317317} 
    318318 
     
    12601260        if (tsx) { 
    12611261            pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); 
    1262             pj_mutex_unlock(tsx->mutex); 
     1262            pj_grp_lock_release(tsx->grp_lock); 
    12631263            flush_events(1000); 
    12641264        } 
Note: See TracChangeset for help on using the changeset viewer.