Merge remote-tracking branch 'origin/develop' into develop-entv
This commit is contained in:
@@ -2,6 +2,6 @@
|
||||
|
||||
The oai shared library loader is implemented in two source files, located in [common/utils](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils)
|
||||
1. [load_module_shlib.c](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/load_module_shlib.c) contains the loader implementation
|
||||
1. [load_module_shlib.h](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/load_module_shlib.h) is the loader include file containing both private and public data type definitions. It also contain API prototypes.
|
||||
1. [load_module_shlib.h](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/load_module_shlib.h) is the loader include file containing both private and public data type definitions. It also contain API prototypes.
|
||||
|
||||
[loader home page](../loader.md)
|
||||
[loader home page](../loader.md)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
The loader objectives are
|
||||
The loader objectives are
|
||||
1. provides a common mechanism to prevent an executable to include code that is only used under specific configurations, without rebuilding the code
|
||||
1. Provide a common mechanism to allow to choose between different implementations of a given set of functions, without rebuilding the code
|
||||
|
||||
As a developer you may need to look at these sections:
|
||||
|
||||
* [loading a shared library](devusage/loading.md)
|
||||
* [loader API](devusage/api.md)
|
||||
* [loader public structures](devusage/struct.md)
|
||||
* [loader API](devusage/api.md)
|
||||
* [loader public structures](devusage/struct.md)
|
||||
|
||||
Loader usage examples can be found in oai sources:
|
||||
Loader usage examples can be found in oai sources:
|
||||
|
||||
* device and transport initialization code: [function `load_lib` in *targets/ARCH/COMMON/__common_lib.c__* ](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/targets/ARCH/COMMON/common_lib.c#L91)
|
||||
* device and transport initialization code: [function `load_lib` in *targets/ARCH/COMMON/__common_lib.c__* ](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/targets/ARCH/COMMON/common_lib.c#L91)
|
||||
* turbo encoder and decoder initialization: [function `load_codinglib`in *openair1/PHY/CODING/__coding_load.c__*](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/PHY/CODING/coding_load.c#L113)
|
||||
|
||||
[loader home page](../loader.md)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Loader API is defined in the [common/utils/load_module_shlib.h](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/load_module_shlib.h) include file.
|
||||
Loader API is defined in the [common/utils/load_module_shlib.h](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/load_module_shlib.h) include file.
|
||||
```c
|
||||
int load_module_shlib(char *modname,loader_shlibfunc_t *farray, int numf)
|
||||
```
|
||||
* possibly initializes the loader, if it has not been already initialized
|
||||
* Formats the full shared library path, using the `modname` argument and the loader `shlibpath` and `shlibversion`configuration parameters.
|
||||
* possibly initializes the loader, if it has not been already initialized
|
||||
* Formats the full shared library path, using the `modname` argument and the loader `shlibpath` and `shlibversion`configuration parameters.
|
||||
* loads the shared library, using the dlopen system call
|
||||
* looks for `< modname >_autoinit` symbol, using the `dlsym` system call and possibly call the corresponding function.
|
||||
* looks for `< modname >_checkbuildver` symbol, using the `dlsym` system call and possibly calls the corresponding function. If the return value of this call is `-1`, program execution is stopped. It is the responsibility of the shared library developer to implement or not a `< modname >_checkbuildver` function and to decide if a version mismatch is a fatal condition. The `< modname >_checkbuildver` function must match the `checkverfunc_t` function type. The first argument is the main executable version, as set in the `PACKAGE_VERSION` macro defined in the [oai CMakeLists](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/cmake_targets/CMakeLists.txt#L218), around line 218. The second argument points to the shared library version which should be set by the `< modname >_checkbuildver` function.
|
||||
* looks for `< modname >_checkbuildver` symbol, using the `dlsym` system call and possibly calls the corresponding function. If the return value of this call is `-1`, program execution is stopped. It is the responsibility of the shared library developer to implement or not a `< modname >_checkbuildver` function and to decide if a version mismatch is a fatal condition. The `< modname >_checkbuildver` function must match the `checkverfunc_t` function type. The first argument is the main executable version, as set in the `PACKAGE_VERSION` macro defined in the [oai CMakeLists](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/cmake_targets/CMakeLists.txt#L218), around line 218. The second argument points to the shared library version which should be set by the `< modname >_checkbuildver` function.
|
||||
* If the farray pointer is null, looks for `< modname >_getfarray` symbol, calls the corresponding function when the symbol is found. `< modname >_getfarray` takes one argument, a pointer to a `loader_shlibfunc_t` array, and returns the number of items in this array, as defined by the `getfarrayfunc_t` type. The `loader_shlibfunc_t` array returned by the shared library must be fully filled (both `fname` and `fptr` fields).
|
||||
* looks for the `numf` function symbols listed in the `farray[i].fname` arguments and set the corresponding `farray[i].fptr`function pointers
|
||||
|
||||
@@ -14,7 +14,7 @@ int load_module_shlib(char *modname,loader_shlibfunc_t *farray, int numf)
|
||||
```c
|
||||
void * get_shlibmodule_fptr(char *modname, char *fname)
|
||||
```
|
||||
Returns a pointer to the symbol `fname`, defined in module `modname`, or `NULL` if the symbol is not found.
|
||||
Returns a pointer to the symbol `fname`, defined in module `modname`, or `NULL` if the symbol is not found.
|
||||
|
||||
[loader home page](../../loader.md)
|
||||
[loader developer home page](../devusage.md)
|
||||
[loader home page](../../loader.md)
|
||||
[loader developer home page](../devusage.md)
|
||||
|
||||
@@ -10,16 +10,16 @@ Typical loader usage looks like:
|
||||
/* shared library loader include file */
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
.............
|
||||
/*
|
||||
define and initialize the array, describing the list of functions
|
||||
/*
|
||||
define and initialize the array, describing the list of functions
|
||||
implemented in "mymodule"
|
||||
*/
|
||||
loader_shlibfunc_t mymodule_fdesc[2];
|
||||
mymodule_fdesc[0].fname="mymodule_f1";
|
||||
mymodule_fdesc[1].fname="mymodule_f2";
|
||||
mymodule_fdesc[0].fname="mymodule_f1";
|
||||
mymodule_fdesc[1].fname="mymodule_f2";
|
||||
|
||||
/*
|
||||
load the library, it's name must be libmymod.so. Configuration can be
|
||||
load the library, it's name must be libmymod.so. Configuration can be
|
||||
used to specify a specific path to look for libmymod.so. Configuration
|
||||
can also specify a version, for example "V1", in this case the loader
|
||||
will look for libmymodV1.so
|
||||
@@ -28,13 +28,13 @@ Typical loader usage looks like:
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,"Library couldn't be loaded\n");
|
||||
} else {
|
||||
/*
|
||||
/*
|
||||
library has been loaded, we probably want to call some functions...
|
||||
*/
|
||||
ret=((funcf1_t)mymodule_fdesc[0].fptr)();
|
||||
|
||||
..................
|
||||
/*
|
||||
/*
|
||||
later and/or somewhere else in the code you may want to call function "mymodule_f2"
|
||||
You can use the loader get_shlibmodule_fptr(char *modname, char *fname) function
|
||||
to retrieve the pointer to that function
|
||||
@@ -50,7 +50,7 @@ if (f2 != NULL) {
|
||||
}
|
||||
...............
|
||||
```
|
||||
When loading a shared library the loader looks for a symbol named `< module name > _autoinit` and, if it finds it, calls it. The `autoinit` function is called without any argument and the returned value, if any, is not tested.
|
||||
When loading a shared library the loader looks for a symbol named `< module name > _autoinit` and, if it finds it, calls it. The `autoinit` function is called without any argument and the returned value, if any, is not tested.
|
||||
|
||||
[loader home page](../loader.md)
|
||||
[loader developer home page](../../loader/devusage.md)
|
||||
[loader home page](../loader.md)
|
||||
[loader developer home page](../../loader/devusage.md)
|
||||
|
||||
@@ -6,5 +6,5 @@ It is defined in include file [ common/util/load_module_shlib.h ](https://gitlab
|
||||
| `fname` | symbol name, is passed to the [`dlsym`](http://man7.org/linux/man-pages/man3/dlsym.3.html) system call performed by the loader to get a pointer to the symbol | I |
|
||||
| `fptr` | pointer to the symbol name, set by the loader. `fptr` is defined as a `int (*fptr)(void)` function type | O |
|
||||
|
||||
[loader home page](../../loader.md)
|
||||
[loader developer home page](../devusage.md)
|
||||
[loader home page](../../loader.md)
|
||||
[loader developer home page](../devusage.md)
|
||||
|
||||
@@ -6,7 +6,7 @@ Shared library full names are built by the loader using the format:
|
||||
1. the < *module version* > and < *path* > optional parameters, are defined at run-time, depending on the configuration.
|
||||
|
||||
## loader parameters
|
||||
The loader is using the [configuration module](../../../config/DOC/config.md), and defines global and per library parameters. Global parameters must be specified under the **loader** section and library specific parameters under a **loader.<*module name*>** section. Module specific parameters override the global parameters.
|
||||
The loader is using the [configuration module](../../../config/DOC/config.md), and defines global and per library parameters. Global parameters must be specified under the **loader** section and library specific parameters under a **loader.<*module name*>** section. Module specific parameters override the global parameters.
|
||||
### Global loader parameters
|
||||
| name | type | default | description |
|
||||
|:---:|:---:|:---:|:----|
|
||||
@@ -39,7 +39,7 @@ If you want to load a device called *liboai_device_USRP.so* without writting a s
|
||||
|
||||
With this latest example, nn the softmodem logs, you can check that the right device library has been loaded:
|
||||
```bash
|
||||
[LIBCONFIG] loader.oai_device.shlibpath not found in /usr/local/oai/develop-nb-iot-merge/openairinterface5g/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.nbiot.band7.tm1.50PRB.usrpb210.conf
|
||||
[LIBCONFIG] loader.oai_device.shlibpath not found in /usr/local/oai/develop-nb-iot-merge/openairinterface5g/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.nbiot.band7.tm1.50PRB.usrpb210.conf
|
||||
[LIBCONFIG] loader.oai_device.shlibversion set to default value ""
|
||||
[LIBCONFIG] loader.oai_device: 1/2 parameters successfully set, (1 to default value)
|
||||
[CONFIG] shlibversion set to _USRP from command line
|
||||
@@ -47,4 +47,4 @@ With this latest example, nn the softmodem logs, you can check that the right de
|
||||
|
||||
```
|
||||
|
||||
[loader home page](../loader.md)
|
||||
[loader home page](../loader.md)
|
||||
|
||||
@@ -12,11 +12,11 @@ these macros are used in place of the printf C function. The additionnal ***comp
|
||||
|
||||
| macro | level letter | level value | level name |
|
||||
|:---------|:---------------|:---------------|----------------:|
|
||||
| LOG_E | E | 0 | error |
|
||||
| LOG_E | E | 0 | error |
|
||||
| LOG_W | W | 1 | warning |
|
||||
| LOG_I | I | 2 | informational |
|
||||
| LOG_D | D | 3 | debug |
|
||||
| LOG_T | T | 4 | trace |
|
||||
| LOG_T | T | 4 | trace |
|
||||
|
||||
component list is defined as an `enum` in [log.h](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/LOG/log.h). A new component can be defined by adding an item in this type, it must also be defined in the T tracer [T_messages.txt ](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/T/T_messages.txt).
|
||||
|
||||
@@ -27,18 +27,18 @@ Most oai sources are including LOG macros.
|
||||
```C
|
||||
LOG_DEBUGFLAG(<flag>)
|
||||
```
|
||||
this macro is to be used in if statements. The condition is true if the flag has been set, as described in the [run time usage page](rtusage.md)
|
||||
this macro is to be used in if statements. The condition is true if the flag has been set, as described in the [run time usage page](rtusage.md)
|
||||
```C
|
||||
if ( LOG_DEBUGFLAG(<flag>) {
|
||||
/*
|
||||
/*
|
||||
the code below is only executed if the corresponding
|
||||
<flag>_debug option is set.
|
||||
*/
|
||||
*/
|
||||
......................
|
||||
......................
|
||||
}
|
||||
```
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c#L396)
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c#L396)
|
||||
|
||||
#### memory dump macros
|
||||
```C
|
||||
@@ -47,16 +47,16 @@ LOG_DUMPFLAG(<flag>)
|
||||
this macro is to be used in if statements. The condition is true if the flag has been set, as described in the [run time usage page](rtusage.md). It is mainly provided to surround LOG_M macros or direct calls to `log_dump`which otherwise would be unconditionals.
|
||||
```C
|
||||
if ( LOG_DUMPFLAG(<flag>) {
|
||||
/*
|
||||
/*
|
||||
the code below is only executed if the corresponding
|
||||
<flag>_dump option is set.
|
||||
*/
|
||||
*/
|
||||
LOG_M(.............
|
||||
LOG_M(.............
|
||||
log_dump(...
|
||||
}
|
||||
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/PHY/LTE_TRANSPORT/prach.c#L205)
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/PHY/LTE_TRANSPORT/prach.c#L205)
|
||||
#### matlab format dump
|
||||
```C
|
||||
LOG_M(file, vector, data, len, dec, format)
|
||||
@@ -71,13 +71,13 @@ LOG_M(file, vector, data, len, dec, format)
|
||||
|format| int | defines the type of data to be dumped|
|
||||
|
||||
This macro can be used to dump a buffer in a format that can be used for analyze via tools like matlab or octave. **It must be surrounded by LOG_DEBUGFLAG or LOG_DUMPFLAG macros, to prevent the dump to be built unconditionally.** The LOG_M macro points to the `write_file_matlab` function implemented in [log.c](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/LOG/log.c). **This function should be revisited for more understandable implementation and ease of use (format parameter ???)**
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/PHY/LTE_TRANSPORT/prach.c#L205)
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/PHY/LTE_TRANSPORT/prach.c#L205)
|
||||
|
||||
#### hexadecimal format dump
|
||||
```C
|
||||
LOG_DUMPMSG(c, f, b, s, x...)
|
||||
```
|
||||
dumps a memory region if the corresponding debug flag `f` is set as explained here [run time usage page](rtusage.md)
|
||||
dumps a memory region if the corresponding debug flag `f` is set as explained here [run time usage page](rtusage.md)
|
||||
|
||||
|argument| type| description |
|
||||
|:-----------|:-------|-----------------:|
|
||||
@@ -88,12 +88,12 @@ dumps a memory region if the corresponding debug flag `f` is set as explained he
|
||||
| x...| printf format and arguments| text string to be printed at the top of the dump|
|
||||
|
||||
This macro can be used to conditionaly dump a buffer, bytes by bytes, giving the integer value of each byte in hexadecimal form.
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair2/RRC/LTE/rrc_eNB.c#L1181)
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair2/RRC/LTE/rrc_eNB.c#L1181)
|
||||
|
||||
This macro points to the `log_dump` function, implemented in [log.c](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/LOG/log.c). This function can also dump buffers containing `double` data via the LOG_UDUMPMSG macro
|
||||
|
||||
```C
|
||||
LOG_UDUMPMSG(c, b, s, f, x...)
|
||||
LOG_UDUMPMSG(c, b, s, f, x...)
|
||||
```
|
||||
|argument| type| description |
|
||||
|:-----------|:-------|-----------------:|
|
||||
@@ -103,8 +103,8 @@ LOG_UDUMPMSG(c, b, s, f, x...)
|
||||
|f| int | format of dumped data LOG_DUMP_CHAR or LOG_DUMP_DOUBLE|
|
||||
| x...| printf format and arguments| text string to be printed at the top of the dump|
|
||||
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/SIMULATION/LTE_PHY/dlsim.c#L1974)
|
||||
[example in oai code](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/SIMULATION/LTE_PHY/dlsim.c#L1974)
|
||||
|
||||
[logging facility developer main page](devusage.md)
|
||||
[logging facility main page](log.md)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
[logging facility developer main page](devusage.md)
|
||||
[logging facility main page](log.md)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
The oai logging facility is implemented in two source files, located in [common/utils/LOG](LOG)
|
||||
1. [log.c](../log.c) contains logging implementation
|
||||
1. [log.h](../log.h) is the logging facility include file containing both private and public data type definitions. It also contain API prototypes.
|
||||
1. [log.h](../log.h) is the logging facility include file containing both private and public data type definitions. It also contain API prototypes.
|
||||
|
||||
The logging facility doesn't create any thread, all api's are executed in the context of the caller. The tracing macro's `LOG_<X>` are all using the logRecord_mt function to output the messages. To keep this function thread safe it must perform a single system call to the output stream. The buffer used to build the message must be specific to the calling thread, which is today enforced by using a variable in the logRecord_mt stack.
|
||||
|
||||
Data used by the logging utility are defined by the `log_t` structure which is allocated at init time, when calling the `logInit` function.
|
||||
|
||||
[logging facility main page](log.md)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
[logging facility main page](log.md)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
```C
|
||||
int logInit (void);
|
||||
```
|
||||
Allocate the internal data used by the logging utility, set the configuration, using the [configuration module](../../../config/DOC/config.md)
|
||||
Allocate the internal data used by the logging utility, set the configuration, using the [configuration module](../../../config/DOC/config.md)
|
||||
|
||||
```C
|
||||
void logClean (void)
|
||||
@@ -30,9 +30,9 @@ void close_component_filelog(int comp)
|
||||
Redirect or reset to stdout the output stream used by the logging facility. When the output stream is redirected to a file, it is created under /tmp with a hard-coded filename including the componemt name.
|
||||
|
||||
```C
|
||||
SET_LOG_DEBUG(flag)
|
||||
SET_LOG_DEBUG(flag)
|
||||
CLEAR_LOG_DEBUG(flag)
|
||||
SET_LOG_DUMP(flag)
|
||||
SET_LOG_DUMP(flag)
|
||||
CLEAR_LOG_DUMP(flag)
|
||||
```
|
||||
These macros are used to set or clear the corresponding bit flag, trigerring the activation or un-activation of conditional code or memory dumps generation.
|
||||
@@ -42,8 +42,8 @@ Example of using the logging utility APIs can be found, for initialization and c
|
||||
#### components and debug flags definitions
|
||||
|
||||
Adding a new component is just adding an item in the `comp_name_t` enum defined in [log.h](../log.h) . You must also declare it in the T Tracer facility [message fefinitions](../../T/T_messages.txt).
|
||||
To add a flag than can then be used for adding conditional code or memory dumps you have to add the flag definition in the `LOG_MASKMAP_INIT` macro, in [log.h](../log.h).
|
||||
To add a flag than can then be used for adding conditional code or memory dumps you have to add the flag definition in the `LOG_MASKMAP_INIT` macro, in [log.h](../log.h).
|
||||
|
||||
[logging facility developer main page](devusage.md)
|
||||
[logging facility main page](log.md)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
[logging facility developer main page](devusage.md)
|
||||
[logging facility main page](log.md)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
### logging facility developer usage
|
||||
The logging facility objectives are
|
||||
1. provide a common console tracing mechanism
|
||||
The logging facility objectives are
|
||||
1. provide a common console tracing mechanism
|
||||
1. Allow a flexible activation of console traces, by configuration or dynamically at any time while code is running.
|
||||
|
||||
Most developpers will only use the log macros to add console messages to the code. The logging facility also provides an api that is used for initialization and configuration.
|
||||
Most developpers will only use the log macros to add console messages to the code. The logging facility also provides an api that is used for initialization and configuration.
|
||||
|
||||
[Adding console traces in oaicode](addconsoletrace.md)
|
||||
[Adding console traces in oaicode](addconsoletrace.md)
|
||||
|
||||
[Configuring the logging facility](configurelog.md)
|
||||
[Configuring the logging facility](configurelog.md)
|
||||
|
||||
|
||||
[logging facility main page](log.md)
|
||||
[logging facility main page](log.md)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# OAI console logging facility
|
||||
|
||||
oai includes a console logging facility that any component should use when writting informational or debugging messages to the softmodem or uesoftmodem stdout stream.
|
||||
oai includes a console logging facility that any component should use when writting informational or debugging messages to the softmodem or uesoftmodem stdout stream.
|
||||
By default, this facility is included at build-time and activated at run-time. The T Tracer and the Logging facility share common options for activation:
|
||||
|
||||
- To disable the logging facility (and T Tracer) at build-time use the *--disable-T-Tracer* switch:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
## configuring the logging facility
|
||||
The logging facility is fully configurable and it uses the [config module](../../../config/config.md) to get its parameters at init time. The [telnet server](../../telnetsrv/DOC/telnetsrv.md) includes a set of commands which can be used to dynamically modify the logging facility behavior
|
||||
The logging facility is fully configurable and it uses the [config module](../../../config/config.md) to get its parameters at init time. The [telnet server](../../telnetsrv/DOC/telnetsrv.md) includes a set of commands which can be used to dynamically modify the logging facility behavior
|
||||
|
||||
All logging facility parameters are defined in the log_config section. Some parameters are global to the logging facility, they modify the way messages are printed to stdout. Conversely, some parameters are specific to a component and only modify the behavior for messages issued by a given component. A third type of parameters can be used to activate conditional debug code or dump messages or buffers.
|
||||
|
||||
@@ -14,7 +14,7 @@ All logging facility parameters are defined in the log_config section. Some para
|
||||
### Component specific parameters
|
||||
| name | type | default | description |
|
||||
|:---:|:---:|:---:|:----|
|
||||
| `<component>_log_level` | `boolean` | global log level, as defined by the `global_log_level ` parameter) |
|
||||
| `<component>_log_level` | `boolean` | global log level, as defined by the `global_log_level ` parameter) |
|
||||
| `<component>_log_infile` | `boolean` | 0 = false| Triggers the redirection of log messages printed by the specified component in a file. The file path and name is /tmp/<componemt>.[extension] the extension is optional and component dependant, it can be `log `, `dat `, `txt `|
|
||||
|
||||
The list of components defined within oai can be retrieved from the [config module](../../../config/config.md) traces, when asking for config module debugging info on the command line:
|
||||
@@ -215,7 +215,7 @@ The list of components defined within oai can be retrieved from the [config mod
|
||||
log init done
|
||||
|
||||
```
|
||||
It can also be retrieved when using the telnet server, as explained [below](### Using the telnet server to configure the logging facility)
|
||||
It can also be retrieved when using the telnet server, as explained [below](### Using the telnet server to configure the logging facility)
|
||||
|
||||
### parameters to activate conditional code
|
||||
| name | type | default | description |
|
||||
@@ -238,15 +238,15 @@ The following example sets all components log level to info, exept for hw,phy,ma
|
||||
};
|
||||
```
|
||||
### Using the command line to configure the logging facility
|
||||
Command line parameter values supersedes values specified in the configuration file.
|
||||
Command line parameter values supersedes values specified in the configuration file.
|
||||
```bash
|
||||
./lte-softmodem -O --log_config.global_log_options nocolor,level,thread --log_config.prach_log_level debug --log_config.PRACH_debug
|
||||
./lte-softmodem -O --log_config.global_log_options nocolor,level,thread --log_config.prach_log_level debug --log_config.PRACH_debug
|
||||
```
|
||||
In this example to get all the debug PRACH messages it is necessary to also set the PRACH_debug flag. This is a choice from the developper.
|
||||
The log messages will be printed whithout color and the header will include the lmessage evel and the thread name:
|
||||
```bash
|
||||
[PHY]I ru thread Time in secs now: 104652566
|
||||
[PHY]I ru thread Time in secs last pps: 91827117
|
||||
[PHY]I ru thread Time in secs now: 104652566
|
||||
[PHY]I ru thread Time in secs last pps: 91827117
|
||||
[PHY]I ru thread RU 0 rf device ready
|
||||
[PHY]I ru thread RU 0 no asynch_south interface
|
||||
[MAC]E rxtx processing SCHED_MODE=0
|
||||
@@ -256,10 +256,10 @@ The log messages will be printed whithout color and the header will include the
|
||||
[PHY]I lte-softmodem PRACH (eNB) : running rx_prach for subframe 1, prach_FreqOffset 2, prach_ConfigIndex 0 , rootSequenceIndex 0
|
||||
[PHY]I lte-softmodem PRACH (eNB) : running rx_prach for subframe 1, prach_FreqOffset 2, prach_ConfigIndex 0 , rootSequenceIndex 0
|
||||
```
|
||||
|
||||
|
||||
### Using the telnet server to configure the logging facility
|
||||
The telnet server includes a `log` command which can be used to dymically modify the logging facility configuration parameters.
|
||||
[telnet server ***softmodem log*** commands](../../telnetsrv/DOC/telnetlog.md)
|
||||
[telnet server ***softmodem log*** commands](../../telnetsrv/DOC/telnetlog.md)
|
||||
|
||||
[logging facility main page](log.md)
|
||||
[logging facility main page](log.md)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
+16
-6
@@ -303,8 +303,8 @@ void log_getconfig(log_t *g_log) {
|
||||
logparams_dump[i].numelt = 0;
|
||||
}
|
||||
|
||||
config_get( logparams_debug,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
|
||||
config_get( logparams_dump,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
|
||||
config_get( logparams_debug,(sizeof(log_maskmap)/sizeof(mapping)) - 1,CONFIG_STRING_LOG_PREFIX);
|
||||
config_get( logparams_dump,(sizeof(log_maskmap)/sizeof(mapping)) - 1,CONFIG_STRING_LOG_PREFIX);
|
||||
config_check_unknown_cmdlineopt(CONFIG_STRING_LOG_PREFIX);
|
||||
|
||||
/* set the debug mask according to the debug parameters values */
|
||||
@@ -385,7 +385,6 @@ int logInit (void) {
|
||||
register_log_component("OCG","",OCG);
|
||||
register_log_component("PERF","",PERF);
|
||||
register_log_component("OIP","",OIP);
|
||||
register_log_component("CLI","",CLI);
|
||||
register_log_component("MSC","log",MSC);
|
||||
register_log_component("OCM","log",OCM);
|
||||
register_log_component("HW","",HW);
|
||||
@@ -394,20 +393,25 @@ int logInit (void) {
|
||||
register_log_component("mRAL","",RAL_UE);
|
||||
register_log_component("ENB_APP","log",ENB_APP);
|
||||
register_log_component("FLEXRAN_AGENT","log",FLEXRAN_AGENT);
|
||||
register_log_component("PROTO_AGENT","log",PROTO_AGENT);
|
||||
register_log_component("TMR","",TMR);
|
||||
register_log_component("USIM","txt",USIM);
|
||||
register_log_component("SIM","txt",SIM);
|
||||
/* following log component are used for the localization*/
|
||||
/* following log component are used for the localization*/
|
||||
register_log_component("LOCALIZE","log",LOCALIZE);
|
||||
register_log_component("NAS","log",NAS);
|
||||
register_log_component("UDP","",UDP_);
|
||||
register_log_component("GTPV1U","",GTPU);
|
||||
register_log_component("S1AP","",S1AP);
|
||||
register_log_component("F1AP","",F1AP);
|
||||
register_log_component("X2AP","",X2AP);
|
||||
register_log_component("SCTP","",SCTP);
|
||||
register_log_component("X2AP","",X2AP);
|
||||
register_log_component("LOADER","log",LOADER);
|
||||
register_log_component("ASN","log",ASN);
|
||||
register_log_component("NFAPI_PNF","log",NFAPI_PNF);
|
||||
register_log_component("NFAPI_VNF","log",NFAPI_VNF);
|
||||
|
||||
for (int i=0 ; log_level_names[i].name != NULL ; i++)
|
||||
g_log->level2string[i] = toupper(log_level_names[i].name[0]); // uppercased first letter of level name
|
||||
@@ -438,7 +442,7 @@ char *log_getthreadname(char *threadname, int bufsize) {
|
||||
|
||||
static int log_header(char *log_buffer, int buffsize, int comp, int level,const char *format) {
|
||||
char threadname[PR_SET_NAME];
|
||||
return snprintf(log_buffer, buffsize , "%s%s[%s]%c %s %s%s",
|
||||
return snprintf(log_buffer, buffsize, "%s%s[%s]%c %s %s%s",
|
||||
log_level_highlight_end[level],
|
||||
( (g_log->flag & FLAG_NOCOLOR)?"":log_level_highlight_start[level]),
|
||||
g_log->log_component[comp].name,
|
||||
@@ -452,11 +456,17 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, int le
|
||||
char log_buffer[MAX_LOG_TOTAL];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_header(log_buffer,MAX_LOG_TOTAL ,comp, level,format);
|
||||
log_header(log_buffer,MAX_LOG_TOTAL,comp, level,format);
|
||||
g_log->log_component[comp].vprint(g_log->log_component[comp].stream,log_buffer, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void vlogRecord_mt(const char *file, const char *func, int line, int comp, int level, const char *format, va_list args ) {
|
||||
char log_buffer[MAX_LOG_TOTAL];
|
||||
log_header(log_buffer,MAX_LOG_TOTAL,comp, level,format);
|
||||
g_log->log_component[comp].vprint(g_log->log_component[comp].stream,log_buffer, args);
|
||||
}
|
||||
|
||||
void log_dump(int component, void *buffer, int buffsize,int datatype, const char *format, ... ) {
|
||||
va_list args;
|
||||
char *wbuf;
|
||||
@@ -474,7 +484,7 @@ void log_dump(int component, void *buffer, int buffsize,int datatype, const char
|
||||
|
||||
if (wbuf != NULL) {
|
||||
va_start(args, format);
|
||||
int pos=log_header(wbuf,MAX_LOG_TOTAL ,component, OAILOG_INFO,"");
|
||||
int pos=log_header(wbuf,MAX_LOG_TOTAL,component, OAILOG_INFO,"");
|
||||
int pos2=vsprintf(wbuf+pos,format, args);
|
||||
pos=pos+pos2;
|
||||
va_end(args);
|
||||
|
||||
@@ -198,13 +198,13 @@ typedef enum {
|
||||
NAS,
|
||||
PERF,
|
||||
OIP,
|
||||
CLI,
|
||||
MSC,
|
||||
OCM,
|
||||
UDP_,
|
||||
GTPU,
|
||||
SPGW,
|
||||
S1AP,
|
||||
F1AP,
|
||||
SCTP,
|
||||
HW,
|
||||
OSA,
|
||||
@@ -215,9 +215,13 @@ typedef enum {
|
||||
TMR,
|
||||
USIM,
|
||||
LOCALIZE,
|
||||
PROTO_AGENT,
|
||||
F1U,
|
||||
X2AP,
|
||||
LOADER,
|
||||
ASN,
|
||||
NFAPI_VNF,
|
||||
NFAPI_PNF,
|
||||
MAX_LOG_PREDEF_COMPONENTS,
|
||||
}
|
||||
comp_name_t;
|
||||
@@ -286,6 +290,7 @@ extern "C" {
|
||||
int logInit (void);
|
||||
int isLogInitDone (void);
|
||||
void logRecord_mt(const char *file, const char *func, int line,int comp, int level, const char *format, ...) __attribute__ ((format (printf, 6, 7)));
|
||||
void vlogRecord_mt(const char *file, const char *func, int line, int comp, int level, const char *format, va_list args );
|
||||
void log_dump(int component, void *buffer, int buffsize,int datatype, const char *format, ... );
|
||||
int set_log(int component, int level);
|
||||
void set_glog(int level);
|
||||
@@ -365,9 +370,9 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int
|
||||
# define LOG_I(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_INFO ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ;} else { T(T_LEGACY_ ## c ## _INFO, T_PRINTF(x)) ;}} while (0)
|
||||
# define LOG_D(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_DEBUG ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_DEBUG, x) ;} else { T(T_LEGACY_ ## c ## _DEBUG, T_PRINTF(x)) ;}} while (0)
|
||||
# define LOG_T(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_TRACE ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_TRACE, x) ;} else { T(T_LEGACY_ ## c ## _TRACE, T_PRINTF(x)) ;}} while (0)
|
||||
# define VLOG(c,l, f, args) do { if (T_stdout) { if( g_log->log_component[c].level >= l ) vlogRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, l, f, args) ;} } while (0)
|
||||
/* macro used to dump a buffer or a message as in openair2/RRC/LTE/RRC_eNB.c, replaces LOG_F macro */
|
||||
# define LOG_DUMPMSG(c, f, b, s, x...) do { if(g_log->dump_mask & f) log_dump(c, b, s, LOG_DUMP_CHAR, x) ;} while (0) /* */
|
||||
# define nfapi_log(FILE, FNC, LN, COMP, LVL, F...) do { if (T_stdout) { logRecord_mt(__FILE__, __FUNCTION__, __LINE__,COMP, LVL, F) ;}} while (0) /* */
|
||||
/* bitmask dependant macros, to isolate debugging code */
|
||||
# define LOG_DEBUGFLAG(D) (g_log->debug_mask & D)
|
||||
|
||||
|
||||
@@ -189,7 +189,15 @@ const char* eurecomVariablesNames[] = {
|
||||
"ue0_trx_write_ns_missing",
|
||||
"enb_thread_rxtx_CPUID",
|
||||
"ru_thread_CPUID",
|
||||
"ru_thread_tx_CPUID"
|
||||
"ru_thread_tx_CPUID",
|
||||
"ue0_on_duration_timer",
|
||||
"ue0_drx_inactivity",
|
||||
"ue0_drx_short_cycle",
|
||||
"ue0_short_drx_cycle_number",
|
||||
"ue0_drx_long_cycle",
|
||||
"ue0_drx_retransmission_harq0",
|
||||
"ue0_drx_active_time",
|
||||
"ue0_drx_active_time_condition"
|
||||
};
|
||||
|
||||
const char* eurecomFunctionsNames[] = {
|
||||
|
||||
@@ -167,6 +167,14 @@ typedef enum {
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_CPUID_ENB_THREAD_RXTX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD_TX,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_ON_DURATION_TIMER,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DRX_INACTIVITY,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DRX_SHORT_CYCLE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_SHORT_DRX_CYCLE_NUMBER,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DRX_LONG_CYCLE,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DRX_RETRANSMISSION_HARQ0,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME_CONDITION,
|
||||
VCD_SIGNAL_DUMPER_VARIABLES_END
|
||||
} vcd_signal_dump_variables;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ typedef struct {
|
||||
#define VCD_NUM_FUNCTIONS 195
|
||||
|
||||
/* number of VCD variables (to be kept up to date! see in T_messages.txt) */
|
||||
#define VCD_NUM_VARIABLES 128
|
||||
#define VCD_NUM_VARIABLES 136
|
||||
|
||||
/* first VCD function (to be kept up to date! see in T_messages.txt) */
|
||||
#define VCD_FIRST_FUNCTION ((uintptr_t)T_VCD_FUNCTION_RT_SLEEP)
|
||||
|
||||
+134
-17
@@ -629,7 +629,7 @@ ID = LEGACY_OCM_DEBUG
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_OCM_TRACE
|
||||
DESC = OCM legacy logs - trace level
|
||||
GROUP = ALL:LEGACY_OCM:LEGACY_GROUP_TRACE:LEGACY
|
||||
OGROUP = ALL:LEGACY_OCM:LEGACY_GROUP_TRACE:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
ID = LEGACY_OIP_INFO
|
||||
@@ -800,6 +800,47 @@ ID = LEGACY_SIM_TRACE
|
||||
GROUP = ALL:LEGACY_SIM:LEGACY_GROUP_TRACE:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
ID = LEGACY_NFAPI_VNF_INFO
|
||||
DESC = NFAPI_VNF legacy logs - info level
|
||||
GROUP = ALL:LEGACY_NFAPI_VNF:LEGACY_GROUP_INFO:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_NFAPI_VNF_ERROR
|
||||
DESC = NFAPI_VNF legacy logs - error level
|
||||
GROUP = ALL:LEGACY_NFAPI_VNF:LEGACY_GROUP_ERROR:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_NFAPI_VNF_WARNING
|
||||
DESC = NFAPI_VNF legacy logs - warning level
|
||||
GROUP = ALL:LEGACY_NFAPI_VNF:LEGACY_GROUP_WARNING:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_NFAPI_VNF_DEBUG
|
||||
DESC = NFAPI_VNF legacy logs - debug level
|
||||
GROUP = ALL:LEGACY_NFAPI_VNF:LEGACY_GROUP_DEBUG:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_NFAPI_VNF_TRACE
|
||||
DESC = NFAPI_VNF legacy logs - trace level
|
||||
GROUP = ALL:LEGACY_NFAPI_VNF:LEGACY_GROUP_TRACE:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
ID = LEGACY_NFAPI_PNF_INFO
|
||||
DESC = NFAPI_PNF legacy logs - info level
|
||||
GROUP = ALL:LEGACY_NFAPI_PNF:LEGACY_GROUP_INFO:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_NFAPI_PNF_ERROR
|
||||
DESC = NFAPI_PNF legacy logs - error level
|
||||
GROUP = ALL:LEGACY_NFAPI_PNF:LEGACY_GROUP_ERROR:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_NFAPI_PNF_WARNING
|
||||
DESC = NFAPI_PNF legacy logs - warning level
|
||||
GROUP = ALL:LEGACY_NFAPI_PNF:LEGACY_GROUP_WARNING:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_NFAPI_PNF_DEBUG
|
||||
DESC = NFAPI_PNF legacy logs - debug level
|
||||
GROUP = ALL:LEGACY_NFAPI_PNF:LEGACY_GROUP_DEBUG:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_NFAPI_PNF_TRACE
|
||||
DESC = NFAPI_PNF legacy logs - trace level
|
||||
GROUP = ALL:LEGACY_NFAPI_PNF:LEGACY_GROUP_TRACE:LEGACY
|
||||
FORMAT = string,log
|
||||
# this is a bad hack but I won't fix (function util_print_hex_octets
|
||||
# in openairinterface5g/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c
|
||||
# does funky things with the LOG_x macros but we work on the C pre-processor
|
||||
@@ -845,26 +886,62 @@ ID = LEGACY_componentP_TRACE
|
||||
GROUP = ALL:LEGACY_componentP:LEGACY_GROUP_TRACE:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
#needed?
|
||||
ID = LEGACY_CLI_INFO
|
||||
DESC = CLI legacy logs - info level
|
||||
GROUP = ALL:LEGACY_CLI:LEGACY_GROUP_INFO:LEGACY
|
||||
|
||||
|
||||
ID = LEGACY_PROTO_AGENT_DEBUG
|
||||
DESC = PROTO AGENT DEBUG LEVEL
|
||||
GROUP = ALL:LEGACY_PROTO:LEGACY_GROUP_DEBUG:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_CLI_ERROR
|
||||
DESC = CLI legacy logs - error level
|
||||
GROUP = ALL:LEGACY_CLI:LEGACY_GROUP_ERROR:LEGACY
|
||||
|
||||
ID = LEGACY_PROTO_AGENT_INFO
|
||||
DESC = PROTO AGENT INFO LEVEL
|
||||
GROUP = ALL:LEGACY_PROTO:LEGACY_GROUP_INFO:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_CLI_WARNING
|
||||
DESC = CLI legacy logs - warning level
|
||||
GROUP = ALL:LEGACY_CLI:LEGACY_GROUP_WARNING:LEGACY
|
||||
|
||||
ID = LEGACY_PROTO_AGENT_WARNING
|
||||
DESC = PROTO AGENT WARNING LEVEL
|
||||
GROUP = ALL:LEGACY_PROTO:LEGACY_GROUP_WARNING:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_CLI_DEBUG
|
||||
DESC = CLI legacy logs - debug level
|
||||
GROUP = ALL:LEGACY_CLI:LEGACY_GROUP_DEBUG:LEGACY
|
||||
|
||||
ID = LEGACY_PROTO_AGENT_ERROR
|
||||
DESC = PROTO AGENT ERROR LEVEL
|
||||
GROUP = ALL:LEGACY_PROTO:LEGACY_GROUP_ERROR:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_CLI_TRACE
|
||||
DESC = CLI legacy logs - trace level
|
||||
GROUP = ALL:LEGACY_CLI:LEGACY_GROUP_TRACE:LEGACY
|
||||
|
||||
ID = LEGACY_F1U_DEBUG
|
||||
DESC = F1U DEBUG LEVEL
|
||||
GROUP = ALL:LEGACY_F1U:LEGACY_GROUP_DEBUG:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
ID = LEGACY_F1U_INFO
|
||||
DESC = F1U INFO LEVEL
|
||||
GROUP = ALL:LEGACY_F1U:LEGACY_GROUP_INFO:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
ID = LEGACY_F1U_ERROR
|
||||
DESC = F1U ERROR LEVEL
|
||||
GROUP = ALL:LEGACY_F1U:LEGACY_GROUP_ERROR:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
ID = LEGACY_F1AP_TRACE
|
||||
DESC = F1AP TRACE LEVEL
|
||||
GROUP = ALL:LEGACY_F1AP:LEGACY_GROUP_TRACE:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_F1AP_DEBUG
|
||||
DESC = F1AP DEBUG LEVEL
|
||||
GROUP = ALL:LEGACY_F1AP:LEGACY_GROUP_DEBUG:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_F1AP_INFO
|
||||
DESC = F1AP INFO LEVEL
|
||||
GROUP = ALL:LEGACY_F1AP:LEGACY_GROUP_INFO:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_F1AP_WARNING
|
||||
DESC = F1AP WARNING LEVEL
|
||||
GROUP = ALL:LEGACY_F1AP:LEGACY_GROUP_WARNING:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_F1AP_ERROR
|
||||
DESC = F1AP ERROR LEVEL
|
||||
GROUP = ALL:LEGACY_F1AP:LEGACY_GROUP_ERROR:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
#################
|
||||
@@ -1599,6 +1676,46 @@ ID = VCD_VARIABLE_CPUID_RU_THREAD_TX
|
||||
GROUP = ALL:VCD:ENB:VCD_VARIABLE
|
||||
FORMAT = ulong,value
|
||||
VCD_NAME = ru_thread_tx_CPUID
|
||||
ID = VCD_VARIABLE_ON_DURATION_TIMER
|
||||
DESC = VCD variable ON_DURATION_TIMER
|
||||
GROUP = ALL:VCD:ENB:VCD_VARIABLE
|
||||
FORMAT = ulong,value
|
||||
VCD_NAME = ue0_on_duration_timer
|
||||
ID = VCD_VARIABLE_DRX_INACTIVITY
|
||||
DESC = VCD variable DRX_INACTIVITY
|
||||
GROUP = ALL:VCD:ENB:VCD_VARIABLE
|
||||
FORMAT = ulong,value
|
||||
VCD_NAME = ue0_drx_inactivity
|
||||
ID = VCD_VARIABLE_DRX_SHORT_CYCLE
|
||||
DESC = VCD variable DRX_SHORT_CYCLE
|
||||
GROUP = ALL:VCD:ENB:VCD_VARIABLE
|
||||
FORMAT = ulong,value
|
||||
VCD_NAME = ue0_drx_short_cycle
|
||||
ID = VCD_VARIABLE_SHORT_DRX_CYCLE_NUMBER
|
||||
DESC = VCD variable SHORT_DRX_CYCLE_NUMBER
|
||||
GROUP = ALL:VCD:ENB:VCD_VARIABLE
|
||||
FORMAT = ulong,value
|
||||
VCD_NAME = ue0_short_drx_cycle_number
|
||||
ID = VCD_VARIABLE_DRX_LONG_CYCLE
|
||||
DESC = VCD variable DRX_LONG_CYCLE
|
||||
GROUP = ALL:VCD:ENB:VCD_VARIABLE
|
||||
FORMAT = ulong,value
|
||||
VCD_NAME = ue0_drx_long_cycle
|
||||
ID = VCD_VARIABLE_DRX_RETRANSMISSION_HARQ0
|
||||
DESC = VCD variable DRX_RETRANSMISSION_HARQ0
|
||||
GROUP = ALL:VCD:ENB:VCD_VARIABLE
|
||||
FORMAT = ulong,value
|
||||
VCD_NAME = ue0_drx_retransmission_harq0
|
||||
ID = VCD_VARIABLE_DRX_ACTIVE_TIME
|
||||
DESC = VCD variable DRX_ACTIVE_TIME
|
||||
GROUP = ALL:VCD:ENB:VCD_VARIABLE
|
||||
FORMAT = ulong,value
|
||||
VCD_NAME = ue0_drx_active_time
|
||||
ID = VCD_VARIABLE_DRX_ACTIVE_TIME_CONDITION
|
||||
DESC = VCD variable DRX_ACTIVE_TIME_CONDITION
|
||||
GROUP = ALL:VCD:ENB:VCD_VARIABLE
|
||||
FORMAT = ulong,value
|
||||
VCD_NAME = ue0_drx_active_time_condition
|
||||
|
||||
#functions
|
||||
|
||||
|
||||
+154
-94
@@ -31,7 +31,7 @@ typedef struct {
|
||||
int remote_port;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
databuf * volatile head, *tail;
|
||||
databuf *volatile head, *tail;
|
||||
uint64_t memusage;
|
||||
uint64_t last_warning_memusage;
|
||||
} forward_data;
|
||||
@@ -40,80 +40,115 @@ typedef struct {
|
||||
/* utility functions */
|
||||
/****************************************************************************/
|
||||
|
||||
static void new_thread(void *(*f)(void *), void *data)
|
||||
{
|
||||
static void new_thread(void *(*f)(void *), void *data) {
|
||||
pthread_t t;
|
||||
pthread_attr_t att;
|
||||
|
||||
if (pthread_attr_init(&att))
|
||||
{ fprintf(stderr, "pthread_attr_init err\n"); exit(1); }
|
||||
if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED))
|
||||
{ fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); }
|
||||
if (pthread_attr_setstacksize(&att, 10000000))
|
||||
{ fprintf(stderr, "pthread_attr_setstacksize err\n"); exit(1); }
|
||||
if (pthread_create(&t, &att, f, data))
|
||||
{ fprintf(stderr, "pthread_create err\n"); exit(1); }
|
||||
if (pthread_attr_destroy(&att))
|
||||
{ fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); }
|
||||
if (pthread_attr_init(&att)) {
|
||||
fprintf(stderr, "pthread_attr_init err\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) {
|
||||
fprintf(stderr, "pthread_attr_setdetachstate err\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_attr_setstacksize(&att, 10000000)) {
|
||||
fprintf(stderr, "pthread_attr_setstacksize err\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_create(&t, &att, f, data)) {
|
||||
fprintf(stderr, "pthread_create err\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_attr_destroy(&att)) {
|
||||
fprintf(stderr, "pthread_attr_destroy err\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int get_connection(char *addr, int port)
|
||||
{
|
||||
static int get_connection(char *addr, int port) {
|
||||
struct sockaddr_in a;
|
||||
socklen_t alen;
|
||||
int s, t;
|
||||
|
||||
printf("T tracer: waiting for connection on %s:%d\n", addr, port);
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) { perror("socket"); exit(1); }
|
||||
|
||||
if (s == -1) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
t = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(int)))
|
||||
{ perror("setsockopt"); exit(1); }
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(int))) {
|
||||
perror("setsockopt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = htons(port);
|
||||
a.sin_addr.s_addr = inet_addr(addr);
|
||||
|
||||
if (bind(s, (struct sockaddr *)&a, sizeof(a))) { perror("bind"); exit(1); }
|
||||
if (listen(s, 5)) { perror("bind"); exit(1); }
|
||||
if (bind(s, (struct sockaddr *)&a, sizeof(a))) {
|
||||
perror("bind");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (listen(s, 5)) {
|
||||
perror("bind");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
alen = sizeof(a);
|
||||
t = accept(s, (struct sockaddr *)&a, &alen);
|
||||
if (t == -1) { perror("accept"); exit(1); }
|
||||
|
||||
if (t == -1) {
|
||||
perror("accept");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
printf("T tracer: connected\n");
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void forward(void *_forwarder, char *buf, int size);
|
||||
|
||||
void send_T_messages_txt(void *forwarder)
|
||||
{
|
||||
void send_T_messages_txt(void *forwarder) {
|
||||
char buf[T_BUFFER_MAX];
|
||||
char *T_LOCAL_buf = buf;
|
||||
int T_LOCAL_size;
|
||||
unsigned char *src;
|
||||
int src_len;
|
||||
|
||||
/* trace T_message.txt
|
||||
* Send several messages -1 with content followed by message -2.
|
||||
*/
|
||||
src = T_messages_txt;
|
||||
src_len = T_messages_txt_len;
|
||||
|
||||
while (src_len) {
|
||||
int send_size = src_len;
|
||||
|
||||
if (send_size > T_PAYLOAD_MAXSIZE - sizeof(int))
|
||||
send_size = T_PAYLOAD_MAXSIZE - sizeof(int);
|
||||
|
||||
/* TODO: be careful, we use internal T stuff, to rewrite? */
|
||||
T_LOCAL_size = 0;
|
||||
T_HEADER(T_ID(-1));
|
||||
T_PUT_buffer(1, ((T_buffer){addr:(src), length:(send_size)}));
|
||||
T_PUT_buffer(1, ((T_buffer) {
|
||||
addr:
|
||||
(src), length:
|
||||
(send_size)
|
||||
}));
|
||||
forward(forwarder, buf, T_LOCAL_size);
|
||||
src += send_size;
|
||||
src_len -= send_size;
|
||||
}
|
||||
|
||||
T_LOCAL_size = 0;
|
||||
T_HEADER(T_ID(-2));
|
||||
forward(forwarder, buf, T_LOCAL_size);
|
||||
@@ -123,49 +158,54 @@ void send_T_messages_txt(void *forwarder)
|
||||
/* forward functions */
|
||||
/****************************************************************************/
|
||||
|
||||
static void *data_sender(void *_f)
|
||||
{
|
||||
static void *data_sender(void *_f) {
|
||||
forward_data *f = _f;
|
||||
databuf *cur;
|
||||
char *buf, *b;
|
||||
int size;
|
||||
|
||||
wait:
|
||||
|
||||
if (pthread_mutex_lock(&f->lock)) abort();
|
||||
|
||||
while (f->head == NULL)
|
||||
if (pthread_cond_wait(&f->cond, &f->lock)) abort();
|
||||
|
||||
cur = f->head;
|
||||
buf = cur->d;
|
||||
size = cur->l;
|
||||
f->head = cur->next;
|
||||
f->memusage -= size;
|
||||
|
||||
if (f->head == NULL) f->tail = NULL;
|
||||
|
||||
if (pthread_mutex_unlock(&f->lock)) abort();
|
||||
|
||||
free(cur);
|
||||
goto process;
|
||||
|
||||
process:
|
||||
b = buf;
|
||||
|
||||
if (f->socket_remote != -1)
|
||||
while (size) {
|
||||
int l = write(f->socket_remote, b, size);
|
||||
if (l <= 0) {
|
||||
printf("T tracer: forward error\n");
|
||||
close(f->socket_remote);
|
||||
f->socket_remote = -1;
|
||||
break;
|
||||
while (size) {
|
||||
int l = write(f->socket_remote, b, size);
|
||||
|
||||
if (l <= 0) {
|
||||
printf("T tracer: forward error\n");
|
||||
close(f->socket_remote);
|
||||
f->socket_remote = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
size -= l;
|
||||
b += l;
|
||||
}
|
||||
size -= l;
|
||||
b += l;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
goto wait;
|
||||
}
|
||||
|
||||
static void *forward_remote_messages(void *_f)
|
||||
{
|
||||
|
||||
static void *forward_remote_messages(void *_f) {
|
||||
#define PUT(x) do { \
|
||||
if (bufsize == bufmaxsize) { \
|
||||
bufmaxsize += 4096; \
|
||||
@@ -180,7 +220,6 @@ static void *forward_remote_messages(void *_f)
|
||||
int len = l; \
|
||||
while (len) { PUT(*zz); zz++; len--; } \
|
||||
} while (0)
|
||||
|
||||
forward_data *f = _f;
|
||||
int from;
|
||||
int to;
|
||||
@@ -190,43 +229,53 @@ static void *forward_remote_messages(void *_f)
|
||||
int bufsize = 0;
|
||||
int bufmaxsize = 0;
|
||||
char t;
|
||||
|
||||
again:
|
||||
|
||||
while (1) {
|
||||
from = f->socket_remote;
|
||||
to = f->socket_local;
|
||||
|
||||
bufsize = 0;
|
||||
|
||||
/* let's read and process messages */
|
||||
len = read(from, &t, 1); if (len <= 0) goto dead;
|
||||
len = read(from, &t, 1);
|
||||
|
||||
if (len <= 0) goto dead;
|
||||
|
||||
PUT(t);
|
||||
|
||||
switch (t) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* message 0 and 1: get a length and then 'length' numbers */
|
||||
if (read(from, &len, sizeof(int)) != sizeof(int)) goto dead;
|
||||
PUT_BUF(&len, 4);
|
||||
while (len) {
|
||||
if (read(from, &l, sizeof(int)) != sizeof(int)) goto dead;
|
||||
PUT_BUF(&l, 4);
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
|
||||
case 2: break;
|
||||
default:
|
||||
printf("%s:%d:%s: unhandled message type %d\n",
|
||||
__FILE__, __LINE__, __FUNCTION__, t);
|
||||
abort();
|
||||
/* message 0 and 1: get a length and then 'length' numbers */
|
||||
if (read(from, &len, sizeof(int)) != sizeof(int)) goto dead;
|
||||
|
||||
PUT_BUF(&len, 4);
|
||||
|
||||
while (len) {
|
||||
if (read(from, &l, sizeof(int)) != sizeof(int)) goto dead;
|
||||
|
||||
PUT_BUF(&l, 4);
|
||||
len--;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s:%d:%s: unhandled message type %d\n",
|
||||
__FILE__, __LINE__, __FUNCTION__, t);
|
||||
abort();
|
||||
}
|
||||
|
||||
b = buf;
|
||||
|
||||
while (bufsize) {
|
||||
l = write(to, b, bufsize);
|
||||
|
||||
if (l <= 0) abort();
|
||||
|
||||
bufsize -= l;
|
||||
b += l;
|
||||
}
|
||||
@@ -236,71 +285,80 @@ dead:
|
||||
/* socket died, let's stop all traces and wait for another tracer */
|
||||
/* TODO: be careful with those write, they might write less than wanted */
|
||||
buf[0] = 1;
|
||||
|
||||
if (write(to, buf, 1) != 1) abort();
|
||||
|
||||
len = T_NUMBER_OF_IDS;
|
||||
|
||||
if (write(to, &len, sizeof(int)) != sizeof(int)) abort();
|
||||
|
||||
l = 0;
|
||||
|
||||
while (len) {
|
||||
if (write(to, &l, sizeof(int)) != sizeof(int)) abort();
|
||||
|
||||
len--;
|
||||
};
|
||||
|
||||
close(f->socket_remote);
|
||||
|
||||
f->socket_remote = get_connection("0.0.0.0", f->remote_port);
|
||||
|
||||
send_T_messages_txt(f);
|
||||
|
||||
goto again;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *forwarder(int port, int s)
|
||||
{
|
||||
static void *forwarder(int port, int s) {
|
||||
forward_data *f;
|
||||
f = malloc(sizeof(*f));
|
||||
|
||||
f = malloc(sizeof(*f)); if (f == NULL) abort();
|
||||
if (f == NULL) abort();
|
||||
|
||||
pthread_mutex_init(&f->lock, NULL);
|
||||
pthread_cond_init(&f->cond, NULL);
|
||||
|
||||
f->socket_local = s;
|
||||
f->head = f->tail = NULL;
|
||||
|
||||
f->memusage = 0;
|
||||
f->last_warning_memusage = 0;
|
||||
|
||||
printf("T tracer: waiting for remote tracer on port %d\n", port);
|
||||
|
||||
f->remote_port = port;
|
||||
f->socket_remote = get_connection("0.0.0.0", port);
|
||||
send_T_messages_txt(f);
|
||||
|
||||
new_thread(data_sender, f);
|
||||
new_thread(forward_remote_messages, f);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static void forward(void *_forwarder, char *buf, int size)
|
||||
{
|
||||
static void forward(void *_forwarder, char *buf, int size) {
|
||||
forward_data *f = _forwarder;
|
||||
int32_t ssize = size;
|
||||
databuf *new;
|
||||
new = malloc(sizeof(*new));
|
||||
|
||||
new = malloc(sizeof(*new)); if (new == NULL) abort();
|
||||
if (new == NULL) abort();
|
||||
|
||||
if (pthread_mutex_lock(&f->lock)) abort();
|
||||
|
||||
new->d = malloc(size + 4); if (new->d == NULL) abort();
|
||||
new->d = malloc(size + 4);
|
||||
|
||||
if (new->d == NULL) abort();
|
||||
|
||||
/* put the size of the message at the head */
|
||||
memcpy(new->d, &ssize, 4);
|
||||
memcpy(new->d+4, buf, size);
|
||||
new->l = size+4;
|
||||
new->next = NULL;
|
||||
if (f->head == NULL) f->head = new;
|
||||
if (f->tail != NULL) f->tail->next = new;
|
||||
f->tail = new;
|
||||
|
||||
if (f->head == NULL) f->head = new;
|
||||
|
||||
if (f->tail != NULL) f->tail->next = new;
|
||||
|
||||
f->tail = new;
|
||||
#if BASIC_SIMULATOR
|
||||
|
||||
/* When runnng the basic simulator, the tracer may be too slow.
|
||||
* Let's not take too much memory in the tracee and
|
||||
* wait if there is too much data to send. 200MB is
|
||||
@@ -308,26 +366,30 @@ static void forward(void *_forwarder, char *buf, int size)
|
||||
*/
|
||||
while (f->memusage > 200 * 1024 * 1024) {
|
||||
if (pthread_cond_signal(&f->cond)) abort();
|
||||
|
||||
if (pthread_mutex_unlock(&f->lock)) abort();
|
||||
|
||||
usleep(1000);
|
||||
|
||||
if (pthread_mutex_lock(&f->lock)) abort();
|
||||
}
|
||||
#endif /* BASIC_SIMULATOR */
|
||||
|
||||
#endif /* BASIC_SIMULATOR */
|
||||
f->memusage += size+4;
|
||||
|
||||
/* warn every 100MB */
|
||||
if (f->memusage > f->last_warning_memusage &&
|
||||
f->memusage - f->last_warning_memusage > 100000000) {
|
||||
f->last_warning_memusage += 100000000;
|
||||
printf("T tracer: WARNING: memory usage is over %"PRIu64"MB\n",
|
||||
f->last_warning_memusage / 1000000);
|
||||
} else
|
||||
if (f->memusage < f->last_warning_memusage &&
|
||||
f->last_warning_memusage - f->memusage > 100000000) {
|
||||
} else if (f->memusage < f->last_warning_memusage &&
|
||||
f->last_warning_memusage - f->memusage > 100000000) {
|
||||
f->last_warning_memusage = (f->memusage/100000000) * 100000000;
|
||||
}
|
||||
|
||||
if (pthread_cond_signal(&f->cond)) abort();
|
||||
|
||||
if (pthread_mutex_unlock(&f->lock)) abort();
|
||||
}
|
||||
|
||||
@@ -335,14 +397,12 @@ static void forward(void *_forwarder, char *buf, int size)
|
||||
/* local functions */
|
||||
/****************************************************************************/
|
||||
|
||||
static void wait_message(void)
|
||||
{
|
||||
static void wait_message(void) {
|
||||
while ((T_local_cache[T_busylist_head].busy & 0x02) == 0) usleep(1000);
|
||||
}
|
||||
|
||||
void T_local_tracer_main(int remote_port, int wait_for_tracer,
|
||||
int local_socket, void *shm_array)
|
||||
{
|
||||
int local_socket, void *shm_array) {
|
||||
int s;
|
||||
int port = remote_port;
|
||||
int dont_wait = wait_for_tracer ? 0 : 1;
|
||||
@@ -350,16 +410,16 @@ void T_local_tracer_main(int remote_port, int wait_for_tracer,
|
||||
|
||||
/* write on a socket fails if the other end is closed and we get SIGPIPE */
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
printf("local tracer received SIGPIPE\n");
|
||||
abort();
|
||||
printf("local tracer received SIGPIPE\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
T_local_cache = shm_array;
|
||||
|
||||
s = local_socket;
|
||||
|
||||
if (dont_wait) {
|
||||
char t = 2;
|
||||
|
||||
if (write(s, &t, 1) != 1) abort();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,62 +5,56 @@
|
||||
#include <string.h>
|
||||
|
||||
unsigned long register_notifier(gui *_g, char *notification, widget *w,
|
||||
notifier handler, void *private)
|
||||
{
|
||||
notifier handler, void *private) {
|
||||
struct gui *g = _g;
|
||||
unsigned long ret;
|
||||
|
||||
glock(g);
|
||||
|
||||
if (g->next_notifier_id == 2UL * 1024 * 1024 * 1024)
|
||||
ERR("%s:%d: report a bug\n", __FILE__, __LINE__);
|
||||
|
||||
g->notifiers = realloc(g->notifiers,
|
||||
(g->notifiers_count+1) * sizeof(struct notifier));
|
||||
(g->notifiers_count+1) * sizeof(struct notifier));
|
||||
|
||||
if (g->notifiers == NULL) abort();
|
||||
|
||||
ret = g->next_notifier_id;
|
||||
|
||||
g->notifiers[g->notifiers_count].handler = handler;
|
||||
g->notifiers[g->notifiers_count].id = g->next_notifier_id;
|
||||
g->next_notifier_id++;
|
||||
g->notifiers[g->notifiers_count].notification = strdup(notification);
|
||||
|
||||
if (g->notifiers[g->notifiers_count].notification == NULL) abort();
|
||||
|
||||
g->notifiers[g->notifiers_count].w = w;
|
||||
g->notifiers[g->notifiers_count].private = private;
|
||||
/* initialize done to 1 so as not to call the handler if it's created
|
||||
* by the call of another one that is in progress
|
||||
*/
|
||||
g->notifiers[g->notifiers_count].done = 1;
|
||||
|
||||
g->notifiers_count++;
|
||||
|
||||
gunlock(g);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void unregister_notifier(gui *_g, unsigned long notifier_id)
|
||||
{
|
||||
void unregister_notifier(gui *_g, unsigned long notifier_id) {
|
||||
struct gui *g = _g;
|
||||
int i;
|
||||
|
||||
glock(g);
|
||||
|
||||
for (i = 0; i < g->notifiers_count; i++)
|
||||
if (g->notifiers[i].id == notifier_id) break;
|
||||
|
||||
if (i == g->notifiers_count)
|
||||
ERR("%s:%d: notifier_id %ld not found\n", __FILE__,__LINE__,notifier_id);
|
||||
ERR("%s:%d: notifier_id %lu not found\n", __FILE__,__LINE__,notifier_id);
|
||||
|
||||
free(g->notifiers[i].notification);
|
||||
|
||||
memmove(g->notifiers + i, g->notifiers + i + 1,
|
||||
(g->notifiers_count-1 - i) * sizeof(struct notifier));
|
||||
|
||||
(g->notifiers_count-1 - i) * sizeof(struct notifier));
|
||||
g->notifiers_count--;
|
||||
g->notifiers = realloc(g->notifiers,
|
||||
g->notifiers_count * sizeof(struct notifier));
|
||||
g->notifiers_count * sizeof(struct notifier));
|
||||
|
||||
if (g->notifiers == NULL) abort();
|
||||
|
||||
gunlock(g);
|
||||
@@ -68,19 +62,19 @@ void unregister_notifier(gui *_g, unsigned long notifier_id)
|
||||
|
||||
/* called with lock ON */
|
||||
void gui_notify(struct gui *g, char *notification, widget *w,
|
||||
void *notification_data)
|
||||
{
|
||||
void *notification_data) {
|
||||
void *private;
|
||||
notifier handler;
|
||||
int i;
|
||||
|
||||
/* this function is not re-entrant, for the moment keep as is
|
||||
* and if the need is there, we'll make a new thread to handle
|
||||
* notifications (or something)
|
||||
* for now let's crash in case of recursive call
|
||||
*/
|
||||
static int inside = 0;
|
||||
|
||||
if (inside) ERR("%s:%d: BUG! contact the authors\n", __FILE__, __LINE__);
|
||||
|
||||
inside = 1;
|
||||
|
||||
/* clear all handlers */
|
||||
@@ -91,26 +85,25 @@ void gui_notify(struct gui *g, char *notification, widget *w,
|
||||
* need to be careful here
|
||||
*/
|
||||
loop:
|
||||
|
||||
for (i = 0; i < g->notifiers_count; i++) {
|
||||
if (g->notifiers[i].done == 1 ||
|
||||
g->notifiers[i].w != w ||
|
||||
strcmp(g->notifiers[i].notification, notification) != 0)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == g->notifiers_count) goto done;
|
||||
|
||||
g->notifiers[i].done = 1;
|
||||
|
||||
handler = g->notifiers[i].handler;
|
||||
private = g->notifiers[i].private;
|
||||
|
||||
gunlock(g);
|
||||
handler(private, g, notification, w, notification_data);
|
||||
glock(g);
|
||||
|
||||
goto loop;
|
||||
|
||||
done:
|
||||
inside = 0;
|
||||
}
|
||||
|
||||
@@ -130,9 +130,13 @@ static void paint(gui *_gui, widget *_this)
|
||||
this->common.y + FLIP(y),
|
||||
this->common.x + this->vrule_width + 5,
|
||||
this->common.y + FLIP(y));
|
||||
/* do not print out of the widget (take care of top) */
|
||||
y = FLIP(y)-this->label_height/2+this->label_baseline;
|
||||
if (y - this->label_baseline < 0)
|
||||
y = this->label_baseline;
|
||||
x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR,
|
||||
this->common.x + this->vrule_width - vwidth - 2,
|
||||
this->common.y + FLIP(y)-this->label_height/2+this->label_baseline,
|
||||
this->common.y + y,
|
||||
v);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3,7 +3,7 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I. -I..
|
||||
|
||||
LIBS=-lX11 -lm -lpng -lXft
|
||||
|
||||
all: dump_nack_signal time_meas timeplot
|
||||
all: dump_nack_signal time_meas timeplot multi-rru-clean
|
||||
|
||||
dump_nack_signal: ../utils.o ../database.o ../config.o ../event.o \
|
||||
dump_nack_signal.o
|
||||
@@ -16,6 +16,9 @@ time_meas: ../utils.o ../database.o ../config.o ../event.o \
|
||||
timplot: timeplot.o
|
||||
$(CC) $(CFLAGS) -o timeplot $^ $(LIBS)
|
||||
|
||||
multi-rru-clean: ../utils.o ../database.o ../event.o ../config.o multi-rru-clean.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
.PHONY: all
|
||||
|
||||
%.o: %.c
|
||||
|
||||
@@ -7,21 +7,19 @@
|
||||
#include "config.h"
|
||||
#include "../T_defs.h"
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
void usage(void) {
|
||||
printf(
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
" -ip <host> connect to given IP address (default %s)\n"
|
||||
" -p <port> connect to given port (default %d)\n",
|
||||
DEFAULT_REMOTE_IP,
|
||||
DEFAULT_REMOTE_PORT
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
" -ip <host> connect to given IP address (default %s)\n"
|
||||
" -p <port> connect to given port (default %d)\n",
|
||||
DEFAULT_REMOTE_IP,
|
||||
DEFAULT_REMOTE_PORT
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
int main(int n, char **v) {
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
char *ip = DEFAULT_REMOTE_IP;
|
||||
@@ -36,11 +34,28 @@ int main(int n, char **v)
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
|
||||
if (!strcmp(v[i], "-d"))
|
||||
{ if (i > n-2) usage(); database_filename = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-p"))
|
||||
{ if (i > n-2) usage(); port = atoi(v[++i]); continue; }
|
||||
|
||||
if (!strcmp(v[i], "-d")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
database_filename = v[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-ip")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
ip = v[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-p")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
port = atoi(v[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
usage();
|
||||
}
|
||||
|
||||
@@ -50,71 +65,92 @@ int main(int n, char **v)
|
||||
}
|
||||
|
||||
database = parse_database(database_filename);
|
||||
|
||||
load_config_file(database_filename);
|
||||
|
||||
number_of_events = number_of_ids(database);
|
||||
is_on = calloc(number_of_events, sizeof(int));
|
||||
|
||||
if (is_on == NULL) abort();
|
||||
|
||||
on_off(database, "ENB_PHY_INPUT_SIGNAL", is_on, 1);
|
||||
on_off(database, "ENB_PHY_ULSCH_UE_NACK", is_on, 1);
|
||||
on_off(database, "ENB_PHY_ULSCH_UE_ACK", is_on, 1);
|
||||
|
||||
ev_input = event_id_from_name(database, "ENB_PHY_INPUT_SIGNAL");
|
||||
ev_nack = event_id_from_name(database, "ENB_PHY_ULSCH_UE_NACK");
|
||||
ev_ack = event_id_from_name(database, "ENB_PHY_ULSCH_UE_ACK");
|
||||
|
||||
socket = connect_to(ip, port);
|
||||
|
||||
t = 1;
|
||||
|
||||
if (socket_send(socket, &t, 1) == -1 ||
|
||||
socket_send(socket, &number_of_events, sizeof(int)) == -1 ||
|
||||
socket_send(socket, is_on, number_of_events * sizeof(int)) == -1)
|
||||
abort();
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
char dump[10][T_BUFFER_MAX];
|
||||
event dump_ev[10];
|
||||
FILE *z = fopen("/tmp/dd", "w"); if (z == NULL) abort();
|
||||
FILE *z = fopen("/tmp/dd", "w");
|
||||
|
||||
if (z == NULL) abort();
|
||||
|
||||
while (1) {
|
||||
char *v;
|
||||
event e;
|
||||
e = get_event(socket, &ebuf, database);
|
||||
v = ebuf.obuf;
|
||||
|
||||
if (e.type == -1) break;
|
||||
|
||||
if (e.type == ev_input) {
|
||||
int sf = e.e[2].i;
|
||||
if (ebuf.osize > T_BUFFER_MAX)
|
||||
{ printf("event size too big\n"); exit(1); }
|
||||
|
||||
if (ebuf.osize > T_BUFFER_MAX) {
|
||||
printf("event size too big\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(dump[sf], ebuf.obuf, ebuf.osize);
|
||||
dump_ev[sf] = e;
|
||||
printf("input %d/%d\n", e.e[1].i, sf);
|
||||
if (fwrite(dump_ev[sf].e[4].b, dump_ev[sf].e[4].bsize, 1, z) != 1) abort();
|
||||
fflush(z);
|
||||
|
||||
if (fwrite(dump_ev[sf].e[4].b, dump_ev[sf].e[4].bsize, 1, z) != 1) abort();
|
||||
|
||||
fflush(z);
|
||||
}
|
||||
|
||||
if (e.type == ev_nack) {
|
||||
int sf = e.e[2].i;
|
||||
printf("nack %d/%d\n", e.e[1].i, sf);
|
||||
FILE *f = fopen("/tmp/dump.raw", "w"); if (f == NULL) abort();
|
||||
FILE *f = fopen("/tmp/dump.raw", "w");
|
||||
|
||||
if (f == NULL) abort();
|
||||
|
||||
if (fwrite(dump[sf] + ((char *)dump_ev[sf].e[4].b - v),
|
||||
dump_ev[sf].e[4].bsize, 1, f) != 1) abort();
|
||||
dump_ev[sf].e[4].bsize, 1, f) != 1) abort();
|
||||
|
||||
if (fclose(f)) abort();
|
||||
|
||||
printf("dumped... press enter (delta %d)\n", (int)((char *)dump_ev[sf].e[4].b - v));
|
||||
// getchar();
|
||||
// getchar();
|
||||
}
|
||||
|
||||
if (e.type == ev_ack) {
|
||||
int sf = e.e[2].i;
|
||||
printf("ack %d/%d\n", e.e[1].i, sf);
|
||||
FILE *f = fopen("/tmp/dump.raw", "w"); if (f == NULL) abort();
|
||||
FILE *f = fopen("/tmp/dump.raw", "w");
|
||||
|
||||
if (f == NULL) abort();
|
||||
|
||||
if (fwrite(dump[sf] + ((char *)dump_ev[sf].e[4].b - v),
|
||||
dump_ev[sf].e[4].bsize, 1, f) != 1) abort();
|
||||
dump_ev[sf].e[4].bsize, 1, f) != 1) abort();
|
||||
|
||||
if (fclose(f)) abort();
|
||||
|
||||
printf("dumped... press enter (delta %d)\n", (int)((char *)dump_ev[sf].e[4].b - v));
|
||||
// getchar();
|
||||
// getchar();
|
||||
}
|
||||
}
|
||||
if (z)
|
||||
fclose(z);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "database.h"
|
||||
#include "utils.h"
|
||||
#include "event.h"
|
||||
#include "../T_defs.h"
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf(
|
||||
"usage: <number of tags> <input record file> <output curated record file>\n"
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#define ERR printf("ERROR: read file %s failed\n", input_filename)
|
||||
|
||||
typedef struct {
|
||||
OBUF b;
|
||||
struct timespec t;
|
||||
int filled;
|
||||
int error;
|
||||
} cache_t;
|
||||
|
||||
void clear_cache(int n, cache_t *c)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
c[i].filled = 0;
|
||||
c[i].error = 0;
|
||||
c[i].b.osize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void store_in_cache(cache_t *c, int pos, OBUF *b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < b->osize; i++)
|
||||
PUTC(&c[pos].b, b->obuf[i]);
|
||||
}
|
||||
|
||||
int get_field(database_event_format *f, char *field, char *type)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < f->count; i++)
|
||||
if (!strcmp(f->name[i], field)) {
|
||||
if (strcmp(f->type[i], type)) break;
|
||||
return i;
|
||||
}
|
||||
printf("bad field %s, check that it exists and has type '%s'\n",field,type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void process_cache(FILE *out, cache_t *c, int n, int frame, int subframe)
|
||||
{
|
||||
int i;
|
||||
struct tm *t;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (c[i].filled == 0 || c[i].error == 1)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
fwrite(c[i].b.obuf, c[i].b.osize, 1, out);
|
||||
|
||||
clear_cache(n, c);
|
||||
return;
|
||||
|
||||
error:
|
||||
printf("ERROR: incorrect data at frame %d subframe %d", frame, subframe);
|
||||
for (i = 0; i < n; i++) if (c[i].filled) {
|
||||
t = localtime(&c[i].t.tv_sec);
|
||||
printf(" [tag %d time %2.2d:%2.2d:%2.2d.%9.9ld]", i,
|
||||
t->tm_hour, t->tm_min, t->tm_sec, c[i].t.tv_nsec);
|
||||
}
|
||||
printf("\n");
|
||||
clear_cache(n, c);
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
int channel_estimate_id;
|
||||
int number_of_tags = -1;
|
||||
char *input_filename = NULL;
|
||||
char *output_filename = NULL;
|
||||
int i;
|
||||
FILE *in;
|
||||
FILE *out;
|
||||
database_event_format f;
|
||||
int frame_arg;
|
||||
int subframe_arg;
|
||||
int tag_arg;
|
||||
|
||||
cache_t *cache;
|
||||
int cur_frame = -1;
|
||||
int cur_subframe = -1;
|
||||
int frame;
|
||||
int subframe;
|
||||
int tag;
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
|
||||
if (!strcmp(v[i], "-d")) { if (i > n-2) usage();
|
||||
database_filename = v[++i]; continue; }
|
||||
if (number_of_tags == -1) { number_of_tags = atoi(v[i]);
|
||||
if (number_of_tags <= 0) {usage();} continue; }
|
||||
if (input_filename == NULL) { input_filename = v[i]; continue; }
|
||||
if (output_filename == NULL) { output_filename = v[i]; continue; }
|
||||
usage();
|
||||
}
|
||||
|
||||
if (database_filename == NULL) {
|
||||
printf("ERROR: provide a database file (-d)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (output_filename == NULL || input_filename == NULL || number_of_tags == -1)
|
||||
usage();
|
||||
|
||||
database = parse_database(database_filename);
|
||||
|
||||
channel_estimate_id = event_id_from_name(database, "CALIBRATION_CHANNEL_ESTIMATES");
|
||||
f = get_format(database, channel_estimate_id);
|
||||
|
||||
frame_arg = get_field(&f, "frame", "int");
|
||||
subframe_arg = get_field(&f, "subframe", "int");
|
||||
tag_arg = get_field(&f, "tag", "int");
|
||||
|
||||
in = fopen(input_filename, "r");
|
||||
if (in == NULL) { perror(input_filename); abort(); }
|
||||
out = fopen(output_filename, "w");
|
||||
if (out == NULL) { perror(output_filename); abort(); }
|
||||
|
||||
cache = calloc(number_of_tags, sizeof(cache_t));
|
||||
if (cache == NULL) { perror("malloc"); exit(1); }
|
||||
|
||||
clear_cache(number_of_tags, cache);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
while (1) {
|
||||
int type;
|
||||
int32_t length;
|
||||
char *v;
|
||||
int vpos = 0;
|
||||
struct timespec t;
|
||||
char *buf;
|
||||
|
||||
/* read event from file */
|
||||
if (fread(&length, 4, 1, in) != 1) break;
|
||||
if (ebuf.omaxsize < length) {
|
||||
ebuf.omaxsize = (length + 65535) & ~65535;
|
||||
ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize);
|
||||
if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); }
|
||||
}
|
||||
v = ebuf.obuf;
|
||||
memcpy(v+vpos, &length, 4);
|
||||
vpos += 4;
|
||||
#ifdef T_SEND_TIME
|
||||
if (length < sizeof(struct timespec)) { ERR; break; }
|
||||
if (fread(&t, sizeof(struct timespec), 1, in) != 1) { ERR; break; }
|
||||
memcpy(v+vpos, &t, sizeof(struct timespec));
|
||||
vpos += sizeof(struct timespec);
|
||||
length -= sizeof(struct timespec);
|
||||
#endif
|
||||
if (length < sizeof(int)) { ERR; break; }
|
||||
if (fread(&type, sizeof(int), 1, in) != 1) { ERR; break; }
|
||||
memcpy(v+vpos, &type, sizeof(int));
|
||||
vpos += sizeof(int);
|
||||
length -= sizeof(int);
|
||||
if (length) if (fread(v+vpos, length, 1, in) != 1) { ERR; break; }
|
||||
buf = v + vpos;
|
||||
vpos += length;
|
||||
ebuf.osize = vpos;
|
||||
|
||||
if (type != channel_estimate_id) continue;
|
||||
|
||||
event e;
|
||||
#ifdef T_SEND_TIME
|
||||
e = new_event(t, type, length, buf, database);
|
||||
#else
|
||||
e = new_event(type, length, buf, database);
|
||||
#endif
|
||||
|
||||
frame = e.e[frame_arg].i;
|
||||
subframe = e.e[subframe_arg].i;
|
||||
tag = e.e[tag_arg].i;
|
||||
|
||||
if (tag < 0 || tag >= number_of_tags) {
|
||||
struct tm *tt;
|
||||
tt = localtime(&t.tv_sec);
|
||||
printf("ERROR: invalid tag (%d), skipping event for frame %d subframe %d (time %2.2d:%2.2d:%2.2d.%9.9ld)\n",
|
||||
tag, frame, subframe,
|
||||
tt->tm_hour, tt->tm_min, tt->tm_sec, t.tv_nsec);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur_frame != frame || cur_subframe != subframe)
|
||||
if (cur_frame != -1)
|
||||
process_cache(out, cache, number_of_tags, cur_frame, cur_subframe);
|
||||
|
||||
cur_frame = frame;
|
||||
cur_subframe = subframe;
|
||||
|
||||
if (cache[tag].filled) {
|
||||
struct tm *tt;
|
||||
tt = localtime(&t.tv_sec);
|
||||
printf("ERROR: tag %d present twice at frame %d subframe %d (time %2.2d:%2.2d:%2.2d.%9.9ld)\n",
|
||||
tag, frame, subframe,
|
||||
tt->tm_hour, tt->tm_min, tt->tm_sec, t.tv_nsec);
|
||||
cache[tag].error = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
store_in_cache(cache, tag, &ebuf);
|
||||
cache[tag].filled = 1;
|
||||
cache[tag].t = t;
|
||||
}
|
||||
|
||||
if (fclose(in)) perror(input_filename);
|
||||
if (fclose(out)) perror(output_filename);
|
||||
free(cache);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -58,14 +58,11 @@ typedef struct {
|
||||
} ev_data;
|
||||
|
||||
void trace(ev_data *d, int direction, int rnti_type, int rnti,
|
||||
int frame, int subframe, void *buf, int bufsize, int preamble)
|
||||
{
|
||||
int frame, int subframe, void *buf, int bufsize, int preamble) {
|
||||
ssize_t ret;
|
||||
int fsf;
|
||||
int i;
|
||||
|
||||
d->buf.osize = 0;
|
||||
|
||||
PUTS(&d->buf, MAC_LTE_START_STRING);
|
||||
PUTC(&d->buf, FDD_RADIO);
|
||||
PUTC(&d->buf, direction);
|
||||
@@ -92,16 +89,17 @@ void trace(ev_data *d, int direction, int rnti_type, int rnti,
|
||||
}
|
||||
|
||||
PUTC(&d->buf, MAC_LTE_PAYLOAD_TAG);
|
||||
|
||||
for (i = 0; i < bufsize; i++)
|
||||
PUTC(&d->buf, ((char*)buf)[i]);
|
||||
PUTC(&d->buf, ((char *)buf)[i]);
|
||||
|
||||
ret = sendto(d->socket, d->buf.obuf, d->buf.osize, 0,
|
||||
(struct sockaddr *)&d->to, sizeof(struct sockaddr_in));
|
||||
(struct sockaddr *)&d->to, sizeof(struct sockaddr_in));
|
||||
|
||||
if (ret != d->buf.osize) abort();
|
||||
}
|
||||
|
||||
void ul(void *_d, event e)
|
||||
{
|
||||
void ul(void *_d, event e) {
|
||||
ev_data *d = _d;
|
||||
trace(d, DIRECTION_UPLINK, C_RNTI, e.e[d->ul_rnti].i,
|
||||
e.e[d->ul_frame].i, e.e[d->ul_subframe].i,
|
||||
@@ -109,13 +107,14 @@ void ul(void *_d, event e)
|
||||
NO_PREAMBLE);
|
||||
}
|
||||
|
||||
void dl(void *_d, event e)
|
||||
{
|
||||
void dl(void *_d, event e) {
|
||||
ev_data *d = _d;
|
||||
|
||||
if (e.e[d->dl_rnti].i == 0xffff) {
|
||||
if (d->no_sib) return;
|
||||
|
||||
if (d->max_sib && d->cur_sib == d->max_sib) return;
|
||||
|
||||
d->cur_sib++;
|
||||
}
|
||||
|
||||
@@ -126,22 +125,21 @@ void dl(void *_d, event e)
|
||||
NO_PREAMBLE);
|
||||
}
|
||||
|
||||
void mib(void *_d, event e)
|
||||
{
|
||||
void mib(void *_d, event e) {
|
||||
ev_data *d = _d;
|
||||
|
||||
if (d->no_mib) return;
|
||||
if (d->max_mib && d->cur_mib == d->max_mib) return;
|
||||
d->cur_mib++;
|
||||
|
||||
if (d->max_mib && d->cur_mib == d->max_mib) return;
|
||||
|
||||
d->cur_mib++;
|
||||
trace(d, DIRECTION_DOWNLINK, NO_RNTI, 0,
|
||||
e.e[d->mib_frame].i, e.e[d->mib_subframe].i,
|
||||
e.e[d->mib_data].b, e.e[d->mib_data].bsize,
|
||||
NO_PREAMBLE);
|
||||
}
|
||||
|
||||
void preamble(void *_d, event e)
|
||||
{
|
||||
void preamble(void *_d, event e) {
|
||||
ev_data *d = _d;
|
||||
trace(d, DIRECTION_UPLINK, NO_RNTI, 0,
|
||||
e.e[d->preamble_frame].i, e.e[d->preamble_subframe].i,
|
||||
@@ -149,8 +147,7 @@ void preamble(void *_d, event e)
|
||||
e.e[d->preamble_preamble].i);
|
||||
}
|
||||
|
||||
void rar(void *_d, event e)
|
||||
{
|
||||
void rar(void *_d, event e) {
|
||||
ev_data *d = _d;
|
||||
trace(d, DIRECTION_DOWNLINK, RA_RNTI, e.e[d->rar_rnti].i,
|
||||
e.e[d->rar_frame].i, e.e[d->rar_subframe].i,
|
||||
@@ -159,114 +156,118 @@ void rar(void *_d, event e)
|
||||
}
|
||||
|
||||
void setup_data(ev_data *d, void *database, int ul_id, int dl_id, int mib_id,
|
||||
int preamble_id, int rar_id)
|
||||
{
|
||||
int preamble_id, int rar_id) {
|
||||
database_event_format f;
|
||||
int i;
|
||||
|
||||
d->ul_rnti = -1;
|
||||
d->ul_frame = -1;
|
||||
d->ul_subframe = -1;
|
||||
d->ul_data = -1;
|
||||
|
||||
d->dl_rnti = -1;
|
||||
d->dl_frame = -1;
|
||||
d->dl_subframe = -1;
|
||||
d->dl_data = -1;
|
||||
|
||||
d->mib_frame = -1;
|
||||
d->mib_subframe = -1;
|
||||
d->mib_data = -1;
|
||||
|
||||
d->preamble_frame = -1;
|
||||
d->preamble_subframe = -1;
|
||||
d->preamble_preamble = -1;
|
||||
|
||||
d->rar_rnti = -1;
|
||||
d->rar_frame = -1;
|
||||
d->rar_subframe = -1;
|
||||
d->rar_data = -1;
|
||||
|
||||
#define G(var_name, var_type, var) \
|
||||
if (!strcmp(f.name[i], var_name)) { \
|
||||
if (strcmp(f.type[i], var_type)) goto error; \
|
||||
var = i; \
|
||||
continue; \
|
||||
}
|
||||
|
||||
/* ul: rnti, frame, subframe, data */
|
||||
f = get_format(database, ul_id);
|
||||
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("rnti", "int", d->ul_rnti);
|
||||
G("frame", "int", d->ul_frame);
|
||||
G("subframe", "int", d->ul_subframe);
|
||||
G("data", "buffer", d->ul_data);
|
||||
}
|
||||
|
||||
if (d->ul_rnti == -1 || d->ul_frame == -1 || d->ul_subframe == -1 ||
|
||||
d->ul_data == -1) goto error;
|
||||
|
||||
/* dl: rnti, frame, subframe, data */
|
||||
f = get_format(database, dl_id);
|
||||
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("rnti", "int", d->dl_rnti);
|
||||
G("frame", "int", d->dl_frame);
|
||||
G("subframe", "int", d->dl_subframe);
|
||||
G("data", "buffer", d->dl_data);
|
||||
}
|
||||
|
||||
if (d->dl_rnti == -1 || d->dl_frame == -1 || d->dl_subframe == -1 ||
|
||||
d->dl_data == -1) goto error;
|
||||
|
||||
/* MIB: frame, subframe, data */
|
||||
f = get_format(database, mib_id);
|
||||
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("frame", "int", d->mib_frame);
|
||||
G("subframe", "int", d->mib_subframe);
|
||||
G("data", "buffer", d->mib_data);
|
||||
}
|
||||
|
||||
if (d->mib_frame == -1 || d->mib_subframe == -1 || d->mib_data == -1)
|
||||
goto error;
|
||||
|
||||
/* preamble: frame, subframe, preamble */
|
||||
f = get_format(database, preamble_id);
|
||||
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("frame", "int", d->preamble_frame);
|
||||
G("subframe", "int", d->preamble_subframe);
|
||||
G("preamble", "int", d->preamble_preamble);
|
||||
}
|
||||
|
||||
if (d->preamble_frame == -1 || d->preamble_subframe == -1 ||
|
||||
d->preamble_preamble == -1) goto error;
|
||||
|
||||
/* rar: rnti, frame, subframe, data */
|
||||
f = get_format(database, rar_id);
|
||||
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("rnti", "int", d->rar_rnti);
|
||||
G("frame", "int", d->rar_frame);
|
||||
G("subframe", "int", d->rar_subframe);
|
||||
G("data", "buffer", d->rar_data);
|
||||
}
|
||||
|
||||
if (d->rar_rnti == -1 || d->rar_frame == -1 || d->rar_subframe == -1 ||
|
||||
d->rar_data == -1) goto error;
|
||||
|
||||
#undef G
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
printf("bad T_messages.txt\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
void *receiver(void *_d)
|
||||
{
|
||||
void *receiver(void *_d) {
|
||||
ev_data *d = _d;
|
||||
int s;
|
||||
char buf[100000];
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s == -1) { perror("socket"); abort(); }
|
||||
|
||||
if (bind(s, (struct sockaddr *)&d->to, sizeof(struct sockaddr_in)) == -1)
|
||||
{ perror("bind"); abort(); }
|
||||
if (s == -1) {
|
||||
perror("socket");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&d->to, sizeof(struct sockaddr_in)) == -1) {
|
||||
perror("bind");
|
||||
abort();
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (recv(s, buf, 100000, 0) <= 0) abort();
|
||||
@@ -275,33 +276,31 @@ void *receiver(void *_d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
void usage(void) {
|
||||
printf(
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
" -i <dump file> read events from this dump file\n"
|
||||
" -ip <IP address> send packets to this IP address (default %s)\n"
|
||||
" -p <port> send packets to this port (default %d)\n"
|
||||
" -no-mib do not report MIB\n"
|
||||
" -no-sib do not report SIBs\n"
|
||||
" -max-mib <n> report at maximum n MIB\n"
|
||||
" -max-sib <n> report at maximum n SIBs\n"
|
||||
" -live run live\n"
|
||||
" -live-ip <IP address> tracee's IP address (default %p)\n"
|
||||
" -live-port <por> tracee's port (default %d)\n"
|
||||
"-i and -live are mutually exclusive options. One of them must be provided\n"
|
||||
"but not both.\n",
|
||||
DEFAULT_IP,
|
||||
DEFAULT_PORT,
|
||||
DEFAULT_LIVE_IP,
|
||||
DEFAULT_LIVE_PORT
|
||||
"options:\n"
|
||||
" -d <database file> this option is mandatory\n"
|
||||
" -i <dump file> read events from this dump file\n"
|
||||
" -ip <IP address> send packets to this IP address (default %s)\n"
|
||||
" -p <port> send packets to this port (default %d)\n"
|
||||
" -no-mib do not report MIB\n"
|
||||
" -no-sib do not report SIBs\n"
|
||||
" -max-mib <n> report at maximum n MIB\n"
|
||||
" -max-sib <n> report at maximum n SIBs\n"
|
||||
" -live run live\n"
|
||||
" -live-ip <IP address> tracee's IP address (default %s)\n"
|
||||
" -live-port <port> tracee's port (default %d)\n"
|
||||
"-i and -live are mutually exclusive options. One of them must be provided\n"
|
||||
"but not both.\n",
|
||||
DEFAULT_IP,
|
||||
DEFAULT_PORT,
|
||||
DEFAULT_LIVE_IP,
|
||||
DEFAULT_LIVE_PORT
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
int main(int n, char **v) {
|
||||
char *database_filename = NULL;
|
||||
char *input_filename = NULL;
|
||||
void *database;
|
||||
@@ -315,28 +314,82 @@ int main(int n, char **v)
|
||||
char *live_ip = DEFAULT_LIVE_IP;
|
||||
int live_port = DEFAULT_LIVE_PORT;
|
||||
int live = 0;
|
||||
|
||||
memset(&d, 0, sizeof(ev_data));
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
|
||||
if (!strcmp(v[i], "-d"))
|
||||
{ if (i > n-2) usage(); database_filename = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-i"))
|
||||
{ if (i > n-2) usage(); input_filename = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-p")) {if(i>n-2)usage(); port=atoi(v[++i]); continue; }
|
||||
if (!strcmp(v[i], "-no-mib")) { d.no_mib = 1; continue; }
|
||||
if (!strcmp(v[i], "-no-sib")) { d.no_sib = 1; continue; }
|
||||
if (!strcmp(v[i], "-max-mib"))
|
||||
{ if (i > n-2) usage(); d.max_mib = atoi(v[++i]); continue; }
|
||||
if (!strcmp(v[i], "-max-sib"))
|
||||
{ if (i > n-2) usage(); d.max_sib = atoi(v[++i]); continue; }
|
||||
if (!strcmp(v[i], "-live")) { live = 1; continue; }
|
||||
if (!strcmp(v[i], "-live-ip"))
|
||||
{ if (i > n-2) usage(); live_ip = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-live-port"))
|
||||
{ if (i > n-2) usage(); live_port = atoi(v[++i]); continue; }
|
||||
|
||||
if (!strcmp(v[i], "-d")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
database_filename = v[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-i")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
input_filename = v[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-ip")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
ip = v[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-p")) {
|
||||
if(i>n-2)usage();
|
||||
|
||||
port=atoi(v[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-no-mib")) {
|
||||
d.no_mib = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-no-sib")) {
|
||||
d.no_sib = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-max-mib")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
d.max_mib = atoi(v[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-max-sib")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
d.max_sib = atoi(v[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-live")) {
|
||||
live = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-live-ip")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
live_ip = v[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(v[i], "-live-port")) {
|
||||
if (i > n-2) usage();
|
||||
|
||||
live_port = atoi(v[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
usage();
|
||||
}
|
||||
|
||||
@@ -357,25 +410,34 @@ int main(int n, char **v)
|
||||
|
||||
if (live == 0) {
|
||||
in = open(input_filename, O_RDONLY);
|
||||
if (in == -1) { perror(input_filename); return 1; }
|
||||
|
||||
if (in == -1) {
|
||||
perror(input_filename);
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
in = connect_to(live_ip, live_port);
|
||||
|
||||
database = parse_database(database_filename);
|
||||
load_config_file(database_filename);
|
||||
|
||||
h = new_handler(database);
|
||||
|
||||
if (live) {
|
||||
char mt = 1;
|
||||
int number_of_events = number_of_ids(database);
|
||||
int *is_on = calloc(number_of_events, sizeof(int));
|
||||
if (is_on == NULL) { printf("ERROR: out of memory\n"); exit(1); }
|
||||
|
||||
if (is_on == NULL) {
|
||||
printf("ERROR: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
on_off(database, "ENB_MAC_UE_UL_PDU_WITH_DATA", is_on, 1);
|
||||
on_off(database, "ENB_MAC_UE_DL_PDU_WITH_DATA", is_on, 1);
|
||||
on_off(database, "ENB_PHY_MIB", is_on, 1);
|
||||
on_off(database, "ENB_PHY_INITIATE_RA_PROCEDURE", is_on, 1);
|
||||
on_off(database, "ENB_MAC_UE_DL_RAR_PDU_WITH_DATA", is_on, 1);
|
||||
|
||||
/* activate selected traces */
|
||||
if (socket_send(in, &mt, 1) == -1 ||
|
||||
socket_send(in, &number_of_events, sizeof(int)) == -1 ||
|
||||
@@ -383,6 +445,7 @@ int main(int n, char **v)
|
||||
printf("ERROR: socket_send failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(is_on);
|
||||
}
|
||||
|
||||
@@ -392,31 +455,34 @@ int main(int n, char **v)
|
||||
preamble_id = event_id_from_name(database, "ENB_PHY_INITIATE_RA_PROCEDURE");
|
||||
rar_id = event_id_from_name(database, "ENB_MAC_UE_DL_RAR_PDU_WITH_DATA");
|
||||
setup_data(&d, database, ul_id, dl_id, mib_id, preamble_id, rar_id);
|
||||
|
||||
register_handler_function(h, ul_id, ul, &d);
|
||||
register_handler_function(h, dl_id, dl, &d);
|
||||
register_handler_function(h, mib_id, mib, &d);
|
||||
register_handler_function(h, preamble_id, preamble, &d);
|
||||
register_handler_function(h, rar_id, rar, &d);
|
||||
|
||||
d.socket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (d.socket == -1) { perror("socket"); exit(1); }
|
||||
|
||||
if (d.socket == -1) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
d.to.sin_family = AF_INET;
|
||||
d.to.sin_port = htons(port);
|
||||
d.to.sin_addr.s_addr = inet_addr(ip);
|
||||
|
||||
new_thread(receiver, &d);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
/* read messages */
|
||||
while (1) {
|
||||
event e;
|
||||
e = get_event(in, &ebuf, database);
|
||||
|
||||
if (e.type == -1) break;
|
||||
|
||||
if (!(e.type == ul_id || e.type == dl_id || e.type == mib_id ||
|
||||
e.type == preamble_id || e.type == rar_id)) continue;
|
||||
|
||||
handle_event(h, e);
|
||||
}
|
||||
|
||||
|
||||
@@ -195,5 +195,8 @@ int main(int n, char **v)
|
||||
handle_event(h, e);
|
||||
}
|
||||
|
||||
free(on_off_name);
|
||||
free(on_off_action);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+102
-197
@@ -23,9 +23,6 @@ typedef struct {
|
||||
view *pdcpview;
|
||||
view *rrcview;
|
||||
view *legacy;
|
||||
widget *current_ue_label;
|
||||
widget *prev_ue_button;
|
||||
widget *next_ue_button;
|
||||
widget *pdsch_iq_ue_xy_plot;
|
||||
widget *dl_estimate_ue_xy_plot;
|
||||
widget *pdcch_energy_ue_xy_plot;
|
||||
@@ -121,15 +118,14 @@ static void *gui_thread(void *_g)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static filter *ticktime_filter(void *database, char *event, int i, int ue)
|
||||
static filter *ticktime_filter(void *database, char *event, int i)
|
||||
{
|
||||
/* filter is "harq_pid == i && UE_id == 0 && eNB_id == 0" */
|
||||
/* filter is "harq_pid == i and eNB_id == 0" */
|
||||
return
|
||||
filter_and(
|
||||
filter_eq(filter_evarg(database, event, "harq_pid"), filter_int(i)),
|
||||
filter_and(
|
||||
filter_eq(filter_evarg(database, event, "UE_id"), filter_int(ue)),
|
||||
filter_eq(filter_evarg(database, event, "eNB_ID"), filter_int(0))));
|
||||
filter_eq(filter_evarg(database, event, "eNB_ID"), filter_int(0)));
|
||||
|
||||
}
|
||||
|
||||
static void set_current_ue(gui *g, ue_data *e, int ue)
|
||||
@@ -137,8 +133,6 @@ static void set_current_ue(gui *g, ue_data *e, int ue)
|
||||
int i;
|
||||
char s[256];
|
||||
|
||||
sprintf(s, "[UE %d] ", ue);
|
||||
label_set_text(g, e->e->current_ue_label, s);
|
||||
sprintf(s, "PDSCH IQ [UE %d]", ue);
|
||||
xy_plot_set_title(g, e->e->pdsch_iq_ue_xy_plot, s);
|
||||
sprintf(s, "DL estimated channel [UE %d]", ue);
|
||||
@@ -161,97 +155,24 @@ static void set_current_ue(gui *g, ue_data *e, int ue)
|
||||
xy_plot_set_title(g, e->e->pucch_power_xy_plot, s);
|
||||
sprintf(s, "PHY Measurements [UE %d]", ue);
|
||||
xy_plot_set_title(g, e->e->phy_meas_xy_plot, s);
|
||||
|
||||
logger_set_filter(e->e->pdsch_iq_ue_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_PDSCH_IQ", "UE_ID"),
|
||||
filter_int(ue)));
|
||||
logger_set_filter(e->e->dl_estimate_ue_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_DL_CHANNEL_ESTIMATE", "UE_ID"),
|
||||
filter_int(ue)));
|
||||
logger_set_filter(e->e->pdcch_energy_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_PDCCH_ENERGY", "UE_ID"),
|
||||
filter_int(ue)));
|
||||
logger_set_filter(e->e->pdsch_energy_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_PDSCH_ENERGY", "UE_ID"),
|
||||
filter_int(ue)));
|
||||
logger_set_filter(e->e->phy_meas_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_MEAS", "UE_ID"),
|
||||
filter_int(ue)));
|
||||
/*logger_set_filter(e->pucch1_energy_ue_energy_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "ENB_PHY_PUCCH_1_ENERGY", "UE_ID"),
|
||||
filter_int(ue)));*/
|
||||
/*logger_set_filter(e->e->pdcch_iq_ue_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_PDCCH_IQ", "UE_ID"),
|
||||
filter_int(ue)));*/
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
logger_set_filter(e->e->dl_dci_logger[i],
|
||||
ticktime_filter(e->database, "UE_PHY_DLSCH_UE_DCI", i, ue));
|
||||
ticktime_filter(e->database, "UE_PHY_DLSCH_UE_DCI", i));
|
||||
logger_set_filter(e->e->dl_ack_logger[i],
|
||||
ticktime_filter(e->database, "UE_PHY_DLSCH_UE_ACK", i, ue));
|
||||
ticktime_filter(e->database, "UE_PHY_DLSCH_UE_ACK", i));
|
||||
logger_set_filter(e->e->dl_nack_logger[i],
|
||||
ticktime_filter(e->database, "UE_PHY_DLSCH_UE_NACK", i, ue));
|
||||
ticktime_filter(e->database, "UE_PHY_DLSCH_UE_NACK", i));
|
||||
logger_set_filter(e->e->ul_dci_logger[i],
|
||||
ticktime_filter(e->database, "UE_PHY_ULSCH_UE_DCI", i, ue));
|
||||
ticktime_filter(e->database, "UE_PHY_ULSCH_UE_DCI", i));
|
||||
/*logger_set_filter(e->ul_dci_retransmission_logger[i],
|
||||
ticktime_filter(e->database,
|
||||
"ENB_PHY_ULSCH_UE_NO_DCI_RETRANSMISSION", i, ue));*/
|
||||
"ENB_PHY_ULSCH_UE_NO_DCI_RETRANSMISSION", i));*/
|
||||
logger_set_filter(e->e->ul_ack_logger[i],
|
||||
ticktime_filter(e->database, "UE_PHY_ULSCH_UE_ACK", i, ue));
|
||||
ticktime_filter(e->database, "UE_PHY_ULSCH_UE_ACK", i));
|
||||
logger_set_filter(e->e->ul_nack_logger[i],
|
||||
ticktime_filter(e->database, "UE_PHY_ULSCH_UE_NACK", i, ue));
|
||||
ticktime_filter(e->database, "UE_PHY_ULSCH_UE_NACK", i));
|
||||
}
|
||||
logger_set_filter(e->e->dl_mcs_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_DLSCH_UE_DCI", "UE_id"),
|
||||
filter_int(ue)));
|
||||
logger_set_filter(e->e->ul_mcs_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_ULSCH_UE_DCI", "UE_id"),
|
||||
filter_int(ue)));
|
||||
logger_set_filter(e->e->pusch_power_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_PUSCH_TX_POWER", "UE_id"),
|
||||
filter_int(ue)));
|
||||
logger_set_filter(e->e->pusch_ampl_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_PUSCH_TX_POWER", "UE_id"),
|
||||
filter_int(ue)));
|
||||
logger_set_filter(e->e->pucch_power_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_PUCCH_TX_POWER", "UE_id"),
|
||||
filter_int(ue)));
|
||||
logger_set_filter(e->e->pucch_ampl_logger,
|
||||
filter_eq(
|
||||
filter_evarg(e->database, "UE_PHY_PUCCH_TX_POWER", "UE_id"),
|
||||
filter_int(ue)));
|
||||
}
|
||||
|
||||
static void click(void *private, gui *g,
|
||||
char *notification, widget *w, void *notification_data)
|
||||
{
|
||||
int *d = notification_data;
|
||||
int button = d[0];
|
||||
ue_data *ed = private;
|
||||
ue_gui *e = ed->e;
|
||||
int ue = ed->ue;
|
||||
|
||||
if (button != 1) return;
|
||||
if (w == e->prev_ue_button) { ue--; if (ue < 0) ue = 0; }
|
||||
if (w == e->next_ue_button) ue++;
|
||||
|
||||
if (pthread_mutex_lock(&ed->lock)) abort();
|
||||
if (ue != ed->ue) {
|
||||
set_current_ue(g, ed, ue);
|
||||
ed->ue = ue;
|
||||
}
|
||||
if (pthread_mutex_unlock(&ed->lock)) abort();
|
||||
}
|
||||
|
||||
static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
|
||||
@@ -271,7 +192,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
|
||||
widget *text;
|
||||
view *textview;
|
||||
int i;
|
||||
widget *w, *w2;
|
||||
widget *w;
|
||||
view *v;
|
||||
logger *l;
|
||||
|
||||
@@ -283,24 +204,8 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
|
||||
widget_add_child(g, top_container, line, -1);
|
||||
logo = new_image(g, openair_logo_png, openair_logo_png_len);
|
||||
|
||||
/* logo + prev/next UE buttons */
|
||||
col = new_container(g, VERTICAL);
|
||||
widget_add_child(g, col, logo, -1);
|
||||
w = new_container(g, HORIZONTAL);
|
||||
widget_add_child(g, col, w, -1);
|
||||
w2 = new_label(g, "");
|
||||
widget_add_child(g, w, w2, -1);
|
||||
e->current_ue_label = w2;
|
||||
/* TODO: use button widget, not label widget */
|
||||
w2 = new_label(g, " [prev UE] ");
|
||||
widget_add_child(g, w, w2, -1);
|
||||
label_set_clickable(g, w2, 1);
|
||||
e->prev_ue_button = w2;
|
||||
w2 = new_label(g, " [next UE] ");
|
||||
widget_add_child(g, w, w2, -1);
|
||||
label_set_clickable(g, w2, 1);
|
||||
e->next_ue_button = w2;
|
||||
widget_add_child(g, line, col, -1);
|
||||
/* logo */
|
||||
widget_add_child(g, line, logo, -1);
|
||||
|
||||
input_signal_plot = new_xy_plot(g, 256, 55, "input signal", 20);
|
||||
widget_add_child(g, line, input_signal_plot, -1);
|
||||
@@ -356,80 +261,13 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0c720c"));
|
||||
logger_add_view(l, v);
|
||||
e->phy_meas_logger = l;
|
||||
|
||||
/* UE x PDSCH energy */
|
||||
w = new_xy_plot(g, 128, 55, "", 50);
|
||||
e->pdsch_energy_ue_xy_plot = w;
|
||||
|
||||
/* a bit of space */
|
||||
line = new_container(g, HORIZONTAL);
|
||||
widget_add_child(g, top_container, line, -1);
|
||||
w = new_space(g, 1, 10);
|
||||
widget_add_child(g, line, w, -1);
|
||||
xy_plot_set_range(g, w, 0, 1024*10, -10, 80);
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level00", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#ff0000"));
|
||||
logger_add_view(l, v);
|
||||
e->pdsch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level01", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#00ff00"));
|
||||
logger_add_view(l, v);
|
||||
e->pdsch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level10", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"));
|
||||
logger_add_view(l, v);
|
||||
e->pdsch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level11", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0000ff"));
|
||||
logger_add_view(l, v);
|
||||
e->pdsch_energy_logger = l;
|
||||
|
||||
/* UE x PDCCH energy */
|
||||
w = new_xy_plot(g, 128, 55, "", 50);
|
||||
e->pdcch_energy_ue_xy_plot = w;
|
||||
widget_add_child(g, line, w, -1);
|
||||
xy_plot_set_range(g, w, 0, 1024*10, -10, 80);
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level00", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#ff0000"));
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level01", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#00ff00"));
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level10", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"));
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level11", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0000ff"));
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_energy_logger = l;
|
||||
|
||||
/* UE x PDCCH IQ data */
|
||||
w = new_xy_plot(g, 55, 55, "", 50);
|
||||
e->pdcch_iq_ue_xy_plot = w;
|
||||
widget_add_child(g, line, w, -1);
|
||||
xy_plot_set_range(g, w, -100, 100, -100, 100);
|
||||
l = new_iqlog(h, database, "UE_PHY_PDCCH_IQ", "nb_rb",
|
||||
"NB_RB_DL", "symbols_per_tti", "rxdataF_comp");
|
||||
v = new_view_xy(100*12*14,10,g,w,new_color(g,"#000"),XY_FORCED_MODE);
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_iq_ue_logger = l;
|
||||
|
||||
/* UE x PDCCH IQ data */
|
||||
/*w = new_xy_plot(g, 55, 55, "", 50);
|
||||
e->pdcch_iq_ue_xy_plot = w;
|
||||
widget_add_child(g, line, w, -1);
|
||||
xy_plot_set_range(g, w, -2000, 2000, -2000, 2000);
|
||||
l = new_iqdotlog(h, database, "UE_PHY_PDCCH_IQ", "I", "Q");
|
||||
v = new_view_xy(500, 10, g, w, new_color(g,"#000"), XY_LOOP_MODE);
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_iq_ue_logger = l;*/
|
||||
|
||||
|
||||
/* UE x DL mcs */
|
||||
line = new_container(g, HORIZONTAL);
|
||||
widget_add_child(g, top_container, line, -1);
|
||||
@@ -448,7 +286,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
|
||||
xy_plot_set_range(g, w, 0, 1024*10, -2, 30);
|
||||
e->ul_mcs_xy_plot = w;
|
||||
widget_add_child(g, line, w, -1);
|
||||
l = new_ticked_ttilog(h, database, "UE_PHY_UL_TICK", "frame", "subframe",
|
||||
l = new_ticked_ttilog(h, database, "UE_PHY_DL_TICK", "frame", "subframe",
|
||||
"UE_PHY_ULSCH_UE_DCI", "mcs", 0, -1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"));
|
||||
logger_add_view(l, v);
|
||||
@@ -471,7 +309,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
|
||||
v = new_view_tti(10, g, w, new_color(g, "#720c0c"));
|
||||
logger_add_view(l, v);
|
||||
e->pusch_ampl_logger = l;
|
||||
|
||||
|
||||
/* UE x PUCCH TX Power */
|
||||
// line = new_container(g, HORIZONTAL);
|
||||
// widget_add_child(g, top_container, line, -1);
|
||||
@@ -489,8 +327,81 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
|
||||
v = new_view_tti(10, g, w, new_color(g, "#720c0c"));
|
||||
logger_add_view(l, v);
|
||||
e->pucch_ampl_logger = l;
|
||||
|
||||
|
||||
|
||||
/* UE x PDSCH energy */
|
||||
w = new_xy_plot(g, 128, 55, "", 50);
|
||||
e->pdsch_energy_ue_xy_plot = w;
|
||||
widget_add_child(g, line, w, -1);
|
||||
xy_plot_set_range(g, w, 0, 1024*10, -10, 80);
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level00", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#ff0000"));
|
||||
logger_add_view(l, v);
|
||||
e->pdsch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level01", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#00ff00"));
|
||||
logger_add_view(l, v);
|
||||
e->pdsch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level10", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"));
|
||||
logger_add_view(l, v);
|
||||
e->pdsch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level11", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0000ff"));
|
||||
logger_add_view(l, v);
|
||||
e->pdsch_energy_logger = l;
|
||||
|
||||
/* UE x PDCCH energy */
|
||||
w = new_xy_plot(g, 128, 55, "", 50);
|
||||
e->pdcch_energy_ue_xy_plot = w;
|
||||
widget_add_child(g, line, w, -1);
|
||||
xy_plot_set_range(g, w, 0, 1024*10, -10, 80);
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level00", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#ff0000"));
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level01", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#00ff00"));
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level10", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"));
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_energy_logger = l;
|
||||
l = new_ttilog(h, database,
|
||||
"UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level11", 1);
|
||||
v = new_view_tti(10, g, w, new_color(g, "#0000ff"));
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_energy_logger = l;
|
||||
|
||||
/* UE x PDCCH IQ data */
|
||||
w = new_xy_plot(g, 55, 55, "", 50);
|
||||
e->pdcch_iq_ue_xy_plot = w;
|
||||
widget_add_child(g, line, w, -1);
|
||||
xy_plot_set_range(g, w, -100, 100, -100, 100);
|
||||
l = new_iqlog(h, database, "UE_PHY_PDCCH_IQ", "nb_rb",
|
||||
"NB_RB_DL", "symbols_per_tti", "rxdataF_comp");
|
||||
v = new_view_xy(100*12*14,10,g,w,new_color(g,"#000"),XY_FORCED_MODE);
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_iq_ue_logger = l;
|
||||
|
||||
/* UE x PDCCH IQ data */
|
||||
/*w = new_xy_plot(g, 55, 55, "", 50);
|
||||
e->pdcch_iq_ue_xy_plot = w;
|
||||
widget_add_child(g, line, w, -1);
|
||||
xy_plot_set_range(g, w, -2000, 2000, -2000, 2000);
|
||||
l = new_iqdotlog(h, database, "UE_PHY_PDCCH_IQ", "I", "Q");
|
||||
v = new_view_xy(500, 10, g, w, new_color(g,"#000"), XY_LOOP_MODE);
|
||||
logger_add_view(l, v);
|
||||
e->pdcch_iq_ue_logger = l;*/
|
||||
|
||||
|
||||
/* downlink/uplink UE DCIs */
|
||||
widget_add_child(g, top_container,
|
||||
new_label(g,"DL/UL TICK/DCI/ACK/NACK [all UEs]"), -1);
|
||||
@@ -600,14 +511,14 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
|
||||
logger_add_view(timelog, subview);
|
||||
e->ul_dci_logger[i] = timelog;
|
||||
/* retransmission */
|
||||
|
||||
|
||||
timelog = new_ticklog(h, database,
|
||||
"ENB_PHY_ULSCH_UE_NO_DCI_RETRANSMISSION", "frame", "subframe");
|
||||
subview = new_subview_ticktime(timeview, i+9+1,
|
||||
new_color(g,"#99f"), 3600*1000);
|
||||
logger_add_view(timelog, subview);
|
||||
e->ul_dci_retransmission_logger[i] = timelog;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* UL ACK */
|
||||
@@ -707,8 +618,6 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database,
|
||||
#endif
|
||||
|
||||
set_current_ue(g, ed, 0);
|
||||
register_notifier(g, "click", e->prev_ue_button, click, ed);
|
||||
register_notifier(g, "click", e->next_ue_button, click, ed);
|
||||
}
|
||||
|
||||
void view_add_log(view *v, char *log, event_handler *h, void *database,
|
||||
@@ -824,13 +733,11 @@ int main(int n, char **v)
|
||||
on_off(database, "UE_PHY_PUSCH_TX_POWER", is_on, 1);
|
||||
on_off(database, "UE_PHY_PUCCH_TX_POWER", is_on, 1);
|
||||
on_off(database, "UE_PHY_MEAS", is_on, 1);
|
||||
|
||||
|
||||
on_off(database, "LEGACY_GROUP_INFO", is_on, 1);
|
||||
on_off(database, "LEGACY_GROUP_ERROR", is_on, 1);
|
||||
on_off(database, "LEGACY_GROUP_WARNING", is_on, 1);
|
||||
|
||||
view_add_log(eg.phyview, "UE_PHY_UL_TICK", h, database, is_on);
|
||||
view_add_log(eg.phyview, "UE_PHY_DL_TICK", h, database, is_on);
|
||||
|
||||
view_add_log(eg.phyview, "UE_PHY_DLSCH_UE_DCI", h, database, is_on);
|
||||
view_add_log(eg.phyview, "UE_PHY_DLSCH_UE_ACK", h, database, is_on);
|
||||
view_add_log(eg.phyview, "UE_PHY_DLSCH_UE_NACK",h, database, is_on);
|
||||
@@ -838,8 +745,6 @@ int main(int n, char **v)
|
||||
view_add_log(eg.phyview, "UE_PHY_ULSCH_UE_ACK", h, database, is_on);
|
||||
view_add_log(eg.phyview, "UE_PHY_ULSCH_UE_NACK", h, database, is_on);
|
||||
|
||||
|
||||
|
||||
/* deactivate those two by default, they are a bit heavy */
|
||||
//on_off(database, "ENB_MAC_UE_UL_SDU_WITH_DATA", is_on, 0);
|
||||
//on_off(database, "ENB_MAC_UE_UL_PDU_WITH_DATA", is_on, 0);
|
||||
|
||||
+100
-67
@@ -9,27 +9,38 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <math.h>
|
||||
|
||||
void new_thread(void *(*f)(void *), void *data)
|
||||
{
|
||||
void new_thread(void *(*f)(void *), void *data) {
|
||||
pthread_t t;
|
||||
pthread_attr_t att;
|
||||
|
||||
if (pthread_attr_init(&att))
|
||||
{ fprintf(stderr, "pthread_attr_init err\n"); exit(1); }
|
||||
if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED))
|
||||
{ fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); }
|
||||
if (pthread_attr_setstacksize(&att, 10000000))
|
||||
{ fprintf(stderr, "pthread_attr_setstacksize err\n"); exit(1); }
|
||||
if (pthread_create(&t, &att, f, data))
|
||||
{ fprintf(stderr, "pthread_create err\n"); exit(1); }
|
||||
if (pthread_attr_destroy(&att))
|
||||
{ fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); }
|
||||
if (pthread_attr_init(&att)) {
|
||||
fprintf(stderr, "pthread_attr_init err\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) {
|
||||
fprintf(stderr, "pthread_attr_setdetachstate err\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_attr_setstacksize(&att, 10000000)) {
|
||||
fprintf(stderr, "pthread_attr_setstacksize err\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_create(&t, &att, f, data)) {
|
||||
fprintf(stderr, "pthread_create err\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_attr_destroy(&att)) {
|
||||
fprintf(stderr, "pthread_attr_destroy err\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void sleepms(int ms)
|
||||
{
|
||||
void sleepms(int ms) {
|
||||
struct timespec t;
|
||||
|
||||
t.tv_sec = ms / 1000;
|
||||
t.tv_nsec = (ms % 1000) * 1000000L;
|
||||
|
||||
@@ -37,12 +48,15 @@ void sleepms(int ms)
|
||||
if (nanosleep(&t, NULL)) abort();
|
||||
}
|
||||
|
||||
void bps(char *out, float v, char *suffix)
|
||||
{
|
||||
void bps(char *out, float v, char *suffix) {
|
||||
static char *bps_unit[4] = { "", "k", "M", "G" };
|
||||
int flog;
|
||||
if (v < 1000) flog = 0; else flog = floor(floor(log10(v)) / 3);
|
||||
|
||||
if (v < 1000) flog = 0;
|
||||
else flog = floor(floor(log10(v)) / 3);
|
||||
|
||||
if (flog > 3) flog = 3;
|
||||
|
||||
v /= pow(10, flog*3);
|
||||
sprintf(out, "%g%s%s", round(v*100)/100, bps_unit[flog], suffix);
|
||||
}
|
||||
@@ -51,25 +65,31 @@ void bps(char *out, float v, char *suffix)
|
||||
/* list */
|
||||
/****************************************************************************/
|
||||
|
||||
list *list_remove_head(list *l)
|
||||
{
|
||||
list *list_remove_head(list *l) {
|
||||
list *ret;
|
||||
|
||||
if (l == NULL) return NULL;
|
||||
|
||||
ret = l->next;
|
||||
|
||||
if (ret != NULL) ret->last = l->last;
|
||||
|
||||
free(l);
|
||||
return ret;
|
||||
}
|
||||
|
||||
list *list_append(list *l, void *data)
|
||||
{
|
||||
list *list_append(list *l, void *data) {
|
||||
list *new = calloc(1, sizeof(list));
|
||||
|
||||
if (new == NULL) abort();
|
||||
|
||||
new->data = data;
|
||||
|
||||
if (l == NULL) {
|
||||
new->last = new;
|
||||
return new;
|
||||
}
|
||||
|
||||
l->last->next = new;
|
||||
l->last = new;
|
||||
return l;
|
||||
@@ -79,88 +99,107 @@ list *list_append(list *l, void *data)
|
||||
/* socket */
|
||||
/****************************************************************************/
|
||||
|
||||
int create_listen_socket(char *addr, int port)
|
||||
{
|
||||
int create_listen_socket(char *addr, int port) {
|
||||
struct sockaddr_in a;
|
||||
int s;
|
||||
int v;
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) { perror("socket"); exit(1); }
|
||||
|
||||
if (s == -1) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
v = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(int)))
|
||||
{ perror("setsockopt"); exit(1); }
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(int))) {
|
||||
perror("setsockopt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = htons(port);
|
||||
a.sin_addr.s_addr = inet_addr(addr);
|
||||
|
||||
if (bind(s, (struct sockaddr *)&a, sizeof(a))) { perror("bind"); exit(1); }
|
||||
if (listen(s, 5)) { perror("listen"); exit(1); }
|
||||
if (bind(s, (struct sockaddr *)&a, sizeof(a))) {
|
||||
perror("bind");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (listen(s, 5)) {
|
||||
perror("listen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int socket_accept(int s)
|
||||
{
|
||||
int socket_accept(int s) {
|
||||
struct sockaddr_in a;
|
||||
socklen_t alen;
|
||||
alen = sizeof(a);
|
||||
return accept(s, (struct sockaddr *)&a, &alen);
|
||||
}
|
||||
|
||||
int socket_send(int socket, void *buffer, int size)
|
||||
{
|
||||
int socket_send(int socket, void *buffer, int size) {
|
||||
char *x = buffer;
|
||||
int ret;
|
||||
|
||||
while (size) {
|
||||
ret = write(socket, x, size);
|
||||
|
||||
if (ret <= 0) return -1;
|
||||
|
||||
size -= ret;
|
||||
x += ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_connection(char *addr, int port)
|
||||
{
|
||||
int get_connection(char *addr, int port) {
|
||||
int s, t;
|
||||
|
||||
printf("waiting for connection on %s:%d\n", addr, port);
|
||||
|
||||
s = create_listen_socket(addr, port);
|
||||
|
||||
t = socket_accept(s);
|
||||
if (t == -1) { perror("accept"); exit(1); }
|
||||
|
||||
if (t == -1) {
|
||||
perror("accept");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
printf("connected\n");
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
int fullread(int fd, void *_buf, int count)
|
||||
{
|
||||
int fullread(int fd, void *_buf, int count) {
|
||||
char *buf = _buf;
|
||||
int ret = 0;
|
||||
int l;
|
||||
|
||||
while (count) {
|
||||
l = read(fd, buf, count);
|
||||
|
||||
if (l <= 0) return -1;
|
||||
|
||||
count -= l;
|
||||
buf += l;
|
||||
ret += l;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int try_connect_to(char *addr, int port)
|
||||
{
|
||||
int try_connect_to(char *addr, int port) {
|
||||
int s;
|
||||
struct sockaddr_in a;
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) { perror("socket"); exit(1); }
|
||||
|
||||
if (s == -1) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
a.sin_family = AF_INET;
|
||||
a.sin_port = htons(port);
|
||||
@@ -175,14 +214,12 @@ int try_connect_to(char *addr, int port)
|
||||
return s;
|
||||
}
|
||||
|
||||
int connect_to(char *addr, int port)
|
||||
{
|
||||
int connect_to(char *addr, int port) {
|
||||
int s;
|
||||
|
||||
printf("connecting to %s:%d\n", addr, port);
|
||||
|
||||
again:
|
||||
s = try_connect_to(addr, port);
|
||||
|
||||
if (s == -1) {
|
||||
printf("trying again in 1s\n");
|
||||
sleep(1);
|
||||
@@ -196,50 +233,46 @@ again:
|
||||
/* buffer */
|
||||
/****************************************************************************/
|
||||
|
||||
void PUTC(OBUF *o, char c)
|
||||
{
|
||||
void PUTC(OBUF *o, char c) {
|
||||
if (o->osize == o->omaxsize) {
|
||||
o->omaxsize += 512;
|
||||
o->obuf = realloc(o->obuf, o->omaxsize);
|
||||
|
||||
if (o->obuf == NULL) abort();
|
||||
}
|
||||
|
||||
o->obuf[o->osize] = c;
|
||||
o->osize++;
|
||||
}
|
||||
|
||||
void PUTS(OBUF *o, char *s)
|
||||
{
|
||||
void PUTS(OBUF *o, char *s) {
|
||||
while (*s) PUTC(o, *s++);
|
||||
}
|
||||
|
||||
static int clean(char c)
|
||||
{
|
||||
static int clean(char c) {
|
||||
if (!isprint(c)) c = ' ';
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void PUTS_CLEAN(OBUF *o, char *s)
|
||||
{
|
||||
void PUTS_CLEAN(OBUF *o, char *s) {
|
||||
while (*s) PUTC(o, clean(*s++));
|
||||
}
|
||||
|
||||
void PUTI(OBUF *o, int i)
|
||||
{
|
||||
void PUTI(OBUF *o, int i) {
|
||||
char s[64];
|
||||
sprintf(s, "%d", i);
|
||||
PUTS(o, s);
|
||||
}
|
||||
|
||||
void PUTX2(OBUF *o, int i)
|
||||
{
|
||||
void PUTX2(OBUF *o, int i) {
|
||||
char s[64];
|
||||
sprintf(s, "%2.2x", i);
|
||||
PUTS(o, s);
|
||||
}
|
||||
|
||||
void PUTUL(OBUF *o, unsigned long l)
|
||||
{
|
||||
void PUTUL(OBUF *o, unsigned long l) {
|
||||
char s[128];
|
||||
sprintf(s, "%ld", l);
|
||||
sprintf(s, "%lu", l);
|
||||
PUTS(o, s);
|
||||
}
|
||||
|
||||
@@ -35,13 +35,11 @@
|
||||
|
||||
void output_log_mem(void);
|
||||
#define _Assert_Exit_ \
|
||||
{ \
|
||||
fprintf(stderr, "\nExiting execution\n"); \
|
||||
display_backtrace(); \
|
||||
fflush(stdout); \
|
||||
fflush(stderr); \
|
||||
exit(EXIT_FAILURE); \
|
||||
}
|
||||
|
||||
#define _Assert_(cOND, aCTION, fORMAT, aRGS...) \
|
||||
do { \
|
||||
|
||||
@@ -31,18 +31,18 @@
|
||||
#include "backtrace.h"
|
||||
|
||||
/* Obtain a backtrace and print it to stdout. */
|
||||
void display_backtrace(void)
|
||||
{
|
||||
void display_backtrace(void) {
|
||||
void *array[10];
|
||||
size_t size;
|
||||
char **strings;
|
||||
size_t i;
|
||||
char* test=getenv("NO_BACKTRACE");
|
||||
if (test!=0) *((int*)0)=0;
|
||||
char *test=getenv("NO_BACKTRACE");
|
||||
|
||||
if (test!=0) *((int *)0)=0;
|
||||
|
||||
size = backtrace(array, 10);
|
||||
strings = backtrace_symbols(array, size);
|
||||
|
||||
printf("Obtained %zd stack frames.\n", size);
|
||||
printf("Obtained %u stack frames.\n", (unsigned int)size);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
printf("%s\n", strings[i]);
|
||||
@@ -50,8 +50,7 @@ void display_backtrace(void)
|
||||
free(strings);
|
||||
}
|
||||
|
||||
void backtrace_handle_signal(siginfo_t *info)
|
||||
{
|
||||
void backtrace_handle_signal(siginfo_t *info) {
|
||||
display_backtrace();
|
||||
//exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+257
-217
@@ -2,9 +2,9 @@
|
||||
* 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 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.
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
@@ -28,17 +28,33 @@
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
char* hashtable_rc_code2string(hashtable_rc_t rcP)
|
||||
char *hashtable_rc_code2string(hashtable_rc_t rcP)
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
switch (rcP) {
|
||||
case HASH_TABLE_OK: return "HASH_TABLE_OK";break;
|
||||
case HASH_TABLE_INSERT_OVERWRITTEN_DATA: return "HASH_TABLE_INSERT_OVERWRITTEN_DATA";break;
|
||||
case HASH_TABLE_KEY_NOT_EXISTS: return "HASH_TABLE_KEY_NOT_EXISTS";break;
|
||||
case HASH_TABLE_KEY_ALREADY_EXISTS: return "HASH_TABLE_KEY_ALREADY_EXISTS";break;
|
||||
case HASH_TABLE_BAD_PARAMETER_HASHTABLE: return "HASH_TABLE_BAD_PARAMETER_HASHTABLE";break;
|
||||
default: return "UNKNOWN hashtable_rc_t";
|
||||
}
|
||||
switch (rcP) {
|
||||
case HASH_TABLE_OK:
|
||||
return "HASH_TABLE_OK";
|
||||
break;
|
||||
|
||||
case HASH_TABLE_INSERT_OVERWRITTEN_DATA:
|
||||
return "HASH_TABLE_INSERT_OVERWRITTEN_DATA";
|
||||
break;
|
||||
|
||||
case HASH_TABLE_KEY_NOT_EXISTS:
|
||||
return "HASH_TABLE_KEY_NOT_EXISTS";
|
||||
break;
|
||||
|
||||
case HASH_TABLE_KEY_ALREADY_EXISTS:
|
||||
return "HASH_TABLE_KEY_ALREADY_EXISTS";
|
||||
break;
|
||||
|
||||
case HASH_TABLE_BAD_PARAMETER_HASHTABLE:
|
||||
return "HASH_TABLE_BAD_PARAMETER_HASHTABLE";
|
||||
break;
|
||||
|
||||
default:
|
||||
return "UNKNOWN hashtable_rc_t";
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
@@ -46,7 +62,7 @@ char* hashtable_rc_code2string(hashtable_rc_t rcP)
|
||||
* hash_free_int_func() is used when this hashtable is used to store int values as data (pointer = value).
|
||||
*/
|
||||
|
||||
void hash_free_int_func(void* memoryP){}
|
||||
void hash_free_int_func(void *memoryP) {}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
@@ -55,9 +71,8 @@ void hash_free_int_func(void* memoryP){}
|
||||
* This is a simple/naive hash function which adds the key's ASCII char values. It will probably generate lots of collisions on large hash tables.
|
||||
*/
|
||||
|
||||
static hash_size_t def_hashfunc(const uint64_t keyP)
|
||||
{
|
||||
return (hash_size_t)keyP;
|
||||
static hash_size_t def_hashfunc(const uint64_t keyP) {
|
||||
return (hash_size_t)keyP;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -67,132 +82,147 @@ static hash_size_t def_hashfunc(const uint64_t keyP)
|
||||
* The user can also specify a hash function. If the hashfunc argument is NULL, a default hash function is used.
|
||||
* If an error occurred, NULL is returned. All other values in the returned hash_table_t pointer should be released with hashtable_destroy().
|
||||
*/
|
||||
hash_table_t *hashtable_create(const hash_size_t sizeP, hash_size_t (*hashfuncP)(const hash_key_t ), void (*freefuncP)(void*))
|
||||
{
|
||||
hash_table_t *hashtbl = NULL;
|
||||
hash_table_t *hashtable_create(const hash_size_t sizeP, hash_size_t (*hashfuncP)(const hash_key_t ), void (*freefuncP)(void *)) {
|
||||
hash_table_t *hashtbl = NULL;
|
||||
|
||||
if(!(hashtbl=malloc(sizeof(hash_table_t)))) {
|
||||
return NULL;
|
||||
}
|
||||
if(!(hashtbl=malloc(sizeof(hash_table_t)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!(hashtbl->nodes=calloc(sizeP, sizeof(hash_node_t*)))) {
|
||||
free(hashtbl);
|
||||
return NULL;
|
||||
}
|
||||
if(!(hashtbl->nodes=calloc(sizeP, sizeof(hash_node_t *)))) {
|
||||
free(hashtbl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hashtbl->size=sizeP;
|
||||
hashtbl->size=sizeP;
|
||||
|
||||
if(hashfuncP) hashtbl->hashfunc=hashfuncP;
|
||||
else hashtbl->hashfunc=def_hashfunc;
|
||||
if(hashfuncP) hashtbl->hashfunc=hashfuncP;
|
||||
else hashtbl->hashfunc=def_hashfunc;
|
||||
|
||||
if(freefuncP) hashtbl->freefunc=freefuncP;
|
||||
else hashtbl->freefunc=free;
|
||||
if(freefuncP) hashtbl->freefunc=freefuncP;
|
||||
else hashtbl->freefunc=free;
|
||||
|
||||
return hashtbl;
|
||||
return hashtbl;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
* Cleanup
|
||||
* The hashtable_destroy() walks through the linked lists for each possible hash value, and releases the elements. It also releases the nodes array and the hash_table_t.
|
||||
*/
|
||||
hashtable_rc_t hashtable_destroy(hash_table_t * hashtblP)
|
||||
{
|
||||
hash_size_t n;
|
||||
hash_node_t *node, *oldnode;
|
||||
hashtable_rc_t hashtable_destroy(hash_table_t **hashtblP) {
|
||||
hash_size_t n;
|
||||
hash_node_t *node, *oldnode;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
if (*hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
for(n=0; n<hashtblP->size; ++n) {
|
||||
node=hashtblP->nodes[n];
|
||||
while(node) {
|
||||
oldnode=node;
|
||||
node=node->next;
|
||||
if (oldnode->data) {
|
||||
hashtblP->freefunc(oldnode->data);
|
||||
}
|
||||
free(oldnode);
|
||||
}
|
||||
}
|
||||
free(hashtblP->nodes);
|
||||
free(hashtblP);
|
||||
hashtblP=NULL;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
hashtable_rc_t hashtable_is_key_exists (const hash_table_t * const hashtblP, const hash_key_t keyP)
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
hash_node_t *node = NULL;
|
||||
hash_size_t hash = 0;
|
||||
for(n=0; n<(*hashtblP)->size; ++n) {
|
||||
node=(*hashtblP)->nodes[n];
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
oldnode=node;
|
||||
node=node->next;
|
||||
|
||||
if (oldnode->data) {
|
||||
(*hashtblP)->freefunc(oldnode->data);
|
||||
}
|
||||
|
||||
free(oldnode);
|
||||
}
|
||||
}
|
||||
|
||||
free((*hashtblP)->nodes);
|
||||
free((*hashtblP));
|
||||
*hashtblP=NULL;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
hashtable_rc_t hashtable_is_key_exists (const hash_table_t *const hashtblP, const hash_key_t keyP)
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
hash_node_t *node = NULL;
|
||||
hash_size_t hash = 0;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
|
||||
node=node->next;
|
||||
}
|
||||
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
hashtable_rc_t hashtable_apply_funct_on_elements (hash_table_t *const hashtblP, void functP(hash_key_t keyP, void *dataP, void *parameterP), void *parameterP)
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
hash_node_t *node = NULL;
|
||||
unsigned int i = 0;
|
||||
unsigned int num_elements = 0;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
while ((num_elements < hashtblP->num_elements) && (i < hashtblP->size)) {
|
||||
if (hashtblP->nodes[i] != NULL) {
|
||||
node=hashtblP->nodes[i];
|
||||
|
||||
while(node) {
|
||||
num_elements += 1;
|
||||
functP(node->key, node->data, parameterP);
|
||||
node=node->next;
|
||||
}
|
||||
}
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
hashtable_rc_t hashtable_apply_funct_on_elements (hash_table_t *const hashtblP, void functP(hash_key_t keyP, void* dataP, void* parameterP), void* parameterP)
|
||||
hashtable_rc_t hashtable_dump_content (const hash_table_t *const hashtblP, char *const buffer_pP, int *const remaining_bytes_in_buffer_pP )
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
hash_node_t *node = NULL;
|
||||
unsigned int i = 0;
|
||||
unsigned int num_elements = 0;
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
while ((num_elements < hashtblP->num_elements) && (i < hashtblP->size)) {
|
||||
if (hashtblP->nodes[i] != NULL) {
|
||||
node=hashtblP->nodes[i];
|
||||
while(node) {
|
||||
num_elements += 1;
|
||||
functP(node->key, node->data, parameterP);
|
||||
node=node->next;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
hashtable_rc_t hashtable_dump_content (const hash_table_t * const hashtblP, char * const buffer_pP, int * const remaining_bytes_in_buffer_pP )
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
hash_node_t *node = NULL;
|
||||
unsigned int i = 0;
|
||||
if (hashtblP == NULL) {
|
||||
hash_node_t *node = NULL;
|
||||
unsigned int i = 0;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
*remaining_bytes_in_buffer_pP = snprintf(
|
||||
buffer_pP,
|
||||
*remaining_bytes_in_buffer_pP,
|
||||
"HASH_TABLE_BAD_PARAMETER_HASHTABLE");
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
while ((i < hashtblP->size) && (*remaining_bytes_in_buffer_pP > 0)) {
|
||||
if (hashtblP->nodes[i] != NULL) {
|
||||
node=hashtblP->nodes[i];
|
||||
|
||||
while(node) {
|
||||
*remaining_bytes_in_buffer_pP = snprintf(
|
||||
buffer_pP,
|
||||
*remaining_bytes_in_buffer_pP,
|
||||
"HASH_TABLE_BAD_PARAMETER_HASHTABLE");
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
buffer_pP,
|
||||
*remaining_bytes_in_buffer_pP,
|
||||
"Key 0x%"PRIx64" Element %p\n",
|
||||
node->key,
|
||||
node->data);
|
||||
node=node->next;
|
||||
}
|
||||
}
|
||||
while ((i < hashtblP->size) && (*remaining_bytes_in_buffer_pP > 0)) {
|
||||
if (hashtblP->nodes[i] != NULL) {
|
||||
node=hashtblP->nodes[i];
|
||||
while(node) {
|
||||
*remaining_bytes_in_buffer_pP = snprintf(
|
||||
buffer_pP,
|
||||
*remaining_bytes_in_buffer_pP,
|
||||
"Key 0x%"PRIx64" Element %p\n",
|
||||
node->key,
|
||||
node->data);
|
||||
node=node->next;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return HASH_TABLE_OK;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -200,97 +230,110 @@ hashtable_rc_t hashtable_dump_content (const hash_table_t * const hashtblP, char
|
||||
* Adding a new element
|
||||
* To make sure the hash value is not bigger than size, the result of the user provided hash function is used modulo size.
|
||||
*/
|
||||
hashtable_rc_t hashtable_insert(hash_table_t * const hashtblP, const hash_key_t keyP, void *dataP)
|
||||
{
|
||||
hash_node_t *node = NULL;
|
||||
hash_size_t hash = 0;
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
hash=hashtblP->hashfunc(keyP)%hashtblP->size;
|
||||
hashtable_rc_t hashtable_insert(hash_table_t *const hashtblP, const hash_key_t keyP, void *dataP) {
|
||||
hash_node_t *node = NULL;
|
||||
hash_size_t hash = 0;
|
||||
|
||||
node=hashtblP->nodes[hash];
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
if (node->data) {
|
||||
hashtblP->freefunc(node->data);
|
||||
}
|
||||
node->data=dataP;
|
||||
return HASH_TABLE_INSERT_OVERWRITTEN_DATA;
|
||||
}
|
||||
node=node->next;
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
if (node->data) {
|
||||
hashtblP->freefunc(node->data);
|
||||
}
|
||||
|
||||
node->data=dataP;
|
||||
return HASH_TABLE_INSERT_OVERWRITTEN_DATA;
|
||||
}
|
||||
if(!(node=malloc(sizeof(hash_node_t)))) return -1;
|
||||
node->key=keyP;
|
||||
node->data=dataP;
|
||||
if (hashtblP->nodes[hash]) {
|
||||
node->next=hashtblP->nodes[hash];
|
||||
} else {
|
||||
node->next = NULL;
|
||||
}
|
||||
hashtblP->nodes[hash]=node;
|
||||
hashtblP->num_elements += 1;
|
||||
return HASH_TABLE_OK;
|
||||
|
||||
node=node->next;
|
||||
}
|
||||
|
||||
if(!(node=malloc(sizeof(hash_node_t)))) return -1;
|
||||
|
||||
node->key=keyP;
|
||||
node->data=dataP;
|
||||
|
||||
if (hashtblP->nodes[hash]) {
|
||||
node->next=hashtblP->nodes[hash];
|
||||
} else {
|
||||
node->next = NULL;
|
||||
}
|
||||
|
||||
hashtblP->nodes[hash]=node;
|
||||
hashtblP->num_elements += 1;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
* To remove an element from the hash table, we just search for it in the linked list for that hash value,
|
||||
* and remove it if it is found. If it was not found, it is an error and -1 is returned.
|
||||
*/
|
||||
hashtable_rc_t hashtable_remove(hash_table_t * const hashtblP, const hash_key_t keyP)
|
||||
{
|
||||
hash_node_t *node, *prevnode=NULL;
|
||||
hash_size_t hash = 0;
|
||||
hashtable_rc_t hashtable_remove(hash_table_t *const hashtblP, const hash_key_t keyP) {
|
||||
hash_node_t *node, *prevnode=NULL;
|
||||
hash_size_t hash = 0;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
if(prevnode) prevnode->next=node->next;
|
||||
else hashtblP->nodes[hash]=node->next;
|
||||
|
||||
if (node->data) {
|
||||
hashtblP->freefunc(node->data);
|
||||
}
|
||||
|
||||
free(node);
|
||||
hashtblP->num_elements -= 1;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
hash=hashtblP->hashfunc(keyP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
if(prevnode) prevnode->next=node->next;
|
||||
else hashtblP->nodes[hash]=node->next;
|
||||
if (node->data) {
|
||||
hashtblP->freefunc(node->data);
|
||||
}
|
||||
free(node);
|
||||
hashtblP->num_elements -= 1;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
prevnode=node;
|
||||
node=node->next;
|
||||
}
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
|
||||
prevnode=node;
|
||||
node=node->next;
|
||||
}
|
||||
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
* Searching for an element is easy. We just search through the linked list for the corresponding hash value.
|
||||
* NULL is returned if we didn't find it.
|
||||
*/
|
||||
hashtable_rc_t hashtable_get(const hash_table_t * const hashtblP, const hash_key_t keyP, void** dataP)
|
||||
{
|
||||
hash_node_t *node = NULL;
|
||||
hash_size_t hash = 0;
|
||||
hashtable_rc_t hashtable_get(const hash_table_t *const hashtblP, const hash_key_t keyP, void **dataP) {
|
||||
hash_node_t *node = NULL;
|
||||
hash_size_t hash = 0;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
*dataP = NULL;
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
hash=hashtblP->hashfunc(keyP)%hashtblP->size;
|
||||
/* fprintf(stderr, "hashtable_get() key=%s, hash=%d\n", key, hash);*/
|
||||
|
||||
node=hashtblP->nodes[hash];
|
||||
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
*dataP = node->data;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
node=node->next;
|
||||
}
|
||||
if (hashtblP == NULL) {
|
||||
*dataP = NULL;
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP)%hashtblP->size;
|
||||
/* fprintf(stderr, "hashtable_get() key=%s, hash=%d\n", key, hash);*/
|
||||
node=hashtblP->nodes[hash];
|
||||
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
*dataP = node->data;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
|
||||
node=node->next;
|
||||
}
|
||||
|
||||
*dataP = NULL;
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
@@ -304,36 +347,33 @@ hashtable_rc_t hashtable_get(const hash_table_t * const hashtblP, const hash_key
|
||||
* After that, we can just free the old table and copy the elements from newtbl to hashtbl.
|
||||
*/
|
||||
|
||||
hashtable_rc_t hashtable_resize(hash_table_t * const hashtblP, const hash_size_t sizeP)
|
||||
{
|
||||
hash_table_t newtbl;
|
||||
hash_size_t n;
|
||||
hash_node_t *node,*next;
|
||||
hashtable_rc_t hashtable_resize(hash_table_t *const hashtblP, const hash_size_t sizeP) {
|
||||
hash_table_t newtbl;
|
||||
hash_size_t n;
|
||||
hash_node_t *node,*next;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
newtbl.size = sizeP;
|
||||
newtbl.hashfunc = hashtblP->hashfunc;
|
||||
|
||||
if(!(newtbl.nodes=calloc(sizeP, sizeof(hash_node_t *)))) return -1;
|
||||
|
||||
for(n=0; n<hashtblP->size; ++n) {
|
||||
for(node=hashtblP->nodes[n]; node; node=next) {
|
||||
next = node->next;
|
||||
hashtable_insert(&newtbl, node->key, node->data);
|
||||
// Lionel GAUTHIER: BAD CODE TO BE REWRITTEN
|
||||
hashtable_remove(hashtblP, node->key);
|
||||
}
|
||||
}
|
||||
|
||||
newtbl.size = sizeP;
|
||||
newtbl.hashfunc = hashtblP->hashfunc;
|
||||
|
||||
if(!(newtbl.nodes=calloc(sizeP, sizeof(hash_node_t*)))) return -1;
|
||||
|
||||
for(n=0; n<hashtblP->size; ++n) {
|
||||
for(node=hashtblP->nodes[n]; node; node=next) {
|
||||
next = node->next;
|
||||
hashtable_insert(&newtbl, node->key, node->data);
|
||||
// Lionel GAUTHIER: BAD CODE TO BE REWRITTEN
|
||||
hashtable_remove(hashtblP, node->key);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
free(hashtblP->nodes);
|
||||
hashtblP->size=newtbl.size;
|
||||
hashtblP->nodes=newtbl.nodes;
|
||||
|
||||
return HASH_TABLE_OK;
|
||||
free(hashtblP->nodes);
|
||||
hashtblP->size=newtbl.size;
|
||||
hashtblP->nodes=newtbl.nodes;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* 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 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.
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
@@ -31,41 +31,41 @@ typedef uint64_t hash_key_t;
|
||||
#define HASHTABLE_NOT_A_KEY_VALUE ((uint64_t)-1)
|
||||
|
||||
typedef enum hashtable_return_code_e {
|
||||
HASH_TABLE_OK = 0,
|
||||
HASH_TABLE_INSERT_OVERWRITTEN_DATA = 1,
|
||||
HASH_TABLE_KEY_NOT_EXISTS = 2,
|
||||
HASH_TABLE_KEY_ALREADY_EXISTS = 3,
|
||||
HASH_TABLE_BAD_PARAMETER_HASHTABLE = 4,
|
||||
HASH_TABLE_SYSTEM_ERROR = 5,
|
||||
HASH_TABLE_CODE_MAX
|
||||
HASH_TABLE_OK = 0,
|
||||
HASH_TABLE_INSERT_OVERWRITTEN_DATA = 1,
|
||||
HASH_TABLE_KEY_NOT_EXISTS = 2,
|
||||
HASH_TABLE_KEY_ALREADY_EXISTS = 3,
|
||||
HASH_TABLE_BAD_PARAMETER_HASHTABLE = 4,
|
||||
HASH_TABLE_SYSTEM_ERROR = 5,
|
||||
HASH_TABLE_CODE_MAX
|
||||
} hashtable_rc_t;
|
||||
|
||||
|
||||
typedef struct hash_node_s {
|
||||
hash_key_t key;
|
||||
void *data;
|
||||
struct hash_node_s *next;
|
||||
hash_key_t key;
|
||||
void *data;
|
||||
struct hash_node_s *next;
|
||||
} hash_node_t;
|
||||
|
||||
typedef struct hash_table_s {
|
||||
hash_size_t size;
|
||||
hash_size_t num_elements;
|
||||
struct hash_node_s **nodes;
|
||||
hash_size_t (*hashfunc)(const hash_key_t);
|
||||
void (*freefunc)(void*);
|
||||
hash_size_t size;
|
||||
hash_size_t num_elements;
|
||||
struct hash_node_s **nodes;
|
||||
hash_size_t (*hashfunc)(const hash_key_t);
|
||||
void (*freefunc)(void *);
|
||||
} hash_table_t;
|
||||
|
||||
char* hashtable_rc_code2string(hashtable_rc_t rcP);
|
||||
void hash_free_int_func(void* memoryP);
|
||||
hash_table_t *hashtable_create (const hash_size_t size, hash_size_t (*hashfunc)(const hash_key_t ), void (*freefunc)(void*));
|
||||
hashtable_rc_t hashtable_destroy(hash_table_t * const hashtbl);
|
||||
hashtable_rc_t hashtable_is_key_exists (const hash_table_t * const hashtbl, const uint64_t key);
|
||||
hashtable_rc_t hashtable_apply_funct_on_elements (hash_table_t * const hashtblP, void funct(hash_key_t keyP, void* dataP, void* parameterP), void* parameterP);
|
||||
hashtable_rc_t hashtable_dump_content (const hash_table_t * const hashtblP, char * const buffer_pP, int * const remaining_bytes_in_buffer_pP );
|
||||
hashtable_rc_t hashtable_insert (hash_table_t * const hashtbl, const hash_key_t key, void *data);
|
||||
hashtable_rc_t hashtable_remove (hash_table_t * const hashtbl, const hash_key_t key);
|
||||
hashtable_rc_t hashtable_get (const hash_table_t * const hashtbl, const hash_key_t key, void **dataP);
|
||||
hashtable_rc_t hashtable_resize (hash_table_t * const hashtbl, const hash_size_t size);
|
||||
char *hashtable_rc_code2string(hashtable_rc_t rcP);
|
||||
void hash_free_int_func(void *memoryP);
|
||||
hash_table_t *hashtable_create (const hash_size_t size, hash_size_t (*hashfunc)(const hash_key_t ), void (*freefunc)(void *));
|
||||
hashtable_rc_t hashtable_destroy(hash_table_t **hashtbl);
|
||||
hashtable_rc_t hashtable_is_key_exists (const hash_table_t *const hashtbl, const uint64_t key);
|
||||
hashtable_rc_t hashtable_apply_funct_on_elements (hash_table_t *const hashtblP, void funct(hash_key_t keyP, void *dataP, void *parameterP), void *parameterP);
|
||||
hashtable_rc_t hashtable_dump_content (const hash_table_t *const hashtblP, char *const buffer_pP, int *const remaining_bytes_in_buffer_pP );
|
||||
hashtable_rc_t hashtable_insert (hash_table_t *const hashtbl, const hash_key_t key, void *data);
|
||||
hashtable_rc_t hashtable_remove (hash_table_t *const hashtbl, const hash_key_t key);
|
||||
hashtable_rc_t hashtable_get (const hash_table_t *const hashtbl, const hash_key_t key, void **dataP);
|
||||
hashtable_rc_t hashtable_resize (hash_table_t *const hashtbl, const hash_size_t size);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
* 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 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.
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
@@ -30,13 +30,12 @@
|
||||
* This is a simple/naive hash function which adds the key's ASCII char values. It will probably generate lots of collisions on large hash tables.
|
||||
*/
|
||||
|
||||
static hash_size_t def_hashfunc(const void *keyP, int key_sizeP)
|
||||
{
|
||||
hash_size_t hash=0;
|
||||
static hash_size_t def_hashfunc(const void *keyP, int key_sizeP) {
|
||||
hash_size_t hash=0;
|
||||
|
||||
while(key_sizeP) hash^=((unsigned char*)keyP)[key_sizeP --];
|
||||
while(key_sizeP) hash^=((unsigned char *)keyP)[key_sizeP --];
|
||||
|
||||
return hash;
|
||||
return hash;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -46,201 +45,221 @@ static hash_size_t def_hashfunc(const void *keyP, int key_sizeP)
|
||||
* The user can also specify a hash function. If the hashfunc argument is NULL, a default hash function is used.
|
||||
* If an error occurred, NULL is returned. All other values in the returned obj_hash_table_t pointer should be released with hashtable_destroy().
|
||||
*/
|
||||
obj_hash_table_t *obj_hashtable_create(hash_size_t sizeP, hash_size_t (*hashfuncP)(const void*, int ), void (*freekeyfuncP)(void*), void (*freedatafuncP)(void*))
|
||||
{
|
||||
obj_hash_table_t *hashtbl;
|
||||
obj_hash_table_t *obj_hashtable_create(hash_size_t sizeP, hash_size_t (*hashfuncP)(const void *, int ), void (*freekeyfuncP)(void *), void (*freedatafuncP)(void *)) {
|
||||
obj_hash_table_t *hashtbl;
|
||||
|
||||
if(!(hashtbl=malloc(sizeof(obj_hash_table_t)))) return NULL;
|
||||
if(!(hashtbl=malloc(sizeof(obj_hash_table_t)))) return NULL;
|
||||
|
||||
if(!(hashtbl->nodes=calloc(sizeP, sizeof(obj_hash_node_t*)))) {
|
||||
free(hashtbl);
|
||||
return NULL;
|
||||
}
|
||||
if(!(hashtbl->nodes=calloc(sizeP, sizeof(obj_hash_node_t *)))) {
|
||||
free(hashtbl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hashtbl->size=sizeP;
|
||||
hashtbl->size=sizeP;
|
||||
|
||||
if(hashfuncP) hashtbl->hashfunc=hashfuncP;
|
||||
else hashtbl->hashfunc=def_hashfunc;
|
||||
if(hashfuncP) hashtbl->hashfunc=hashfuncP;
|
||||
else hashtbl->hashfunc=def_hashfunc;
|
||||
|
||||
if(freekeyfuncP) hashtbl->freekeyfunc=freekeyfuncP;
|
||||
else hashtbl->freekeyfunc=free;
|
||||
if(freekeyfuncP) hashtbl->freekeyfunc=freekeyfuncP;
|
||||
else hashtbl->freekeyfunc=free;
|
||||
|
||||
if(freedatafuncP) hashtbl->freedatafunc=freedatafuncP;
|
||||
else hashtbl->freedatafunc=free;
|
||||
if(freedatafuncP) hashtbl->freedatafunc=freedatafuncP;
|
||||
else hashtbl->freedatafunc=free;
|
||||
|
||||
return hashtbl;
|
||||
return hashtbl;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
* Cleanup
|
||||
* The hashtable_destroy() walks through the linked lists for each possible hash value, and releases the elements. It also releases the nodes array and the obj_hash_table_t.
|
||||
*/
|
||||
hashtable_rc_t obj_hashtable_destroy(obj_hash_table_t *hashtblP)
|
||||
{
|
||||
hash_size_t n;
|
||||
obj_hash_node_t *node, *oldnode;
|
||||
hashtable_rc_t obj_hashtable_destroy(obj_hash_table_t *hashtblP) {
|
||||
hash_size_t n;
|
||||
obj_hash_node_t *node, *oldnode;
|
||||
|
||||
for(n=0; n<hashtblP->size; ++n) {
|
||||
node=hashtblP->nodes[n];
|
||||
while(node) {
|
||||
oldnode=node;
|
||||
node=node->next;
|
||||
hashtblP->freekeyfunc(oldnode->key);
|
||||
hashtblP->freedatafunc(oldnode->data);
|
||||
free(oldnode);
|
||||
}
|
||||
for(n=0; n<hashtblP->size; ++n) {
|
||||
node=hashtblP->nodes[n];
|
||||
|
||||
while(node) {
|
||||
oldnode=node;
|
||||
node=node->next;
|
||||
hashtblP->freekeyfunc(oldnode->key);
|
||||
hashtblP->freedatafunc(oldnode->data);
|
||||
free(oldnode);
|
||||
}
|
||||
free(hashtblP->nodes);
|
||||
free(hashtblP);
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
|
||||
free(hashtblP->nodes);
|
||||
free(hashtblP);
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
hashtable_rc_t obj_hashtable_is_key_exists (obj_hash_table_t *hashtblP, void* keyP, int key_sizeP)
|
||||
hashtable_rc_t obj_hashtable_is_key_exists (obj_hash_table_t *hashtblP, void *keyP, int key_sizeP)
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
{
|
||||
obj_hash_node_t *node;
|
||||
hash_size_t hash;
|
||||
obj_hash_node_t *node;
|
||||
hash_size_t hash;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
return HASH_TABLE_OK;
|
||||
} else if (node->key_size == key_sizeP) {
|
||||
if (memcmp(node->key, keyP, key_sizeP) == 0) {
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
}
|
||||
hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
return HASH_TABLE_OK;
|
||||
} else if (node->key_size == key_sizeP) {
|
||||
if (memcmp(node->key, keyP, key_sizeP) == 0) {
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
}
|
||||
node=node->next;
|
||||
}
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
|
||||
node=node->next;
|
||||
}
|
||||
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
* Adding a new element
|
||||
* To make sure the hash value is not bigger than size, the result of the user provided hash function is used modulo size.
|
||||
*/
|
||||
hashtable_rc_t obj_hashtable_insert(obj_hash_table_t *hashtblP, void* keyP, int key_sizeP, void *dataP)
|
||||
{
|
||||
obj_hash_node_t *node;
|
||||
hash_size_t hash;
|
||||
hashtable_rc_t obj_hashtable_insert(obj_hash_table_t *hashtblP, void *keyP, int key_sizeP, void *dataP) {
|
||||
obj_hash_node_t *node;
|
||||
hash_size_t hash;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
if (node->data) {
|
||||
hashtblP->freedatafunc(node->data);
|
||||
}
|
||||
|
||||
node->data=dataP;
|
||||
// waste of memory here (keyP is lost) we should free it now
|
||||
return HASH_TABLE_INSERT_OVERWRITTEN_DATA;
|
||||
}
|
||||
hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
if (node->data) {
|
||||
hashtblP->freedatafunc(node->data);
|
||||
}
|
||||
node->data=dataP;
|
||||
// waste of memory here (keyP is lost) we should free it now
|
||||
return HASH_TABLE_INSERT_OVERWRITTEN_DATA;
|
||||
}
|
||||
node=node->next;
|
||||
}
|
||||
if(!(node=malloc(sizeof(obj_hash_node_t)))) return -1;
|
||||
node->key=keyP;
|
||||
node->data=dataP;
|
||||
if (hashtblP->nodes[hash]) {
|
||||
node->next=hashtblP->nodes[hash];
|
||||
} else {
|
||||
node->next = NULL;
|
||||
}
|
||||
hashtblP->nodes[hash]=node;
|
||||
return HASH_TABLE_OK;
|
||||
|
||||
node=node->next;
|
||||
}
|
||||
|
||||
if(!(node=malloc(sizeof(obj_hash_node_t)))) return -1;
|
||||
|
||||
node->key=keyP;
|
||||
node->data=dataP;
|
||||
|
||||
if (hashtblP->nodes[hash]) {
|
||||
node->next=hashtblP->nodes[hash];
|
||||
} else {
|
||||
node->next = NULL;
|
||||
}
|
||||
|
||||
hashtblP->nodes[hash]=node;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
* To remove an element from the hash table, we just search for it in the linked list for that hash value,
|
||||
* and remove it if it is found. If it was not found, it is an error and -1 is returned.
|
||||
*/
|
||||
hashtable_rc_t obj_hashtable_remove(obj_hash_table_t *hashtblP, const void* keyP, int key_sizeP)
|
||||
{
|
||||
obj_hash_node_t *node, *prevnode=NULL;
|
||||
hash_size_t hash;
|
||||
hashtable_rc_t obj_hashtable_remove(obj_hash_table_t *hashtblP, const void *keyP, int key_sizeP) {
|
||||
obj_hash_node_t *node, *prevnode=NULL;
|
||||
hash_size_t hash;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
|
||||
while(node) {
|
||||
if ((node->key == keyP) || ((node->key_size == key_sizeP) && (memcmp(node->key, keyP, key_sizeP) == 0))) {
|
||||
if(prevnode) {
|
||||
prevnode->next=node->next;
|
||||
} else {
|
||||
hashtblP->nodes[hash]=node->next;
|
||||
}
|
||||
|
||||
hashtblP->freekeyfunc(node->key);
|
||||
hashtblP->freedatafunc(node->data);
|
||||
free(node);
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
while(node) {
|
||||
if ((node->key == keyP) || ((node->key_size == key_sizeP) && (memcmp(node->key, keyP, key_sizeP) == 0))){
|
||||
if(prevnode) {
|
||||
prevnode->next=node->next;
|
||||
} else {
|
||||
hashtblP->nodes[hash]=node->next;
|
||||
}
|
||||
hashtblP->freekeyfunc(node->key);
|
||||
hashtblP->freedatafunc(node->data);
|
||||
free(node);
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
prevnode=node;
|
||||
node=node->next;
|
||||
}
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
prevnode=node;
|
||||
node=node->next;
|
||||
}
|
||||
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
* Searching for an element is easy. We just search through the linked list for the corresponding hash value.
|
||||
* NULL is returned if we didn't find it.
|
||||
*/
|
||||
hashtable_rc_t obj_hashtable_get(obj_hash_table_t *hashtblP, const void* keyP, int key_sizeP, void** dataP)
|
||||
{
|
||||
obj_hash_node_t *node;
|
||||
hash_size_t hash;
|
||||
hashtable_rc_t obj_hashtable_get(obj_hash_table_t *hashtblP, const void *keyP, int key_sizeP, void **dataP) {
|
||||
obj_hash_node_t *node;
|
||||
hash_size_t hash;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
*dataP = NULL;
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
*dataP = node->data;
|
||||
return HASH_TABLE_OK;
|
||||
} else if (node->key_size == key_sizeP) {
|
||||
if (memcmp(node->key, keyP, key_sizeP) == 0) {
|
||||
*dataP = node->data;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
}
|
||||
node=node->next;
|
||||
}
|
||||
if (hashtblP == NULL) {
|
||||
*dataP = NULL;
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size;
|
||||
node=hashtblP->nodes[hash];
|
||||
|
||||
while(node) {
|
||||
if(node->key == keyP) {
|
||||
*dataP = node->data;
|
||||
return HASH_TABLE_OK;
|
||||
} else if (node->key_size == key_sizeP) {
|
||||
if (memcmp(node->key, keyP, key_sizeP) == 0) {
|
||||
*dataP = node->data;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
node=node->next;
|
||||
}
|
||||
|
||||
*dataP = NULL;
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
* Function to return all keys of an object hash table
|
||||
*/
|
||||
hashtable_rc_t obj_hashtable_get_keys(obj_hash_table_t *hashtblP, void ** keysP, unsigned int *sizeP)
|
||||
{
|
||||
size_t n = 0;
|
||||
obj_hash_node_t *node = NULL;
|
||||
obj_hash_node_t *next = NULL;
|
||||
|
||||
*sizeP = 0;
|
||||
keysP = calloc(hashtblP->num_elements, sizeof(void *));
|
||||
if (keysP) {
|
||||
for(n=0; n<hashtblP->size; ++n) {
|
||||
for(node=hashtblP->nodes[n]; node; node=next) {
|
||||
keysP[*sizeP++] = node->key;
|
||||
next = node->next;
|
||||
}
|
||||
}
|
||||
return HASH_TABLE_OK;
|
||||
hashtable_rc_t obj_hashtable_get_keys(obj_hash_table_t *hashtblP, void **keysP, unsigned int *sizeP) {
|
||||
size_t n = 0;
|
||||
obj_hash_node_t *node = NULL;
|
||||
obj_hash_node_t *next = NULL;
|
||||
*sizeP = 0;
|
||||
keysP = calloc(hashtblP->num_elements, sizeof(void *));
|
||||
|
||||
if (keysP) {
|
||||
for(n=0; n<hashtblP->size; ++n) {
|
||||
for(node=hashtblP->nodes[n]; node; node=next) {
|
||||
keysP[*sizeP++] = node->key;
|
||||
next = node->next;
|
||||
}
|
||||
}
|
||||
return HASH_TABLE_SYSTEM_ERROR;
|
||||
|
||||
// cppcheck-suppress memleak
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
|
||||
return HASH_TABLE_SYSTEM_ERROR;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
@@ -253,34 +272,32 @@ hashtable_rc_t obj_hashtable_get_keys(obj_hash_table_t *hashtblP, void ** keysP,
|
||||
* This allows us to reuse hashtable_insert() and hashtable_remove(), when moving the elements to the new table.
|
||||
* After that, we can just free the old table and copy the elements from newtbl to hashtbl.
|
||||
*/
|
||||
hashtable_rc_t obj_hashtable_resize(obj_hash_table_t *hashtblP, hash_size_t sizeP)
|
||||
{
|
||||
obj_hash_table_t newtbl;
|
||||
hash_size_t n;
|
||||
obj_hash_node_t *node,*next;
|
||||
hashtable_rc_t obj_hashtable_resize(obj_hash_table_t *hashtblP, hash_size_t sizeP) {
|
||||
obj_hash_table_t newtbl;
|
||||
hash_size_t n;
|
||||
obj_hash_node_t *node,*next;
|
||||
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
if (hashtblP == NULL) {
|
||||
return HASH_TABLE_BAD_PARAMETER_HASHTABLE;
|
||||
}
|
||||
|
||||
newtbl.size = sizeP;
|
||||
newtbl.hashfunc = hashtblP->hashfunc;
|
||||
|
||||
if(!(newtbl.nodes=calloc(sizeP, sizeof(obj_hash_node_t *)))) return HASH_TABLE_SYSTEM_ERROR;
|
||||
|
||||
for(n=0; n<hashtblP->size; ++n) {
|
||||
for(node=hashtblP->nodes[n]; node; node=next) {
|
||||
next = node->next;
|
||||
obj_hashtable_insert(&newtbl, node->key, node->key_size, node->data);
|
||||
obj_hashtable_remove(hashtblP, node->key, node->key_size);
|
||||
}
|
||||
}
|
||||
|
||||
newtbl.size = sizeP;
|
||||
newtbl.hashfunc = hashtblP->hashfunc;
|
||||
|
||||
if(!(newtbl.nodes=calloc(sizeP, sizeof(obj_hash_node_t*)))) return HASH_TABLE_SYSTEM_ERROR;
|
||||
|
||||
for(n=0; n<hashtblP->size; ++n) {
|
||||
for(node=hashtblP->nodes[n]; node; node=next) {
|
||||
next = node->next;
|
||||
obj_hashtable_insert(&newtbl, node->key, node->key_size, node->data);
|
||||
obj_hashtable_remove(hashtblP, node->key, node->key_size);
|
||||
}
|
||||
}
|
||||
|
||||
free(hashtblP->nodes);
|
||||
hashtblP->size=newtbl.size;
|
||||
hashtblP->nodes=newtbl.nodes;
|
||||
|
||||
return HASH_TABLE_OK;
|
||||
free(hashtblP->nodes);
|
||||
hashtblP->size=newtbl.size;
|
||||
hashtblP->nodes=newtbl.nodes;
|
||||
return HASH_TABLE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+19
-85
@@ -23,19 +23,19 @@
|
||||
#include "memory_pools.h"
|
||||
|
||||
#if T_TRACER
|
||||
#include <string.h>
|
||||
#include "T.h"
|
||||
#include <string.h>
|
||||
#include "T.h"
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
const static int mp_debug = 0;
|
||||
|
||||
# define MP_DEBUG(x, args...) do { if (mp_debug) fprintf(stdout, "[MP][D]"x, ##args); fflush (stdout); } \
|
||||
while(0)
|
||||
while(0)
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
#ifndef CHARS_TO_UINT32
|
||||
#define CHARS_TO_UINT32(c1, c2, c3, c4) (((c1) << 24) | ((c2) << 16) | ((c3) << 8) | (c4))
|
||||
#define CHARS_TO_UINT32(c1, c2, c3, c4) (((c1) << 24) | ((c2) << 16) | ((c3) << 8) | (c4))
|
||||
#endif
|
||||
|
||||
#define MEMORY_POOL_ITEM_INFO_NUMBER 2
|
||||
@@ -129,33 +129,25 @@ static const pool_start_mark_t POOL_START_MARK = CHARS_TO_UINT32 ('P'
|
||||
static const pools_start_mark_t POOLS_START_MARK = CHARS_TO_UINT32 ('P', 'S', 's', 't');
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static inline uint32_t items_group_number_items (items_group_t *items_group)
|
||||
{
|
||||
static inline uint32_t items_group_number_items (items_group_t *items_group) {
|
||||
return items_group->number_plus_one - 1;
|
||||
}
|
||||
|
||||
static inline uint32_t items_group_free_items (items_group_t *items_group)
|
||||
{
|
||||
static inline uint32_t items_group_free_items (items_group_t *items_group) {
|
||||
items_group_positions_t positions;
|
||||
uint32_t free_items;
|
||||
|
||||
positions.all = items_group->positions.all;
|
||||
|
||||
free_items = items_group->number_plus_one + positions.ind.put - positions.ind.get;
|
||||
free_items %= items_group->number_plus_one;
|
||||
|
||||
return free_items;
|
||||
}
|
||||
|
||||
static inline items_group_index_t items_group_get_free_item (items_group_t *items_group)
|
||||
{
|
||||
static inline items_group_index_t items_group_get_free_item (items_group_t *items_group) {
|
||||
items_group_position_t get_raw;
|
||||
items_group_position_t put;
|
||||
items_group_position_t get;
|
||||
items_group_position_t free_items;
|
||||
|
||||
items_group_index_t index = ITEMS_GROUP_INDEX_INVALID;
|
||||
|
||||
/* Get current put position */
|
||||
put = items_group->positions.ind.put % items_group->number_plus_one;
|
||||
/* Get current get position and increase it */
|
||||
@@ -193,11 +185,9 @@ static inline items_group_index_t items_group_get_free_item (items_group_t *item
|
||||
return (index);
|
||||
}
|
||||
|
||||
static inline int items_group_put_free_item (items_group_t *items_group, items_group_index_t index)
|
||||
{
|
||||
static inline int items_group_put_free_item (items_group_t *items_group, items_group_index_t index) {
|
||||
items_group_position_t put_raw;
|
||||
items_group_position_t put;
|
||||
|
||||
/* Get current put position and increase it */
|
||||
put_raw = __sync_fetch_and_add (&items_group->positions.ind.put, 1);
|
||||
put = put_raw % items_group->number_plus_one;
|
||||
@@ -209,70 +199,54 @@ static inline int items_group_put_free_item (items_group_t *items_group, items_g
|
||||
|
||||
AssertError (items_group->indexes[put] <= ITEMS_GROUP_INDEX_INVALID, return (EXIT_FAILURE),
|
||||
"Index at current put position (%d) is not marked as free (%d)!\n", put, items_group->number_plus_one);
|
||||
|
||||
/* Save freed item index at current put position */
|
||||
items_group->indexes[put] = index;
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static inline memory_pools_t *memory_pools_from_handler (memory_pools_handle_t memory_pools_handle)
|
||||
{
|
||||
static inline memory_pools_t *memory_pools_from_handler (memory_pools_handle_t memory_pools_handle) {
|
||||
memory_pools_t *memory_pools;
|
||||
|
||||
/* Recover memory_pools */
|
||||
memory_pools = (memory_pools_t *) memory_pools_handle;
|
||||
/* Sanity check on passed handle */
|
||||
AssertError (memory_pools->start_mark == POOLS_START_MARK, memory_pools = NULL,
|
||||
"Handle %p is not a valid memory pools handle, start mark is missing!\n", memory_pools_handle);
|
||||
|
||||
return (memory_pools);
|
||||
}
|
||||
|
||||
static inline memory_pool_item_t *memory_pool_item_from_handler (memory_pool_item_handle_t memory_pool_item_handle)
|
||||
{
|
||||
static inline memory_pool_item_t *memory_pool_item_from_handler (memory_pool_item_handle_t memory_pool_item_handle) {
|
||||
void *address;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
|
||||
/* Recover memory_pools */
|
||||
address = memory_pool_item_handle - sizeof(memory_pool_item_start_t);
|
||||
memory_pool_item = (memory_pool_item_t *) address;
|
||||
|
||||
/* Sanity check on passed handle */
|
||||
AssertError (memory_pool_item->start.start_mark == POOL_ITEM_START_MARK, memory_pool_item = NULL,
|
||||
"Handle %p is not a valid memory pool item handle, start mark is missing!\n", memory_pool_item);
|
||||
|
||||
return (memory_pool_item);
|
||||
}
|
||||
|
||||
static inline memory_pool_item_t *memory_pool_item_from_index (memory_pool_t *memory_pool, items_group_index_t index)
|
||||
{
|
||||
static inline memory_pool_item_t *memory_pool_item_from_index (memory_pool_t *memory_pool, items_group_index_t index) {
|
||||
void *address;
|
||||
|
||||
address = (void *) memory_pool->items;
|
||||
address += index * memory_pool->pool_item_size;
|
||||
|
||||
return (address);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
memory_pools_handle_t memory_pools_create (uint32_t pools_number)
|
||||
{
|
||||
memory_pools_handle_t memory_pools_create (uint32_t pools_number) {
|
||||
memory_pools_t *memory_pools;
|
||||
pool_id_t pool;
|
||||
|
||||
AssertFatal (pools_number <= MAX_POOLS_NUMBER, "Too many memory pools requested (%d/%d)!\n", pools_number, MAX_POOLS_NUMBER); /* Limit to a reasonable number of pools */
|
||||
|
||||
/* Allocate memory_pools */
|
||||
memory_pools = malloc (sizeof(memory_pools_t));
|
||||
AssertFatal (memory_pools != NULL, "Memory pools structure allocation failed!\n");
|
||||
|
||||
/* Initialize memory_pools */
|
||||
{
|
||||
memory_pools->start_mark = POOLS_START_MARK;
|
||||
memory_pools->pools_number = pools_number;
|
||||
memory_pools->pools_defined = 0;
|
||||
|
||||
/* Allocate pools */
|
||||
memory_pools->pools = calloc (pools_number, sizeof(memory_pool_t));
|
||||
AssertFatal (memory_pools->pools != NULL, "Memory pools allocation failed!\n");
|
||||
@@ -282,12 +256,10 @@ memory_pools_handle_t memory_pools_create (uint32_t pools_number)
|
||||
memory_pools->pools[pool].start_mark = POOL_START_MARK;
|
||||
}
|
||||
}
|
||||
|
||||
return ((memory_pools_handle_t) memory_pools);
|
||||
}
|
||||
|
||||
char *memory_pools_statistics(memory_pools_handle_t memory_pools_handle)
|
||||
{
|
||||
char *memory_pools_statistics(memory_pools_handle_t memory_pools_handle) {
|
||||
memory_pools_t *memory_pools;
|
||||
pool_id_t pool;
|
||||
char *statistics;
|
||||
@@ -296,13 +268,10 @@ char *memory_pools_statistics(memory_pools_handle_t memory_pools_handle)
|
||||
uint32_t allocated_pools_memory = 0;
|
||||
items_group_t *items_group;
|
||||
uint32_t pool_items_size;
|
||||
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertFatal (memory_pools != NULL, "Failed to retrieve memory pool for handle %p!\n", memory_pools_handle);
|
||||
|
||||
statistics = malloc(memory_pools->pools_defined * 200);
|
||||
|
||||
printed_chars = sprintf (&statistics[0], "Pool: size, number, minimum, free, address space and memory used in Kbytes\n");
|
||||
|
||||
for (pool = 0; pool < memory_pools->pools_defined; pool++) {
|
||||
@@ -321,32 +290,25 @@ char *memory_pools_statistics(memory_pools_handle_t memory_pools_handle)
|
||||
}
|
||||
|
||||
printed_chars = sprintf (&statistics[printed_chars], "Pools memory %u Kbytes\n", allocated_pools_memory / (1024));
|
||||
|
||||
return (statistics);
|
||||
}
|
||||
|
||||
int memory_pools_add_pool (memory_pools_handle_t memory_pools_handle, uint32_t pool_items_number, uint32_t pool_item_size)
|
||||
{
|
||||
int memory_pools_add_pool (memory_pools_handle_t memory_pools_handle, uint32_t pool_items_number, uint32_t pool_item_size) {
|
||||
memory_pools_t *memory_pools;
|
||||
memory_pool_t *memory_pool;
|
||||
pool_id_t pool;
|
||||
items_group_index_t item_index;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
|
||||
AssertFatal (pool_items_number <= MAX_POOL_ITEMS_NUMBER, "Too many items for a memory pool (%u/%d)!\n", pool_items_number, MAX_POOL_ITEMS_NUMBER); /* Limit to a reasonable number of items */
|
||||
AssertFatal (pool_item_size <= MAX_POOL_ITEM_SIZE, "Item size is too big for memory pool items (%u/%d)!\n", pool_item_size, MAX_POOL_ITEM_SIZE); /* Limit to a reasonable item size */
|
||||
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertFatal (memory_pools != NULL, "Failed to retrieve memory pool for handle %p!\n", memory_pools_handle);
|
||||
|
||||
/* Check number of already created pools */
|
||||
AssertFatal (memory_pools->pools_defined < memory_pools->pools_number, "Can not allocate more memory pool (%d)!\n", memory_pools->pools_number);
|
||||
|
||||
/* Select pool */
|
||||
pool = memory_pools->pools_defined;
|
||||
memory_pool = &memory_pools->pools[pool];
|
||||
|
||||
/* Initialize pool */
|
||||
{
|
||||
memory_pool->pool_id = pool;
|
||||
@@ -357,7 +319,6 @@ int memory_pools_add_pool (memory_pools_handle_t memory_pools_handle, uint32_t p
|
||||
memory_pool->items_group_free.minimum = pool_items_number;
|
||||
memory_pool->items_group_free.positions.ind.put = pool_items_number;
|
||||
memory_pool->items_group_free.positions.ind.get = 0;
|
||||
|
||||
/* Allocate free indexes */
|
||||
memory_pool->items_group_free.indexes = malloc(memory_pool->items_group_free.number_plus_one * sizeof(items_group_index_t));
|
||||
AssertFatal (memory_pool->items_group_free.indexes != NULL, "Memory pool indexes allocation failed!\n");
|
||||
@@ -369,7 +330,6 @@ int memory_pools_add_pool (memory_pools_handle_t memory_pools_handle, uint32_t p
|
||||
|
||||
/* Last index is not allocated */
|
||||
memory_pool->items_group_free.indexes[item_index] = ITEMS_GROUP_INDEX_INVALID;
|
||||
|
||||
/* Allocate items */
|
||||
memory_pool->items = calloc (pool_items_number, memory_pool->pool_item_size);
|
||||
AssertFatal (memory_pool->items != NULL, "Memory pool items allocation failed!\n");
|
||||
@@ -383,20 +343,16 @@ int memory_pools_add_pool (memory_pools_handle_t memory_pools_handle, uint32_t p
|
||||
memory_pool_item->data[memory_pool->item_data_number] = POOL_ITEM_END_MARK;
|
||||
}
|
||||
}
|
||||
|
||||
memory_pools->pools_defined ++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
memory_pool_item_handle_t memory_pools_allocate (memory_pools_handle_t memory_pools_handle, uint32_t item_size, uint16_t info_0, uint16_t info_1)
|
||||
{
|
||||
memory_pool_item_handle_t memory_pools_allocate (memory_pools_handle_t memory_pools_handle, uint32_t item_size, uint16_t info_0, uint16_t info_1) {
|
||||
memory_pools_t *memory_pools;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
memory_pool_item_handle_t memory_pool_item_handle = NULL;
|
||||
pool_id_t pool;
|
||||
items_group_index_t item_index = ITEMS_GROUP_INDEX_INVALID;
|
||||
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertError (memory_pools != NULL, {}, "Failed to retrieve memory pool for handle %p!\n", memory_pools_handle);
|
||||
@@ -424,12 +380,10 @@ memory_pool_item_handle_t memory_pools_allocate (memory_pools_handle_t memory_po
|
||||
/* Sanity check on item status, must be free */
|
||||
AssertFatal (memory_pool_item->start.item_status == ITEM_STATUS_FREE, "Item status is not set to free (%d) in pool %u, item %d!\n",
|
||||
memory_pool_item->start.item_status, pool, item_index);
|
||||
|
||||
memory_pool_item->start.item_status = ITEM_STATUS_ALLOCATED;
|
||||
memory_pool_item->start.info[0] = info_0;
|
||||
memory_pool_item->start.info[1] = info_1;
|
||||
memory_pool_item_handle = memory_pool_item->data;
|
||||
|
||||
MP_DEBUG(" Alloc [%2u][%6d]{%6d}, %3u %3u, %6u, %p, %p, %p\n",
|
||||
pool, item_index,
|
||||
items_group_free_items (&memory_pools->pools[pool].items_group_free),
|
||||
@@ -445,8 +399,7 @@ memory_pool_item_handle_t memory_pools_allocate (memory_pools_handle_t memory_po
|
||||
return memory_pool_item_handle;
|
||||
}
|
||||
|
||||
int memory_pools_free (memory_pools_handle_t memory_pools_handle, memory_pool_item_handle_t memory_pool_item_handle, uint16_t info_0)
|
||||
{
|
||||
int memory_pools_free (memory_pools_handle_t memory_pools_handle, memory_pool_item_handle_t memory_pool_item_handle, uint16_t info_0) {
|
||||
memory_pools_t *memory_pools;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
pool_id_t pool;
|
||||
@@ -455,36 +408,29 @@ int memory_pools_free (memory_pools_handle_t memory_pools_handle, memory_pool_it
|
||||
uint32_t pool_item_size;
|
||||
uint16_t info_1;
|
||||
int result;
|
||||
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertError (memory_pools != NULL, return (EXIT_FAILURE), "Failed to retrieve memory pools for handle %p!\n", memory_pools_handle);
|
||||
|
||||
/* Recover memory pool item */
|
||||
memory_pool_item = memory_pool_item_from_handler (memory_pool_item_handle);
|
||||
AssertError (memory_pool_item != NULL, return (EXIT_FAILURE), "Failed to retrieve memory pool item for handle %p!\n", memory_pool_item_handle);
|
||||
|
||||
info_1 = memory_pool_item->start.info[1];
|
||||
|
||||
/* Recover pool index */
|
||||
pool = memory_pool_item->start.pool_id;
|
||||
AssertFatal (pool < memory_pools->pools_defined, "Pool index is invalid (%u/%u)!\n", pool, memory_pools->pools_defined);
|
||||
|
||||
item_size = memory_pools->pools[pool].item_data_number;
|
||||
pool_item_size = memory_pools->pools[pool].pool_item_size;
|
||||
item_index = (((void *) memory_pool_item) - ((void *) memory_pools->pools[pool].items)) / pool_item_size;
|
||||
|
||||
MP_DEBUG(" Free [%2u][%6d]{%6d}, %3u %3u, %p, %p, %p, %u\n",
|
||||
pool, item_index,
|
||||
items_group_free_items (&memory_pools->pools[pool].items_group_free),
|
||||
memory_pool_item->start.info[0], info_1,
|
||||
memory_pool_item_handle, memory_pool_item,
|
||||
memory_pools->pools[pool].items, ((uint32_t) (item_size * sizeof(memory_pool_data_t))));
|
||||
|
||||
/* Sanity check on calculated item index */
|
||||
AssertFatal (memory_pool_item == memory_pool_item_from_index(&memory_pools->pools[pool], item_index),
|
||||
"Incorrect memory pool item address (%p, %p) for pool %u, item %d!\n",
|
||||
memory_pool_item, memory_pool_item_from_index(&memory_pools->pools[pool], item_index), pool, item_index);
|
||||
memory_pool_item,(void *)memory_pool_item_from_index(&memory_pools->pools[pool], item_index), pool, item_index);
|
||||
/* Sanity check on end marker, must still be present (no write overflow) */
|
||||
AssertFatal (memory_pool_item->data[item_size] == POOL_ITEM_END_MARK,
|
||||
"Memory pool item is corrupted, end mark is not present for pool %u, item %d!\n", pool, item_index);
|
||||
@@ -492,31 +438,23 @@ int memory_pools_free (memory_pools_handle_t memory_pools_handle, memory_pool_it
|
||||
AssertFatal (memory_pool_item->start.item_status == ITEM_STATUS_ALLOCATED,
|
||||
"Trying to free a non allocated (%x) memory pool item (pool %u, item %d)!\n",
|
||||
memory_pool_item->start.item_status, pool, item_index);
|
||||
|
||||
memory_pool_item->start.item_status = ITEM_STATUS_FREE;
|
||||
|
||||
result = items_group_put_free_item(&memory_pools->pools[pool].items_group_free, item_index);
|
||||
|
||||
AssertError (result == EXIT_SUCCESS, {}, "Failed to free memory pool item (pool %u, item %d)!\n", pool, item_index);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
void memory_pools_set_info (memory_pools_handle_t memory_pools_handle, memory_pool_item_handle_t memory_pool_item_handle, int index, uint16_t info)
|
||||
{
|
||||
void memory_pools_set_info (memory_pools_handle_t memory_pools_handle, memory_pool_item_handle_t memory_pool_item_handle, int index, uint16_t info) {
|
||||
memory_pools_t *memory_pools;
|
||||
memory_pool_item_t *memory_pool_item;
|
||||
pool_id_t pool;
|
||||
items_group_index_t item_index;
|
||||
uint32_t item_size;
|
||||
uint32_t pool_item_size;
|
||||
|
||||
AssertFatal (index < MEMORY_POOL_ITEM_INFO_NUMBER, "Incorrect info index (%d/%d)!\n", index, MEMORY_POOL_ITEM_INFO_NUMBER);
|
||||
|
||||
/* Recover memory pool item */
|
||||
memory_pool_item = memory_pool_item_from_handler (memory_pool_item_handle);
|
||||
AssertFatal (memory_pool_item != NULL, "Failed to retrieve memory pool item for handle %p!\n", memory_pool_item_handle);
|
||||
|
||||
/* Set info[1] */
|
||||
memory_pool_item->start.info[index] = info;
|
||||
|
||||
@@ -525,26 +463,22 @@ void memory_pools_set_info (memory_pools_handle_t memory_pools_handle, memory_po
|
||||
/* Recover memory_pools */
|
||||
memory_pools = memory_pools_from_handler (memory_pools_handle);
|
||||
AssertFatal (memory_pools != NULL, "Failed to retrieve memory pool for handle %p!\n", memory_pools_handle);
|
||||
|
||||
/* Recover pool index */
|
||||
pool = memory_pool_item->start.pool_id;
|
||||
AssertFatal (pool < memory_pools->pools_defined, "Pool index is invalid (%u/%u)!\n", pool, memory_pools->pools_defined);
|
||||
|
||||
item_size = memory_pools->pools[pool].item_data_number;
|
||||
pool_item_size = memory_pools->pools[pool].pool_item_size;
|
||||
item_index = (((void *) memory_pool_item) - ((void *) memory_pools->pools[pool].items)) / pool_item_size;
|
||||
|
||||
MP_DEBUG(" Info [%2u][%6d]{%6d}, %3u %3u, %p, %p, %p, %u\n",
|
||||
pool, item_index,
|
||||
items_group_free_items (&memory_pools->pools[pool].items_group_free),
|
||||
memory_pool_item->start.info[0], memory_pool_item->start.info[1],
|
||||
memory_pool_item_handle, memory_pool_item,
|
||||
memory_pools->pools[pool].items, ((uint32_t) (item_size * sizeof(memory_pool_data_t))));
|
||||
|
||||
/* Sanity check on calculated item index */
|
||||
AssertFatal (memory_pool_item == memory_pool_item_from_index(&memory_pools->pools[pool], item_index),
|
||||
"Incorrect memory pool item address (%p, %p) for pool %u, item %d!\n",
|
||||
memory_pool_item, memory_pool_item_from_index(&memory_pools->pools[pool], item_index), pool, item_index);
|
||||
memory_pool_item, (void *)memory_pool_item_from_index(&memory_pools->pools[pool], item_index), pool, item_index);
|
||||
/* Sanity check on end marker, must still be present (no write overflow) */
|
||||
AssertFatal (memory_pool_item->data[item_size] == POOL_ITEM_END_MARK,
|
||||
"Memory pool item is corrupted, end mark is not present for pool %u, item %d!\n", pool, item_index);
|
||||
|
||||
+15
-2
@@ -150,7 +150,7 @@ int msc_init(const msc_env_t envP, const int max_threadsP)
|
||||
pointer_p = malloc(MSC_MAX_MESSAGE_LENGTH);
|
||||
AssertFatal (pointer_p, "malloc failed!\n");
|
||||
rv = lfds611_stack_guaranteed_push( g_msc_memory_stack_p, pointer_p );
|
||||
AssertFatal (rv, "lfds611_stack_guaranteed_push failed for item %u\n", i);
|
||||
AssertFatal (rv, "lfds611_stack_guaranteed_push failed for item %d\n", i);
|
||||
}
|
||||
|
||||
for (i = MIN_MSC_PROTOS; i < MAX_MSC_PROTOS; i++) {
|
||||
@@ -476,7 +476,20 @@ int msc_init(const msc_env_t envP, const int max_threadsP)
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MSC_F1AP_CU:
|
||||
rv = snprintf(&g_msc_proto2str[i][0], MSC_MAX_PROTO_NAME_LENGTH, "F1AP_CU");
|
||||
if (rv >= MSC_MAX_PROTO_NAME_LENGTH) {g_msc_proto2str[i][MSC_MAX_PROTO_NAME_LENGTH-1] = 0;}
|
||||
//if ((envP == MSC_E_UTRAN) || (envP == MSC_MME_GW) || (envP == MSC_MME)) {
|
||||
msc_log_declare_proto(i);
|
||||
//}
|
||||
break;
|
||||
case MSC_F1AP_DU:
|
||||
rv = snprintf(&g_msc_proto2str[i][0], MSC_MAX_PROTO_NAME_LENGTH, "F1AP_DU");
|
||||
if (rv >= MSC_MAX_PROTO_NAME_LENGTH) {g_msc_proto2str[i][MSC_MAX_PROTO_NAME_LENGTH-1] = 0;}
|
||||
//if ((envP == MSC_E_UTRAN) || (envP == MSC_MME_GW) || (envP == MSC_MME)) {
|
||||
msc_log_declare_proto(i);
|
||||
//}
|
||||
break;
|
||||
default:
|
||||
rv = snprintf(&g_msc_proto2str[i][0], MSC_MAX_PROTO_NAME_LENGTH, "UNKNOWN");
|
||||
|
||||
|
||||
@@ -62,9 +62,11 @@ typedef enum {
|
||||
MSC_S11_MME,
|
||||
MSC_S6A_MME,
|
||||
MSC_HSS,
|
||||
MAX_MSC_PROTOS,
|
||||
MSC_F1AP_CU,
|
||||
MSC_F1AP_DU,
|
||||
MSC_X2AP_SRC_ENB,
|
||||
MSC_X2AP_TARGET_ENB,
|
||||
MAX_MSC_PROTOS,
|
||||
} msc_proto_t;
|
||||
|
||||
|
||||
|
||||
@@ -13,3 +13,4 @@
|
||||
#include "openair2/COMMON/udp_messages_def.h"
|
||||
#include "openair2/COMMON/gtpv1_u_messages_def.h"
|
||||
#include "openair2/COMMON/flexran_messages_def.h"
|
||||
#include "openair2/COMMON/f1ap_messages_def.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Author: Laurent THOMAS, Open Cells
|
||||
copyleft: OpenAirInterface Software Alliance and it's licence
|
||||
copyleft: OpenAirInterface Software Alliance and it's licence
|
||||
*/
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@@ -122,7 +122,7 @@ extern "C" {
|
||||
pthread_mutex_unlock (&t->queue_cond_lock);
|
||||
t->admin.func(NULL);
|
||||
pthread_mutex_lock (&t->queue_cond_lock);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&t->queue_cond_lock);
|
||||
return ret;
|
||||
}
|
||||
@@ -290,12 +290,12 @@ extern "C" {
|
||||
struct sched_param sparam;
|
||||
memset(&sparam, 0, sizeof(sparam));
|
||||
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-10;
|
||||
policy = SCHED_FIFO ;
|
||||
policy = SCHED_FIFO ;
|
||||
if (pthread_setschedparam(t->thread, policy, &sparam) != 0) {
|
||||
LOG_E(TMR,"task %s : Failed to set pthread priority\n", itti_get_task_name(task_id) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Author: Laurent THOMAS, Open Cells
|
||||
Copyleft: OpenAirInterface software alliance and it's licence
|
||||
Copyleft: OpenAirInterface software alliance and it's licence
|
||||
*/
|
||||
#ifndef INTERTASK_INTERFACE_H_
|
||||
#define INTERTASK_INTERFACE_H_
|
||||
@@ -300,6 +300,8 @@ typedef struct {
|
||||
TASK_DEF(TASK_MSC, TASK_PRIORITY_MED, 200, NULL, NULL)\
|
||||
TASK_DEF(TASK_GTPV1_U, TASK_PRIORITY_MED, 1000,NULL, NULL)\
|
||||
TASK_DEF(TASK_UDP, TASK_PRIORITY_MED, 1000, NULL, NULL)\
|
||||
TASK_DEF(TASK_CU_F1, TASK_PRIORITY_MED, 200, NULL, NULL) \
|
||||
TASK_DEF(TASK_DU_F1, TASK_PRIORITY_MED, 200, NULL, NULL) \
|
||||
TASK_DEF(TASK_MAX, TASK_PRIORITY_MED, 200, NULL, NULL)
|
||||
|
||||
#define TASK_DEF(TaskID, pRIO, qUEUEsIZE, FuNc, ThreadFunc) { pRIO, qUEUEsIZE, #TaskID, FuNc, ThreadFunc },
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
The following example is extracted from [the oai `openair1/PHY/CODING/coding_load.c` file](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/openair1/PHY/CODING/coding_load.c).
|
||||
|
||||
```c
|
||||
/*
|
||||
/*
|
||||
include the telnet server data structures and API definitions
|
||||
*/
|
||||
#include "common/utils/telnetsrv/telnetsrv.h"
|
||||
#include "common/utils/telnetsrv/telnetsrv.h"
|
||||
|
||||
|
||||
/*
|
||||
define the null terminated array of telnetshell_cmddef_t structures
|
||||
which map each sub-command string to a function implementing it.
|
||||
which map each sub-command string to a function implementing it.
|
||||
you may also provide a help string which will be printed when
|
||||
the global help command is used. The prototype for the function
|
||||
implementing sub commands must match the `cmdfunc_t` type defined
|
||||
@@ -25,7 +25,7 @@ static telnetshell_cmddef_t coding_cmdarray[] = {
|
||||
|
||||
/*
|
||||
define the null terminated list of telnetshell_vardef_t structures defining the
|
||||
variables that can be set and get using the pre-defined get and set command
|
||||
variables that can be set and get using the pre-defined get and set command
|
||||
of the telnet server
|
||||
*/
|
||||
telnetshell_vardef_t coding_vardef[] = {
|
||||
@@ -34,7 +34,7 @@ telnetshell_vardef_t coding_vardef[] = {
|
||||
};
|
||||
.................
|
||||
/*
|
||||
look for telnet server, if it is loaded, add the coding commands to it
|
||||
look for telnet server, if it is loaded, add the coding commands to it
|
||||
we use the shared library loader API to check the telnet server availibility
|
||||
The telnet server TELNET_ADDCMD_FNAME function takes three arguments:
|
||||
1. The name of the telnet command to be added, here "coding"
|
||||
@@ -43,9 +43,9 @@ The telnet server TELNET_ADDCMD_FNAME function takes three arguments:
|
||||
*/
|
||||
add_telnetcmd_func_t addcmd = (add_telnetcmd_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_ADDCMD_FNAME);
|
||||
if (addcmd != NULL) {
|
||||
addcmd("coding",coding_vardef,coding_cmdarray);
|
||||
addcmd("coding",coding_vardef,coding_cmdarray);
|
||||
.......
|
||||
/*
|
||||
/*
|
||||
functions implementing the "coding mode" sub command, as defined in
|
||||
the `coding_cmdarray` passed earlier to the TELNET_ADDCMD_FNAME function.
|
||||
This function will be called by the telnet server, when the `coding_cmdarray`
|
||||
@@ -53,15 +53,15 @@ The telnet server TELNET_ADDCMD_FNAME function takes three arguments:
|
||||
*/
|
||||
int coding_setmod_cmd(char *buff, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
/*
|
||||
/*
|
||||
1. buff argument is an input argument, pointer to the string received
|
||||
from the telnet client, the command and sub-command parts are removed
|
||||
In this case it points after "coding setmod" and is of no use as
|
||||
we don't have second level sub-commands.
|
||||
we don't have second level sub-commands.
|
||||
1. debug argument is an input argument set by the telnet server
|
||||
1. prnt arguments is also an input argument, a function pointer, to be used
|
||||
1. prnt arguments is also an input argument, a function pointer, to be used
|
||||
in place of printf to print messages on the telnet client interface. As this function
|
||||
is called by the telnet server stdout points to the main executable console,
|
||||
is called by the telnet server stdout points to the main executable console,
|
||||
*/
|
||||
if (debug > 0)
|
||||
prnt( "coding_setmod_cmd received %s\n",buff);
|
||||
@@ -89,28 +89,28 @@ int coding_setmod_cmd(char *buff, int debug, telnet_printfunc_t prnt)
|
||||
```c
|
||||
int add_telnetcmd(char *modulename, telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd)
|
||||
```
|
||||
Add a command and the `cmd` list of sub-commands to the telnet server. After a successful call to `add_telnetcmd` function, the telnet server calls the function defined for each sub-commands in the null terminated `cmd` array, when the character string received from the telnet client matches the command and sub-command strings.
|
||||
Also adds the list of variables described in the `var` array to the list of variable which can be set and read.
|
||||
The function returns -1 if one argument is NULL.
|
||||
The telnet server is dynamically loaded, to use the `add_telnetcmd` function, the shared library loader API should be used to check the availability of the telnet server and retrieve it's address, as shown in [the example at the top of this page](telnetaddcmd.md#code-example-of-adding-a-command-to-the-telnet-server).
|
||||
Add a command and the `cmd` list of sub-commands to the telnet server. After a successful call to `add_telnetcmd` function, the telnet server calls the function defined for each sub-commands in the null terminated `cmd` array, when the character string received from the telnet client matches the command and sub-command strings.
|
||||
Also adds the list of variables described in the `var` array to the list of variable which can be set and read.
|
||||
The function returns -1 if one argument is NULL.
|
||||
The telnet server is dynamically loaded, to use the `add_telnetcmd` function, the shared library loader API should be used to check the availability of the telnet server and retrieve it's address, as shown in [the example at the top of this page](telnetaddcmd.md#code-example-of-adding-a-command-to-the-telnet-server).
|
||||
|
||||
# telnet server public data types
|
||||
## `telnetshell_vardef_t`structure
|
||||
## `telnetshell_vardef_t`structure
|
||||
This structure is used by developers to describe the variables that can be set or read using the get,set and getall sub-commands.
|
||||
|
||||
| Fields | type |Description |
|
||||
| Fields | type |Description |
|
||||
|:-----------|:------:|:-----------------------|
|
||||
| `varname` | `char[TELNET_CMD_MAXSIZE]` | variable name, as specified when using the get and set commands. |
|
||||
| `vartype` | `char` | Defines the type of the variable pointed by the `varvalptr`field. Supported values: TELNET_VARTYPE_INT32 TELNET_VARTYPE_INT16 TELNET_VARTYPE_INT64 TELNET_VARTYPE_STRING TELNET_VARTYPE_DOUBLE |
|
||||
| `varvalptr` | `void*` | Defines the type of the variable pointed by the `varvalptr`field |
|
||||
|
||||
## `telnetshell_cmddef_t`structure
|
||||
## `telnetshell_cmddef_t`structure
|
||||
This structure is used by developers to describe the first level sub-commands to be added to the telnet server.
|
||||
|
||||
| Fields | type |Description |
|
||||
| Fields | type |Description |
|
||||
|:-----------|:------:|:-----------------------|
|
||||
| `cmdname` | `char[TELNET_CMD_MAXSIZE]` | command name, as tested by the telnet server to check it should call the `cmdfunc` function |
|
||||
| `helpstr` | `char[TELNET_HELPSTR_SIZE]` | character string to print when the elp`command is received from the telnet client |
|
||||
| `cmdfunc` | `cmdfunc_t` | pointer to the function implementing the `cmdname` sub command. |
|
||||
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
|
||||
@@ -4,18 +4,18 @@ The oai telnet server is implemented in a shared library to be loaded by the [oa
|
||||
|
||||
Currently the telnet server only supports one user connection. The same dedicated thread is used to wait for a user connection and process the input received from this connection.
|
||||
|
||||
The telnet server provides an API which can be used by any oai component to add new CLI commands to the server. A pre-defined command can be used to get or set a list of variables.
|
||||
The telnet server provides an API which can be used by any oai component to add new CLI commands to the server. A pre-defined command can be used to get or set a list of variables.
|
||||
|
||||
|
||||
|
||||
|
||||
# telnet server source files
|
||||
|
||||
telnet server source files are located in [common/utils/telnetsrv](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv)
|
||||
|
||||
1. [telnetsrv.c](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.c) contains the telnet server implementation, including the implementation of the telnet CLI command.
|
||||
1. [telnetsrv.c](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.c) contains the telnet server implementation, including the implementation of the telnet CLI command.
|
||||
1. [telnetsrv.h](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.h) is the telnet server include file containing both private and public data type definitions. It also contains API prototypes for functions that are used to register a new command in the server.
|
||||
1. `telnetsrv\_\<XXX\>.c`: implementation of \<XXX\> CLI command which are delivered with the telnet server.
|
||||
1. `telnetsrv\_\<XXX\>.h`: include file for the implementation of XXX CLI command. Usually included only in the corresponding `.c`file
|
||||
1. [telnetsrv_CMakeLists.txt](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/telnetsrv/telnetsrv_CMakeLists.txt): CMakelists file containing the cmake instructions to build the telnet server. this file is included in the [global oai CMakelists](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/cmake_targets/CMakeLists.txt).
|
||||
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
|
||||
@@ -10,12 +10,12 @@ telnet, phypb = 65000
|
||||
telnet, hsize = 50
|
||||
telnet, hfile = "oaitelnet.history"
|
||||
softmodem> telnet set loopc 100
|
||||
telnet, loopc set to
|
||||
telnet, loopc set to
|
||||
100
|
||||
softmodem> telnet get loopc
|
||||
telnet, loopc = 100
|
||||
softmodem>
|
||||
softmodem>
|
||||
|
||||
```
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
|
||||
@@ -22,7 +22,7 @@ softmodem> help
|
||||
softmodem show loglvl|thread|config
|
||||
softmodem log (enter help for details)
|
||||
softmodem thread (enter help for details)
|
||||
softmodem exit
|
||||
softmodem exit
|
||||
module 2 = phy:
|
||||
phy disp [phycnt,uedump,uestat UE<x>]
|
||||
module 3 = loader:
|
||||
@@ -34,24 +34,24 @@ softmodem> help
|
||||
module 4 = coding:
|
||||
coding [get set] maxiter <value>
|
||||
coding mode [sse,avx2,stdc,none]
|
||||
softmodem>
|
||||
```
|
||||
softmodem>
|
||||
```
|
||||
|
||||
# oai telnet server, specific commands help
|
||||
# oai telnet server, specific commands help
|
||||
|
||||
``` bash
|
||||
softmodem> softmodem log help
|
||||
log sub commands:
|
||||
show: display current log configuration
|
||||
online, noonline: enable or disable console logs
|
||||
enable, disable id1-id2: enable or disable logs for components index id1 to id2
|
||||
level_<level> id1-id2: set log level to <level> for components index id1 to id2
|
||||
level_<verbosity> id1-id2: set log verbosity to <verbosity> for components index id1 to id2
|
||||
use the show command to get the values for <level>, <verbosity> and the list of component indexes that can be used for id1 and id2
|
||||
log sub commands:
|
||||
show: display current log configuration
|
||||
online, noonline: enable or disable console logs
|
||||
enable, disable id1-id2: enable or disable logs for components index id1 to id2
|
||||
level_<level> id1-id2: set log level to <level> for components index id1 to id2
|
||||
level_<verbosity> id1-id2: set log verbosity to <verbosity> for components index id1 to id2
|
||||
use the show command to get the values for <level>, <verbosity> and the list of component indexes that can be used for id1 and id2
|
||||
softmodem>
|
||||
|
||||
|
||||
```
|
||||
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
|
||||
@@ -40,5 +40,5 @@ softmodem>
|
||||
|
||||
```
|
||||
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
|
||||
@@ -43,5 +43,5 @@ softmodem> loader show modules
|
||||
softmodem>
|
||||
```
|
||||
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
|
||||
@@ -38,10 +38,10 @@ log level/verbosity comp 33 USIM set to info / medium (disabled)
|
||||
log level/verbosity comp 34 LOCALIZE set to info / medium (disabled)
|
||||
log level/verbosity comp 35 RRH set to info / medium (disabled)
|
||||
softmodem> softmodem log show
|
||||
Available log levels:
|
||||
emerg alert crit error warn notice info debug file trace
|
||||
Available verbosity:
|
||||
none low medium high full
|
||||
Available log levels:
|
||||
emerg alert crit error warn notice info debug file trace
|
||||
Available verbosity:
|
||||
none low medium high full
|
||||
component verbosity level enabled
|
||||
00 PHY: medium info N
|
||||
01 MAC: medium info N
|
||||
@@ -89,8 +89,8 @@ log level/verbosity comp 3 OCG set to error / medium (enabled)
|
||||
log level/verbosity comp 4 OMG set to error / medium (enabled)
|
||||
softmodem> exit
|
||||
Connection closed by foreign host.
|
||||
```
|
||||
```
|
||||
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
The telnet server includes a **_loop_** command that can be used to iterate a given command. The number of iterations and the delay, in ms between two iterations can be modified, as shown in the following example:
|
||||
The telnet server includes a **_loop_** command that can be used to iterate a given command. The number of iterations and the delay, in ms between two iterations can be modified, as shown in the following example:
|
||||
|
||||
```bash
|
||||
softmodem> telnet get loopc
|
||||
@@ -6,35 +6,35 @@ telnet, loopc = 10
|
||||
softmodem> telnet get loopd
|
||||
telnet, loopd = 2000
|
||||
softmodem> telnet set loopd 1000
|
||||
telnet, loopd set to
|
||||
telnet, loopd set to
|
||||
1000
|
||||
softmodem> loop softmodem show thread
|
||||
2018-03-27 17:58:49.000 2/10
|
||||
id name state USRmod KRNmod prio nice vsize proc pol
|
||||
id name state USRmod KRNmod prio nice vsize proc pol
|
||||
|
||||
3946 lte-softmodem S 20005 9440 20 0 236560384 2 0 other
|
||||
3946 lte-softmodem S 20005 9440 20 0 236560384 2 0 other
|
||||
|
||||
3946 lte-softmodem S 7 95 20 0 236560384 2 0 other
|
||||
3948 telnet R 0 0 20 0 236560384 2 0 other
|
||||
3949 ITTI acceptor S 2 9 20 0 236560384 2 0 other
|
||||
3951 ITTI 12 S 2 2 20 0 236560384 7 0 other
|
||||
3952 ITTI 11 S 0 0 20 0 236560384 0 0 other
|
||||
3953 ITTI 9 S 0 0 20 0 236560384 1 0 other
|
||||
3954 ITTI 7 S 0 0 20 0 236560384 7 0 other
|
||||
3955 ITTI 8 S 0 0 20 0 236560384 7 0 other
|
||||
3956 ITTI 4 S 35 0 20 0 236560384 2 0 other
|
||||
3957 ru_thread S 15366 3072 -10 0 236560384 0 2 rt: rr
|
||||
3958 ru_thread_prach S 0 0 -10 0 236560384 7 1 rt: fifo
|
||||
3959 fep_thread S 1874 123 -10 0 236560384 5 1 rt: fifo
|
||||
3960 feptx_thread S 1554 101 -10 0 236560384 7 1 rt: fifo
|
||||
3969 ru_thread S 0 0 -10 0 236560384 0 2 rt: rr
|
||||
3970 ru_thread S 1313 5522 -10 0 236560384 5 2 rt: rr
|
||||
3971 ru_thread S 4 6 -10 0 236560384 1 2 rt: rr
|
||||
3972 lte-softmodem S 318 9 -10 0 236560384 7 1 rt: fifo
|
||||
3973 lte-softmodem S 6 13 -10 0 236560384 4 1 rt: fifo
|
||||
3946 lte-softmodem S 7 95 20 0 236560384 2 0 other
|
||||
3948 telnet R 0 0 20 0 236560384 2 0 other
|
||||
3949 ITTI acceptor S 2 9 20 0 236560384 2 0 other
|
||||
3951 ITTI 12 S 2 2 20 0 236560384 7 0 other
|
||||
3952 ITTI 11 S 0 0 20 0 236560384 0 0 other
|
||||
3953 ITTI 9 S 0 0 20 0 236560384 1 0 other
|
||||
3954 ITTI 7 S 0 0 20 0 236560384 7 0 other
|
||||
3955 ITTI 8 S 0 0 20 0 236560384 7 0 other
|
||||
3956 ITTI 4 S 35 0 20 0 236560384 2 0 other
|
||||
3957 ru_thread S 15366 3072 -10 0 236560384 0 2 rt: rr
|
||||
3958 ru_thread_prach S 0 0 -10 0 236560384 7 1 rt: fifo
|
||||
3959 fep_thread S 1874 123 -10 0 236560384 5 1 rt: fifo
|
||||
3960 feptx_thread S 1554 101 -10 0 236560384 7 1 rt: fifo
|
||||
3969 ru_thread S 0 0 -10 0 236560384 0 2 rt: rr
|
||||
3970 ru_thread S 1313 5522 -10 0 236560384 5 2 rt: rr
|
||||
3971 ru_thread S 4 6 -10 0 236560384 1 2 rt: rr
|
||||
3972 lte-softmodem S 318 9 -10 0 236560384 7 1 rt: fifo
|
||||
3973 lte-softmodem S 6 13 -10 0 236560384 4 1 rt: fifo
|
||||
|
||||
```
|
||||
A **_loop_** command can be interrupted by pressing the **_enter_** key till getting the prompt.
|
||||
```
|
||||
A **_loop_** command can be interrupted by pressing the **_enter_** key till getting the prompt.
|
||||
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
[oai telnetserver home](telnetsrv.md)
|
||||
[oai telnetserver usage home](telnetusage.md)
|
||||
|
||||
@@ -3,5 +3,5 @@ The oai embedded telnet server is an optional monitoring and debugging tool. It
|
||||
* [Using the telnet server](telnetusage.md)
|
||||
* [Adding commands to the oai telnet server](telnetaddcmd.md)
|
||||
* [telnet server architecture ](telnetarch.md)
|
||||
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
# starting the softmodem with the telnet server
|
||||
# starting the softmodem with the telnet server
|
||||
By default the embedded telnet server, which is implemented in a shared library, is not built. It can be built after compiling the softmodem executable using the `build_oai` script:
|
||||
|
||||
```bash
|
||||
cd \<oai repository\>/openairinterface5g
|
||||
source oaienv
|
||||
cd cmake_targets
|
||||
./build_oai --build-telnetsrv
|
||||
cd \<oai repository\>/openairinterface5g
|
||||
source oaienv
|
||||
cd cmake_targets
|
||||
./build_oai --build-telnetsrv
|
||||
```
|
||||
|
||||
This will create the `libtelnetsrv.so` file in the `targets/bin` and `cmake_targets/lte_build_oai/build` sub directories of the oai repository.
|
||||
|
||||
When starting the softmodem, you must specify the **_\-\-telnetsrv_** option to load and start the telnet server. The telnet server is loaded via the [oai shared library loader](loader).
|
||||
|
||||
# using the Command Line Interface
|
||||
By default the telnet server listen on all the ip addresses configured on the system and on port 9090. This behavior can be changed using the `listenaddr` and `listenport` parameters.
|
||||
# using the Command Line Interface
|
||||
By default the telnet server listen on all the ip addresses configured on the system and on port 9090. This behavior can be changed using the `listenaddr` and `listenport` parameters.
|
||||
The telnet server includes a basic help, listing available commands and some commands also provide a specific detailed help sub-command.
|
||||
Below are examples of telnet sessions:
|
||||
Below are examples of telnet sessions:
|
||||
|
||||
* [getting help](telnethelp.md)
|
||||
* [using the history](telnethist.md)
|
||||
* [using the get and set commands](telnetgetset.md)
|
||||
* [using the loop command](telnetloop.md)
|
||||
* [loader command](telnetloader.md)
|
||||
* [log command](telnetlog.md)
|
||||
* [log command](telnetlog.md)
|
||||
|
||||
# telnet server parameters
|
||||
The telnet server is using the [oai configuration module](Config/Rtusage). Telnet parameters must be specified in the `telnetsrv` section. Some parameters can be modified via the telnet telnet server command, as specified in the last column of the following table.
|
||||
@@ -36,4 +36,4 @@ The telnet server is using the [oai configuration module](Config/Rtusage). Telne
|
||||
| `histfile` | `character string` | "oaitelnet.history" | file used for command history persistency | Y |
|
||||
| `histfsize` | `integer` | 50 | maximum number of commands saved in the history | Y |
|
||||
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
#include "telnetsrv_phycmd.h"
|
||||
#include "telnetsrv_proccmd.h"
|
||||
static char *telnet_defstatmod[] = {"softmodem","phy","loader"};
|
||||
static char *telnet_defstatmod[] = {"softmodem","phy","loader","measur"};
|
||||
static telnetsrv_params_t telnetparams;
|
||||
#define TELNETSRV_LISTENADDR 0
|
||||
#define TELNETSRV_LISTENPORT 1
|
||||
@@ -355,7 +355,7 @@ int setgetvar(int moduleindex,char getorset,char *params) {
|
||||
char varname[TELNET_CMD_MAXSIZE];
|
||||
char *varval=NULL;
|
||||
memset(varname,0,sizeof(varname));
|
||||
n = sscanf(params,"%s %ms",varname,&varval);
|
||||
n = sscanf(params,"%9s %ms",varname,&varval);
|
||||
|
||||
for ( i=0 ; telnetparams.CmdParsers[moduleindex].var[i].varvalptr != NULL ; i++) {
|
||||
if ( strncasecmp(telnetparams.CmdParsers[moduleindex].var[i].varname,varname,strlen(telnetparams.CmdParsers[moduleindex].var[i].varname)) == 0) {
|
||||
@@ -475,7 +475,7 @@ int process_command(char *buf) {
|
||||
memset(cmdb,0,sizeof(cmdb));
|
||||
bufbck=strdup(buf);
|
||||
rt=CMDSTATUS_NOTFOUND;
|
||||
j = sscanf(buf,"%9s %9s %[^\t\n]",modulename,cmd,cmdb);
|
||||
j = sscanf(buf,"%9s %9s %9[^\t\n]",modulename,cmd,cmdb);
|
||||
|
||||
if (telnetparams.telnetdbg > 0)
|
||||
printf("process_command: %i words, module=%s cmd=%s, parameters= %s\n",j,modulename,cmd,cmdb);
|
||||
@@ -500,23 +500,32 @@ int process_command(char *buf) {
|
||||
}/* else */
|
||||
}/* strncmp: module name test */
|
||||
else if (strncasecmp(modulename,"loop",4) == 0 ) {
|
||||
int lc;
|
||||
int f = fcntl(telnetparams.new_socket,F_GETFL);
|
||||
fcntl (telnetparams.new_socket, F_SETFL, O_NONBLOCK | f);
|
||||
int f1=fcntl (telnetparams.new_socket, F_SETFL, O_NONBLOCK | f);
|
||||
|
||||
for(lc=0; lc<telnetparams.loopcount; lc++) {
|
||||
if (f<0 || f1 <0) {
|
||||
client_printf( " Loop won't be cancelable: %s\n",strerror(errno) );
|
||||
}
|
||||
|
||||
for(int lc=0; lc<telnetparams.loopcount; lc++) {
|
||||
char dummybuff[20];
|
||||
char tbuff[64];
|
||||
int rs;
|
||||
client_printf(CSI "1J" CSI "1;10H " STDFMT "%s %i/%i\n",
|
||||
get_time(tbuff,sizeof(tbuff)),lc,telnetparams.loopcount );
|
||||
process_command(bufbck+strlen("loop")+1);
|
||||
usleep(telnetparams.loopdelay * 1000);
|
||||
rs = read(telnetparams.new_socket,dummybuff,sizeof(dummybuff));
|
||||
errno=0;
|
||||
int rs = read(telnetparams.new_socket,dummybuff,sizeof(dummybuff));
|
||||
|
||||
if ( rs > 0 ) {
|
||||
if (telnetparams.telnetdbg > 0)
|
||||
client_printf("Received \"%s\" status %d, errno %s while running loop\n",dummybuff,rs,strerror(errno));
|
||||
|
||||
if ( errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
client_printf( STDFMT " Loop canceled, iteration %i/%i\n",lc,telnetparams.loopcount );
|
||||
lc=telnetparams.loopcount;
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(telnetparams.loopdelay * 1000);
|
||||
}
|
||||
|
||||
fcntl (telnetparams.new_socket, F_SETFL, f);
|
||||
|
||||
@@ -69,7 +69,8 @@ typedef struct cmddef {
|
||||
#define TELNET_VARTYPE_INT64 3
|
||||
#define TELNET_VARTYPE_STRING 4
|
||||
#define TELNET_VARTYPE_DOUBLE 5
|
||||
//#define TELNET_VARTYPE_PTR 6
|
||||
#define TELNET_VARTYPE_INT8 6
|
||||
#define TELNET_VARTYPE_UINT 7
|
||||
typedef struct variabledef {
|
||||
char varname[TELNET_CMD_MAXSIZE];
|
||||
char vartype;
|
||||
|
||||
@@ -9,6 +9,7 @@ set(TELNETSRV_SOURCE
|
||||
${TELNETROOT}/telnetsrv_phycmd.c
|
||||
${TELNETROOT}/telnetsrv_proccmd.c
|
||||
${TELNETROOT}/telnetsrv_loader.c
|
||||
${TELNETROOT}/telnetsrv_measurements.c
|
||||
)
|
||||
|
||||
#set(TELNETSRV_ETHDEVCMD_SOURCE
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file common/utils/telnetsrv/telnetsrv_cpumeasur_def.h
|
||||
* \brief: definitions of macro used to initialize the telnet_ltemeasurdef_t
|
||||
* \ strucures arrays which are then used by the display functions
|
||||
* \ in telnetsrv_measurements.c.
|
||||
* \author Francois TABURET
|
||||
* \date 2019
|
||||
* \version 0.1
|
||||
* \company NOKIA BellLabs France
|
||||
* \email: francois.taburet@nokia-bell-labs.com
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
|
||||
#define CPU_PHYENB_MEASURE \
|
||||
{ \
|
||||
{"phy_proc_tx", &(phyvars->phy_proc_tx),0},\
|
||||
{"phy_proc_rx", &(phyvars->phy_proc_rx),0},\
|
||||
{"rx_prach", &(phyvars->rx_prach),0},\
|
||||
{"ofdm_mod", &(phyvars->ofdm_mod_stats),0},\
|
||||
{"dlsch_common_and_dci", &(phyvars->dlsch_common_and_dci),0},\
|
||||
{"dlsch_ue_specific", &(phyvars->dlsch_ue_specific),0},\
|
||||
{"dlsch_encoding", &(phyvars->dlsch_encoding_stats),0},\
|
||||
{"dlsch_modulation", &(phyvars->dlsch_modulation_stats),0},\
|
||||
{"dlsch_scrambling", &(phyvars->dlsch_scrambling_stats),0},\
|
||||
{"dlsch_rate_matching", &(phyvars->dlsch_rate_matching_stats),0},\
|
||||
{"dlsch_turbo_encod_prep", &(phyvars->dlsch_turbo_encoding_preperation_stats),0},\
|
||||
{"dlsch_turbo_encod_segm", &(phyvars->dlsch_turbo_encoding_segmentation_stats),0},\
|
||||
{"dlsch_turbo_encod", &(phyvars->dlsch_turbo_encoding_stats),0},\
|
||||
{"dlsch_turbo_encod_waiting", &(phyvars->dlsch_turbo_encoding_waiting_stats),0},\
|
||||
{"dlsch_turbo_encod_signal", &(phyvars->dlsch_turbo_encoding_signal_stats),0},\
|
||||
{"dlsch_turbo_encod_main", &(phyvars->dlsch_turbo_encoding_main_stats),0},\
|
||||
{"dlsch_turbo_encod_wakeup0", &(phyvars->dlsch_turbo_encoding_wakeup_stats0),0},\
|
||||
{"dlsch_turbo_encod_wakeup1", &(phyvars->dlsch_turbo_encoding_wakeup_stats1),0},\
|
||||
{"dlsch_interleaving", &(phyvars->dlsch_interleaving_stats),0},\
|
||||
{"rx_dft", &(phyvars->rx_dft_stats),0},\
|
||||
{"ulsch_channel_estimation", &(phyvars->ulsch_channel_estimation_stats),0},\
|
||||
{"ulsch_freq_offset_estimation", &(phyvars->ulsch_freq_offset_estimation_stats),0},\
|
||||
{"ulsch_decoding", &(phyvars->ulsch_decoding_stats),0},\
|
||||
{"ulsch_demodulation", &(phyvars->ulsch_demodulation_stats),0},\
|
||||
{"ulsch_rate_unmatching", &(phyvars->ulsch_rate_unmatching_stats),0},\
|
||||
{"ulsch_turbo_decoding", &(phyvars->ulsch_turbo_decoding_stats),0},\
|
||||
{"ulsch_deinterleaving", &(phyvars->ulsch_deinterleaving_stats),0},\
|
||||
{"ulsch_demultiplexing", &(phyvars->ulsch_demultiplexing_stats),0},\
|
||||
{"ulsch_llr", &(phyvars->ulsch_llr_stats),0},\
|
||||
{"ulsch_tc_init", &(phyvars->ulsch_tc_init_stats),0},\
|
||||
{"ulsch_tc_alpha", &(phyvars->ulsch_tc_alpha_stats),0},\
|
||||
{"ulsch_tc_beta", &(phyvars->ulsch_tc_beta_stats),0},\
|
||||
{"ulsch_tc_gamma", &(phyvars->ulsch_tc_gamma_stats),0},\
|
||||
{"ulsch_tc_ext", &(phyvars->ulsch_tc_ext_stats),0},\
|
||||
{"ulsch_tc_intl1", &(phyvars->ulsch_tc_intl1_stats),0},\
|
||||
{"ulsch_tc_intl2", &(phyvars->ulsch_tc_intl2_stats),0},\
|
||||
}
|
||||
|
||||
#define CPU_MACENB_MEASURE \
|
||||
{ \
|
||||
{"eNB_scheduler", &(macvars->eNB_scheduler),0},\
|
||||
{"schedule_si", &(macvars->schedule_si),0},\
|
||||
{"schedule_ra", &(macvars->schedule_ra),0},\
|
||||
{"schedule_ulsch", &(macvars->schedule_ulsch),0},\
|
||||
{"fill_DLSCH_dci", &(macvars->fill_DLSCH_dci),0},\
|
||||
{"schedule_dlsch_pre", &(macvars->schedule_dlsch_preprocessor),0},\
|
||||
{"schedule_dlsch", &(macvars->schedule_dlsch),0},\
|
||||
{"schedule_mch", &(macvars->schedule_mch),0},\
|
||||
{"rx_ulsch_sdu", &(macvars->rx_ulsch_sdu),0},\
|
||||
{"schedule_pch", &(macvars->schedule_pch),0},\
|
||||
}
|
||||
|
||||
#define CPU_PDCPENB_MEASURE \
|
||||
{ \
|
||||
{"pdcp_run", &(pdcpvars->pdcp_run),0},\
|
||||
{"data_req", &(pdcpvars->data_req),0},\
|
||||
{"data_ind", &(pdcpvars->data_ind),0},\
|
||||
{"apply_security", &(pdcpvars->apply_security),0},\
|
||||
{"validate_security", &(pdcpvars->validate_security),0},\
|
||||
{"pdcp_ip", &(pdcpvars->pdcp_ip),0},\
|
||||
{"ip_pdcp", &(pdcpvars->ip_pdcp),0},\
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file common/utils/telnetsrv/telnetsrv_ltemeasur_def.h
|
||||
* \brief: definitions of macro used to initialize the telnet_ltemeasurdef_t
|
||||
* \ strucures arrays which are then used by the display functions
|
||||
* \ in telnetsrv_measurements.c.
|
||||
* \author Francois TABURET
|
||||
* \date 2019
|
||||
* \version 0.1
|
||||
* \company NOKIA BellLabs France
|
||||
* \email: francois.taburet@nokia-bell-labs.com
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
|
||||
#define LTEMAC_MEASURE \
|
||||
{ \
|
||||
{"total_num_bcch_pdu", &(macstatptr->total_num_bcch_pdu),TELNET_VARTYPE_INT32,0},\
|
||||
{"bcch_buffer", &(macstatptr->bcch_buffer),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_bcch_buffer", &(macstatptr->total_bcch_buffer),TELNET_VARTYPE_INT32,0},\
|
||||
{"bcch_mcs", &(macstatptr->bcch_mcs),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_num_ccch_pdu", &(macstatptr->total_num_ccch_pdu),TELNET_VARTYPE_INT32,0},\
|
||||
{"ccch_buffer", &(macstatptr->ccch_buffer),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_ccch_buffer", &(macstatptr->total_ccch_buffer),TELNET_VARTYPE_INT32,0},\
|
||||
{"ccch_mcs", &(macstatptr->ccch_mcs),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_num_pcch_pdu", &(macstatptr->total_num_pcch_pdu),TELNET_VARTYPE_INT32,0},\
|
||||
{"pcch_buffer", &(macstatptr->pcch_buffer),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_pcch_buffer", &(macstatptr->total_pcch_buffer),TELNET_VARTYPE_INT32,0},\
|
||||
{"pcch_mcs", &(macstatptr->pcch_mcs),TELNET_VARTYPE_INT32,0},\
|
||||
{"num_dlactive_UEs", &(macstatptr->num_dlactive_UEs),TELNET_VARTYPE_INT16,0},\
|
||||
{"available_prbs", &(macstatptr->available_prbs),TELNET_VARTYPE_INT16,0},\
|
||||
{"total_available_prbs", &(macstatptr->total_available_prbs),TELNET_VARTYPE_INT32,0},\
|
||||
{"available_ncces", &(macstatptr->available_ncces),TELNET_VARTYPE_INT16,0},\
|
||||
{"dlsch_bitrate", &(macstatptr->dlsch_bitrate),TELNET_VARTYPE_INT32,0},\
|
||||
{"dlsch_bytes_tx", &(macstatptr->dlsch_bytes_tx),TELNET_VARTYPE_INT32,0},\
|
||||
{"dlsch_pdus_tx", &(macstatptr->dlsch_pdus_tx),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_dlsch_bitrate", &(macstatptr->total_dlsch_bitrate),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_dlsch_bytes_tx", &(macstatptr->total_dlsch_bytes_tx),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_dlsch_pdus_tx", &(macstatptr->total_dlsch_pdus_tx),TELNET_VARTYPE_INT32,0},\
|
||||
{"ulsch_bitrate", &(macstatptr->ulsch_bitrate),TELNET_VARTYPE_INT32,0},\
|
||||
{"ulsch_bytes_rx", &(macstatptr->ulsch_bytes_rx),TELNET_VARTYPE_INT32,0},\
|
||||
{"ulsch_pdus_rx", &(macstatptr->ulsch_pdus_rx),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_ulsch_bitrate", &(macstatptr->total_ulsch_bitrate),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_ulsch_bytes_rx", &(macstatptr->total_ulsch_bytes_rx),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_ulsch_pdus_rx", &(macstatptr->total_ulsch_pdus_rx),TELNET_VARTYPE_INT32,0},\
|
||||
{"sched_decisions", &(macstatptr->sched_decisions),TELNET_VARTYPE_INT32,0},\
|
||||
{"missed_deadlines", &(macstatptr->missed_deadlines),TELNET_VARTYPE_INT32,0},\
|
||||
}
|
||||
|
||||
#define LTEMAC_UEMEASURE \
|
||||
{ \
|
||||
{"dlsch_mcs1", &(macuestatptr->dlsch_mcs1),TELNET_VARTYPE_INT8,0},\
|
||||
{"dlsch_mcs2", &(macuestatptr->dlsch_mcs2),TELNET_VARTYPE_INT8,0},\
|
||||
{"rbs_used", &(macuestatptr->rbs_used),TELNET_VARTYPE_INT32,0},\
|
||||
{"rbs_used_retx", &(macuestatptr->rbs_used_retx),TELNET_VARTYPE_INT16,0},\
|
||||
{"total_rbs_used", &(macuestatptr->total_rbs_used),TELNET_VARTYPE_INT16,0},\
|
||||
{"ncce_used", &(macuestatptr->ncce_used),TELNET_VARTYPE_INT16,0},\
|
||||
{"ncce_used_retx", &(macuestatptr->ncce_used_retx),TELNET_VARTYPE_INT16,0},\
|
||||
{"TBS", &(macuestatptr->TBS),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_pdu_bytes", &(macuestatptr->total_pdu_bytes),TELNET_VARTYPE_INT64,0},\
|
||||
{"total_num_pdus", &(macuestatptr->total_num_pdus),TELNET_VARTYPE_INT32,0},\
|
||||
{"overhead_bytes", &(macuestatptr->overhead_bytes),TELNET_VARTYPE_INT64,0},\
|
||||
{"crnti", &(macuestatptr->crnti),TELNET_VARTYPE_INT16,0},\
|
||||
{"normalized_rx_power", &(macuestatptr->normalized_rx_power),TELNET_VARTYPE_INT32,0},\
|
||||
{"target_rx_power", &(macuestatptr->target_rx_power),TELNET_VARTYPE_INT32,0},\
|
||||
{"ulsch_mcs1", &(macuestatptr->ulsch_mcs1),TELNET_VARTYPE_INT8,0},\
|
||||
{"ulsch_mcs2", &(macuestatptr->ulsch_mcs2),TELNET_VARTYPE_INT8,0},\
|
||||
{"rbs_used_rx", &(macuestatptr->rbs_used_rx),TELNET_VARTYPE_INT32,0},\
|
||||
{"rbs_used_retx_rx", &(macuestatptr->rbs_used_retx_rx),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_rbs_used_rx", &(macuestatptr->total_rbs_used_rx),TELNET_VARTYPE_INT32,0},\
|
||||
{"ulsch_TBS", &(macuestatptr->ulsch_TBS),TELNET_VARTYPE_INT32,0},\
|
||||
{"total_pdu_bytes_rx", &(macuestatptr->total_pdu_bytes_rx),TELNET_VARTYPE_INT64,0},\
|
||||
{"total_num_pdus_rx", &(macuestatptr->total_num_pdus_rx),TELNET_VARTYPE_INT32,0},\
|
||||
{"num_errors_rx", &(macuestatptr->num_errors_rx),TELNET_VARTYPE_INT32,0},\
|
||||
}
|
||||
|
||||
#define LTE_RLCMEASURE \
|
||||
{ \
|
||||
{"rlc_mode", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_pdcp_sdu", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_pdcp_bytes", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_pdcp_sdu_discarded", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_pdcp_bytes_discarded", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_data_pdu", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_data_bytes", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_retransmit_pdu_by_status", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_retransmit_bytes_by_status", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_retransmit_pdu", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_retransmit_bytes", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_control_pdu", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"tx_control_bytes", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_pdcp_sdu", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_pdcp_bytes", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_data_pdus_duplicate", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_data_bytes_duplicate", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_data_pdu", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_data_bytes", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_data_pdu_dropped", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_data_bytes_dropped", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_data_pdu_out_of_window", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_data_bytes_out_of_window", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_control_pdu", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"rx_control_bytes", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"timer_reorder_tout", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"timer_poll_retrans_tout", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
{"timer_status_prohibit_tout", NULL, TELNET_VARTYPE_UINT, 0},\
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file common/utils/telnetsrv/telnetsrv_measurements.c
|
||||
* \brief: implementation of telnet commands related to measurments
|
||||
* \author Francois TABURET
|
||||
* \date 2019
|
||||
* \version 0.1
|
||||
* \company NOKIA BellLabs France
|
||||
* \email: francois.taburet@nokia-bell-labs.com
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#define TELNETSERVERCODE
|
||||
#include "telnetsrv.h"
|
||||
#define TELNETSRV_MEASURMENTS_MAIN
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "telnetsrv_measurements.h"
|
||||
#include "telnetsrv_ltemeasur_def.h"
|
||||
#include "telnetsrv_cpumeasur_def.h"
|
||||
#include "openair2/LAYER2/MAC/mac.h"
|
||||
#include "openair1/PHY/phy_extern.h"
|
||||
|
||||
void measurcmd_display_macstats(telnet_printfunc_t prnt);
|
||||
void measurcmd_display_macstats_ue(telnet_printfunc_t prnt);
|
||||
void measurcmd_display_rlcstats(telnet_printfunc_t prnt);
|
||||
void measurcmd_display_phycpu(telnet_printfunc_t prnt);
|
||||
void measurcmd_display_maccpu(telnet_printfunc_t prnt);
|
||||
void measurcmd_display_pdcpcpu(telnet_printfunc_t prnt);
|
||||
|
||||
|
||||
static telnet_measurgroupdef_t measurgroups[] = {
|
||||
{"enb", GROUP_LTESTATS,0, measurcmd_display_macstats, {NULL}},
|
||||
{"enbues",GROUP_LTESTATS,0, measurcmd_display_macstats_ue,{NULL}},
|
||||
{"rlc", GROUP_LTESTATS,0, measurcmd_display_rlcstats, {NULL}},
|
||||
{"phycpu",GROUP_CPUSTATS,0, measurcmd_display_phycpu, {NULL}},
|
||||
{"maccpu",GROUP_CPUSTATS,0, measurcmd_display_maccpu, {NULL}},
|
||||
{"pdcpcpu",GROUP_CPUSTATS,0, measurcmd_display_pdcpcpu, {NULL}},
|
||||
};
|
||||
#define TELNET_NUM_MEASURGROUPS (sizeof(measurgroups)/sizeof(telnet_measurgroupdef_t))
|
||||
|
||||
static int eNB_id =0;
|
||||
static char *grouptypes[] = {"ltestats","cpustats"};
|
||||
static double cpufreq;
|
||||
#define TELNET_NUM_MEASURTYPES (sizeof(grouptypes)/sizeof(char *))
|
||||
|
||||
#define HDR "---------------------------------"
|
||||
|
||||
void measurcmd_display_groups(telnet_printfunc_t prnt) {
|
||||
prnt(" %*s %10s %s\n",TELNET_MAXMEASURNAME_LEN-1,"name","type","nombre de mesures");
|
||||
|
||||
for(int i=0; i<TELNET_NUM_MEASURGROUPS; i++)
|
||||
prnt("%02d %*s %10s %i\n",i,TELNET_MAXMEASURNAME_LEN-1,measurgroups[i].groupname,
|
||||
grouptypes[measurgroups[i].type], measurgroups[i].size);
|
||||
} /* measurcmd_display_groups */
|
||||
/*----------------------------------------------------------------------------------------------------*/
|
||||
/* cpu measurements functions */
|
||||
void measurcmd_display_cpumeasures(telnet_printfunc_t prnt, telnet_cpumeasurdef_t *cpumeasure, int cpumeasure_size) {
|
||||
for (int i=0; i<cpumeasure_size; i++) {
|
||||
prnt("%02d %*s: %15.3f us; %15d %s",i,TELNET_MAXMEASURNAME_LEN-1,(cpumeasure+i)->statname,
|
||||
((cpumeasure+i)->astatptr->trials!=0)?(((cpumeasure+i)->astatptr->diff)/((cpumeasure+i)->astatptr->trials))/cpufreq/1000:0,
|
||||
(cpumeasure+i)->astatptr->trials, ((i%2)==1)?"|\n":" | " );
|
||||
}
|
||||
|
||||
prnt("\n\n");
|
||||
} /* measurcmd_display_measures */
|
||||
|
||||
#define PRINT_CPUMEAS_STATE ((cpumeas(CPUMEAS_GETSTATE))?"enabled":"disabled")
|
||||
void measurcmd_display_phycpu(telnet_printfunc_t prnt) {
|
||||
PHY_VARS_eNB *phyvars = RC.eNB[eNB_id][0];
|
||||
telnet_cpumeasurdef_t cpumeasur[]=CPU_PHYENB_MEASURE;
|
||||
prnt("%s cpu (%1.1g GHz) measurements: PHY (cpustats %s) %s\n",HDR,cpufreq,
|
||||
PRINT_CPUMEAS_STATE,HDR);
|
||||
measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t));
|
||||
}
|
||||
|
||||
void measurcmd_display_maccpu(telnet_printfunc_t prnt) {
|
||||
eNB_MAC_INST *macvars = RC.mac[eNB_id];
|
||||
telnet_cpumeasurdef_t cpumeasur[]=CPU_MACENB_MEASURE;
|
||||
prnt("%s cpu (%1.1g GHz) measurements: MAC (cpustats %s) %s\n",HDR,cpufreq,
|
||||
PRINT_CPUMEAS_STATE,HDR);
|
||||
measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t));
|
||||
}
|
||||
|
||||
void measurcmd_display_pdcpcpu(telnet_printfunc_t prnt) {
|
||||
pdcp_stats_t *pdcpvars = &(eNB_pdcp_stats[eNB_id]);
|
||||
telnet_cpumeasurdef_t cpumeasur[]=CPU_PDCPENB_MEASURE;
|
||||
prnt("%s cpu (%1.1g GHz) measurements: PDCP (cpustats %s) %s \n",HDR,cpufreq,
|
||||
PRINT_CPUMEAS_STATE,HDR);
|
||||
measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t));
|
||||
}
|
||||
/*----------------------------------------------------------------------------------------------------*/
|
||||
/* lte measurements functions */
|
||||
uint64_t measurcmd_getstatvalue(telnet_ltemeasurdef_t *measur,telnet_printfunc_t prnt) {
|
||||
uint64_t val;
|
||||
|
||||
switch(measur->vtyp) {
|
||||
case TELNET_VARTYPE_INT64:
|
||||
val = (uint64_t)(*((uint64_t *)(measur->vptr)));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT32:
|
||||
val = (uint64_t)(*((uint32_t *)(measur->vptr)));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT16:
|
||||
val = (uint64_t)(*((uint16_t *)(measur->vptr)));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT8:
|
||||
val = (uint64_t)(*((uint8_t *)(measur->vptr)));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_UINT:
|
||||
val = (uint64_t)(*((unsigned int *)(measur->vptr)));
|
||||
break;
|
||||
|
||||
default:
|
||||
prnt("%s %i: unknown type \n",measur->statname,measur->vtyp);
|
||||
val = (uint64_t)(*((uint64_t *)(measur->vptr)));
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
} /* measurcmd_getstatvalue */
|
||||
|
||||
void measurcmd_display_measures(telnet_printfunc_t prnt, telnet_ltemeasurdef_t *statsptr, int stats_size) {
|
||||
for (int i=0; i<stats_size; i++) {
|
||||
prnt("%*s = %15llu%s",TELNET_MAXMEASURNAME_LEN-1,statsptr[i].statname,
|
||||
measurcmd_getstatvalue(&(statsptr[i]),prnt), ((i%3)==2)?"\n":" ");
|
||||
}
|
||||
|
||||
prnt("\n\n");
|
||||
} /* measurcmd_display_measures */
|
||||
|
||||
void measurcmd_display_macstats_ue(telnet_printfunc_t prnt) {
|
||||
UE_list_t *UE_list = &(RC.mac[eNB_id]->UE_list);
|
||||
|
||||
for (int UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) {
|
||||
for (int i=0; i<UE_list->numactiveCCs[UE_id]; i++) {
|
||||
int CC_id = UE_list->ordered_CCids[i][UE_id];
|
||||
prnt("%s UE %i Id %i CCid %i %s\n",HDR,i,UE_id,CC_id,HDR);
|
||||
eNB_UE_STATS *macuestatptr = &(UE_list->eNB_UE_stats[CC_id][UE_id]);
|
||||
telnet_ltemeasurdef_t statsptr[]=LTEMAC_UEMEASURE;
|
||||
measurcmd_display_measures(prnt, statsptr, sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t));
|
||||
}
|
||||
}
|
||||
} /* measurcmd_display_macstats_ue */
|
||||
|
||||
void measurcmd_display_macstats(telnet_printfunc_t prnt) {
|
||||
for (int CC_id=0 ; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
eNB_STATS *macstatptr=&(RC.mac[eNB_id]->eNB_stats[CC_id]);
|
||||
telnet_ltemeasurdef_t statsptr[]=LTEMAC_MEASURE;
|
||||
prnt("%s eNB %i mac stats CC %i frame %u %s\n",
|
||||
HDR, eNB_id, CC_id, RC.mac[eNB_id]->frame,HDR);
|
||||
measurcmd_display_measures(prnt,statsptr,sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t));
|
||||
}
|
||||
} /* measurcmd_display_macstats */
|
||||
|
||||
|
||||
void measurcmd_display_one_rlcstat(telnet_printfunc_t prnt, int UE_id, telnet_ltemeasurdef_t *statsptr, int num_rlcmeasure, unsigned int *rlcstats,
|
||||
char *rbid_str, protocol_ctxt_t *ctxt, const srb_flag_t srb_flagP, const rb_id_t rb_idP)
|
||||
|
||||
{
|
||||
int rlc_status = rlc_stat_req(ctxt,srb_flagP,rb_idP,
|
||||
rlcstats, rlcstats+1, rlcstats+2, rlcstats+3, rlcstats+4, rlcstats+5,
|
||||
rlcstats+6, rlcstats+7, rlcstats+8, rlcstats+9, rlcstats+10, rlcstats+11,
|
||||
rlcstats+12, rlcstats+13, rlcstats+14, rlcstats+15, rlcstats+16, rlcstats+17,
|
||||
rlcstats+18, rlcstats+19, rlcstats+20, rlcstats+21, rlcstats+22, rlcstats+23,
|
||||
rlcstats+24, rlcstats+25, rlcstats+26, rlcstats+27);
|
||||
|
||||
if (rlc_status == RLC_OP_STATUS_OK) {
|
||||
prnt("%s UE %i RLC %s mode %s %s\n",HDR,UE_id, rbid_str,
|
||||
(rlcstats[0]==RLC_MODE_AM)? "AM": (rlcstats[0]==RLC_MODE_UM)?"UM":"NONE",HDR);
|
||||
measurcmd_display_measures(prnt, statsptr, num_rlcmeasure);
|
||||
}
|
||||
} /* status measurcmd_rlc_stat_req */
|
||||
|
||||
|
||||
void measurcmd_display_rlcstats(telnet_printfunc_t prnt) {
|
||||
protocol_ctxt_t ctxt;
|
||||
UE_list_t *UE_list = &(RC.mac[eNB_id]->UE_list);
|
||||
telnet_ltemeasurdef_t statsptr[]=LTE_RLCMEASURE;
|
||||
int num_rlcmeasure = sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t );
|
||||
unsigned int *rlcstats = malloc(num_rlcmeasure*sizeof(unsigned int));
|
||||
eNB_MAC_INST *eNB = RC.mac[eNB_id];
|
||||
|
||||
for(int i=0; i <num_rlcmeasure ; i++) {
|
||||
statsptr[i].vptr = rlcstats + i;
|
||||
}
|
||||
|
||||
for (int UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) {
|
||||
#define NB_eNB_INST 1
|
||||
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt,eNB_id, ENB_FLAG_YES,UE_list->eNB_UE_stats[0][UE_id].crnti,
|
||||
eNB->frame,eNB->subframe,eNB_id);
|
||||
measurcmd_display_one_rlcstat(prnt, UE_id, statsptr, num_rlcmeasure, rlcstats, "DCCH", &ctxt, SRB_FLAG_YES, DCCH);
|
||||
measurcmd_display_one_rlcstat(prnt, UE_id, statsptr, num_rlcmeasure, rlcstats, "DTCH", &ctxt, SRB_FLAG_NO, DTCH-2);
|
||||
}
|
||||
} /* measurcmd_display_macstats_ue */
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* function called by the telnet server when measur command is entered */
|
||||
int measurcmd_show(char *buf, int debug, telnet_printfunc_t prnt) {
|
||||
char *subcmd=NULL;
|
||||
int idx1, idx2;
|
||||
int badcmd=1;
|
||||
|
||||
if (debug > 0)
|
||||
prnt(" measurcmd_show received %s\n",buf);
|
||||
|
||||
// char tmp[20480];
|
||||
// dump_eNB_l2_stats(tmp, 0);
|
||||
// prnt("%s\n",tmp);
|
||||
int s = sscanf(buf,"%ms %i-%i\n",&subcmd, &idx1,&idx2);
|
||||
|
||||
if (s>0) {
|
||||
if ( strcmp(subcmd,"groups") == 0) {
|
||||
measurcmd_display_groups(prnt);
|
||||
badcmd=0;
|
||||
} else {
|
||||
for (int i=0; i<TELNET_NUM_MEASURTYPES; i++) {
|
||||
if(strcmp(subcmd,grouptypes[i]) == 0) {
|
||||
for(int j=0; j<TELNET_NUM_MEASURGROUPS; j++) {
|
||||
if(i == measurgroups[j].type) {
|
||||
badcmd=0;
|
||||
measurgroups[j].displayfunc(prnt);
|
||||
}
|
||||
} /* for j...*/
|
||||
}
|
||||
}/* for i...*/
|
||||
|
||||
for (int i=0; i<TELNET_NUM_MEASURGROUPS; i++) {
|
||||
if(strcmp(subcmd,measurgroups[i].groupname) == 0) {
|
||||
measurgroups[i].displayfunc(prnt);
|
||||
badcmd=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(subcmd);
|
||||
} /* s>0 */
|
||||
|
||||
if (badcmd) {
|
||||
prnt("%s: unknown measur command\n",buf);
|
||||
}
|
||||
|
||||
return CMDSTATUS_FOUND;
|
||||
}
|
||||
|
||||
|
||||
int measurcmd_cpustats(char *buf, int debug, telnet_printfunc_t prnt) {
|
||||
char *subcmd=NULL;
|
||||
int idx1, idx2;
|
||||
int badcmd=1;
|
||||
|
||||
if (debug > 0)
|
||||
prnt(" measurcmd_show received %s\n",buf);
|
||||
|
||||
int s = sscanf(buf,"%ms %i-%i\n",&subcmd, &idx1,&idx2);
|
||||
|
||||
if (s>0) {
|
||||
if ( strcmp(subcmd,"enable") == 0) {
|
||||
cpumeas(CPUMEAS_ENABLE);
|
||||
badcmd=0;
|
||||
} else if ( strcmp(subcmd,"disable") == 0) {
|
||||
cpumeas(CPUMEAS_DISABLE);
|
||||
badcmd=0;
|
||||
}
|
||||
}
|
||||
|
||||
if (badcmd) {
|
||||
prnt("Cpu measurments state: %s\n",PRINT_CPUMEAS_STATE);
|
||||
}
|
||||
|
||||
free(subcmd);
|
||||
return CMDSTATUS_FOUND;
|
||||
}
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
|
||||
/* function called at telnet server init to add the measur command */
|
||||
void add_measur_cmds(void) {
|
||||
add_telnetcmd("measur",measur_vardef,measur_cmdarray);
|
||||
cpufreq = get_cpu_freq_GHz();
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
/*! \file common/utils/telnetsrv/telnetsrv_measurements.h
|
||||
* \brief: Include file defining constants, structures and function prototypes
|
||||
* \ used to implement the measurements functionality of the telnet server
|
||||
* \author Francois TABURET
|
||||
* \date 2019
|
||||
* \version 0.1
|
||||
* \company NOKIA BellLabs France
|
||||
* \email: francois.taburet@nokia-bell-labs.com
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
#include <dlfcn.h>
|
||||
#include "telnetsrv.h"
|
||||
#include "openair1/PHY/defs_eNB.h"
|
||||
#ifdef TELNETSRV_MEASURMENTS_MAIN
|
||||
|
||||
|
||||
#define TELNET_MAXMEASURNAME_LEN 30
|
||||
#define TELNET_MAXMEASURGROUPS 10
|
||||
|
||||
telnetshell_vardef_t measur_vardef[] = {
|
||||
{"",0,NULL}
|
||||
};
|
||||
|
||||
typedef struct cpumeasurdef {
|
||||
char statname[TELNET_MAXMEASURNAME_LEN];
|
||||
time_stats_t *astatptr;
|
||||
unsigned int statemask;
|
||||
} telnet_cpumeasurdef_t;
|
||||
|
||||
typedef struct ltemeasurdef {
|
||||
char statname[TELNET_MAXMEASURNAME_LEN];
|
||||
void *vptr;
|
||||
char vtyp;
|
||||
unsigned int statemask;
|
||||
} telnet_ltemeasurdef_t;
|
||||
|
||||
#define GROUP_LTESTATS 0
|
||||
#define GROUP_CPUSTATS 1
|
||||
typedef void(*measur_dislayfunc_t)(telnet_printfunc_t prnt);
|
||||
typedef struct mesurgroupdef {
|
||||
char groupname[TELNET_MAXMEASURNAME_LEN];
|
||||
unsigned char type;
|
||||
unsigned char size;
|
||||
measur_dislayfunc_t displayfunc;
|
||||
union {
|
||||
telnet_cpumeasurdef_t *cpustats;
|
||||
telnet_ltemeasurdef_t *ltestats;
|
||||
};
|
||||
} telnet_measurgroupdef_t;
|
||||
|
||||
#define MACSTATS_NAME(valptr) #valptr
|
||||
#define LTEMAC_MEASURGROUP_NAME "ltemac"
|
||||
#define PHYCPU_MEASURGROUP_NAME "phycpu"
|
||||
|
||||
int measurcmd_show(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
int measurcmd_cpustats(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
telnetshell_cmddef_t measur_cmdarray[] = {
|
||||
{"show", "groups | <group name>" , measurcmd_show},
|
||||
{"cpustats","[enable | disable]",measurcmd_cpustats},
|
||||
{"","",NULL}
|
||||
};
|
||||
|
||||
#else
|
||||
extern void add_measur_cmds(void);
|
||||
#endif /* TELNETSRV_MEASURCMD_MAIN */
|
||||
@@ -183,7 +183,7 @@ struct dirent *entry;
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
continue;
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/task/%s/stat", getpid(),entry->d_name);
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/task/%.*s/stat", getpid(),(int)(sizeof(aname)-24),entry->d_name);
|
||||
read_statfile(aname,debug,prnt);
|
||||
} /* while entry != NULL */
|
||||
closedir(proc_dir);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
all: measurement_display thread-pool-test
|
||||
|
||||
measurement_display: measurement_display.c thread-pool.h
|
||||
gcc measurement_display.c -I /data/openairinterface5g.nr/common/utils/ -I. /data/openairinterface5g.nr/common/utils/backtrace.c -lpthread -D TEST_THREAD_POOL -I../LOG -I../../utils/T -o measurement_display
|
||||
|
||||
thread-pool-test: thread-pool.c thread-pool.h
|
||||
gcc -g thread-pool.c -I /data/openairinterface5g.nr/common/utils/ -I. /data/openairinterface5g.nr/common/utils/backtrace.c -lpthread -D TEST_THREAD_POOL -I../LOG -I../../utils/T -o thread-pool-test
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Author: Laurent THOMAS, Open Cells
|
||||
copyleft: OpenAirInterface Software Alliance and it's licence
|
||||
*/
|
||||
|
||||
#define __USE_GNU
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "thread-pool.h"
|
||||
|
||||
#define SEP "\t"
|
||||
|
||||
uint64_t cpuCyclesMicroSec;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if(argc != 2) {
|
||||
printf("Need one paramter: the trace Linux pipe (fifo)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mkfifo(argv[1],0666);
|
||||
int fd=open(argv[1], O_RDONLY);
|
||||
|
||||
if ( fd == -1 ) {
|
||||
perror("open read mode trace file:");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint64_t deb=rdtsc();
|
||||
usleep(100000);
|
||||
cpuCyclesMicroSec=(rdtsc()-deb)/100000;
|
||||
printf("Cycles per µs: %lu\n",cpuCyclesMicroSec);
|
||||
printf("Key" SEP "delay to process" SEP "processing time" SEP "delay to be read answer\n");
|
||||
notifiedFIFO_elt_t doneRequest;
|
||||
|
||||
while ( 1 ) {
|
||||
if ( read(fd,&doneRequest, sizeof(doneRequest)) == sizeof(doneRequest)) {
|
||||
printf("%lu" SEP "%lu" SEP "%lu" SEP "%lu" "\n",
|
||||
doneRequest.key,
|
||||
(doneRequest.startProcessingTime-doneRequest.creationTime)/cpuCyclesMicroSec,
|
||||
(doneRequest.endProcessingTime-doneRequest.startProcessingTime)/cpuCyclesMicroSec,
|
||||
(doneRequest.returnTime-doneRequest.endProcessingTime)/cpuCyclesMicroSec
|
||||
);
|
||||
} else {
|
||||
printf("no measurements\n");
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
Author: Laurent THOMAS, Open Cells
|
||||
copyleft: OpenAirInterface Software Alliance and it's licence
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <threadPool/thread-pool.h>
|
||||
|
||||
void displayList(notifiedFIFO_t *nf) {
|
||||
int n=0;
|
||||
notifiedFIFO_elt_t *ptr=nf->outF;
|
||||
|
||||
while(ptr) {
|
||||
printf("element: %d, key: %lu\n",++n,ptr->key);
|
||||
ptr=ptr->next;
|
||||
}
|
||||
|
||||
printf("End of list: %d elements\n",n);
|
||||
}
|
||||
|
||||
static inline notifiedFIFO_elt_t *pullNotifiedFifoRemember( notifiedFIFO_t *nf, struct one_thread *thr) {
|
||||
mutexlock(nf->lockF);
|
||||
|
||||
while(!nf->outF)
|
||||
condwait(nf->notifF, nf->lockF);
|
||||
|
||||
notifiedFIFO_elt_t *ret=nf->outF;
|
||||
nf->outF=nf->outF->next;
|
||||
|
||||
if (nf->outF==NULL)
|
||||
nf->inF=NULL;
|
||||
|
||||
// For abort feature
|
||||
thr->runningOnKey=ret->key;
|
||||
thr->abortFlag=false;
|
||||
mutexunlock(nf->lockF);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *one_thread(void *arg) {
|
||||
struct one_thread *myThread=(struct one_thread *) arg;
|
||||
struct thread_pool *tp=myThread->pool;
|
||||
|
||||
// configure the thread core assignment
|
||||
// TBD: reserve the core for us exclusively
|
||||
if ( myThread->coreID >= 0 && myThread->coreID < get_nprocs_conf()) {
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(myThread->coreID, &cpuset);
|
||||
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
|
||||
}
|
||||
|
||||
//Configure the thread scheduler policy for Linux
|
||||
struct sched_param sparam= {0};
|
||||
sparam.sched_priority = sched_get_priority_max(SCHED_RR);
|
||||
pthread_setschedparam(pthread_self(), SCHED_RR, &sparam);
|
||||
// set the thread name for debugging
|
||||
sprintf(myThread->name,"Tpool_%d",myThread->coreID);
|
||||
pthread_setname_np(pthread_self(), myThread->name );
|
||||
|
||||
// Infinite loop to process requests
|
||||
do {
|
||||
notifiedFIFO_elt_t *elt=pullNotifiedFifoRemember(&tp->incomingFifo, myThread);
|
||||
|
||||
if (tp->measurePerf) elt->startProcessingTime=rdtsc();
|
||||
|
||||
elt->processingFunc(NotifiedFifoData(elt));
|
||||
|
||||
if (tp->measurePerf) elt->endProcessingTime=rdtsc();
|
||||
|
||||
if (elt->reponseFifo) {
|
||||
// Check if the job is still alive, else it has been aborted
|
||||
mutexlock(tp->incomingFifo.lockF);
|
||||
|
||||
if (myThread->abortFlag)
|
||||
delNotifiedFIFO_elt(elt);
|
||||
else
|
||||
pushNotifiedFIFO(elt->reponseFifo, elt);
|
||||
|
||||
mutexunlock(tp->incomingFifo.lockF);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
void initTpool(char *params,tpool_t *pool, bool performanceMeas) {
|
||||
memset(pool,0,sizeof(*pool));
|
||||
char *measr=getenv("threadPoolMeasurements");
|
||||
pool->measurePerf=performanceMeas;
|
||||
// force measurement if the output is defined
|
||||
pool->measurePerf=measr!=NULL;
|
||||
|
||||
if (measr) {
|
||||
mkfifo(measr,0666);
|
||||
AssertFatal(-1 != (pool->dummyTraceFd=
|
||||
open(measr, O_RDONLY| O_NONBLOCK)),"");
|
||||
AssertFatal(-1 != (pool->traceFd=
|
||||
open(measr, O_WRONLY|O_APPEND|O_NOATIME|O_NONBLOCK)),"");
|
||||
} else
|
||||
pool->traceFd=-1;
|
||||
|
||||
//Configure the thread scheduler policy for Linux
|
||||
struct sched_param sparam= {0};
|
||||
sparam.sched_priority = sched_get_priority_max(SCHED_RR)-1;
|
||||
pthread_setschedparam(pthread_self(), SCHED_RR, &sparam);
|
||||
pool->activated=true;
|
||||
initNotifiedFIFO(&pool->incomingFifo);
|
||||
char *saveptr, * curptr;
|
||||
pool->nbThreads=0;
|
||||
pool->restrictRNTI=false;
|
||||
curptr=strtok_r(params,",",&saveptr);
|
||||
|
||||
while ( curptr!=NULL ) {
|
||||
int c=toupper(curptr[0]);
|
||||
|
||||
switch (c) {
|
||||
case 'U':
|
||||
pool->restrictRNTI=true;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
pool->activated=false;
|
||||
break;
|
||||
|
||||
default:
|
||||
pool->allthreads=(struct one_thread *)malloc(sizeof(struct one_thread));
|
||||
pool->allthreads->next=pool->allthreads;
|
||||
printf("create a thread for core %d\n", atoi(curptr));
|
||||
pool->allthreads->coreID=atoi(curptr);
|
||||
pool->allthreads->id=pool->nbThreads;
|
||||
pool->allthreads->pool=pool;
|
||||
pthread_create(&pool->allthreads->threadID, NULL, one_thread, (void *)pool->allthreads);
|
||||
pool->nbThreads++;
|
||||
}
|
||||
|
||||
curptr=strtok_r(NULL,",",&saveptr);
|
||||
}
|
||||
|
||||
if (pool->activated && pool->nbThreads==0) {
|
||||
printf("No servers created in the thread pool, exit\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_THREAD_POOL
|
||||
|
||||
struct testData {
|
||||
int id;
|
||||
char txt[30];
|
||||
};
|
||||
|
||||
void processing(void *arg) {
|
||||
struct testData *in=(struct testData *)arg;
|
||||
printf("doing: %d, %s, in thr %ld\n",in->id, in->txt,pthread_self() );
|
||||
sprintf(in->txt,"Done by %ld, job %d", pthread_self(), in->id);
|
||||
usleep(rand()%100);
|
||||
printf("done: %d, %s, in thr %ld\n",in->id, in->txt,pthread_self() );
|
||||
}
|
||||
|
||||
int main() {
|
||||
notifiedFIFO_t myFifo;
|
||||
initNotifiedFIFO(&myFifo);
|
||||
pushNotifiedFIFO(&myFifo,newNotifiedFIFO_elt(sizeof(struct testData), 1234,NULL,NULL));
|
||||
|
||||
for(int i=10; i>1; i--) {
|
||||
pushNotifiedFIFO(&myFifo,newNotifiedFIFO_elt(sizeof(struct testData), 1000+i,NULL,NULL));
|
||||
}
|
||||
|
||||
displayList(&myFifo);
|
||||
notifiedFIFO_elt_t *tmp=pullNotifiedFIFO(&myFifo);
|
||||
printf("pulled: %lu\n", tmp->key);
|
||||
displayList(&myFifo);
|
||||
tmp=pullNotifiedFIFO(&myFifo);
|
||||
printf("pulled: %lu\n", tmp->key);
|
||||
displayList(&myFifo);
|
||||
abortNotifiedFIFO(&myFifo,1005);
|
||||
printf("aborted 1005\n");
|
||||
displayList(&myFifo);
|
||||
pushNotifiedFIFO(&myFifo,newNotifiedFIFO_elt(sizeof(struct testData), 12345678, NULL, NULL));
|
||||
displayList(&myFifo);
|
||||
abortNotifiedFIFO(&myFifo,12345678);
|
||||
printf("aborted 12345678\n");
|
||||
displayList(&myFifo);
|
||||
|
||||
do {
|
||||
tmp=pollNotifiedFIFO(&myFifo);
|
||||
|
||||
if (tmp) {
|
||||
printf("pulled: %lu\n", tmp->key);
|
||||
displayList(&myFifo);
|
||||
} else
|
||||
printf("Empty list \n");
|
||||
} while(tmp);
|
||||
|
||||
tpool_t pool;
|
||||
char params[]="1,2,3,u";
|
||||
initTpool(params,&pool, true);
|
||||
notifiedFIFO_t worker_back;
|
||||
initNotifiedFIFO(&worker_back);
|
||||
|
||||
for (int i=0; i <1000 ; i++) {
|
||||
notifiedFIFO_elt_t *work=newNotifiedFIFO_elt(sizeof(struct testData), i, &worker_back, processing);
|
||||
struct testData *x=(struct testData *)NotifiedFifoData(work);
|
||||
x->id=i;
|
||||
pushTpool(&pool, work);
|
||||
}
|
||||
|
||||
do {
|
||||
tmp=pullTpool(&worker_back,&pool);
|
||||
|
||||
if (tmp) {
|
||||
struct testData *dd=NotifiedFifoData(tmp);
|
||||
printf("Result: %s\n",dd->txt);
|
||||
delNotifiedFIFO_elt(tmp);
|
||||
} else
|
||||
printf("Empty list \n");
|
||||
|
||||
abortTpool(&pool,510);
|
||||
} while(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
Author: Laurent THOMAS, Open Cells
|
||||
copyleft: OpenAirInterface Software Alliance and it's licence
|
||||
*/
|
||||
|
||||
#ifndef THREAD_POOL_H
|
||||
#define THREAD_POOL_H
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <assertions.h>
|
||||
#include <LOG/log.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define THREADINIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
#else
|
||||
#define THREADINIT PTHREAD_MUTEX_INITIALIZER
|
||||
#endif
|
||||
#define mutexinit(mutex) AssertFatal(pthread_mutex_init(&mutex,NULL)==0,"");
|
||||
#define condinit(signal) AssertFatal(pthread_cond_init(&signal,NULL)==0,"");
|
||||
#define mutexlock(mutex) AssertFatal(pthread_mutex_lock(&mutex)==0,"");
|
||||
#define mutextrylock(mutex) pthread_mutex_trylock(&mutex)
|
||||
#define mutexunlock(mutex) AssertFatal(pthread_mutex_unlock(&mutex)==0,"");
|
||||
#define condwait(condition, mutex) AssertFatal(pthread_cond_wait(&condition, &mutex)==0,"");
|
||||
#define condbroadcast(signal) AssertFatal(pthread_cond_broadcast(&signal)==0,"");
|
||||
#define condsignal(signal) AssertFatal(pthread_cond_broadcast(&signal)==0,"");
|
||||
|
||||
typedef struct notifiedFIFO_elt_s {
|
||||
struct notifiedFIFO_elt_s *next;
|
||||
uint64_t key; //To filter out elements
|
||||
struct notifiedFIFO_s *reponseFifo;
|
||||
void (*processingFunc)(void *);
|
||||
bool malloced;
|
||||
uint64_t creationTime;
|
||||
uint64_t startProcessingTime;
|
||||
uint64_t endProcessingTime;
|
||||
uint64_t returnTime;
|
||||
void *msgData;
|
||||
} notifiedFIFO_elt_t;
|
||||
|
||||
typedef struct notifiedFIFO_s {
|
||||
notifiedFIFO_elt_t *outF;
|
||||
notifiedFIFO_elt_t *inF;
|
||||
pthread_mutex_t lockF;
|
||||
pthread_cond_t notifF;
|
||||
} notifiedFIFO_t;
|
||||
|
||||
// You can use this allocator or use any piece of memory
|
||||
static inline notifiedFIFO_elt_t *newNotifiedFIFO_elt(int size,
|
||||
uint64_t key,
|
||||
notifiedFIFO_t *reponseFifo,
|
||||
void (*processingFunc)(void *)) {
|
||||
notifiedFIFO_elt_t *ret;
|
||||
AssertFatal( NULL != (ret=(notifiedFIFO_elt_t *) malloc(sizeof(notifiedFIFO_elt_t)+size+32)), "");
|
||||
ret->next=NULL;
|
||||
ret->key=key;
|
||||
ret->reponseFifo=reponseFifo;
|
||||
ret->processingFunc=processingFunc;
|
||||
// We set user data piece aligend 32 bytes to be able to process it with SIMD
|
||||
ret->msgData=(void *)ret+(sizeof(notifiedFIFO_elt_t)/32+1)*32;
|
||||
ret->malloced=true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void *NotifiedFifoData(notifiedFIFO_elt_t *elt) {
|
||||
return elt->msgData;
|
||||
}
|
||||
|
||||
static inline void delNotifiedFIFO_elt(notifiedFIFO_elt_t *elt) {
|
||||
if (elt->malloced) {
|
||||
elt->malloced=false;
|
||||
free(elt);
|
||||
} else
|
||||
printf("delNotifiedFIFO on something not allocated by newNotifiedFIFO\n");
|
||||
|
||||
//LOG_W(UTIL,"delNotifiedFIFO on something not allocated by newNotifiedFIFO\n");
|
||||
}
|
||||
|
||||
static inline void initNotifiedFIFO(notifiedFIFO_t *nf) {
|
||||
mutexinit(nf->lockF);
|
||||
condinit (nf->notifF);
|
||||
nf->inF=NULL;
|
||||
nf->outF=NULL;
|
||||
// No delete function: the creator has only to free the memory
|
||||
}
|
||||
|
||||
static inline void pushNotifiedFIFO(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) {
|
||||
mutexlock(nf->lockF);
|
||||
msg->next=NULL;
|
||||
|
||||
if (nf->outF == NULL)
|
||||
nf->outF = msg;
|
||||
|
||||
if (nf->inF)
|
||||
nf->inF->next = msg;
|
||||
|
||||
nf->inF = msg;
|
||||
condbroadcast(nf->notifF);
|
||||
mutexunlock(nf->lockF);
|
||||
}
|
||||
|
||||
static inline notifiedFIFO_elt_t *pullNotifiedFIFO(notifiedFIFO_t *nf) {
|
||||
mutexlock(nf->lockF);
|
||||
|
||||
while(!nf->outF)
|
||||
condwait(nf->notifF, nf->lockF);
|
||||
|
||||
notifiedFIFO_elt_t *ret=nf->outF;
|
||||
nf->outF=nf->outF->next;
|
||||
|
||||
if (nf->outF==NULL)
|
||||
nf->inF=NULL;
|
||||
|
||||
mutexunlock(nf->lockF);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline notifiedFIFO_elt_t *pollNotifiedFIFO(notifiedFIFO_t *nf) {
|
||||
int tmp=mutextrylock(nf->lockF);
|
||||
|
||||
if (tmp != 0 )
|
||||
return NULL;
|
||||
|
||||
notifiedFIFO_elt_t *ret=nf->outF;
|
||||
|
||||
if (ret!=NULL)
|
||||
nf->outF=nf->outF->next;
|
||||
|
||||
if (nf->outF==NULL)
|
||||
nf->inF=NULL;
|
||||
|
||||
mutexunlock(nf->lockF);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This function aborts all messages matching the key
|
||||
// If the queue is used in thread pools, it doesn't cancels already running processing
|
||||
// because the message has already been picked
|
||||
static inline void abortNotifiedFIFO(notifiedFIFO_t *nf, uint64_t key) {
|
||||
mutexlock(nf->lockF);
|
||||
notifiedFIFO_elt_t **start=&nf->outF;
|
||||
|
||||
while(*start!=NULL) {
|
||||
if ( (*start)->key == key ) {
|
||||
notifiedFIFO_elt_t *request=*start;
|
||||
*start=(*start)->next;
|
||||
delNotifiedFIFO_elt(request);
|
||||
}
|
||||
|
||||
if (*start != NULL)
|
||||
start=&(*start)->next;
|
||||
}
|
||||
|
||||
mutexunlock(nf->lockF);
|
||||
}
|
||||
|
||||
struct one_thread {
|
||||
pthread_t threadID;
|
||||
int id;
|
||||
int coreID;
|
||||
char name[256];
|
||||
uint64_t runningOnKey;
|
||||
bool abortFlag;
|
||||
struct thread_pool *pool;
|
||||
struct one_thread *next;
|
||||
};
|
||||
|
||||
typedef struct thread_pool {
|
||||
int activated;
|
||||
bool measurePerf;
|
||||
int traceFd;
|
||||
int dummyTraceFd;
|
||||
uint64_t cpuCyclesMicroSec;
|
||||
uint64_t startProcessingUE;
|
||||
int nbThreads;
|
||||
bool restrictRNTI;
|
||||
notifiedFIFO_t incomingFifo;
|
||||
struct one_thread *allthreads;
|
||||
} tpool_t;
|
||||
|
||||
static inline void pushTpool(tpool_t *t, notifiedFIFO_elt_t *msg) {
|
||||
if (t->measurePerf) msg->creationTime=rdtsc();
|
||||
|
||||
pushNotifiedFIFO(&t->incomingFifo, msg);
|
||||
}
|
||||
|
||||
static inline notifiedFIFO_elt_t *pullTpool(notifiedFIFO_t *responseFifo, tpool_t *t) {
|
||||
notifiedFIFO_elt_t *msg= pullNotifiedFIFO(responseFifo);
|
||||
|
||||
if (t->measurePerf)
|
||||
msg->returnTime=rdtsc();
|
||||
|
||||
if (t->traceFd)
|
||||
if(write(t->traceFd, msg, sizeof(*msg)));
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static inline notifiedFIFO_elt_t *tryPullTpool(notifiedFIFO_t *responseFifo, tpool_t *t) {
|
||||
notifiedFIFO_elt_t *msg= pollNotifiedFIFO(responseFifo);
|
||||
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
if (t->measurePerf)
|
||||
msg->returnTime=rdtsc();
|
||||
|
||||
if (t->traceFd)
|
||||
if(write(t->traceFd, msg, sizeof(*msg)));
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static inline void abortTpool(tpool_t *t, uint64_t key) {
|
||||
notifiedFIFO_t *nf=&t->incomingFifo;
|
||||
mutexlock(nf->lockF);
|
||||
notifiedFIFO_elt_t **start=&nf->outF;
|
||||
|
||||
while(*start!=NULL) {
|
||||
if ( (*start)->key == key ) {
|
||||
notifiedFIFO_elt_t *request=*start;
|
||||
*start=(*start)->next;
|
||||
delNotifiedFIFO_elt(request);
|
||||
}
|
||||
|
||||
if (*start != NULL)
|
||||
start=&(*start)->next;
|
||||
}
|
||||
|
||||
struct one_thread *ptr=t->allthreads;
|
||||
|
||||
while(ptr!=NULL) {
|
||||
if (ptr->runningOnKey==key)
|
||||
ptr->abortFlag=true;
|
||||
|
||||
ptr=ptr->next;
|
||||
}
|
||||
|
||||
mutexunlock(nf->lockF);
|
||||
}
|
||||
void initTpool(char *params,tpool_t *pool, bool performanceMeas);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
# Thread pool
|
||||
|
||||
The thread pool is a working server, made of a set of worker threads that can be mapped on CPU cores.
|
||||
|
||||
Each worker loop on pick from the same input queue jobs to do.
|
||||
When a job is done, the worker sends a return if a return is defined.
|
||||
|
||||
A selective abort allows to cancel parallel jobs (usage: a client pushed jobs, but from a response of one job, the other linked jobs becomes useless).
|
||||
|
||||
All the thread pool functions are thread safe, nevertheless the working functions are implemented by the thread pool client, so the client has to tackle the parallel execution of his functions called "processingFunc" hereafter.
|
||||
|
||||
## license
|
||||
Author: Laurent Thomas, Open cells project
|
||||
The owner share this piece code to Openairsoftware alliance as per OSA license terms
|
||||
|
||||
# jobs
|
||||
|
||||
A job is a message (notifiedFIFO_elt_t):
|
||||
next: internal FIFO chain, do not set it
|
||||
key: a long int that the client can use to identify a message or a group of messages
|
||||
responseFifo: if the client defines a response FIFO, the message will be posted back after processing
|
||||
processingFunc: any funtion (type void processingFunc(void *)) that the worker will launch
|
||||
msgData: the data passed to processingFunc. It can be added automatically, or you can set it to a buffer you are managing
|
||||
malloced: a boolean that enable internal free in these cases: no return Fifo or Abort feature
|
||||
|
||||
The job messages can be created with newNotifiedFIFO_elt() and delNotifiedFIFO_elt() or managed by the client.
|
||||
|
||||
# Queues of jobs
|
||||
|
||||
Queues are type of: notifiedFIFO_t that must be initialized by init_notifiedFIFO()
|
||||
No delete function is required, the creator has only to free the data of type notifiedFIFO_t
|
||||
|
||||
push_notifiedFIFO() add a job in the queue
|
||||
pull_notifiedFIFO() is blocking, poll_notifiedFIFO() is non blocking
|
||||
|
||||
abort_notifiedFIFO() allows the customer to delete all waiting jobs that match with the key (see key in jobs definition)
|
||||
|
||||
# Thread pools
|
||||
|
||||
## initialization
|
||||
The clients can create one or more thread pools with init_tpool()
|
||||
the params string structure: describes a list of cores, separated by "," that run a worker thread
|
||||
|
||||
If the core exists on the CPU, the thread pool initialization sets the affinity between this thread and the related code (use negative values is allowed, so the thread will never be mapped on a specific core).
|
||||
|
||||
The threads are all Linux real time scheduler, their name is set automatically is "Tpool_<core id>"
|
||||
|
||||
## adding jobs
|
||||
The client create their jobs messages as a notifiedFIFO_elt_t, then they push it with pushTpool() (that internally calls push_notifiedFIFO())
|
||||
|
||||
If they need a return, they have to create response queues with init_notifiedFIFO() and set this FIFO pointer in the notifiedFIFO_elt_t before pushing the job.
|
||||
|
||||
## abort
|
||||
|
||||
A abort service abortTpool() allows to abort all jobs that match a key (see jobs "key"). When the abort returns, it garanties no job (matching the key) response will be posted on response queues.
|
||||
|
||||
Nevertheless, jobs already performed before the return of abortTpool() are pushed in the response Fifo queue.
|
||||
|
||||
## Performance measurements
|
||||
|
||||
A performance measurement is integrated: the pool will automacillay fill timestamps:
|
||||
|
||||
* creationTime: time the request is push to the pool;
|
||||
* startProcessingTime: time a worker start to run on the job
|
||||
* endProcessingTime: time the worker finished the job
|
||||
* returnTime: time the client reads the result
|
||||
|
||||
if you set the environement variable: thread-pool-measurements to a valid file name
|
||||
These measurements will be wrote to this Linux pipe.
|
||||
|
||||
A tool to read the linux fifo and display it in ascii is provided: see the local directory Makefile for this tool and to compile the thread pool unitary tests.
|
||||
Reference in New Issue
Block a user