/* $Id: mcl_tx.cpp,v 1.1.1.1 2003/09/03 12:45:44 chneuman Exp $ */ /* * Copyright (c) 1999-2003 INRIA - Universite Paris 6 - All rights reserved * (main author: Vincent Roca - vincent.roca@inrialpes.fr) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* * FIXME : if the process is suspended during a long period, avoid sending * a huge amount of packets when it restarts! */ #include "mcl_includes.h" /* private functions */ static int mcl_sendit (mclcb_t *mclcb, txlvl_t *tl, int size); #ifdef LCT_SCHED4 static int mcl_sda_sendit (mclcb_t *mclcb, txlvl_t *tl, int size); #endif /* * for packet traces * store msg in a buf and print everything atomically */ #define TRC_BUF_SIZE 1024 static char trc_buf[TRC_BUF_SIZE]; static int trc_offset = 0; #define ADD_TO_STR_BUF(m) { if (trc_offset + strlen(m) < TRC_BUF_SIZE) { \ strcpy(&trc_buf[trc_offset], m); \ trc_offset += strlen(m); \ } } /* * */ void mcl_try_to_send (mclcb_t *mclcb) { int i; int du_nb; /* number of DUs to send */ txlvl_t *tl; int something_sent; /* flag: is there any DU to tx? */ TRACELVL(5, (mcl_stdout, "-> mcl_try_to_send: mclcb=x%x\n", (int)mclcb)) /* * see what to send next for each tx level */ if (mclcb->sender && !mcl_fsm_closed(mclcb, SENDER)) { something_sent= 0; /* reset first */ mclcb->more_to_tx = 0; /* reset first */ for (i = 0, tl = mclcb->txlvl_tab; i < mclcb->nb_level; i++, tl++) { #ifdef RLC if (tl->wait_sp) { /* no SP on lay i-1 yet, wait */ TRACELVL(4, (mcl_stdout, " mcl_try_to_send: no tx for layer %d (no SP)\n", i)) /* no need to check any layer * above this one => break */ break; } if (tl->wait_after_sp_count > 0) { /* cannot tx yet, wait */ TRACELVL(4, (mcl_stdout, " mcl_try_to_send: no tx for layer %d (wait count=%d)\n", i, tl->wait_after_sp_count)) tl->wait_after_sp_count--; /* more to come... */ /*mclcb->more_to_tx = 1;*/ /* no need to check any layer * above this one => break */ break; } #endif /* RLC */ if ((du_nb = min(tl->du_per_tick, tl->tot_rem)) > 0) { /* reset SP at first pkt tx */ if (mclcb->first_tx_for_mclcb) { mclcb->first_tx_for_mclcb = 0; #ifdef RLC rlc_reset_tx_sp(mclcb); #endif /* RLC */ } /* something to send! */ mcl_sendit(mclcb, tl, du_nb); something_sent = 1; } // if (tl->tot_rem == 0 && // mclcb->delivery_mode == DEL_MODE_ON_DEMAND) if (tl->tot_rem == 0) { /* * get ready for a new tx cycle * on that layer */ mcl_new_tx_cycle(mclcb, tl); } /* remain DU to send for mclcb or not?*/ /*if (tl->tot_rem > 0)*/ /* mclcb->more_to_tx = 1;*/ } /* * print all the packet traces atomically */ if (trc_offset > 0) { ADD_TO_STR_BUF("\n"); PRINT_OUT((mcl_stdout, trc_buf)) trc_offset = 0; } if (something_sent != 0) mclcb->more_to_tx = 1; if (something_sent == 0 && mcl_fsm_no_new_adu(mclcb, SENDER)) { /* * finished, stop everything * hope the close msg won't be lost!!! */ mcl_fsm_update_state(mclcb, SENDER, TEVENT_ALL_DU_SENT, REVENT_NIL); SendCLOSE(mclcb); mcl_fsm_update_state(mclcb, SENDER, TEVENT_CLOSE_SENT, REVENT_NIL); } } TRACELVL(5, (mcl_stdout, "<- mcl_try_to_send:\n")) } /* * Send this number of DUs for this level */ static int mcl_sendit (mclcb_t *mclcb, txlvl_t *tl, int du_nb) { du_t *du = NULL; int rem; char s[64]; /* for string */ TRACELVL(5, (mcl_stdout, "-> mcl_sendit: %d du\n", du_nb)) ASSERT(du_nb > 0); ASSERT(tl && (tl->tot_rem >= du_nb)); if (mclcb->verbose == 1) ADD_TO_STR_BUF("\t\t") for (rem = du_nb; rem > 0; rem--) { du = mcl_get_next_du (mclcb, tl); ASSERT(du); if (mclcb->verbose == 1) { /* compact, imprecise but easily readable trace */ #ifdef FEC if (du->is_fec) sprintf(s, "(%d) ", du->seq); else #endif /* FEC */ sprintf(s, "[%d] ", du->seq); ADD_TO_STR_BUF(s) } /* then send data*/ mcl_send_pkt(mclcb, tl->level, du, du->block->adu); } TRACELVL(5, (mcl_stdout, "<- mcl_sendit:\n")) return 0; } /* * scan all the remaining du transmissions and free * buffers for ADUs completely sent */ void mcl_tx_cleanup (mclcb_t *mclcb) { adu_t *list; /* head of adu list */ adu_t *adu; txlvl_t *tl; int i; TRACELVL(5, (mcl_stdout, "-> mcl_tx_cleanup:\n")) ASSERT(mclcb->delivery_mode == DEL_MODE_PUSH); if ((list = mclcb->txlvl_tab[0].adu_head) != NULL) { /* * reset the in_txtab flag for each ADU */ adu = list; do { #ifdef DEBUG if (adu->block_nb == 0) { /* already free'ed, just to check */ ASSERT((adu->block_head == NULL && adu->data == NULL)) } #endif /* DEBUG */ adu->in_txtab = 0; /* by default not in txtab */ adu = adu->next; } while (adu != list); /* * search in txtab all the layers which ADUs have pending DUs */ for (i = 0, tl = mclcb->txlvl_tab; i < mclcb->nb_level; i++, tl++) { mcl_mark_adus_in_txtab(mclcb, tl); } /* * and free ADUs with no pending DU */ adu = list; do { if (adu->block_nb > 0 && adu->in_txtab == 0) { /* * everything has been sent; free this ADU * nb: in fact adu buffer is not free'ed! */ mcl_tx_free_this_adu(mclcb, adu); ASSERT((adu->block_nb == 0 && adu->block_head == NULL && adu->data == NULL)) } adu = adu->next; } while (adu != list); } TRACELVL(5, (mcl_stdout, "<- mcl_tx_cleanup: ok\n")) }