]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merged revisions 221844 via svnmerge from
authorRichard Mudgett <rmudgett@digium.com>
Fri, 2 Oct 2009 01:26:47 +0000 (01:26 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Fri, 2 Oct 2009 01:26:47 +0000 (01:26 +0000)
https://origsvn.digium.com/svn/asterisk/trunk

................
  r221844 | rmudgett | 2009-10-01 20:09:31 -0500 (Thu, 01 Oct 2009) | 33 lines

  Merged revisions 221769 via svnmerge from
  https://origsvn.digium.com/svn/asterisk/branches/1.4

  ........
    r221769 | rmudgett | 2009-10-01 18:18:28 -0500 (Thu, 01 Oct 2009) | 26 lines

    Occasionally losing use of B channels in chan_misdn.

    I have not been able to reproduce the problem of losing channels.
    However, I have seen in the code a reentrancy problem that might give
    these symptoms.

    The reentrancy patch does several things:
    1) Guards B channel and B channel structure allocation.
    2) Makes the B channel structure find routines more precise in locating records.
    3) Never leave a B channel allocated if we received cause 44.

    The last item may cause temporary outgoing call problems, but they should
    clear when the line becomes idle.

    (closes issue #15490)
    Reported by: slutec18
    Patches:
          issue15490_channel_alloc_reentrancy.patch uploaded by rmudgett (license 664)
    Tested by: rmudgett, slutec18

    (closes issue #15458)
    Reported by: FabienToune
    Patches:
          issue15458_channel_alloc_reentrancy.patch uploaded by rmudgett (license 664)
    Tested by: FabienToune, rmudgett, slutec18
  ........
................

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.6.1@221871 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/misdn/isdn_lib.c
channels/misdn/isdn_lib_intern.h

index cb66932241a4487383e04428e454970209aea487..29637828597fb69f10ecb7188eda873a07d30f92 100644 (file)
@@ -516,6 +516,7 @@ static int find_free_chan_in_stack(struct misdn_stack *stack, struct misdn_bchan
        
        channel--;
 
+       pthread_mutex_lock(&stack->st_lock);
        if (dec) {
                for (i = bnums; i >=0; i--) {
                        if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */
@@ -539,6 +540,7 @@ static int find_free_chan_in_stack(struct misdn_stack *stack, struct misdn_bchan
        }
 
        if (!chan) {
+               pthread_mutex_unlock(&stack->st_lock);
                cb_log (1, stack->port, " !! NO FREE CHAN IN STACK\n");
                dump_chan_list(stack);
                bc->out_cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
@@ -546,10 +548,12 @@ static int find_free_chan_in_stack(struct misdn_stack *stack, struct misdn_bchan
        }       
 
        if (set_chan_in_stack(stack, chan)<0) {
+               pthread_mutex_unlock(&stack->st_lock);
                cb_log (0, stack->port, "Channel Already in use:%d\n", chan);
                bc->out_cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
                return -1;
        }
+       pthread_mutex_unlock(&stack->st_lock);
 
        bc->channel=chan;
        return 0;
@@ -795,9 +799,9 @@ static void clear_l3(struct misdn_stack *stack)
        for (i=0; i<=stack->b_num; i++) {
                if (global_state == MISDN_INITIALIZED)  {
                        cb_event(EVENT_CLEANUP, &stack->bc[i], NULL); 
-                       empty_chan_in_stack(stack,i+1);
                        empty_bc(&stack->bc[i]);
                        clean_up_bc(&stack->bc[i]);
+                       empty_chan_in_stack(stack, i + 1);
                        stack->bc[i].in_use = 0;
                }
                
@@ -1260,6 +1264,8 @@ static struct misdn_stack *stack_init(int midev, int port, int ptp)
   
        msg_queue_init(&stack->downqueue);
        msg_queue_init(&stack->upqueue);
+
+       pthread_mutex_init(&stack->st_lock, NULL);
   
        /* query port's requirements */
        ret = mISDN_get_stack_info(midev, port, buff, sizeof(buff));
@@ -1434,6 +1440,8 @@ static void stack_destroy(struct misdn_stack *stack)
 
        if (stack->upper_id) 
                mISDN_write_frame(stack->midev, buf, stack->upper_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+
+       pthread_mutex_destroy(&stack->st_lock);
 }
 
 
@@ -1479,8 +1487,11 @@ static struct misdn_stack * find_stack_by_mgr(manager_t* mgr_nt)
 static struct misdn_bchannel *find_bc_by_masked_l3id(struct misdn_stack *stack, unsigned long l3id, unsigned long mask)
 {
        int i;
-       for (i=0; i<=stack->b_num; i++) {
-               if ( (stack->bc[i].l3_id & mask)  ==  (l3id & mask)) return &stack->bc[i] ;
+
+       for (i = 0; i <= stack->b_num; i++) {
+               if (stack->bc[i].in_use && (stack->bc[i].l3_id & mask) == (l3id & mask)) {
+                       return &stack->bc[i];
+               }
        }
        return stack_holder_find(stack,l3id);
 }
@@ -1489,8 +1500,11 @@ static struct misdn_bchannel *find_bc_by_masked_l3id(struct misdn_stack *stack,
 struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long l3id)
 {
        int i;
-       for (i=0; i<=stack->b_num; i++) {
-               if (stack->bc[i].l3_id == l3id) return &stack->bc[i] ;
+
+       for (i = 0; i <= stack->b_num; i++) {
+               if (stack->bc[i].in_use && stack->bc[i].l3_id == l3id) {
+                       return &stack->bc[i];
+               }
        }
        return stack_holder_find(stack,l3id);
 }
@@ -1500,11 +1514,11 @@ static struct misdn_bchannel *find_bc_by_addr(unsigned long addr)
        struct misdn_stack *stack;
        int i;
 
-       for (stack=glob_mgr->stack_list;
-            stack;
-            stack=stack->next) {
-               for (i=0; i<=stack->b_num; i++) {
-                       if ( (stack->bc[i].addr&STACK_ID_MASK)==(addr&STACK_ID_MASK) ||  stack->bc[i].layer_id== addr ) {
+       for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
+               for (i = 0; i <= stack->b_num; i++) {
+                       if (stack->bc[i].in_use
+                               && ((stack->bc[i].addr & STACK_ID_MASK) == (addr & STACK_ID_MASK)
+                                       || stack->bc[i].layer_id == addr)) {
                                return &stack->bc[i];
                        }
                }
@@ -1518,11 +1532,9 @@ static struct misdn_bchannel *find_bc_by_confid(unsigned long confid)
        struct misdn_stack *stack;
        int i;
        
-       for (stack=glob_mgr->stack_list;
-            stack;
-            stack=stack->next) {
-               for (i=0; i<=stack->b_num; i++) {
-                       if ( stack->bc[i].conf_id==confid ) {
+       for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
+               for (i = 0; i <= stack->b_num; i++) {
+                       if (stack->bc[i].in_use && stack->bc[i].conf_id == confid) {
                                return &stack->bc[i];
                        }
                }
@@ -1536,10 +1548,12 @@ static struct misdn_bchannel *find_bc_by_channel(int port, int channel)
        struct misdn_stack *stack = find_stack_by_port(port);
        int i;
 
-       if (!stack) return NULL;        
+       if (!stack) {
+               return NULL;
+       }
        
-       for (i=0; i<=stack->b_num; i++) {
-               if ( stack->bc[i].channel== channel ) {
+       for (i = 0; i <= stack->b_num; i++) {
+               if (stack->bc[i].in_use && stack->bc[i].channel == channel) {
                        return &stack->bc[i];
                }
        }
@@ -1606,7 +1620,9 @@ static int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_
                                if (!bc->channel)
                                        cb_log(0, stack->port, "Any Channel Requested, but we have no more!!\n");
                                else 
-                                       cb_log(0, stack->port, "Requested Channel Already in Use releasing this call with cause 34!!!!\n");
+                                       cb_log(0, stack->port,
+                                               "Requested Channel Already in Use releasing this call with cause %d!!!!\n",
+                                               bc->out_cause);
 
                                /* when the channel is already in use, we can't
                                 * simply clear it, we need to make sure that 
@@ -1717,6 +1733,7 @@ static int handle_cr ( struct misdn_stack *stack, iframe_t *frm)
 /* Empties bc if it's reserved (no SETUP out yet) */
 void misdn_lib_release(struct misdn_bchannel *bc)
 {
+       int channel;
        struct misdn_stack *stack=get_stack_by_bc(bc);
 
        if (!stack) {
@@ -1724,11 +1741,12 @@ void misdn_lib_release(struct misdn_bchannel *bc)
                return;
        }
        
-       if (bc->channel>0) 
-               empty_chan_in_stack(stack,bc->channel);
-       
+       channel = bc->channel;
        empty_bc(bc);
        clean_up_bc(bc);
+       if (channel > 0) {
+               empty_chan_in_stack(stack, channel);
+       }
        bc->in_use=0;
 }
 
@@ -2774,22 +2792,19 @@ handle_frm_bc:
                                bc->cause=tmpcause;
                                bc->out_cause=tmp_out_cause;
                                clean_up_bc(bc);
+                               bc->in_use = 0;
                                
                                if (tmpcause == AST_CAUSE_REQUESTED_CHAN_UNAVAIL) {
-                                       cb_log(0,stack->port,"**** Received CAUSE:%d, so not cleaning up channel %d\n", AST_CAUSE_REQUESTED_CHAN_UNAVAIL, channel);
-                                       cb_log(0,stack->port,"**** This channel is now no longer available,\nplease try to restart it with 'misdn send restart <port> <channel>'\n");
-                                       set_chan_in_stack(stack, channel);
-                                       bc->channel=channel;
+                                       cb_log(0, stack->port, "**** Received CAUSE:%d, restarting channel %d\n", AST_CAUSE_REQUESTED_CHAN_UNAVAIL, channel);
                                        misdn_lib_send_restart(stack->port, channel);
-                               } else {
-                                       if (channel>0)
-                                               empty_chan_in_stack(stack, channel);
                                }
-                               bc->in_use=0;
+                               if (channel > 0) {
+                                       empty_chan_in_stack(stack, channel);
+                               }
                        }
 
                        if (event == EVENT_RESTART) {
-                               cb_log(0, stack->port, "**** Received RESTART_ACK channel:%d\n", bc->restart_channel);
+                               cb_log(0, stack->port, "**** Received RESTART channel:%d\n", bc->restart_channel);
                                empty_chan_in_stack(stack, bc->restart_channel);
                        }
 
@@ -3171,11 +3186,12 @@ struct misdn_bchannel *manager_find_bc_by_pid(int pid)
        struct misdn_stack *stack;
        int i;
   
-       for (stack=glob_mgr->stack_list;
-            stack;
-            stack=stack->next) {
-               for (i=0; i<=stack->b_num; i++)
-                       if (stack->bc[i].pid == pid) return &stack->bc[i];
+       for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
+               for (i = 0; i <= stack->b_num; i++) {
+                       if (stack->bc[i].in_use && stack->bc[i].pid == pid) {
+                               return &stack->bc[i];
+                       }
+               }
        }
   
        return NULL;
@@ -3205,7 +3221,6 @@ static void prepare_bc(struct misdn_bchannel*bc, int channel)
 {
        bc->channel = channel;
        bc->channel_preselected = channel?1:0;
-       bc->in_use = 1;
        bc->need_disconnect=1;
        bc->need_release=1;
        bc->need_release_complete=1;
@@ -3219,6 +3234,8 @@ static void prepare_bc(struct misdn_bchannel*bc, int channel)
        bc->b_stid=0;
        bc->layer_id=0;
 #endif
+
+       bc->in_use = 1;
 }
 
 struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, int dec)
@@ -3231,8 +3248,6 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i
                return NULL;
        }
 
-       usleep(1000);
-
        for (stack=glob_mgr->stack_list; stack; stack=stack->next) {
     
                if (stack->port == port) {
@@ -3243,21 +3258,25 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i
                                return NULL;
                        }
                
+                       pthread_mutex_lock(&stack->st_lock);
                        if (channel > 0) {
                                if (channel <= stack->b_num) {
                                        for (i = 0; i < stack->b_num; i++) {
                                                if ( stack->bc[i].channel == channel) {
                                                        if (test_inuse(&stack->bc[i])) { 
+                                                               pthread_mutex_unlock(&stack->st_lock);
                                                                cb_log(0,port,"Requested channel:%d on port:%d is already in use\n",channel, port);
                                                                return NULL;
 
                                                        } else {
                                                                prepare_bc(&stack->bc[i], channel);
+                                                               pthread_mutex_unlock(&stack->st_lock);
                                                                return &stack->bc[i];
                                                        }
                                                }
                                        }
                                } else {
+                                       pthread_mutex_unlock(&stack->st_lock);
                                        cb_log(0,port,"Requested channel:%d is out of bounds on port:%d\n",channel, port);
                                        return NULL;
                                }
@@ -3274,6 +3293,7 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i
                                                        
                                                prepare_bc(&stack->bc[i], channel);
                                                stack->bc[i].dec=1;
+                                               pthread_mutex_unlock(&stack->st_lock);
                                                return &stack->bc[i];
                                        }
                                }
@@ -3285,10 +3305,12 @@ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, i
                                                        stack->bc[i].cw=1;
 
                                                prepare_bc(&stack->bc[i], channel);
+                                               pthread_mutex_unlock(&stack->st_lock);
                                                return &stack->bc[i];
                                        }
                                }
                        }
+                       pthread_mutex_unlock(&stack->st_lock);
 
                        cb_log(1,port,"There is no free channel on port (%d)\n",port);
                        return NULL;
@@ -3867,7 +3889,7 @@ int misdn_lib_send_restart(int port, int channel)
                /* clean up chan in stack, to be sure we don't think it's
                 * in use anymore */
                for (cnt=0; cnt<=stack->b_num; cnt++) {
-                       if (stack->bc[cnt].channel == channel) {
+                       if (stack->bc[cnt].in_use && stack->bc[cnt].channel == channel) {
                                empty_bc(&stack->bc[cnt]);
                                clean_up_bc(&stack->bc[cnt]);
                                stack->bc[cnt].in_use=0;
index c7efe8c79f7941cf95783b3e2d75c5cb23520d62..9411cbbaefc7e202306e220854d241c1ea114dfb 100644 (file)
@@ -58,6 +58,9 @@ struct misdn_stack {
        manager_t mgr;
        pthread_mutex_t nstlock;
 
+       /*! \brief Stack struct critical section lock. */
+       pthread_mutex_t st_lock;
+
        /*! \brief D Channel mISDN driver stack ID (Parent stack ID) */
        int d_stid;
 
@@ -123,7 +126,7 @@ struct misdn_stack {
        /*! \brief Array of B channels in use (a[0] = B1).  TRUE if B channel in use */
        int channels[MAX_BCHANS + 1];
 
-       /*! \brief List of holded channels */
+       /*! \brief List of held channels */
        struct misdn_bchannel *holding;
 
        /*! \brief Next stack in the list of stacks */