Merge remote-tracking branch 'origin/bugfixes-2018-w10' into develop_integration_2018_w10
This commit is contained in:
@@ -391,6 +391,103 @@ int itti_send_msg_to_task(task_id_t destination_task_id, instance_t instance, Me
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* same as itti_send_msg_to_task but returns -1 in case of failure instead of crashing */
|
||||
/* TODO: this is a hack - the whole logic needs a proper rework. */
|
||||
/* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */
|
||||
int itti_try_send_msg_to_task(task_id_t destination_task_id, instance_t instance, MessageDef *message)
|
||||
{
|
||||
thread_id_t destination_thread_id;
|
||||
task_id_t origin_task_id;
|
||||
message_list_t *new;
|
||||
uint32_t priority;
|
||||
message_number_t message_number;
|
||||
uint32_t message_id;
|
||||
|
||||
AssertFatal (message != NULL, "Message is NULL!\n");
|
||||
AssertFatal (destination_task_id < itti_desc.task_max, "Destination task id (%d) is out of range (%d)\n", destination_task_id, itti_desc.task_max);
|
||||
|
||||
destination_thread_id = TASK_GET_THREAD_ID(destination_task_id);
|
||||
message->ittiMsgHeader.destinationTaskId = destination_task_id;
|
||||
message->ittiMsgHeader.instance = instance;
|
||||
message->ittiMsgHeader.lte_time.frame = itti_desc.lte_time.frame;
|
||||
message->ittiMsgHeader.lte_time.slot = itti_desc.lte_time.slot;
|
||||
message_id = message->ittiMsgHeader.messageId;
|
||||
AssertFatal (message_id < itti_desc.messages_id_max, "Message id (%d) is out of range (%d)!\n", message_id, itti_desc.messages_id_max);
|
||||
|
||||
origin_task_id = ITTI_MSG_ORIGIN_ID(message);
|
||||
|
||||
priority = itti_get_message_priority (message_id);
|
||||
|
||||
/* Increment the global message number */
|
||||
message_number = itti_increment_message_number ();
|
||||
|
||||
itti_dump_queue_message (origin_task_id, message_number, message, itti_desc.messages_info[message_id].name,
|
||||
sizeof(MessageHeader) + message->ittiMsgHeader.ittiMsgSize);
|
||||
|
||||
if (destination_task_id != TASK_UNKNOWN) {
|
||||
|
||||
if (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_ENDED) {
|
||||
ITTI_DEBUG(ITTI_DEBUG_ISSUES, " Message %s, number %lu with priority %d can not be sent from %s to queue (%u:%s), ended destination task!\n",
|
||||
itti_desc.messages_info[message_id].name,
|
||||
message_number,
|
||||
priority,
|
||||
itti_get_task_name(origin_task_id),
|
||||
destination_task_id,
|
||||
itti_get_task_name(destination_task_id));
|
||||
} else {
|
||||
/* We cannot send a message if the task is not running */
|
||||
AssertFatal (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_READY,
|
||||
"Task %s Cannot send message %s (%d) to thread %d, it is not in ready state (%d)!\n",
|
||||
itti_get_task_name(origin_task_id),
|
||||
itti_desc.messages_info[message_id].name,
|
||||
message_id,
|
||||
destination_thread_id,
|
||||
itti_desc.threads[destination_thread_id].task_state);
|
||||
|
||||
/* Allocate new list element */
|
||||
new = (message_list_t *) itti_malloc (origin_task_id, destination_task_id, sizeof(struct message_list_s));
|
||||
|
||||
/* Fill in members */
|
||||
new->msg = message;
|
||||
new->message_number = message_number;
|
||||
new->message_priority = priority;
|
||||
|
||||
/* Enqueue message in destination task queue */
|
||||
if (lfds611_queue_enqueue(itti_desc.tasks[destination_task_id].message_queue, new) == 0) {
|
||||
itti_free(origin_task_id, new);
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
/* Only use event fd for tasks, subtasks will pool the queue */
|
||||
if (TASK_GET_PARENT_TASK_ID(destination_task_id) == TASK_UNKNOWN) {
|
||||
ssize_t write_ret;
|
||||
eventfd_t sem_counter = 1;
|
||||
|
||||
/* Call to write for an event fd must be of 8 bytes */
|
||||
write_ret = write (itti_desc.threads[destination_thread_id].task_event_fd, &sem_counter, sizeof(sem_counter));
|
||||
AssertFatal (write_ret == sizeof(sem_counter), "Write to task message FD (%d) failed (%d/%d)\n",
|
||||
destination_thread_id, (int) write_ret, (int) sizeof(sem_counter));
|
||||
}
|
||||
}
|
||||
|
||||
ITTI_DEBUG(ITTI_DEBUG_SEND, " Message %s, number %lu with priority %d successfully sent from %s to queue (%u:%s)\n",
|
||||
itti_desc.messages_info[message_id].name,
|
||||
message_number,
|
||||
priority,
|
||||
itti_get_task_name(origin_task_id),
|
||||
destination_task_id,
|
||||
itti_get_task_name(destination_task_id));
|
||||
}
|
||||
} else {
|
||||
/* This is a debug message to TASK_UNKNOWN, we can release safely release it */
|
||||
int result = itti_free(origin_task_id, message);
|
||||
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void itti_subscribe_event_fd(task_id_t task_id, int fd)
|
||||
{
|
||||
thread_id_t thread_id;
|
||||
|
||||
@@ -108,6 +108,18 @@ int itti_send_broadcast_message(MessageDef *message_p);
|
||||
**/
|
||||
int itti_send_msg_to_task(task_id_t task_id, instance_t instance, MessageDef *message);
|
||||
|
||||
/* TODO: this is a hack. Almost no caller of itti_send_msg_to_task checks
|
||||
* the return value so it has been changed to crash the program in case
|
||||
* of failure instead of returning -1 as the documentation above says.
|
||||
* The RLC UM code may receive too much data when doing UDP at a higher
|
||||
* throughput than the link allows and so for this specific case we need
|
||||
* a version that actually returns -1 on failure.
|
||||
*
|
||||
* This needs to be cleaned at some point.
|
||||
*/
|
||||
/* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */
|
||||
int itti_try_send_msg_to_task(task_id_t task_id, instance_t instance, MessageDef *message);
|
||||
|
||||
/** \brief Add a new fd to monitor.
|
||||
* NOTE: it is up to the user to read data associated with the fd
|
||||
* \param task_id Task ID of the receiving task
|
||||
|
||||
@@ -738,6 +738,8 @@ typedef struct RU_t_s{
|
||||
void (*fh_south_asynch_in)(struct RU_t_s *ru,int *frame, int *subframe);
|
||||
/// function pointer to initialization function for radio interface
|
||||
int (*start_rf)(struct RU_t_s *ru);
|
||||
/// function pointer to release function for radio interface
|
||||
int (*stop_rf)(struct RU_t_s *ru);
|
||||
/// function pointer to initialization function for radio interface
|
||||
int (*start_if)(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB);
|
||||
/// function pointer to RX front-end processing routine (DFTs/prefix removal or NULL)
|
||||
|
||||
@@ -154,7 +154,7 @@ schedule_next_dlue(module_id_t module_idP, int CC_id,
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char
|
||||
int
|
||||
generate_dlsch_header(unsigned char *mac_header,
|
||||
unsigned char num_sdus,
|
||||
unsigned short *sdu_lengths,
|
||||
@@ -344,7 +344,6 @@ generate_dlsch_header(unsigned char *mac_header,
|
||||
//msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header);
|
||||
|
||||
return ((unsigned char *) mac_header_ptr - mac_header);
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -563,33 +562,28 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
frame_t frameP, sub_frame_t subframeP, int *mbsfn_flag)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
|
||||
|
||||
uint8_t CC_id;
|
||||
int CC_id;
|
||||
int UE_id;
|
||||
unsigned char aggregation;
|
||||
int aggregation;
|
||||
mac_rlc_status_resp_t rlc_status;
|
||||
unsigned char header_len_dcch = 0, header_len_dcch_tmp = 0;
|
||||
unsigned char header_len_dtch = 0, header_len_dtch_tmp =
|
||||
0, header_len_dtch_last = 0;
|
||||
unsigned char ta_len = 0;
|
||||
unsigned char sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0;
|
||||
uint16_t nb_rb, nb_rb_temp, nb_available_rb;
|
||||
uint16_t TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding =
|
||||
0, post_padding = 0;
|
||||
int ta_len = 0;
|
||||
unsigned char sdu_lcids[NB_RB_MAX];
|
||||
int lcid, offset, num_sdus = 0;
|
||||
int nb_rb, nb_rb_temp, nb_available_rb;
|
||||
uint16_t sdu_lengths[NB_RB_MAX];
|
||||
int TBS, j, rnti, padding = 0, post_padding = 0;
|
||||
unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
|
||||
unsigned char round = 0;
|
||||
unsigned char harq_pid = 0;
|
||||
int round = 0;
|
||||
int harq_pid = 0;
|
||||
eNB_UE_STATS *eNB_UE_stats = NULL;
|
||||
uint16_t sdu_length_total = 0;
|
||||
int sdu_length_total = 0;
|
||||
|
||||
eNB_MAC_INST *eNB = RC.mac[module_idP];
|
||||
COMMON_channels_t *cc = eNB->common_channels;
|
||||
UE_list_t *UE_list = &eNB->UE_list;
|
||||
int continue_flag = 0;
|
||||
int32_t normalized_rx_power, target_rx_power;
|
||||
int32_t tpc = 1;
|
||||
static int32_t tpc_accumulated = 0;
|
||||
int tpc = 1;
|
||||
UE_sched_ctrl *ue_sched_ctl;
|
||||
int mcs;
|
||||
int i;
|
||||
@@ -601,6 +595,8 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
nfapi_dl_config_request_pdu_t *dl_config_pdu;
|
||||
int tdd_sfa;
|
||||
int ta_update;
|
||||
int header_length_last;
|
||||
int header_length_total;
|
||||
|
||||
#if 0
|
||||
if (UE_list->head == -1) {
|
||||
@@ -792,6 +788,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
|
||||
if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status < RRC_CONNECTED) continue;
|
||||
|
||||
header_length_total = 0;
|
||||
sdu_length_total = 0;
|
||||
num_sdus = 0;
|
||||
|
||||
@@ -838,8 +835,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
if (cc[CC_id].tdd_Config != NULL) {
|
||||
UE_list->UE_template[CC_id][UE_id].DAI++;
|
||||
update_ul_dci(module_idP, CC_id, rnti,
|
||||
UE_list->UE_template[CC_id][UE_id].
|
||||
DAI);
|
||||
UE_list->UE_template[CC_id][UE_id].DAI);
|
||||
LOG_D(MAC,
|
||||
"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n",
|
||||
CC_id, subframeP, UE_id,
|
||||
@@ -988,13 +984,12 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
module_idP, frameP, CC_id, UE_id);
|
||||
}
|
||||
} else { /* This is a potentially new SDU opportunity */
|
||||
|
||||
rlc_status.bytes_in_buffer = 0;
|
||||
|
||||
// Now check RLC information to compute number of required RBs
|
||||
// get maximum TBS size for RLC request
|
||||
TBS =
|
||||
get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb);
|
||||
// check first for RLC data on DCCH
|
||||
TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb);
|
||||
|
||||
// add the length for all the control elements (timing adv, drx, etc) : header + payload
|
||||
|
||||
if (ue_sched_ctl->ta_timer == 0) {
|
||||
@@ -1009,38 +1004,42 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
|
||||
ta_len = (ta_update != 31) ? 2 : 0;
|
||||
|
||||
header_len_dcch = 2; // 2 bytes DCCH SDU subheader
|
||||
|
||||
if (TBS - ta_len - header_len_dcch > 0) {
|
||||
rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, (TBS - ta_len - header_len_dcch)); // transport block set size
|
||||
// RLC data on DCCH
|
||||
if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) {
|
||||
rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH,
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3);
|
||||
|
||||
sdu_lengths[0] = 0;
|
||||
|
||||
if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit
|
||||
LOG_D(MAC,
|
||||
"[eNB %d] SFN/SF %d.%d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
|
||||
if (rlc_status.bytes_in_buffer > 0) {
|
||||
LOG_D(MAC, "[eNB %d] SFN/SF %d.%d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
|
||||
module_idP, frameP, subframeP, CC_id,
|
||||
TBS - header_len_dcch);
|
||||
sdu_lengths[0] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, TBS, //not used
|
||||
(char *)
|
||||
&dlsch_buffer
|
||||
[0]);
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3);
|
||||
|
||||
sdu_lengths[0] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH,
|
||||
TBS, //not used
|
||||
(char *)&dlsch_buffer[0]);
|
||||
|
||||
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP),
|
||||
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
|
||||
T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH),
|
||||
T_INT(sdu_lengths[0]));
|
||||
|
||||
LOG_D(MAC,
|
||||
"[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",
|
||||
LOG_D(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",
|
||||
module_idP, CC_id, sdu_lengths[0]);
|
||||
|
||||
sdu_length_total = sdu_lengths[0];
|
||||
sdu_lcids[0] = DCCH;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[0] = DCCH;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[DCCH] = sdu_lengths[0];
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH] += 1;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] += sdu_lengths[0];
|
||||
|
||||
header_length_last = 1 + 1 + (sdu_lengths[0] >= 128);
|
||||
header_length_total += header_length_last;
|
||||
|
||||
num_sdus = 1;
|
||||
|
||||
#ifdef DEBUG_eNB_SCHEDULER
|
||||
LOG_T(MAC,
|
||||
"[eNB %d][DCCH] CC_id %d Got %d bytes :",
|
||||
@@ -1052,26 +1051,25 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
|
||||
LOG_T(MAC, "\n");
|
||||
#endif
|
||||
} else {
|
||||
header_len_dcch = 0;
|
||||
sdu_length_total = 0;
|
||||
}
|
||||
}
|
||||
// check for DCCH1 and update header information (assume 2 byte sub-header)
|
||||
if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) {
|
||||
rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, (TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and
|
||||
|
||||
// RLC data on DCCH1
|
||||
if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) {
|
||||
rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1,
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3);
|
||||
|
||||
// DCCH SDU
|
||||
sdu_lengths[num_sdus] = 0;
|
||||
|
||||
if (rlc_status.bytes_in_buffer > 0) {
|
||||
LOG_D(MAC,
|
||||
"[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
|
||||
LOG_D(MAC, "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
|
||||
module_idP, frameP, CC_id,
|
||||
TBS - header_len_dcch - sdu_length_total);
|
||||
sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, TBS, //not used
|
||||
(char *)
|
||||
&dlsch_buffer
|
||||
[sdu_length_total]);
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3);
|
||||
|
||||
sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1,
|
||||
TBS, //not used
|
||||
(char *)&dlsch_buffer[sdu_length_total]);
|
||||
|
||||
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP),
|
||||
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
|
||||
@@ -1080,13 +1078,16 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
|
||||
sdu_lcids[num_sdus] = DCCH1;
|
||||
sdu_length_total += sdu_lengths[num_sdus];
|
||||
header_len_dcch += 2;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[num_sdus] = DCCH1;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[DCCH1] = sdu_lengths[num_sdus];
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].
|
||||
num_pdu_tx[DCCH1] += 1;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH1] += 1;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1] += sdu_lengths[num_sdus];
|
||||
|
||||
header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128);
|
||||
header_length_total += header_length_last;
|
||||
|
||||
num_sdus++;
|
||||
|
||||
#ifdef DEBUG_eNB_SCHEDULER
|
||||
LOG_T(MAC,
|
||||
"[eNB %d][DCCH1] CC_id %d Got %d bytes :",
|
||||
@@ -1098,25 +1099,18 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
|
||||
LOG_T(MAC, "\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
// assume the max dtch header size, and adjust it later
|
||||
header_len_dtch = 0;
|
||||
header_len_dtch_last = 0; // the header length of the last mac sdu
|
||||
// lcid has to be sorted before the actual allocation (similar struct as ue_list).
|
||||
|
||||
// TODO: lcid has to be sorted before the actual allocation (similar struct as ue_list).
|
||||
for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) {
|
||||
// TBD: check if the lcid is active
|
||||
// TODO: check if the lcid is active
|
||||
|
||||
header_len_dtch += 3;
|
||||
header_len_dtch_last = 3;
|
||||
LOG_D(MAC,
|
||||
"[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n",
|
||||
LOG_D(MAC, "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n",
|
||||
module_idP, frameP, lcid, TBS,
|
||||
TBS - ta_len - header_len_dcch -
|
||||
sdu_length_total - header_len_dtch);
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3);
|
||||
|
||||
if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ?
|
||||
if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) {
|
||||
rlc_status = mac_rlc_status_ind(module_idP,
|
||||
rnti,
|
||||
module_idP,
|
||||
@@ -1125,25 +1119,22 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
ENB_FLAG_YES,
|
||||
MBMS_FLAG_NO,
|
||||
lcid,
|
||||
TBS - ta_len -
|
||||
header_len_dcch -
|
||||
sdu_length_total -
|
||||
header_len_dtch);
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3);
|
||||
|
||||
|
||||
|
||||
if (rlc_status.bytes_in_buffer > 0) {
|
||||
|
||||
LOG_D(MAC,
|
||||
"[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n",
|
||||
module_idP, frameP,
|
||||
TBS - header_len_dcch -
|
||||
sdu_length_total - header_len_dtch, lcid,
|
||||
header_len_dtch);
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS, //not used
|
||||
(char
|
||||
*)
|
||||
&dlsch_buffer
|
||||
[sdu_length_total]);
|
||||
TBS - ta_len - header_length_total - sdu_length_total - 3,
|
||||
lcid,
|
||||
header_length_total);
|
||||
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid,
|
||||
TBS, //not used
|
||||
(char *)&dlsch_buffer[sdu_length_total]);
|
||||
|
||||
T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP),
|
||||
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
|
||||
T_INT(subframeP), T_INT(harq_pid),
|
||||
@@ -1152,50 +1143,39 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
LOG_D(MAC,
|
||||
"[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",
|
||||
module_idP, sdu_lengths[num_sdus], lcid);
|
||||
|
||||
sdu_lcids[num_sdus] = lcid;
|
||||
sdu_length_total += sdu_lengths[num_sdus];
|
||||
UE_list->
|
||||
eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid]
|
||||
+= 1;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid]++;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[num_sdus] = lcid;
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[lcid] = sdu_lengths[num_sdus];
|
||||
UE_list->
|
||||
eNB_UE_stats[CC_id][UE_id].num_bytes_tx
|
||||
[lcid] += sdu_lengths[num_sdus];
|
||||
if (sdu_lengths[num_sdus] < 128) {
|
||||
header_len_dtch--;
|
||||
header_len_dtch_last--;
|
||||
}
|
||||
UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid] += sdu_lengths[num_sdus];
|
||||
|
||||
header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128);
|
||||
header_length_total += header_length_last;
|
||||
|
||||
num_sdus++;
|
||||
|
||||
UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
|
||||
} // no data for this LCID
|
||||
else {
|
||||
header_len_dtch -= 3;
|
||||
}
|
||||
} // no TBS left
|
||||
else {
|
||||
header_len_dtch -= 3;
|
||||
} else {
|
||||
// no TBS left
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (header_len_dtch == 0)
|
||||
header_len_dtch_last = 0;
|
||||
// there is at least one SDU
|
||||
|
||||
/* last header does not have length field */
|
||||
if (header_length_total) {
|
||||
header_length_total -= header_length_last;
|
||||
header_length_total++;
|
||||
}
|
||||
|
||||
// there is at least one SDU or TA command
|
||||
// if (num_sdus > 0 ){
|
||||
if ((sdu_length_total + header_len_dcch +
|
||||
header_len_dtch) > 0) {
|
||||
if (ta_len + sdu_length_total + header_length_total > 0) {
|
||||
|
||||
// Now compute number of required RBs for total sdu length
|
||||
// Assume RAH format 2
|
||||
// adjust header lengths
|
||||
header_len_dcch_tmp = header_len_dcch;
|
||||
header_len_dtch_tmp = header_len_dtch;
|
||||
if (header_len_dtch == 0) {
|
||||
header_len_dcch = (header_len_dcch > 0) ? 1 : 0; //header_len_dcch; // remove length field
|
||||
} else {
|
||||
header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU
|
||||
header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU
|
||||
}
|
||||
|
||||
mcs = eNB_UE_stats->dlsch_mcs1;
|
||||
|
||||
@@ -1207,16 +1187,12 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
|
||||
TBS = get_TBS_DL(mcs, nb_rb);
|
||||
|
||||
while (TBS <
|
||||
(sdu_length_total + header_len_dcch +
|
||||
header_len_dtch + ta_len)) {
|
||||
while (TBS < sdu_length_total + header_length_total + ta_len) {
|
||||
nb_rb += min_rb_unit[CC_id]; //
|
||||
|
||||
if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs
|
||||
// (can happen if N_RB_DL is odd)
|
||||
TBS =
|
||||
get_TBS_DL(eNB_UE_stats->dlsch_mcs1,
|
||||
nb_available_rb);
|
||||
TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb);
|
||||
nb_rb = nb_available_rb;
|
||||
break;
|
||||
}
|
||||
@@ -1250,13 +1226,13 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
}
|
||||
|
||||
// decrease mcs until TBS falls below required length
|
||||
while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs > 0)) {
|
||||
while ((TBS > sdu_length_total + header_length_total + ta_len) && (mcs > 0)) {
|
||||
mcs--;
|
||||
TBS = get_TBS_DL(mcs, nb_rb);
|
||||
}
|
||||
|
||||
// if we have decreased too much or we don't have enough RBs, increase MCS
|
||||
while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len))
|
||||
while ((TBS < sdu_length_total + header_length_total + ta_len)
|
||||
&& (((ue_sched_ctl->dl_pow_off[CC_id] > 0)
|
||||
&& (mcs < 28))
|
||||
|| ((ue_sched_ctl->dl_pow_off[CC_id] == 0)
|
||||
@@ -1277,23 +1253,14 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
// TBS, sdu_length_total, offset, TBS-sdu_length_total-offset);
|
||||
#endif
|
||||
|
||||
if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) {
|
||||
padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len);
|
||||
if (TBS - header_length_total - sdu_length_total - ta_len <= 2) {
|
||||
padding = TBS - header_length_total - sdu_length_total - ta_len;
|
||||
post_padding = 0;
|
||||
} else {
|
||||
padding = 0;
|
||||
|
||||
// adjust the header len
|
||||
if (header_len_dtch == 0) {
|
||||
header_len_dcch = header_len_dcch_tmp;
|
||||
} else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2)))
|
||||
header_len_dtch = header_len_dtch_tmp;
|
||||
}
|
||||
|
||||
post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header
|
||||
post_padding = 1;
|
||||
}
|
||||
|
||||
|
||||
offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus
|
||||
sdu_lengths, //
|
||||
sdu_lcids, 255, // no drx
|
||||
@@ -1304,12 +1271,12 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
//#ifdef DEBUG_eNB_SCHEDULER
|
||||
if (ta_update != 31) {
|
||||
LOG_D(MAC,
|
||||
"[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n",
|
||||
"[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_length %d\n",
|
||||
module_idP, frameP, UE_id, CC_id,
|
||||
sdu_length_total, num_sdus, sdu_lengths[0],
|
||||
sdu_lcids[0], offset, ta_update, padding,
|
||||
post_padding, mcs, TBS, nb_rb,
|
||||
header_len_dcch, header_len_dtch);
|
||||
header_length_total);
|
||||
}
|
||||
//#endif
|
||||
#ifdef DEBUG_eNB_SCHEDULER
|
||||
@@ -1327,11 +1294,16 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
dlsch_buffer, sdu_length_total);
|
||||
// memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]);
|
||||
|
||||
#if 0
|
||||
// fill remainder of DLSCH with random data
|
||||
for (j = 0; j < (TBS - sdu_length_total - offset); j++) {
|
||||
UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + sdu_length_total + j] = (char) (taus() & 0xff);
|
||||
}
|
||||
|
||||
#endif
|
||||
// fill remainder of DLSCH with 0
|
||||
for (j = 0; j < (TBS - sdu_length_total - offset); j++) {
|
||||
UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + sdu_length_total + j] = 0;
|
||||
}
|
||||
|
||||
if (opt_enabled == 1) {
|
||||
trace_pdu(1, (uint8_t *)
|
||||
@@ -1348,8 +1320,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP),
|
||||
T_INT(CC_id), T_INT(rnti), T_INT(frameP),
|
||||
T_INT(subframeP), T_INT(harq_pid),
|
||||
T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].
|
||||
payload[0], TBS));
|
||||
T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS));
|
||||
|
||||
UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb;
|
||||
|
||||
@@ -1378,6 +1349,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
UE_list->UE_template[CC_id][UE_id].
|
||||
DAI);
|
||||
}
|
||||
|
||||
// do PUCCH power control
|
||||
// this is the normalized RX power
|
||||
eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id];
|
||||
@@ -1399,18 +1371,15 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
|
||||
if (normalized_rx_power > (target_rx_power + 4)) {
|
||||
tpc = 0; //-1
|
||||
tpc_accumulated--;
|
||||
} else if (normalized_rx_power < (target_rx_power - 4)) {
|
||||
tpc = 2; //+1
|
||||
tpc_accumulated++;
|
||||
} else {
|
||||
tpc = 1; //0
|
||||
}
|
||||
|
||||
LOG_D(MAC,
|
||||
"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n",
|
||||
module_idP, frameP, subframeP, harq_pid,
|
||||
tpc, tpc_accumulated,
|
||||
"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, normalized/target rx power %d/%d\n",
|
||||
module_idP, frameP, subframeP, harq_pid, tpc,
|
||||
normalized_rx_power, target_rx_power);
|
||||
|
||||
} // Po_PUCCH has been updated
|
||||
@@ -1456,13 +1425,13 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
module_idP, CC_id, harq_pid, mcs);
|
||||
|
||||
}
|
||||
|
||||
LOG_D(MAC, "Checking feasibility pdu %d (new sdu)\n",
|
||||
dl_req->number_pdu);
|
||||
|
||||
if (!CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP,
|
||||
dl_config_pdu->dci_dl_pdu.
|
||||
dci_dl_pdu_rel8.aggregation_level, rnti)) {
|
||||
|
||||
|
||||
ue_sched_ctl->round[CC_id][harq_pid] = 0;
|
||||
dl_req->number_dci++;
|
||||
dl_req->number_pdu++;
|
||||
@@ -1482,8 +1451,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
|
||||
UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid] = mcs;
|
||||
UE_list->UE_template[CC_id][UE_id].oldmcs2[harq_pid] = 0;
|
||||
AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated !=
|
||||
NULL,
|
||||
AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL,
|
||||
"physicalConfigDedicated is NULL\n");
|
||||
AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated != NULL,
|
||||
"physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n");
|
||||
@@ -1506,15 +1474,10 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
0, //number of PRBs treated as one subband, not used here
|
||||
0 // number of beamforming vectors, not used here
|
||||
);
|
||||
eNB->TX_req[CC_id].sfn_sf = fill_nfapi_tx_req(&eNB->
|
||||
TX_req
|
||||
[CC_id].tx_request_body,
|
||||
eNB->TX_req[CC_id].sfn_sf = fill_nfapi_tx_req(&eNB->TX_req[CC_id].tx_request_body,
|
||||
(frameP * 10) + subframeP,
|
||||
TBS, eNB->pdu_index[CC_id],
|
||||
eNB->
|
||||
UE_list.DLSCH_pdu[CC_id][0][(unsigned char)
|
||||
UE_id].payload
|
||||
[0]);
|
||||
eNB->UE_list.DLSCH_pdu[CC_id][0][UE_id].payload[0]);
|
||||
|
||||
LOG_D(MAC,
|
||||
"Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n",
|
||||
@@ -1523,10 +1486,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
eNB->pdu_index[CC_id]++;
|
||||
program_dlsch_acknak(module_idP, CC_id, UE_id,
|
||||
frameP, subframeP,
|
||||
dl_config_pdu->
|
||||
dci_dl_pdu.dci_dl_pdu_rel8.
|
||||
cce_idx);
|
||||
|
||||
dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx);
|
||||
} else {
|
||||
LOG_W(MAC,
|
||||
"Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d/%x, infeasible CCE allocations\n",
|
||||
@@ -1550,7 +1510,6 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP,
|
||||
|
||||
stop_meas(&eNB->schedule_dlsch);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT);
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -855,15 +855,15 @@ in the DLSCH buffer.
|
||||
@param post_padding number of bytes for padding at the end of MAC PDU
|
||||
@returns Number of bytes used for header
|
||||
*/
|
||||
unsigned char generate_dlsch_header(unsigned char *mac_header,
|
||||
unsigned char num_sdus,
|
||||
unsigned short *sdu_lengths,
|
||||
unsigned char *sdu_lcids,
|
||||
unsigned char drx_cmd,
|
||||
unsigned short timing_advance_cmd,
|
||||
unsigned char *ue_cont_res_id,
|
||||
unsigned char short_padding,
|
||||
unsigned short post_padding);
|
||||
int generate_dlsch_header(unsigned char *mac_header,
|
||||
unsigned char num_sdus,
|
||||
unsigned short *sdu_lengths,
|
||||
unsigned char *sdu_lcids,
|
||||
unsigned char drx_cmd,
|
||||
unsigned short timing_advance_cmd,
|
||||
unsigned char *ue_cont_res_id,
|
||||
unsigned char short_padding,
|
||||
unsigned short post_padding);
|
||||
|
||||
/** \brief RRC eNB Configuration primitive for PHY/MAC. Allows configuration of PHY/MAC resources based on System Information (SI), RRCConnectionSetup and RRCConnectionReconfiguration messages.
|
||||
@param Mod_id Instance ID of eNB
|
||||
|
||||
@@ -437,6 +437,15 @@ rlc_op_status_t rlc_data_req (const protocol_ctxt_t* const ctxt_pP,
|
||||
break;
|
||||
|
||||
case RLC_MODE_UM:
|
||||
/* TODO: this is a hack, needs better solution. Let's not use too
|
||||
* much memory and store at maximum 5 millions bytes.
|
||||
*/
|
||||
/* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */
|
||||
if (rlc_um_get_buffer_occupancy(&rlc_union_p->rlc.um) > 5000000) {
|
||||
free_mem_block(sdu_pP, __func__);
|
||||
return RLC_OP_STATUS_OUT_OF_RESSOURCES;
|
||||
}
|
||||
|
||||
new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_um_data_req_alloc), __func__);
|
||||
|
||||
if (new_sdu_p != NULL) {
|
||||
|
||||
@@ -270,10 +270,21 @@ void udp_eNB_receiver(struct udp_socket_desc_s *udp_sock_pP)
|
||||
n, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
||||
#endif
|
||||
|
||||
if (itti_send_msg_to_task(udp_sock_pP->task_id, INSTANCE_DEFAULT, message_p) < 0) {
|
||||
/* TODO: this is a hack. Let's accept failures and do nothing when
|
||||
* it happens. Since itti_send_msg_to_task crashes when the message
|
||||
* queue is full we wrote itti_try_send_msg_to_task that returns -1
|
||||
* if the queue is full.
|
||||
*/
|
||||
/* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */
|
||||
//if (itti_send_msg_to_task(udp_sock_pP->task_id, INSTANCE_DEFAULT, message_p) < 0) {
|
||||
if (itti_try_send_msg_to_task(udp_sock_pP->task_id, INSTANCE_DEFAULT, message_p) < 0) {
|
||||
#if 0
|
||||
LOG_I(UDP_, "Failed to send message %d to task %d\n",
|
||||
UDP_DATA_IND,
|
||||
udp_sock_pP->task_id);
|
||||
#endif
|
||||
itti_free(TASK_UDP, message_p);
|
||||
itti_free(TASK_UDP, forwarded_buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,13 +163,6 @@ extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset);
|
||||
|
||||
|
||||
static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_name) {
|
||||
|
||||
static double cpu_freq_GHz = 0.0;
|
||||
|
||||
if (cpu_freq_GHz == 0.0)
|
||||
cpu_freq_GHz = get_cpu_freq_GHz();
|
||||
|
||||
|
||||
start_meas(&softmodem_stats_rxtx_sf);
|
||||
|
||||
// *******************************************************************
|
||||
|
||||
@@ -1523,7 +1523,13 @@ static void* ru_thread( void* param ) {
|
||||
|
||||
|
||||
printf( "Exiting ru_thread \n");
|
||||
|
||||
|
||||
if (ru->stop_rf != NULL) {
|
||||
if (ru->stop_rf(ru) != 0)
|
||||
LOG_E(HW,"Could not stop the RF device\n");
|
||||
else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx);
|
||||
}
|
||||
|
||||
ru_thread_status = 0;
|
||||
return &ru_thread_status;
|
||||
|
||||
@@ -1617,6 +1623,12 @@ int start_rf(RU_t *ru) {
|
||||
return(ru->rfdevice.trx_start_func(&ru->rfdevice));
|
||||
}
|
||||
|
||||
int stop_rf(RU_t *ru)
|
||||
{
|
||||
ru->rfdevice.trx_end_func(&ru->rfdevice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void fep_full(RU_t *ru);
|
||||
extern void ru_fep_full_2thread(RU_t *ru);
|
||||
extern void feptx_ofdm(RU_t *ru);
|
||||
@@ -2082,6 +2094,7 @@ void set_function_spec_param(RU_t *ru)
|
||||
ru->fh_south_in = rx_rf; // local synchronous RF RX
|
||||
ru->fh_south_out = tx_rf; // local synchronous RF TX
|
||||
ru->start_rf = start_rf; // need to start the local RF interface
|
||||
ru->stop_rf = stop_rf;
|
||||
printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf);
|
||||
/*
|
||||
if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise
|
||||
@@ -2113,6 +2126,7 @@ void set_function_spec_param(RU_t *ru)
|
||||
ru->fh_south_asynch_in = NULL; // no asynchronous UL
|
||||
}
|
||||
ru->start_rf = NULL; // no local RF
|
||||
ru->stop_rf = NULL;
|
||||
ru->start_if = start_if; // need to start if interface for IF5
|
||||
ru->ifdevice.host_type = RAU_HOST;
|
||||
ru->ifdevice.eth_params = &ru->eth_params;
|
||||
@@ -2137,6 +2151,7 @@ void set_function_spec_param(RU_t *ru)
|
||||
ru->fh_north_out = NULL;
|
||||
ru->fh_north_asynch_in = NULL;
|
||||
ru->start_rf = NULL; // no local RF
|
||||
ru->stop_rf = NULL;
|
||||
ru->start_if = start_if; // need to start if interface for IF4p5
|
||||
ru->ifdevice.host_type = RAU_HOST;
|
||||
ru->ifdevice.eth_params = &ru->eth_params;
|
||||
|
||||
@@ -1005,10 +1005,8 @@ int main( int argc, char **argv )
|
||||
|
||||
printf("Runtime table\n");
|
||||
fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx);
|
||||
cpuf=get_cpu_freq_GHz();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef DEADLINE_SCHEDULER
|
||||
|
||||
printf("NO deadline scheduler\n");
|
||||
|
||||
Reference in New Issue
Block a user