diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index d7cd81cf58823de1791c4a195af33a4ad994052a..dd2eec6d2f9efdc906c45766e51645357e03d321 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1769,6 +1769,7 @@ add_executable(lte-softmodem ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c ${OPENAIR_DIR}/common/utils/utils.c + ${OPENAIR_DIR}/common/utils/system.c ${GTPU_need_ITTI} ${HW_SOURCE} ${TRANSPORT_SOURCE} @@ -1900,6 +1901,7 @@ add_executable(oaisim ${OPENAIR2_DIR}/RRC/NAS/rb_config.c ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c ${OPENAIR_DIR}/common/utils/utils.c + ${OPENAIR_DIR}/common/utils/system.c ${GTPU_need_ITTI} ${OPENAIR_TARGETS}/COMMON/create_tasks.c ${HW_SOURCE} diff --git a/cmake_targets/at_commands/CMakeLists.txt b/cmake_targets/at_commands/CMakeLists.txt index 61d1565bac912d2e03eb6c183a3d0f479ce161f2..db49a9181d6009523a8e596b18d54add9603da16 100755 --- a/cmake_targets/at_commands/CMakeLists.txt +++ b/cmake_targets/at_commands/CMakeLists.txt @@ -716,6 +716,7 @@ ADD_EXECUTABLE(at_nas_ue ${OPENAIR_NAS_DIR}/UE/UEprocess.c ${OPENAIR_NAS_DIR}/UE/nas_proc.c ${OPENAIR_NAS_DIR}/UE/nas_user.c ${OPENAIR_DIR}/common/utils/utils.c + ${OPENAIR_DIR}/common/utils/system.c ) target_link_libraries (at_nas_ue diff --git a/common/utils/system.c b/common/utils/system.c new file mode 100644 index 0000000000000000000000000000000000000000..52fb950e37f2179c9c4de895c1ab9dd456f93230 --- /dev/null +++ b/common/utils/system.c @@ -0,0 +1,186 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* This module provides a separate process to run system(). + * The communication between this process and the main processing + * is done through unix pipes. + * + * Motivation: the UE sets its IP address using system() and + * that disrupts realtime processing in some cases. Having a + * separate process solves this problem. + */ + +#include "system.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthread.h> +#include <string.h> + +#define MAX_COMMAND 4096 + +static int command_pipe_read; +static int command_pipe_write; +static int result_pipe_read; +static int result_pipe_write; + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +static int module_initialized = 0; + +/********************************************************************/ +/* util functions */ +/********************************************************************/ + +static void lock_system(void) +{ + if (pthread_mutex_lock(&lock) != 0) { + printf("pthread_mutex_lock fails\n"); + abort(); + } +} + +static void unlock_system(void) +{ + if (pthread_mutex_unlock(&lock) != 0) { + printf("pthread_mutex_unlock fails\n"); + abort(); + } +} + +static void write_pipe(int p, char *b, int size) +{ + while (size) { + int ret = write(p, b, size); + if (ret <= 0) exit(0); + b += ret; + size -= ret; + } +} + +static void read_pipe(int p, char *b, int size) +{ + while (size) { + int ret = read(p, b, size); + if (ret <= 0) exit(0); + b += ret; + size -= ret; + } +} + +/********************************************************************/ +/* background process */ +/********************************************************************/ + +/* This function is run by background process. It waits for a command, + * runs it, and reports status back. It exits (in normal situations) + * when the main process exits, because then a "read" on the pipe + * will return 0, in which case "read_pipe" exits. + */ +static void background_system_process(void) +{ + int len; + int ret; + char command[MAX_COMMAND+1]; + + while (1) { + read_pipe(command_pipe_read, (char*)&len, sizeof(int)); + read_pipe(command_pipe_read, command, len); + ret = system(command); + write_pipe(result_pipe_write, (char *)&ret, sizeof(int)); + } +} + +/********************************************************************/ +/* background_system() */ +/* return -1 on error, 0 on success */ +/********************************************************************/ + +int background_system(char *command) +{ + int res; + int len; + + if (module_initialized == 0) { + printf("FATAL: calling 'background_system' but 'start_background_system' was not called\n"); + abort(); + } + + len = strlen(command)+1; + if (len > MAX_COMMAND) { + printf("FATAL: command too long. Increase MAX_COMMAND (%d).\n", MAX_COMMAND); + printf("command was: '%s'\n", command); + abort(); + } + /* only one command can run at a time, so let's lock/unlock */ + lock_system(); + write_pipe(command_pipe_write, (char*)&len, sizeof(int)); + write_pipe(command_pipe_write, command, len); + read_pipe(result_pipe_read, (char*)&res, sizeof(int)); + unlock_system(); + if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) return -1; + return 0; +} + +/********************************************************************/ +/* start_background_system() */ +/* initializes the "background system" module */ +/* to be called very early by the main processing */ +/********************************************************************/ + +void start_background_system(void) +{ + int p[2]; + pid_t son; + + module_initialized = 1; + + if (pipe(p) == -1) { + perror("pipe"); + exit(1); + } + command_pipe_read = p[0]; + command_pipe_write = p[1]; + + if (pipe(p) == -1) { + perror("pipe"); + exit(1); + } + result_pipe_read = p[0]; + result_pipe_write = p[1]; + + son = fork(); + if (son == -1) { + perror("fork"); + exit(1); + } + + if (son) { + close(result_pipe_write); + close(command_pipe_read); + return; + } + + close(result_pipe_read); + close(command_pipe_write); + + background_system_process(); +} diff --git a/common/utils/system.h b/common/utils/system.h new file mode 100644 index 0000000000000000000000000000000000000000..784c15fc9a045d6b83e5136fe00122a65c7789b6 --- /dev/null +++ b/common/utils/system.h @@ -0,0 +1,39 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _SYSTEM_H_OAI_ +#define _SYSTEM_H_OAI_ + +/**************************************************** + * send a command to the background process + * return -1 on error, 0 on success + ****************************************************/ + +int background_system(char *command); + +/**************************************************** + * initialize the background process + * to be called very early + ****************************************************/ + +void start_background_system(void); + +#endif /* _SYSTEM_H_OAI_ */ diff --git a/openair3/NAS/UE/ESM/esm_ebr_context.c b/openair3/NAS/UE/ESM/esm_ebr_context.c index bfa4a04cc82dd9d73946ac67702897fe2dce8a51..4700187da179a45ffef1388623a12539881b8673 100644 --- a/openair3/NAS/UE/ESM/esm_ebr_context.c +++ b/openair3/NAS/UE/ESM/esm_ebr_context.c @@ -47,6 +47,7 @@ Description Defines functions used to handle EPS bearer contexts. #include "esm_ebr_context.h" #include "emm_sap.h" +#include "system.h" #if defined(ENABLE_ITTI) # include "assertions.h" @@ -286,7 +287,18 @@ int esm_ebr_context_create( LOG_TRACE(INFO, "ESM-PROC - executing %s ", command_line); - if (system(command_line)) ; /* TODO: what to do? */ + /* Calling system() here disrupts UE's realtime processing in some cases. + * This may be because of the call to fork(), which, for some + * unidentified reason, interacts badly with other (realtime) threads. + * background_system() is a replacement mechanism relying on a + * background process that does the system() and reports result to + * the parent process (lte-softmodem, oaisim, ...). The background + * process is created very early in the life of the parent process. + * The processes interact through standard pipes. See + * common/utils/system.c for details. + */ + if (background_system(command_line) != 0) + LOG_TRACE(ERROR, "ESM-PROC - failed command '%s'", command_line); break; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 03f6ba1a2eddfbc02ca337d6572457e3ecd10f60..ee31831a6b3b35d4d24ad065bc42f064ff7f3f10 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -74,6 +74,8 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "create_tasks.h" #endif +#include "system.h" + #ifdef XFORMS #include "PHY/TOOLS/lte_phy_scope.h" #include "stats.h" @@ -1371,6 +1373,8 @@ int main( int argc, char **argv ) { int ret; #endif + start_background_system(); + #ifdef DEBUG_CONSOLE setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index f1b3944a164609631d38ad1c6312289f478b1bfd..ab801d685c60bf001f402bcc1842d026b3a19f87 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -59,6 +59,7 @@ #include "SCHED/defs.h" #include "SCHED/vars.h" +#include "system.h" #include "PHY/TOOLS/lte_phy_scope.h" @@ -1194,6 +1195,8 @@ main (int argc, char **argv) clock_t t; + start_background_system(); + #ifdef SMBV // Rohde&Schwarz SMBV100A vector signal generator strcpy(smbv_ip,DEFAULT_SMBV_IP);