/* $Id: mcl_txtab.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. */ #include "mcl_includes.h" /* * private functions */ static txtab_t * mcl_create_txtab (mclcb_t *mclcb); /*static txtab_t * mcl_last_txtab (txtab_t *list);*/ static int mcl_insert_txtab (mclcb_t *mclcb, txtab_t *tt, txtab_t **list); static void mcl_remove_txtab (mclcb_t *mclcb, txtab_t *tt, txtab_t **list); static txtab_t * mcl_get_first_ready_txtab(mclcb_t *mclcb,txlvl_t *tl); /* * get last element in txtab */ #define mcl_last_txtab(list) ((list) ? ((list)->prev) : NULL) /****** Public Functions ******************************************************/ /* * register a du for nb_tx transmissions on that layer. */ void mcl_register_du (mclcb_t *mclcb, txlvl_t *tl, du_t *du, int nb_tx) /* desired nb of transmissions */ { txtab_t *tt; #ifdef FEC TRACELVL(5, (mcl_stdout, "-> mcl_register_du: tl=x%x, du=x%x (aseq=%d bseq=%d dseq=%d/%s)\n", (int)tl, (int)du, du->block->adu->seq, du->block->seq, du->seq, (du->is_fec ? "fec" : "data"))) #else TRACELVL(5, (mcl_stdout, "-> mcl_register_du: tl=x%x, du=x%x (aseq=%d bseq=%d dseq=%d)\n", (int)tl, (int)du, du->block->adu->seq, du->block->seq, du->seq)) #endif ASSERT(mclcb && tl && du); if (nb_tx <= 0) { PRINT_ERR((mcl_stderr, "mcl_register_du: ERROR, nb_tx(%d)<=0", nb_tx)) mcl_exit(-1); } tt = mcl_last_txtab(tl->txtab_head); if (tt == NULL || tt->wr_index >= NB_TXTAB_ENTRIES || tt->rem_tx != nb_tx) { /* need a new txtab struct */ tt = mcl_create_txtab(mclcb); mcl_insert_txtab(mclcb, tt, &(tl->txtab_head)); } tt->du_tab[tt->wr_index++] = du; tt->rem_tx = nb_tx; tl->tot_rem++; //printf("register du, wr_index %i, tx_index %i\n",tt->wr_index,tt->tx_index); TRACELVL(5, (mcl_stdout, "<- mcl_register_du:\n")) } /* * Returns the next DU to tx for this layer or NULL. */ du_t * mcl_get_next_du (mclcb_t *mclcb, txlvl_t *tl) { txtab_t *tt; du_t *du; TRACELVL(5, (mcl_stdout, "-> mcl_get_next_du: tl=x%x\n", (int)tl)) ASSERT(mclcb && tl); if (tl->tot_rem <= 0) { TRACELVL(5, (mcl_stdout, "<- mcl_get_next_du: NULL (empty)\n")) return NULL; } /*TRACELVL(5, (mcl_stdout, " mcl_get_next_du: before: tl->cached_txtab=x%x\n", (int)tl->cached_txtab)) */ if ((tt = tl->cached_txtab) == NULL) { /* cache fault */ if ((tt = mcl_get_first_ready_txtab(mclcb, tl)) == NULL) { PRINT_ERR((mcl_stderr, "mcl_get_next_du: ERROR, null tt")) mcl_exit(-1); } tl->cached_txtab = tt; /* remember it */ } if (tt->tx_index >= tt->wr_index) { /* exhausted: move to next tt */ if ((tt = mcl_get_first_ready_txtab(mclcb, tl)) == NULL) { PRINT_ERR((mcl_stderr, "mcl_get_next_du: ERROR, null tt")) mcl_exit(-1); } tl->cached_txtab = tt; /* remember it */ } /*TRACELVL(5, (mcl_stdout, " mcl_get_next_du: after: tl->cached_txtab=x%x\n", (int)tl->cached_txtab)) */ ASSERT(tt->tx_index < tt->wr_index); ASSERT(tt->wr_index <= NB_TXTAB_ENTRIES && tt->tx_index < NB_TXTAB_ENTRIES); du = tt->du_tab[tt->tx_index]; tt->tx_index++; tl->tot_rem--; #ifdef FEC TRACELVL(5, (mcl_stdout, "<- mcl_get_next_du: du=x%x (aseq=%d bseq=%d dseq=%d/%s)\n", (int)du, du->block->adu->seq, du->block->seq, du->seq, (du->is_fec ? "fec" : "data"))) #else TRACELVL(5, (mcl_stdout, "<- mcl_get_next_du: du=x%x (aseq=%d bseq=%d dseq=%d)\n", (int)du, du->block->adu->seq, du->block->seq, du->seq)) #endif return du; } /* * reset the txtab for a new transmission cycle (on demand delivery mode) * returns 0 if ok, < 0 if an error */ int mcl_new_tx_cycle (mclcb_t *mclcb, txlvl_t *tl) { txtab_t *tt; txtab_t *tmp_tt; TRACELVL(5, (mcl_stdout, "-> mcl_new_tx_cycle:\n")) ASSERT(mclcb && tl); ASSERT(tl->tot_rem == 0); if (!(tt = tl->txtab_head)) { TRACELVL(5, (mcl_stdout, "<- mcl_new_tx_cycle: no txtab\n")) return -1; } do { if (mclcb->delivery_mode != DEL_MODE_ON_DEMAND) { /* in on-demand, tx for ever, otherwise decrement */ tt->rem_tx--; } if (tt->rem_tx <= 0) { /* cannot be used for tx anymore, free it */ tmp_tt = tt; tt = tt->next; mcl_remove_txtab(mclcb, tmp_tt, &(tl->txtab_head)); free(tmp_tt); } else { tl->tot_rem += tt->wr_index; tt->tx_index = 0; tt = tt->next; } } while (tl->txtab_head && tt != tl->txtab_head); tl->cached_txtab = NULL; /* reset cache */ TRACELVL(5, (mcl_stdout, "<- mcl_new_tx_cycle:\n")) return 0; } /* * look in the txtab and mark the ADU of all the DUs waiting to be sent * as "in_txtab" */ void mcl_mark_adus_in_txtab (mclcb_t *mclcb, txlvl_t *tl) { txtab_t *tt; du_t *du; int i; TRACELVL(5, (mcl_stdout, "-> mcl_mark_adus_in_txtab: tl=x%x\n", (int)tl)) ASSERT(mclcb && tl); tt = tl->txtab_head; ASSERT(tt != NULL); do { if (tt->wr_index > 0 && tt->tx_index < tt->wr_index) { TRACELVL(5, (mcl_stdout, "<- mcl_mark_adus_in_txtab: mark DUs of tt=x%x\n", (int)tt)) for (i = 0; i + tt->tx_index < tt->wr_index; i++) { du = tt->du_tab[tt->tx_index + i]; /* mark this adu as "in_txtab" */ du->block->adu->in_txtab = 1; } } tt = tt->next; } while (tt != tl->txtab_head); /* we have cycled */ TRACELVL(5, (mcl_stdout, "<- mcl_mark_adus_in_txtab:\n")) return; } /* * free all the txtab structs for this mclcb */ void mcl_free_all_txtab (mclcb_t *mclcb) { int i; txlvl_t *tl; txtab_t *tt; TRACELVL(5, (mcl_stdout, "-> mcl_free_all_txtab:\n")) ASSERT(mclcb->sender); for (i = 0, tl = mclcb->txlvl_tab; i < MAX_TX_LEVEL; i++, tl++) { while ((tt = mcl_last_txtab(tl->txtab_head)) != NULL) { mcl_remove_txtab(mclcb, tt, &(tl->txtab_head)); free(tt); } } tl->cached_txtab = NULL; /* reset cache */ TRACELVL(5, (mcl_stdout, "<- mcl_free_all_txtab:\n")) } /* * free all adus that are in txtabs */ void mcl_free_all_adu_from_txtab (mclcb_t *mclcb) { //adu_t *adu; int i;//,j; txlvl_t *tl; txtab_t *tt; TRACELVL(5, (mcl_stdout, "-> mcl_free_all_adu_from_txtab:\n")) ASSERT(mclcb->sender); for (i = 0, tl = mclcb->txlvl_tab; i < MAX_TX_LEVEL; i++, tl++) { while ((tt = mcl_last_txtab(tl->txtab_head)) != NULL) { /*for( j=0;jdu_tab[j]!=NULL) { if(tt->du_tab[j]->block!=NULL) { if(adu!=NULL) { adu=tt->du_tab[j]->block->adu; mcl_remove_this_ADU(mclcb, adu); mcl_tx_free_this_adu(mclcb,adu); free(adu); } } } } */ mcl_remove_txtab(mclcb, tt, &(tl->txtab_head)); free(tt); } mcl_insert_txtab(mclcb,mcl_create_txtab(mclcb),&(tl->txtab_head)); tl->tot_rem=0; mcl_new_tx_cycle (mclcb,tl); } tl->cached_txtab = NULL; /* reset cache */ TRACELVL(5, (mcl_stdout, "<- mcl_free_all_adu_from_txtab:\n")) } /****** Private Functions *****************************************************/ /* * Create and init a new txtab_t struct. */ static txtab_t * mcl_create_txtab (mclcb_t *mclcb) { txtab_t *tt; TRACELVL(5, (mcl_stdout, "-> mcl_create_txtab:\n")) if (!(tt = (txtab_t*)calloc(1, sizeof(txtab_t)))) { PRINT_ERR((mcl_stderr, "mcl_create_txtab: ERROR, no memory")) mcl_exit(-1); } TRACELVL(5, (mcl_stdout, "<- mcl_create_txtab: return x%x\n", (int)tt)) return (tt); } /* * Insert the txtab list (one or more txtab) at the end of the list. * Returns 1 if list was empty, 0 otherwise. */ static int mcl_insert_txtab (mclcb_t *mclcb, txtab_t *tt, txtab_t **list) { txtab_t *ptt, *ntt; /* insert tt between prev_tt, next_tt */ TRACELVL(5, (mcl_stdout, "-> mcl_insert_txtab:\n")) ASSERT((tt && list)) ptt = mcl_last_txtab(*list); /* last txtab in list */ if (ptt == NULL) { /* * first txtab in list */ *list = tt; if (!tt->next) { /* single txtab to add */ ASSERT((!tt->prev)) tt->next = tt->prev = tt; } TRACELVL(5, (mcl_stdout, "<- mcl_insert_txtab: return 1\n")) return 1; } ntt = ptt->next; /* this is the following txtab in list */ if (!tt->next) { /* single txtab to add */ ASSERT((!tt->prev)) ptt->next = tt; tt->prev = ptt; tt->next = ntt; ntt->prev = tt; } else { /* tt is a txtab list */ ASSERT((tt->prev)) ptt->next = tt; (tt->prev)->next = ntt; ntt->prev = (tt->prev); tt->prev = ptt; } TRACELVL(5, (mcl_stdout, "<- mcl_insert_txtab: return 0\n")) return 0; } /* * Remove this txtab (there's only one) from the list. */ static void mcl_remove_txtab (mclcb_t *mclcb, txtab_t *tt, txtab_t **list) { TRACELVL(5, (mcl_stdout, "-> mcl_remove_txtab:\n")) ASSERT(tt && list); #ifdef DEBUG { /* check that tt is in list (start from the end) */ txtab_t *ltt; for (ltt = mcl_last_txtab(*list); ltt != NULL && ltt != tt && ltt != *list; ltt = ltt->prev); ASSERT(ltt == tt); } #endif /* DEBUG */ /* found, remove it */ ASSERT((tt->prev)) ASSERT((tt->next)) if (*list == tt) { if (tt->next != tt) { ASSERT(tt->prev != tt); *list = tt->next; } else { ASSERT(tt->prev == tt); *list = NULL; } } tt->prev->next = tt->next; tt->next->prev = tt->prev; TRACELVL(5, (mcl_stdout, "<- mcl_remove_txtab:\n")) } /* * Returns the txtab found (if any), NULL if nothing is available. */ static txtab_t * mcl_get_first_ready_txtab (mclcb_t *mclcb, txlvl_t *tl) { txtab_t *tt; TRACELVL(5, (mcl_stdout, "-> mcl_get_first_ready_txtab:\n")) ASSERT(tl); tt = tl->txtab_head; ASSERT(tt != NULL); do { if (tt->wr_index > 0 && tt->tx_index < tt->wr_index) { ASSERT(tt->wr_index <= NB_TXTAB_ENTRIES && tt->tx_index < NB_TXTAB_ENTRIES); TRACELVL(5, (mcl_stdout, "<- mcl_get_first_ready_txtab: found tt=x%x\n", (int)tt)) return tt; } tt = tt->next; } while (tt != tl->txtab_head); /* we have cycled */ TRACELVL(5, (mcl_stdout, "<- mcl_get_first_ready_txtab: NULL (cycled)\n")) return NULL; }