Пример #1
0
/**
 * \brief Node Function
 * Arguments:
 * - my id
 * - the id of a guy I know in the system (except for the first node)
 * - the time to sleep before I join (except for the first node)
 * - the deadline time
 */
static int node(int argc, char *argv[])
{
  double init_time = MSG_get_clock();
  msg_task_t task_received = NULL;  
  int join_success = 0;  
  double deadline;
  xbt_assert(argc == 3 || argc == 5, "Wrong number of arguments for this node");
  s_node_t node = {0};
  node.id = xbt_str_parse_int(argv[1], "Invalid ID: %s");
  node.known_id = -1;
  node.ready = -1;
  node.pending_tasks = xbt_fifo_new();
  get_mailbox(node.id, node.mailbox);
  XBT_DEBUG("New node with id %s (%08x)", node.mailbox, node.id);
  
  int i,j,d;
  for (i=0; i<LEVELS_COUNT; i++){
    d = domain(node.id, i);
    for (j=0; j<LEVEL_SIZE; j++)
      node.routing_table[i][j] = (d==j) ? node.id : -1;
  }

  for (i=0; i<NEIGHBORHOOD_SIZE; i++)
    node.neighborhood_set[i] = -1;

  for (i=0; i<NAMESPACE_SIZE; i++)
    node.namespace_set[i] = -1;

  if (argc == 3) { // first ring
    XBT_DEBUG("Hey! Let's create the system.");
    deadline = xbt_str_parse_double(argv[2], "Invalid deadline: %s");
    create(&node);
    join_success = 1;
  }
  else {
    node.known_id = xbt_str_parse_int(argv[2], "Invalid known ID: %s");
    double sleep_time = xbt_str_parse_double(argv[3], "Invalid sleep time: %s");
    deadline = xbt_str_parse_double(argv[4], "Invalid deadline: %s");

    // sleep before starting
    XBT_DEBUG("Let's sleep during %f", sleep_time);
    MSG_process_sleep(sleep_time);
    XBT_DEBUG("Hey! Let's join the system.");

    join_success = join(&node);
  }

  if (join_success) {
    XBT_DEBUG("Waiting ….");

    while (MSG_get_clock() < init_time + deadline
//      && MSG_get_clock() < node.last_change_date + 1000
        && MSG_get_clock() < max_simulation_time) {
      if (node.comm_receive == NULL) {
        task_received = NULL;
        node.comm_receive = MSG_task_irecv(&task_received, node.mailbox);
        // FIXME: do not make MSG_task_irecv() calls from several functions
      }
      if (!MSG_comm_test(node.comm_receive)) {
        MSG_process_sleep(5);
      } else {
        // a transfer has occurred

        msg_error_t status = MSG_comm_get_status(node.comm_receive);

        if (status != MSG_OK) {
          XBT_DEBUG("Failed to receive a task. Nevermind.");
          MSG_comm_destroy(node.comm_receive);
          node.comm_receive = NULL;
        }
        else {
          // the task was successfully received
          MSG_comm_destroy(node.comm_receive);
          node.comm_receive = NULL;
          handle_task(&node, task_received);
        }
      }

    }
    print_node(&node);
  }
  return 1;
}
Пример #2
0
/*
 * Handle a given task
 */
static void handle_task(node_t node, msg_task_t task) {
  XBT_DEBUG("Handling task %p", task);
  char mailbox[MAILBOX_NAME_SIZE];
  int i, j, min, max, d;
  msg_task_t task_sent;
  task_data_t req_data;
  task_data_t task_data = (task_data_t) MSG_task_get_data(task);
  e_task_type_t type = task_data->type;
  // If the node is not ready keep the task for later
  if (node->ready != 0 && !(type==TASK_JOIN_LAST_REPLY || type==TASK_JOIN_REPLY)) {
    XBT_DEBUG("Task pending %i", type);
    xbt_fifo_push(node->pending_tasks, task);
    return;
  }
  switch (type) {
    /*
     * Try to join the ring
     */
    case TASK_JOIN: {
      int next = routing_next(node, task_data->answer_id);
      XBT_DEBUG("Join request from %08x forwarding to %08x", task_data->answer_id, next);      
      type = TASK_JOIN_LAST_REPLY;

      req_data = xbt_new0(s_task_data_t,1);
      req_data->answer_id = task_data->sender_id;
      req_data->steps = task_data->steps + 1;
      
      // if next different from current node forward the join
      if (next!=node->id) {
        get_mailbox(next, mailbox);
        task_data->sender_id = node->id;
  task_data->steps++;
        task_sent = MSG_task_create(NULL, COMP_SIZE, COMM_SIZE, task_data);
        MSG_task_send_with_timeout(task_sent, mailbox, timeout);
        type = TASK_JOIN_REPLY;
      } 
      
      // send back the current node state to the joining node
      req_data->type = type;
      req_data->sender_id = node->id;
      get_mailbox(node->id, req_data->answer_to);
      req_data->state = node_get_state(node);
      task_sent = MSG_task_create(NULL, COMP_SIZE, COMM_SIZE, req_data);
      MSG_task_send_with_timeout(task_sent, task_data->answer_to, timeout);
      break;
    }
    /*
     * Join reply from all the node touched by the join
     */
    case TASK_JOIN_LAST_REPLY:
      // if last node touched reply, copy its namespace set
      // TODO: it's work only if the two nodes are side to side (is it really the case ?)
      j = (task_data->sender_id < node->id) ? -1 : 0;
      for (i=0; i<NAMESPACE_SIZE/2; i++) {
        node->namespace_set[i] = task_data->state->namespace_set[i-j];
        node->namespace_set[NAMESPACE_SIZE-1-i] = task_data->state->namespace_set[NAMESPACE_SIZE-1-i-j-1];
      }
      node->namespace_set[NAMESPACE_SIZE/2+j] = task_data->sender_id;
      node->ready += task_data->steps + 1;
    case TASK_JOIN_REPLY:
      XBT_DEBUG("Joining Reply");

      // if first node touched reply, copy its neighborood set
      if (task_data->sender_id == node->known_id) {
  node->neighborhood_set[0] = task_data->sender_id;
        for (i=1; i<NEIGHBORHOOD_SIZE; i++)
            node->neighborhood_set[i] = task_data->state->neighborhood_set[i-1]; 
      }
      
      // copy the corresponding routing table levels
      min = (node->id==task_data->answer_id) ? 0 : shl(node->id, task_data->answer_id);      
      max = shl(node->id, task_data->sender_id)+1;
      for (i=min;i<max;i++) {
        d = domain(node->id, i); 
        for (j=0; j<LEVEL_SIZE; j++)
    if (d!=j)
            node->routing_table[i][j] =  task_data->state->routing_table[i][j];
      }

      node->ready--;
      // if the node is ready, do all the pending tasks and send update to known nodes
      if (node->ready==0) {
        XBT_DEBUG("Node %i is ready!!!", node->id);

        while(xbt_fifo_size(node->pending_tasks))
    handle_task(node, xbt_fifo_pop(node->pending_tasks));

  for (i=0; i<NAMESPACE_SIZE; i++) {
          j = node->namespace_set[i];
          if (j!=-1) {
            XBT_DEBUG("Send update to %i", j);
            get_mailbox(j, mailbox);
      
      req_data = xbt_new0(s_task_data_t,1);
            req_data->answer_id = node->id;
            req_data->steps = 0;
            req_data->type = TASK_UPDATE;
            req_data->sender_id = node->id;
            get_mailbox(node->id, req_data->answer_to);
            req_data->state = node_get_state(node);
            task_sent = MSG_task_create(NULL, COMP_SIZE, COMM_SIZE, req_data);
            MSG_task_send_with_timeout(task_sent, mailbox, timeout);
          }
        }
      }
      break;
      
    /*
     * Recieved an update of state
     */
    case TASK_UPDATE:
      XBT_DEBUG("Task update %i !!!", node->id);

      /* Update namespace ses */
      printf("Task update from %i !!!\n", task_data->sender_id);
      print_node_id(node);
      print_node_namespace_set(node);
      int curr_namespace_set[NAMESPACE_SIZE];
      int task_namespace_set[NAMESPACE_SIZE+1];
      
      // Copy the current namedspace
      // and the task state namespace with state->id in the middle
      i=0;
      for (; i<NAMESPACE_SIZE/2; i++){
        curr_namespace_set[i] = node->namespace_set[i];
  task_namespace_set[i] = task_data->state->namespace_set[i];
      }
      task_namespace_set[i] = task_data->state->id;
      for (; i<NAMESPACE_SIZE; i++){
        curr_namespace_set[i] = node->namespace_set[i];  
  task_namespace_set[i+1] = task_data->state->namespace_set[i];  
      }

      // get the index of values before and after node->id in task_namespace
      min = -1;
      max = -1;
      for (i=0; i<=NAMESPACE_SIZE; i++) {
  j = task_namespace_set[i];
        if (i<NAMESPACE_SIZE)
    printf("%08x %08x | ", j, curr_namespace_set[i]);
  if (j != -1 && j < node->id) min = i;
  if (j != -1 && max == -1 && j > node->id) max = i;
      }
      printf("\n");

      // add lower elements
      j = NAMESPACE_SIZE/2-1;
      for (i=NAMESPACE_SIZE/2-1; i>=0; i--) {
  printf("i:%i, j:%i, min:%i, currj:%08x, taskmin:%08x\n", i, j, min, curr_namespace_set[j], task_namespace_set[min]);
        if (min<0) {
    node->namespace_set[i] = curr_namespace_set[j];
    j--; 
  } else if (curr_namespace_set[j] == task_namespace_set[min]) {
    node->namespace_set[i] = curr_namespace_set[j];
    j--; min--;
  } else if (curr_namespace_set[j] > task_namespace_set[min]) {
          node->namespace_set[i] = curr_namespace_set[j];
    j--;
  } else {
          node->namespace_set[i] = task_namespace_set[min];
    min--;
  }
      }

      // add greater elements
      j = NAMESPACE_SIZE/2;
      for (i=NAMESPACE_SIZE/2; i<NAMESPACE_SIZE; i++) {
  printf("i:%i, j:%i, max:%i, currj:%08x, taskmax:%08x\n", i, j, max, curr_namespace_set[j], task_namespace_set[max]);        
        if (min<0 || max>=NAMESPACE_SIZE) {
    node->namespace_set[i] = curr_namespace_set[j];
    j++;
  } else if (curr_namespace_set[j] == -1) {
    node->namespace_set[i] = task_namespace_set[max];
    max++;
  } else if (curr_namespace_set[j] == task_namespace_set[max]) {
    node->namespace_set[i] = curr_namespace_set[j];
    j++; max++;
  } else if (curr_namespace_set[j] < task_namespace_set[max]) {
          node->namespace_set[i] = curr_namespace_set[j];
    j++;
  } else {
          node->namespace_set[i] = task_namespace_set[max];
    max++;
  }
      }
      print_node_namespace_set(node);

      /* Update routing table */
      for (i=shl(node->id, task_data->state->id); i<LEVELS_COUNT; i++) {
        for (j=0; j<LEVEL_SIZE; j++) {
          if (node->routing_table[i][j]==-1 && task_data->state->routing_table[i][j]==-1)
            node->routing_table[i][j] = task_data->state->routing_table[i][j];
        }
      }
  }         
}
Пример #3
0
int main(int argc, char* argv[]){
    int socket_fd;
    if((socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))< 0){
        printf("socket error %s\n", strerror(errno));
        exit(1);
    }
    struct sockaddr_in servaddr;
    if(!load_config(&servaddr)){
        printf("config file error\n");
        exit(0);
    }
//    servaddr.sin_family = AF_INET;
//    char* addr = "23.105.194.17";
//    if(inet_aton(addr, (struct in_addr*)&servaddr.sin_addr) == 0){
//        printf("aton error %s\n", strerror(errno));
//        exit(1);
//    }
//    servaddr.sin_port = htons(80);
    if(bind(socket_fd, (const struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
        printf("bind error %s\n", strerror(errno));
        exit(1);
    }
    if(listen(socket_fd, 100) < 0){
        printf("listen error %s\n", strerror(errno));
        exit(1);
    }
    struct sockaddr_in cliaddr;
    int size = sizeof(cliaddr);
    int len; 
    struct sockaddr_in localaddr; 
    len = sizeof(struct sockaddr_in);
    getsockname(socket_fd, (struct sockaddr*)&localaddr, &len);
    uint16_t port = ntohs(localaddr.sin_port);
    char* addr = inet_ntoa(localaddr.sin_addr);
    printf("addr: %s port: %d\n", addr, port);
    int page_fd = open("./page/test.html",O_RDONLY);
    if (page_fd == -1){
        printf("page file open error %s\n", strerror(errno));
        exit(1);
    }
    int file_size = get_file_size(page_fd);
    void* file_addr = mmap(0, file_size, PROT_READ, MAP_SHARED, page_fd, 0);
    if(file_addr == MAP_FAILED){
        printf("file map error %s\n", strerror(errno));
        exit(1);
    }
    int max_fd = socket_fd;
    fd_set readable;
    FD_ZERO(&readable);
    FD_SET(socket_fd, &readable);
    int flags = fcntl(socket_fd, F_GETFL, 0);
    fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
   // struct fd_list list ;
    //list.head=NULL;
    //list.tail = NULL;
    //list.nodes_count = 0;
    //add_fd(socket_fd, &list);
    for(;;){
        fd_set temp = readable;
        if(select(max_fd+1, &readable, NULL, NULL, NULL) < 0){
            printf("select error\n");
        }
        int ready_fd;
        for(ready_fd = 0;ready_fd<=max_fd;ready_fd++){
           if(FD_ISSET(ready_fd, &readable)){
               break;
           } 
        }
        readable = temp;
        if(ready_fd == socket_fd){
             int serv_fd = accept(socket_fd, (struct sockaddr*)&cliaddr, &size);
             if(serv_fd == -1) continue;
             FD_SET(serv_fd, &readable);
             max_fd = serv_fd>max_fd?serv_fd:max_fd;
        } else {
            handle_task(ready_fd, file_size, file_addr);
            FD_CLR(ready_fd, &readable);
        }
   }
}
Пример #4
0
/** Handle a given task */
static void handle_task(node_t node, msg_task_t task) {
  XBT_DEBUG("Handling task %p", task);
  char mailbox[MAILBOX_NAME_SIZE];
  int i;
  int j;
  int min;
  int max;
  int next;
  msg_task_t task_sent;
  task_data_t req_data;
  task_data_t task_data = (task_data_t) MSG_task_get_data(task);
  e_task_type_t type = task_data->type;
  // If the node is not ready keep the task for later
  if (node->ready != 0 && !(type==TASK_JOIN_LAST_REPLY || type==TASK_JOIN_REPLY)) {
    XBT_DEBUG("Task pending %u", type);
    xbt_dynar_push(node->pending_tasks, &task);
    return;
  }
  switch (type) {
    /* Try to join the ring */
    case TASK_JOIN:
      next = routing_next(node, task_data->answer_id);
      XBT_DEBUG("Join request from %08x forwarding to %08x", (unsigned)task_data->answer_id, (unsigned)next);
      type = TASK_JOIN_LAST_REPLY;

      req_data = xbt_new0(s_task_data_t,1);
      req_data->answer_id = task_data->sender_id;
      req_data->steps = task_data->steps + 1;

      // if next different from current node forward the join
      if (next!=node->id) {
        get_mailbox(next, mailbox);
        task_data->sender_id = node->id;
        task_data->steps++;
        task_sent = MSG_task_create(NULL, COMP_SIZE, COMM_SIZE, task_data);
        if (MSG_task_send_with_timeout(task_sent, mailbox, timeout)== MSG_TIMEOUT) {
          XBT_DEBUG("Timeout expired when forwarding join to next %d", next);
          task_free(task_sent);
        }
        type = TASK_JOIN_REPLY;
      }

      // send back the current node state to the joining node
      req_data->type = type;
      req_data->sender_id = node->id;
      get_mailbox(node->id, req_data->answer_to);
      req_data->state = node_get_state(node);
      task_sent = MSG_task_create(NULL, COMP_SIZE, COMM_SIZE, req_data);
      if (MSG_task_send_with_timeout(task_sent, task_data->answer_to, timeout)== MSG_TIMEOUT) {
        XBT_DEBUG("Timeout expired when sending back the current node state to the joining node to %d", node->id);
        task_free(task_sent);
      }
      break;
    /* Join reply from all the node touched by the join  */
    case TASK_JOIN_LAST_REPLY:
      // if last node touched reply, copy its namespace set
      // TODO: it works only if the two nodes are side to side (is it really the case ?)
      j = (task_data->sender_id < node->id) ? -1 : 0;
      for (i=0; i<NAMESPACE_SIZE/2; i++) {
        node->namespace_set[i] = task_data->state->namespace_set[i-j];
        node->namespace_set[NAMESPACE_SIZE-1-i] = task_data->state->namespace_set[NAMESPACE_SIZE-1-i-j-1];
      }
      node->namespace_set[NAMESPACE_SIZE/2+j] = task_data->sender_id;
      node->ready += task_data->steps + 1;
      /* no break */
    case TASK_JOIN_REPLY:
      XBT_DEBUG("Joining Reply");

      // if first node touched reply, copy its neighborhood set
      if (task_data->sender_id == node->known_id) {
        node->neighborhood_set[0] = task_data->sender_id;
        for (i=1; i<NEIGHBORHOOD_SIZE; i++)
          node->neighborhood_set[i] = task_data->state->neighborhood_set[i-1];
      }

      // copy the corresponding routing table levels
      min = (node->id==task_data->answer_id) ? 0 : shl(node->id, task_data->answer_id);
      max = shl(node->id, task_data->sender_id)+1;
      for (i=min;i<max;i++) {
        int d = domain(node->id, i);
        for (j=0; j<LEVEL_SIZE; j++)
          if (d!=j)
            node->routing_table[i][j] =  task_data->state->routing_table[i][j];
      }

      node->ready--;
      // if the node is ready, do all the pending tasks and send update to known nodes
      if (node->ready==0) {
        XBT_DEBUG("Node %i is ready!!!", node->id);
        while (!xbt_dynar_is_empty(node->pending_tasks)) {
          msg_task_t task;
          xbt_dynar_shift(node->pending_tasks, &task);
          handle_task(node, task);
        }

        for (i=0; i<NAMESPACE_SIZE; i++) {
          j = node->namespace_set[i];
          if (j!=-1) {
            XBT_DEBUG("Send update to %i", j);
            get_mailbox(j, mailbox);

            req_data = xbt_new0(s_task_data_t,1);
            req_data->answer_id = node->id;
            req_data->steps = 0;
            req_data->type = TASK_UPDATE;
            req_data->sender_id = node->id;
            get_mailbox(node->id, req_data->answer_to);
            req_data->state = node_get_state(node);
            task_sent = MSG_task_create(NULL, COMP_SIZE, COMM_SIZE, req_data);
            if (MSG_task_send_with_timeout(task_sent, mailbox, timeout)== MSG_TIMEOUT) {
              XBT_DEBUG("Timeout expired when sending update to %d", j);
              task_free(task_sent);
            }
          }
        }
        }
      break;
    /* Received an update of state */
    case TASK_UPDATE:
      XBT_DEBUG("Task update %i !!!", node->id);

      /* Update namespace ses */
      XBT_INFO("Task update from %i !!!", task_data->sender_id);
      XBT_INFO("Node:");
      print_node_id(node);
      print_node_namespace_set(node);
      int curr_namespace_set[NAMESPACE_SIZE];
      int task_namespace_set[NAMESPACE_SIZE+1];

      // Copy the current namespace and the task state namespace with state->id in the middle
      i=0;
      for (; i<NAMESPACE_SIZE/2; i++){
        curr_namespace_set[i] = node->namespace_set[i];
        task_namespace_set[i] = task_data->state->namespace_set[i];
      }
      task_namespace_set[i] = task_data->state->id;
      for (; i<NAMESPACE_SIZE; i++){
        curr_namespace_set[i] = node->namespace_set[i];
        task_namespace_set[i+1] = task_data->state->namespace_set[i];
      }

      // get the index of values before and after node->id in task_namespace
      min = -1;
      max = -1;
      for (i=0; i<=NAMESPACE_SIZE; i++) {
        j = task_namespace_set[i];
        if (j != -1 && j < node->id)
          min = i;
        if (j != -1 && max == -1 && j > node->id)
          max = i;
      }

      // add lower elements
      j = NAMESPACE_SIZE/2-1;
      for (i=NAMESPACE_SIZE/2-1; i>=0; i--) {
        if (min < 0 || curr_namespace_set[j] > task_namespace_set[min]) {
          node->namespace_set[i] = curr_namespace_set[j];
          j--;
        } else if (curr_namespace_set[j] == task_namespace_set[min]) {
          node->namespace_set[i] = curr_namespace_set[j];
          j--;
          min--;
        } else {
          node->namespace_set[i] = task_namespace_set[min];
          min--;
        }
      }

      // add greater elements
      j = NAMESPACE_SIZE/2;
      for (i=NAMESPACE_SIZE/2; i<NAMESPACE_SIZE; i++) {
        if (min<0 || max>=NAMESPACE_SIZE) {
         node->namespace_set[i] = curr_namespace_set[j];
         j++;
        } else if (max >= 0){
          if (curr_namespace_set[j] == -1 || curr_namespace_set[j] > task_namespace_set[max]) {
            node->namespace_set[i] = task_namespace_set[max];
            max++;
          } else if (curr_namespace_set[j] == task_namespace_set[max]) {
            node->namespace_set[i] = curr_namespace_set[j];
            j++;
            max++;
          } else {
            node->namespace_set[i] = curr_namespace_set[j];
            j++;
          }
        }
      }

      /* Update routing table */
      for (i=shl(node->id, task_data->state->id); i<LEVELS_COUNT; i++) {
        for (j=0; j<LEVEL_SIZE; j++) {
          if (node->routing_table[i][j]==-1 && task_data->state->routing_table[i][j]==-1)
            node->routing_table[i][j] = task_data->state->routing_table[i][j];
        }
      }
      break;
    default:
      THROW_IMPOSSIBLE;
  }
  task_free(task);
}
Пример #5
0
void uplink_user(task_queue *queue, userS *user, task *tasks) {
  mod_type mod    = user->mod;
  int startSc     = user->startRB*SC_PER_RB;
  int nmbSc       = user->nmbRB*SC_PER_RB;
  int nmbLayer    = user->nmbLayer;
  int nmbSymbols  = 2*nmbSc*(OFDM_IN_SLOT-1)*nmbLayer; /* 2* is for two slots in a subframe */
  int nmbSoftbits = nmbSymbols * mod;
  int layer;
  int rx;
  int ofdm;
  int slot;
  int sc;
  int i;

  /* All tasks have the same symbolData and computed so we update the
     first with necessary data */
  symbol_data *symbolData = tasks[0].symbolData;

  /* Output place holders */
  int *pow                = symbolData->pow;
  complexMatrix_t *comb_w = symbolData->comb_w;
  weightSC_t *combWeight  = symbolData->combWeight;
  complex *symbols        = symbolData->symbols;
  complex *deint_symbols  = symbolData->deint_symbols;
  char *softbits          = symbolData->softbits;
  unsigned char *bits     = symbolData->bits;

  symbolData->startSc = startSc;
  symbolData->nmbSc   = nmbSc;
  symbolData->data    = user->data;

  for (slot=0; slot<2; slot++) {
    symbolData->slot = slot;

    /* Process each layer separately
       Assume we can access the 4th ofdm symbol (containing reference symbols)
       Prepare chest items to be put on queue
       Reduces the amount of time in the critical section */
    i = 0;
    for (layer=0; layer<nmbLayer; layer++) {
      for (rx=0; rx<4; rx++) { 
	tasks[i].type     = CHANNEL;
	tasks[i].layer    = layer;
	tasks[i].rx       = rx;
        tasks[i].computed = false;
	if (i != 0) {
	  tasks[i-1].next = &tasks[i];
	}
	i++;
      }
    }
    tasks[i-1].next = NULL;

    /* Add prepared items to private queue */
    pthread_mutex_lock(&(queue->lock));
    if (queue->first == NULL) {
      queue->first = tasks;
    } else {
      queue->last->next = tasks;
    }
    queue->last = &tasks[i-1];
    pthread_mutex_unlock(&(queue->lock));

    /* Process all items that are in the queue */
    while(queue->first)
      handle_task(queue);

    /* Wait until this user's channel estimation items are computed */
    wait_until_computed(tasks, i);

    uplink_layer_verify(user->subframe, symbolData->layer_data, symbolData->R, nmbSc, nmbLayer, slot);

    /* It's time to combine all layers and RX calc. Call the Combiner weights
       calc -> will produce a layer X RX_ant X subcarrier matrix. */
    comb_w_calc(symbolData->layer_data, nmbSc, nmbLayer, symbolData->R, comb_w);


    /* Unfortunatly, we have to reorder the weights, in order to be
       able to split to comming processing inte layers. We can do this
       either in "comb_w_calc", "ant_comb", or here: */
    for (rx=0; rx<RX_ANT; rx++)
      for (layer=0; layer<user->nmbLayer; layer++)
        for (sc=0; sc<nmbSc; sc++)
          combWeight[layer][sc][rx] = comb_w[sc][layer][rx];

    uplink_weight_verify(user->subframe, combWeight, nmbSc, nmbLayer, slot);

    /* We have a lot of channel weights, let's process the user data
       for each ofdm symbol and each layer.  In practice, we need to
       be sure that the ofdm symbols are recived from the radio. */
    i = 0;
    for (layer=0; layer<nmbLayer; layer++) {
      int ofdm_count = 0;
      for (ofdm = 0; ofdm<OFDM_IN_SLOT; ofdm++) {
	if (ofdm != 3) {
	  tasks[i].type       = SYMBOL;
	  tasks[i].ofdm       = ofdm;
	  tasks[i].ofdm_count = ofdm_count;
	  tasks[i].layer      = layer;
	  tasks[i].computed   = false;
	  if (i != 0) {
	    tasks[i-1].next   = &tasks[i];
	  }
	  ofdm_count++;
	  i++;
	}
      }
    }
    tasks[i-1].next = NULL;

    /* Put all symbols on the queue */
    pthread_mutex_lock(&(queue->lock));
    if (queue->first == NULL) {
      queue->first = tasks;
    } else {
      queue->last->next = tasks;
    }
    queue->last = &tasks[i-1];
    pthread_mutex_unlock(&(queue->lock));

    /* Process all items that are in the queue */
    while(queue->first)
      handle_task(queue);

    /* Wait until this user's data symbol items are computed */
    wait_until_computed(tasks, i);
  } /* slot loop */

  /* OK, we have processed data for one user in 2 slots, let's process
     it as one big chunk. In real, we should divide the data into
     code block, but in this example we process all data in one
     block. */
  uplink_symbol_verify(user->subframe, symbols, nmbSymbols);

  interleave(symbols, deint_symbols, nmbSymbols);

  uplink_interleave_verify(user->subframe, deint_symbols, nmbSymbols);

  soft_demap(deint_symbols, pow[0], mod, nmbSymbols, softbits);

  uplink_verify(user->subframe, softbits, nmbSoftbits);

  /* call the turbo decoder and then check CRC */
  turbo_dec(nmbSoftbits);
  crcFast(bits, nmbSoftbits/24);
}