Files
openairinterface5g/common/utils/system.c
T
Raphael Defosseux 2a6ebaaaae Fixes on the array size computation.
This work is based on feedback from Thomas Schlichter.
His comments and suggestions were made just after the original MR was merged.

Signed-off-by: Raphael Defosseux <raphael.defosseux@eurecom.fr>
2021-06-14 14:56:01 +02:00

321 lines
9.3 KiB
C

/*
* 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.1 (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.
*/
#define _GNU_SOURCE
#include "system.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <common/utils/assertions.h>
#include <common/utils/LOG/log.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;
}
}
static int baseRunTimeCommand(char* cmd, size_t cmdSize) {
FILE *fp;
size_t retSize = 0;
fp = popen(cmd, "r");
memset(cmd, 0, cmdSize);
retSize = fread(cmd, 1, cmdSize, fp);
fclose(fp);
if (retSize == 0) {
return 0;
}
return atoi(cmd);
}
int checkIfFedoraDistribution(void) {
char cmd[200];
memset(cmd, 0, 200);
sprintf(cmd, "cat /etc/os-release | grep ID_LIKE | grep -ic fedora || true");
return baseRunTimeCommand(cmd, 200);
}
int checkIfGenericKernelOnFedora(void) {
char cmd[200];
memset(cmd, 0, 200);
sprintf(cmd, "uname -a | grep -c rt || true");
return (1 - baseRunTimeCommand(cmd, 200));
}
int checkIfInsideContainer(void) {
char cmd[200];
int res = 0;
memset(cmd, 0, 200);
sprintf(cmd, "cat /proc/self/cgroup | egrep -c 'libpod|podman|kubepods' || true");
res = baseRunTimeCommand(cmd, 200);
if (res > 0)
return 1;
else
return 0;
}
/********************************************************************/
/* 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();
}
void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name, int affinity, int priority){
pthread_attr_t attr;
int ret;
int settingPriority = 1;
ret=pthread_attr_init(&attr);
AssertFatal(ret==0,"ret: %d, errno: %d\n",ret, errno);
ret=pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
AssertFatal(ret==0,"ret: %d, errno: %d\n",ret, errno);
ret=pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
AssertFatal(ret==0,"ret: %d, errno: %d\n",ret, errno);
if (checkIfFedoraDistribution())
if (checkIfGenericKernelOnFedora())
if (checkIfInsideContainer())
settingPriority = 0;
if (settingPriority) {
ret=pthread_attr_setschedpolicy(&attr, SCHED_OAI);
AssertFatal(ret==0,"ret: %d, errno: %d\n",ret, errno);
if(priority<sched_get_priority_min(SCHED_OAI) || priority>sched_get_priority_max(SCHED_FIFO)) {
LOG_E(TMR,"Prio not possible: %d, min is %d, max: %d, forced in the range\n",
priority,
sched_get_priority_min(SCHED_OAI),
sched_get_priority_max(SCHED_OAI));
if(priority<sched_get_priority_min(SCHED_OAI))
priority=sched_get_priority_min(SCHED_OAI);
if(priority>sched_get_priority_max(SCHED_OAI))
priority=sched_get_priority_max(SCHED_OAI);
}
AssertFatal(priority<=sched_get_priority_max(SCHED_OAI),"");
struct sched_param sparam={0};
sparam.sched_priority = priority;
ret=pthread_attr_setschedparam(&attr, &sparam);
AssertFatal(ret==0,"ret: %d, errno: %d\n",ret, errno);
}
ret=pthread_create(t, &attr, func, param);
AssertFatal(ret==0,"ret: %d, errno: %d\n",ret, errno);
pthread_setname_np(*t, name);
if (affinity != -1 ) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(affinity, &cpuset);
AssertFatal( pthread_setaffinity_np(*t, sizeof(cpu_set_t), &cpuset) == 0, "Error setting processor affinity");
}
pthread_attr_destroy(&attr);
}
// Block CPU C-states deep sleep
void configure_linux(void) {
int ret;
static int latency_target_fd=-1;
uint32_t latency_target_value=10; // in microseconds
if (latency_target_fd == -1) {
if ( (latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR)) != -1 ) {
ret = write(latency_target_fd, &latency_target_value, sizeof(latency_target_value));
if (ret == 0) {
printf("# error setting cpu_dma_latency to %u!: %s\n", latency_target_value, strerror(errno));
close(latency_target_fd);
latency_target_fd=-1;
return;
}
}
}
if (latency_target_fd != -1)
LOG_I(HW,"# /dev/cpu_dma_latency set to %u us\n", latency_target_value);
else
LOG_E(HW,"Can't set /dev/cpu_dma_latency to %u us\n", latency_target_value);
// Set CPU frequency to it's maximum
if ( 0 != system("for d in /sys/devices/system/cpu/cpu[0-9]*; do cat $d/cpufreq/cpuinfo_max_freq > $d/cpufreq/scaling_min_freq; done"))
LOG_E(HW,"Can't set cpu frequency\n");
mlockall(MCL_CURRENT | MCL_FUTURE);
}