Commit 0ac2330e authored by Robert Schmidt's avatar Robert Schmidt

Merge branch 'integration_2022_wk10' into 'develop'

Integration 2022 wk10

See merge request oai/openairinterface5g!1485
parents 4176016c 9a808cd7
......@@ -21,28 +21,14 @@
# OpenAirInterface License #
### Included Fixes: ###
- Ease of use of gprof and address sanitizer for debugging purposes
- Updated json files to allow for GDB, real-time debugging capabilities
- Updated logging features to minimally log only key connection milestones. This imroves scalability of multiple UEs.
- Updated logging to include time stamp for timing analysis
- Updated memory allocation procedures to correct size requirements
- Added debugging features to handle signal terminations
- nfapi.c pullarray8 fix invalid pointer math
- Overlapping destination and source memory in memcpy, so updated to memmove to check for this bug
- Advanced error checking mechanisms in critical pack and unpack functions
- Created option for CPU assignment to UE to improve scalability
- Added EPC integration to allow multiple individual UE entities to each have their USIM information parced by the executables
- Updated random value seeds to minimize probability of error in generation of random values
- Enables capability round robin scheduler if desired
- Enables capability real time scheduler if desired
- Added new standalone functions to the UE phy-layer (phy_stub_ue.c) to incorporate individual UE entities
- Updated sending and packing functions in UE (lte_ue.c) to incorporate new standalone changes
- Incorporated semaphores to control timing of incoming downlink packets
- Implemented new queuing system to handle message exchange from UE to eNB and vice versa
- Updated global value in nFAPI for size of subframe
- Updated global value to increase scalability in system
* [OAI License Model](http://www.openairinterface.org/?page_id=101)
* [OAI License v1.1 on our website](http://www.openairinterface.org/?page_id=698)
It is distributed under **OAI Public License V1.1**.
The license information is distributed under [LICENSE](LICENSE) file in the same directory.
Please see [NOTICE](NOTICE.md) file for third party software that is included in the sources.
# Where to Start #
......
......@@ -84,17 +84,8 @@ gNBs =
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 12;
initialDLBWPcontrolResourceSetZero = 11;
initialDLBWPsearchSpaceZero = 0;
#pdsch-ConfigCommon
#pdschTimeDomainAllocationList (up to 16 entries)
initialDLBWPk0_0 = 0; #for DL slot
initialDLBWPmappingType_0 = 0; #0=typeA,1=typeB
initialDLBWPstartSymbolAndLength_0 = 40; #this is SS=1,L=13
initialDLBWPk0_1 = 0; #for mixed slot
initialDLBWPmappingType_1 = 0;
initialDLBWPstartSymbolAndLength_1 = 57; #this is SS=1,L=5
#uplinkConfigCommon
#frequencyInfoUL
......@@ -149,19 +140,6 @@ gNBs =
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# pusch-ConfigCommon (up to 16 elements)
initialULBWPk2_0 = 6; # used for UL slot
initialULBWPmappingType_0 = 1
initialULBWPstartSymbolAndLength_0 = 41; # this is SS=0 L=13
initialULBWPk2_1 = 6; # used for mixed slot
initialULBWPmappingType_1 = 1;
initialULBWPstartSymbolAndLength_1 = 52; # this is SS=10 L=4
initialULBWPk2_2 = 7; # used for Msg.3 during RA
initialULBWPmappingType_2 = 1;
initialULBWPstartSymbolAndLength_2 = 52; # this is SS=10 L=4
msg3_DeltaPreamble = 1;
p0_NominalWithGrant =-90;
......
......@@ -76,17 +76,8 @@ gNBs =
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 12;
initialDLBWPcontrolResourceSetZero = 11;
initialDLBWPsearchSpaceZero = 0;
#pdsch-ConfigCommon
#pdschTimeDomainAllocationList (up to 16 entries)
initialDLBWPk0_0 = 0; #for DL slot
initialDLBWPmappingType_0 = 0; #0=typeA,1=typeB
initialDLBWPstartSymbolAndLength_0 = 40; #this is SS=1,L=13
initialDLBWPk0_1 = 0; #for mixed slot
initialDLBWPmappingType_1 = 0;
initialDLBWPstartSymbolAndLength_1 = 57; #this is SS=1,L=5
#uplinkConfigCommon
#frequencyInfoUL
......@@ -141,19 +132,6 @@ gNBs =
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# pusch-ConfigCommon (up to 16 elements)
initialULBWPk2_0 = 6; # used for UL slot
initialULBWPmappingType_0 = 1
initialULBWPstartSymbolAndLength_0 = 41; # this is SS=0 L=13
initialULBWPk2_1 = 6; # used for mixed slot
initialULBWPmappingType_1 = 1;
initialULBWPstartSymbolAndLength_1 = 52; # this is SS=10 L=4
initialULBWPk2_2 = 7; # used for Msg.3 during RA
initialULBWPmappingType_2 = 1;
initialULBWPstartSymbolAndLength_2 = 52; # this is SS=10 L=4
msg3_DeltaPreamble = 1;
p0_NominalWithGrant =-90;
......
This diff is collapsed.
......@@ -346,7 +346,7 @@ typedef struct {
@param format data format (0 = real 16-bit, 1 = complex 16-bit,2 real 32-bit, 3 complex 32-bit,4 = real 8-bit, 5 = complex 8-bit)
@param multiVec create new file or append to existing (useful for writing multiple vectors to same file. Just call the function multiple times with same file name and with this parameter set to 1)
*/
#define MATLAB_RAW (1<<31)
#define MATLAB_RAW (1U<<31)
#define MATLAB_SHORT 0
#define MATLAB_CSHORT 1
#define MATLAB_INT 2
......
......@@ -18,6 +18,10 @@ The UE executable is able to "simulate" multiple UEs in order to stimulate the s
**This simulator is available starting the `v1.0.0` release on the `master` branch.**
**2022/03/08: CAUTION, THIS TUTORIAL IS NO LONGER VALID on the `develop` branch after the `2022.w01` tag.**
**2022/03/08: CAUTION, THE LAST VALID TAG on `develop` branch is `2021.w51_c`.**
Currently the Continuous Integration process is validating this simulator the following way:
* the LTE modem executable is run on one host (in our CI deployment it is a **Xenial Virtual Machine**)
......@@ -31,6 +35,17 @@ Normally it should be fine to run both executables on the same host using the `l
1. [With S1 -- eNB and UE on 2 hosts](L2NFAPI_S1.md)
2. [No S1 -- eNB and UE on 2 hosts](L2NFAPI_NOS1.md)
**2022/03/08: Starting the `2022.w01` tag on the `develop` branch, the L2 nFAPI simulation is using a proxy.**
A tutorial is available on the [EpiSci GitHub Repository](https://github.com/EpiSci/oai-lte-5g-multi-ue-proxy#readme).
This proxy allows to perform L2 nFAPI simulator for:
* LTE
* 5G-NSA
* 5G-SA
----
[oai wiki home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
......
......@@ -12,6 +12,10 @@
</tr>
</table>
**2022/03/08: CAUTION, THIS TUTORIAL IS NO LONGER VALID on the `develop` branch after the `2022.w01` tag.**
**2022/03/08: CAUTION, THE LAST VALID TAG on `develop` branch is `2021.w51_c`.**
## Table of Contents ##
1. [Environment](#1-environment)
......
......@@ -12,6 +12,10 @@
</tr>
</table>
**2022/03/08: CAUTION, THIS TUTORIAL IS NO LONGER VALID on the `develop` branch after the `2022.w01` tag.**
**2022/03/08: CAUTION, THE LAST VALID TAG on `develop` branch is `2021.w51_c`.**
## Table of Contents ##
1. [Environment](#1-environment)
......
......@@ -33,7 +33,7 @@ It is planned to enhance this simulator with the following functionalities:
This simulator connects a eNodeB and UEs through a nfapi interface, short-cutting the L1 layer. The objective of this simulator is to allow multi UEs simulation, with a large number of UEs (ideally up to 255 ) .Here to ease the platform setup, UEs are simulated via a single `lte-uesoftmodem` instance. Today the CI tests just with one UE and architecture has to be reviewed to allow a number of UE above about 16. This work is on-going.
As for the rf simulator, no specific hardware is required. The [L2 nfapi simlator page](L2NFAPI.md) contains the detailed documentation.
As for the rf simulator, no specific hardware is required. The [L2 nfapi simulator page](L2NFAPI.md) contains the detailed documentation.
# L1 Simulator
......
......@@ -72,10 +72,10 @@ unsigned int crcbit (unsigned char * inputptr,
unsigned int i, crc = 0, c;
while (octetlen-- > 0) {
c = (*inputptr++) << 24;
c = ((unsigned int)(*inputptr++)) << 24;
for (i = 8; i != 0; i--) {
if ((1 << 31) & (c ^ crc))
if ((1U << 31) & (c ^ crc))
crc = (crc << 1) ^ poly;
else
crc <<= 1;
......
......@@ -445,29 +445,10 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
}
}
// PBCH
pbch_vars[gNB_id]->rxdataF_ext = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) );
pbch_vars[gNB_id]->rxdataF_comp = (int32_t **)malloc16_clear( 4*fp->nb_antennas_rx*sizeof(int32_t *) );
pbch_vars[gNB_id]->dl_ch_estimates = (int32_t **)malloc16_clear( 4*fp->nb_antennas_rx*sizeof(int32_t *) );
pbch_vars[gNB_id]->dl_ch_estimates_ext = (int32_t **)malloc16_clear( 4*fp->nb_antennas_rx*sizeof(int32_t *) );
pbch_vars[gNB_id]->dl_ch_estimates_time = (int32_t **)malloc16_clear( 4*fp->nb_antennas_rx*sizeof(int32_t *) );
pbch_vars[gNB_id]->llr = (int16_t *)malloc16_clear( 1920 ); //
// RACH
prach_vars[gNB_id]->prachF = (int16_t *)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) );
prach_vars[gNB_id]->prach = (int16_t *)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) );
for (i=0; i<fp->nb_antennas_rx; i++) {
pbch_vars[gNB_id]->rxdataF_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*20*12*4 );
for (j=0; j<4; j++) {//fp->nb_antennas_tx;j++) {
int idx = (j*fp->nb_antennas_rx)+i;
pbch_vars[gNB_id]->rxdataF_comp[idx] = (int32_t *)malloc16_clear( sizeof(int32_t)*20*12*4 );
pbch_vars[gNB_id]->dl_ch_estimates[idx] = (int32_t *)malloc16_clear( sizeof(int32_t)*7*2*sizeof(int)*(fp->ofdm_symbol_size) );
pbch_vars[gNB_id]->dl_ch_estimates_time[idx]= (int32_t *)malloc16_clear( sizeof(int32_t)*7*2*sizeof(int)*(fp->ofdm_symbol_size) );
pbch_vars[gNB_id]->dl_ch_estimates_ext[idx] = (int32_t *)malloc16_clear( sizeof(int32_t)*20*12*4 );
}
}
pbch_vars[gNB_id]->decoded_output = (uint8_t *)malloc16_clear(64);
}
// initialization for the last instance of pdsch_vars (used for MU-MIMO)
......@@ -640,25 +621,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
free_and_zero(ue->srs_vars[gNB_id]);
for (int i = 0; i < fp->nb_antennas_rx; i++) {
free_and_zero(ue->pbch_vars[gNB_id]->rxdataF_ext[i]);
for (int j = 0; j < 4; j++) {
int idx = (j*fp->nb_antennas_rx)+i;
free_and_zero(ue->pbch_vars[gNB_id]->rxdataF_comp[idx]);
free_and_zero(ue->pbch_vars[gNB_id]->dl_ch_estimates[idx]);
free_and_zero(ue->pbch_vars[gNB_id]->dl_ch_estimates_time[idx]);
free_and_zero(ue->pbch_vars[gNB_id]->dl_ch_estimates_ext[idx]);
}
}
free_and_zero(ue->pbch_vars[gNB_id]->rxdataF_ext);
free_and_zero(ue->pbch_vars[gNB_id]->rxdataF_comp);
free_and_zero(ue->pbch_vars[gNB_id]->dl_ch_estimates);
free_and_zero(ue->pbch_vars[gNB_id]->dl_ch_estimates_ext);
free_and_zero(ue->pbch_vars[gNB_id]->dl_ch_estimates_time);
free_and_zero(ue->pbch_vars[gNB_id]->llr);
free_and_zero(ue->pbch_vars[gNB_id]->decoded_output);
free_and_zero(ue->pbch_vars[gNB_id]);
free_and_zero(ue->prach_vars[gNB_id]->prachF);
......
......@@ -64,7 +64,7 @@ void nr_gold_pdcch(PHY_VARS_NR_UE* ue,
reset = 1;
x2tmp0 = ((ue->frame_parms.symbols_per_slot*ns+l+1)*((nid<<1)+1))<<17;
x2 = (x2tmp0+(nid<<1))%(1<<31); //cinit
x2 = (x2tmp0+(nid<<1))%(1U<<31); //cinit
for (n=0; n<NR_MAX_PDCCH_DMRS_INIT_LENGTH_DWORD; n++) {
ue->nr_gold_pdcch[0][ns][l][n] = lte_gold_generic(&x1, &x2, reset);
......@@ -95,7 +95,7 @@ void nr_gold_pdsch(PHY_VARS_NR_UE* ue,
reset = 1;
x2tmp0 = ((ue->frame_parms.symbols_per_slot*ns+l+1)*((nid<<1)+1))<<17;
x2 = (x2tmp0+(nid<<1)+nscid)%(1<<31); //cinit
x2 = (x2tmp0+(nid<<1)+nscid)%(1U<<31); //cinit
LOG_D(PHY,"UE DMRS slot %d, symb %d, x2 %x, nscid %d\n",ns,l,x2,nscid);
for (n=0; n<NR_MAX_PDSCH_DMRS_INIT_LENGTH_DWORD; n++) {
......
......@@ -36,6 +36,7 @@
void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
PHY_VARS_NR_UE *ue,
module_id_t gNB_id,
const int estimateSz, struct complex16 dl_ch_estimates_time[][estimateSz],
uint8_t frame,
uint8_t subframe,
unsigned char clear,
......@@ -60,8 +61,8 @@ void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
int j = (i < 0) ? (i + frame_parms->ofdm_symbol_size) : i;
for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) {
int Re = ((int16_t*)ue->pbch_vars[gNB_id]->dl_ch_estimates_time[aa])[(j<<1)];
int Im = ((int16_t*)ue->pbch_vars[gNB_id]->dl_ch_estimates_time[aa])[1+(j<<1)];
int Re = dl_ch_estimates_time[aa][j].r;
int Im = dl_ch_estimates_time[aa][j].i;
temp += (Re*Re/2) + (Im*Im/2);
}
......
......@@ -29,6 +29,7 @@
#include "PHY/NR_REFSIG/ptrs_nr.h"
#include "PHY/NR_TRANSPORT/nr_sch_dmrs.h"
#include "filt16a_32.h"
#include <openair1/PHY/TOOLS/phy_scope_interface.h>
//#define DEBUG_PDSCH
//#define DEBUG_PDCCH
......@@ -43,7 +44,6 @@ int nr_pbch_dmrs_correlation(PHY_VARS_NR_UE *ue,
NR_UE_SSB *current_ssb)
{
int pilot[200] __attribute__((aligned(16)));
unsigned char aarx;
unsigned short k;
unsigned int pilot_cnt;
int16_t ch[2],*pil,*rxF;
......@@ -77,7 +77,7 @@ int nr_pbch_dmrs_correlation(PHY_VARS_NR_UE *ue,
// generate pilot
nr_pbch_dmrs_rx(dmrss,ue->nr_gold_pbch[n_hf][ssb_index], &pilot[0]);
for (aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
for (int aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
int re_offset = ssb_offset;
pil = (int16_t *)&pilot[0];
......@@ -197,6 +197,9 @@ int nr_pbch_dmrs_correlation(PHY_VARS_NR_UE *ue,
int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
int estimateSz,
struct complex16 dl_ch_estimates [][estimateSz],
struct complex16 dl_ch_estimates_time [][estimateSz],
UE_nr_rxtx_proc_t *proc,
uint8_t gNB_id,
unsigned char Ns,
......@@ -206,15 +209,13 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
uint8_t n_hf)
{
int pilot[200] __attribute__((aligned(16)));
unsigned char aarx,p;
unsigned short k;
unsigned int pilot_cnt;
int16_t ch[2],*pil,*rxF,*dl_ch,*fl,*fm,*fr;
int16_t *pil,*rxF,*dl_ch,*fl,*fm,*fr;
int ch_offset,symbol_offset;
//int slot_pbch;
uint8_t nushift;
int **dl_ch_estimates =ue->pbch_vars[gNB_id]->dl_ch_estimates;
int **rxdataF=ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF;
nushift = ue->frame_parms.Nid_cell%4;
......@@ -269,17 +270,57 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
break;
}
idft_size_idx_t idftsizeidx;
switch (ue->frame_parms.ofdm_symbol_size) {
case 128:
idftsizeidx = IDFT_128;
break;
case 256:
idftsizeidx = IDFT_256;
break;
case 512:
idftsizeidx = IDFT_512;
break;
case 1024:
idftsizeidx = IDFT_1024;
break;
case 1536:
idftsizeidx = IDFT_1536;
break;
case 2048:
idftsizeidx = IDFT_2048;
break;
case 3072:
idftsizeidx = IDFT_3072;
break;
case 4096:
idftsizeidx = IDFT_4096;
break;
default:
printf("unsupported ofdm symbol size \n");
assert(0);
}
// generate pilot
nr_pbch_dmrs_rx(dmrss,ue->nr_gold_pbch[n_hf][ssb_index], &pilot[0]);
for (aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
for (int aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
int re_offset = ssb_offset;
pil = (int16_t *)&pilot[0];
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
dl_ch = (int16_t *)&dl_ch_estimates[aarx][ch_offset];
memset(dl_ch,0,4*(ue->frame_parms.ofdm_symbol_size));
memset(dl_ch,0,sizeof(*dl_ch)*(ue->frame_parms.ofdm_symbol_size));
#ifdef DEBUG_CH
printf("pbch ch est pilot addr %p RB_DL %d\n",&pilot[0], ue->frame_parms.N_RB_DL);
......@@ -289,6 +330,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
#endif
// Treat first 2 pilots specially (left edge)
int16_t ch[2];
ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15);
ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15);
......@@ -402,62 +444,18 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
}
idft_size_idx_t idftsizeidx;
switch (ue->frame_parms.ofdm_symbol_size) {
case 128:
idftsizeidx = IDFT_128;
break;
case 256:
idftsizeidx = IDFT_256;
break;
case 512:
idftsizeidx = IDFT_512;
break;
case 1024:
idftsizeidx = IDFT_1024;
break;
case 1536:
idftsizeidx = IDFT_1536;
break;
case 2048:
idftsizeidx = IDFT_2048;
break;
case 3072:
idftsizeidx = IDFT_3072;
break;
case 4096:
idftsizeidx = IDFT_4096;
break;
default:
printf("unsupported ofdm symbol size \n");
assert(0);
}
if( dmrss == 2) // update time statistics for last PBCH symbol
{
// do ifft of channel estimate
for (aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++)
for (p=0; p<ue->frame_parms.nb_antenna_ports_gNB; p++) {
if (ue->pbch_vars[gNB_id]->dl_ch_estimates[(p*ue->frame_parms.nb_antennas_rx)+aarx])
{
LOG_D(PHY,"Channel Impulse Computation Slot %d ThreadId %d Symbol %d ch_offset %d\n", Ns, proc->thread_id, symbol, ch_offset);
LOG_D(PHY,"Channel Impulse Computation Slot %d Symbol %d ch_offset %d\n", Ns, symbol, ch_offset);
idft(idftsizeidx,
(int16_t*) &ue->pbch_vars[gNB_id]->dl_ch_estimates[(p*ue->frame_parms.nb_antennas_rx)+aarx][ch_offset],
(int16_t*) ue->pbch_vars[gNB_id]->dl_ch_estimates_time[(p*ue->frame_parms.nb_antennas_rx)+aarx],1);
}
}
}
}
(int16_t*) &dl_ch_estimates[aarx][ch_offset],
(int16_t*) dl_ch_estimates_time[aarx],
1);
}
}
if (dmrss == 2)
UEscopeCopy(ue, pbchDlChEstimateTime, (void*)dl_ch_estimates_time, sizeof(struct complex16), ue->frame_parms.nb_antennas_rx, idftsizeidx);
return(0);
}
......
......@@ -56,6 +56,9 @@ int nr_pbch_dmrs_correlation(PHY_VARS_NR_UE *ue,
NR_UE_SSB *current_ssb);
int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
int estimateSz,
struct complex16 dl_ch_estimates [][estimateSz],
struct complex16 dl_ch_estimates_time [][estimateSz],
UE_nr_rxtx_proc_t *proc,
uint8_t gNB_id,
unsigned char Ns,
......@@ -79,6 +82,8 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
PHY_VARS_NR_UE *ue,
module_id_t gNB_id,
int estimateSz,
struct complex16 dl_ch_estimates_time [][estimateSz],
uint8_t frame,
uint8_t subframe,
unsigned char clear,
......
......@@ -146,17 +146,23 @@ int nr_pbch_detection(UE_nr_rxtx_proc_t * proc, PHY_VARS_NR_UE *ue, int pbch_ini
start_meas(&ue->dlsch_channel_estimation_stats);
// computing channel estimation for selected best ssb
const int estimateSz=7*2*frame_parms->ofdm_symbol_size;
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates[frame_parms->nb_antennas_rx][estimateSz];
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_time[frame_parms->nb_antennas_rx][estimateSz];
for(int i=pbch_initial_symbol; i<pbch_initial_symbol+3;i++)
nr_pbch_channel_estimation(ue,proc,0,0,i,i-pbch_initial_symbol,temp_ptr->i_ssb,temp_ptr->n_hf);
nr_pbch_channel_estimation(ue,estimateSz, dl_ch_estimates, dl_ch_estimates_time,
proc,0,0,i,i-pbch_initial_symbol,temp_ptr->i_ssb,temp_ptr->n_hf);
stop_meas(&ue->dlsch_channel_estimation_stats);
fapiPbch_t result;
ret = nr_rx_pbch(ue,
proc,
estimateSz, dl_ch_estimates,
ue->pbch_vars[0],
frame_parms,
0,
temp_ptr->i_ssb,
SISO);
SISO,
&result);
temp_ptr=temp_ptr->next_ssb;
}
......
This diff is collapsed.
......@@ -1152,11 +1152,14 @@ int rx_sss(PHY_VARS_NR_UE *phy_vars_ue,int32_t *tot_metric,uint8_t *flip_max,uin
*/
int nr_rx_pbch( PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
const int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
NR_UE_PBCH *nr_ue_pbch_vars,
NR_DL_FRAME_PARMS *frame_parms,
uint8_t eNB_id,
uint8_t i_ssb,
MIMO_mode_t mimo_mode);
MIMO_mode_t mimo_mode,
fapiPbch_t* result);
int nr_pbch_detection(UE_nr_rxtx_proc_t *proc,
PHY_VARS_NR_UE *ue,
......
......@@ -861,7 +861,7 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain
/* perform correlation of rx data and pss sequence ie it is a dot product */
result = dot_product64((short*)primary_synchro_time_nr[pss_index],
(short*) &(rxdata[ar][n+is*frame_parms->samples_per_frame]),
(short*)&(rxdata[ar][n+is*frame_parms->samples_per_frame]),
frame_parms->ofdm_symbol_size,
shift);
pss_corr_ue[pss_index][n] += abs64(result);
......
This diff is collapsed.
......@@ -32,6 +32,8 @@
#ifndef __PHY_SCOPE_INTERFACE_H__
#define __PHY_SCOPE_INTERFACE_H__
#include <openair1/PHY/defs_gNB.h>
#include <openair1/PHY/defs_nr_UE.h>
typedef struct {
int *argc;
char **argv;
......@@ -39,16 +41,25 @@ typedef struct {
PHY_VARS_gNB *gNB;
} scopeParms_t;
enum UEdataType {
pbchDlChEstimateTime,
pbchLlr,
pbchRxdataF_comp,
UEdataTypeNumberOfItems
};
typedef struct scopeData_s {
int *argc;
char **argv;
RU_t *ru;
PHY_VARS_gNB *gNB;
int32_t * rxdataF;
void (*slotFunc)(int32_t* data, int slot, void * scopeData);
void *liveData;
void (*slotFunc)(int32_t *data, int slot, void *scopeData);
void (*copyData)(PHY_VARS_NR_UE *,enum UEdataType, void *data, int elementSz, int colSz, int lineSz);
} scopeData_t;
int load_softscope(char *exectype, void *initarg);
int end_forms(void) ;
#define UEscopeCopy(ue, type, ...) if(ue->scopeData) ((scopeData_t*)ue->scopeData)->copyData(ue, type, ##__VA_ARGS__);
#endif
......@@ -837,6 +837,7 @@ typedef struct {
/// RF and Interface devices per CC
openair0_device rfdevice;
void *scopeData;
} PHY_VARS_UE;
/* this structure is used to pass both UE phy vars and
......
......@@ -654,40 +654,6 @@ typedef struct {
#define PBCH_A 24
typedef struct {
/// \brief Pointers to extracted PBCH symbols in frequency-domain.
/// - first index: rx antenna [0..nb_antennas_rx[
/// - second index: ? [0..287] (hard coded)
int32_t **rxdataF_ext;
/// \brief Pointers to extracted and compensated PBCH symbols in frequency-domain.
/// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
/// - second index: ? [0..287] (hard coded)
int32_t **rxdataF_comp;
/// \brief Hold the channel estimates in frequency domain.
/// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
/// - second index: samples? [0..symbols_per_tti*(ofdm_symbol_size+LTE_CE_FILTER_LENGTH)[
int32_t **dl_ch_estimates;
/// \brief Pointers to downlink channel estimates in frequency-domain extracted in PRBS.
/// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
/// - second index: ? [0..287] (hard coded)
int32_t **dl_ch_estimates_ext;
/// \brief Hold the channel estimates in time domain (used for tracking).
/// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
/// - second index: samples? [0..2*ofdm_symbol_size[
int32_t **dl_ch_estimates_time;
int log2_maxh;
uint8_t pbch_a[NR_POLAR_PBCH_PAYLOAD_BITS>>3];
uint32_t pbch_a_interleaved;
uint32_t pbch_a_prime;
uint8_t pbch_e[NR_POLAR_PBCH_E];
int16_t demod_pbch_e[NR_POLAR_PBCH_E];
/// \brief Pointer to PBCH llrs.
/// - first index: ? [0..1919] (hard coded)
int16_t *llr;
/// \brief Pointer to PBCH decoded output.
/// - first index: ? [0..63] (hard coded)
uint8_t *decoded_output;
/// \brief PBCH additional bits
uint8_t xtra_byte;
/// \brief Total number of PDU errors.
uint32_t pdu_errors;
/// \brief Total number of PDU errors 128 frames ago.
......@@ -695,7 +661,7 @@ typedef struct {
/// \brief Total number of consecutive PDU errors.
uint32_t pdu_errors_conseq;
/// \brief FER (in percent) .
uint32_t pdu_fer;
//uint32_t pdu_fer;
} NR_UE_PBCH;
typedef struct {
......@@ -1073,7 +1039,7 @@ typedef struct {
#endif
int dl_stats[5];
void* scopeData;
} PHY_VARS_NR_UE;
/* this structure is used to pass both UE phy vars and
......
......@@ -82,6 +82,11 @@
#define DAQ_AGC_OFF 0
typedef struct {
uint8_t decoded_output[64];
uint8_t xtra_byte;
} fapiPbch_t;
/** @addtogroup _PHY_PROCEDURES_
* @{
*/
......@@ -395,7 +400,8 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
NR_UE_DLSCH_t *dlsch0,
NR_UE_DLSCH_t *dlsch1,
uint16_t n_pdus,
UE_nr_rxtx_proc_t *proc);
UE_nr_rxtx_proc_t *proc,
void * typeSpecific);
bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
......
......@@ -118,7 +118,8 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
NR_UE_DLSCH_t *dlsch0,
NR_UE_DLSCH_t *dlsch1,
uint16_t n_pdus,
UE_nr_rxtx_proc_t *proc ){
UE_nr_rxtx_proc_t *proc,
void * typeSpecific){
NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
......@@ -162,8 +163,11 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
rx_ind->rx_indication_body[n_pdus - 1].pdsch_pdu.pdu_length = dlsch0->harq_processes[dlsch0->current_harq_pid]->TBS / 8;
break;
case FAPI_NR_RX_PDU_TYPE_SSB:
rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.pdu = ue->pbch_vars[gNB_id]->decoded_output;
rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.additional_bits = ue->pbch_vars[gNB_id]->xtra_byte;
rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.pdu=malloc(sizeof(((fapiPbch_t*)typeSpecific)->decoded_output));
memcpy(rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.pdu,
((fapiPbch_t*)typeSpecific)->decoded_output,
sizeof(((fapiPbch_t*)typeSpecific)->decoded_output));
rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.additional_bits = ((fapiPbch_t*)typeSpecific)->xtra_byte;
rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.ssb_index = (frame_parms->ssb_index)&0x7;
rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.ssb_length = frame_parms->Lmax;
rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.cell_id = frame_parms->Nid_cell;
......@@ -353,10 +357,9 @@ void nr_ue_measurement_procedures(uint16_t l,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_MEASUREMENT_PROCEDURES, VCD_FUNCTION_OUT);
}
void nr_ue_pbch_procedures(uint8_t gNB_id,
static void nr_ue_pbch_procedures(uint8_t gNB_id,
PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
uint8_t abstraction_flag)
UE_nr_rxtx_proc_t *proc,int estimateSz, struct complex16 dl_ch_estimates[][estimateSz])
{
int ret = 0;
......@@ -368,13 +371,15 @@ void nr_ue_pbch_procedures(uint8_t gNB_id,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_IN);
LOG_D(PHY,"[UE %d] Frame %d Slot %d, Trying PBCH (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,nr_slot_rx,ue->frame_parms.Nid_cell,gNB_id);
fapiPbch_t result;
ret = nr_rx_pbch(ue, proc,
estimateSz, dl_ch_estimates,
ue->pbch_vars[gNB_id],
&ue->frame_parms,
gNB_id,
(ue->frame_parms.ssb_index)&7,
SISO);
SISO,
&result);
if (ret==0) {
......@@ -444,7 +449,6 @@ void nr_ue_pbch_procedures(uint8_t gNB_id,
}
if (frame_rx % 100 == 0) {
ue->pbch_vars[gNB_id]->pdu_fer = ue->pbch_vars[gNB_id]->pdu_errors - ue->pbch_vars[gNB_id]->pdu_errors_last;
ue->pbch_vars[gNB_id]->pdu_errors_last = ue->pbch_vars[gNB_id]->pdu_errors;
}
......@@ -795,16 +799,16 @@ bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
switch (pdsch) {
case RA_PDSCH:
nr_fill_dl_indication(&dl_indication, NULL, rx_ind, proc, ue, gNB_id);
nr_fill_rx_indication(rx_ind, FAPI_NR_RX_PDU_TYPE_RAR, gNB_id, ue, dlsch0, NULL, number_pdus, proc);
nr_fill_rx_indication(rx_ind, FAPI_NR_RX_PDU_TYPE_RAR, gNB_id, ue, dlsch0, NULL, number_pdus, proc, NULL);
ue->UE_mode[gNB_id] = RA_RESPONSE;
break;
case PDSCH:
nr_fill_dl_indication(&dl_indication, NULL, rx_ind, proc, ue, gNB_id);
nr_fill_rx_indication(rx_ind, FAPI_NR_RX_PDU_TYPE_DLSCH, gNB_id, ue, dlsch0, NULL, number_pdus, proc);
nr_fill_rx_indication(rx_ind, FAPI_NR_RX_PDU_TYPE_DLSCH, gNB_id, ue, dlsch0, NULL, number_pdus, proc, NULL);
break;
case SI_PDSCH:
nr_fill_dl_indication(&dl_indication, NULL, rx_ind, proc, ue, gNB_id);
nr_fill_rx_indication(rx_ind, FAPI_NR_RX_PDU_TYPE_SIB, gNB_id, ue, dlsch0, NULL, number_pdus, proc);
nr_fill_rx_indication(rx_ind, FAPI_NR_RX_PDU_TYPE_SIB, gNB_id, ue, dlsch0, NULL, number_pdus, proc, NULL);
break;
default:
break;
......@@ -1400,6 +1404,9 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
if (slot_ssb) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PBCH, VCD_FUNCTION_IN);
LOG_D(PHY," ------ PBCH ChannelComp/LLR: frame.slot %d.%d ------ \n", frame_rx%1024, nr_slot_rx);
const int estimateSz=7*2*sizeof(int)*fp->ofdm_symbol_size;
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates[fp->nb_antennas_rx][estimateSz];
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_time[fp->nb_antennas_rx][estimateSz];
for (int i=1; i<4; i++) {
nr_slot_fep(ue,
......@@ -1409,7 +1416,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
start_meas(&ue->dlsch_channel_estimation_stats);
nr_pbch_channel_estimation(ue,proc,gNB_id,nr_slot_rx,(ue->symbol_offset+i)%(fp->symbols_per_slot),i-1,(fp->ssb_index)&7,fp->half_frame_bit);
nr_pbch_channel_estimation(ue, estimateSz, dl_ch_estimates, dl_ch_estimates_time,proc,gNB_id,nr_slot_rx,(ue->symbol_offset+i)%(fp->symbols_per_slot),i-1,(fp->ssb_index)&7,fp->half_frame_bit);
stop_meas(&ue->dlsch_channel_estimation_stats);
}
......@@ -1418,13 +1425,14 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
if ((ue->decode_MIB == 1) && slot_pbch) {
LOG_D(PHY," ------ Decode MIB: frame.slot %d.%d ------ \n", frame_rx%1024, nr_slot_rx);
nr_ue_pbch_procedures(gNB_id, ue, proc, 0);
nr_ue_pbch_procedures(gNB_id, ue, proc, estimateSz, dl_ch_estimates);
if (ue->no_timing_correction==0) {
LOG_D(PHY,"start adjust sync slot = %d no timing %d\n", nr_slot_rx, ue->no_timing_correction);
nr_adjust_synch_ue(fp,
ue,
gNB_id,
estimateSz, dl_ch_estimates_time,
frame_rx,
nr_slot_rx,
0,
......
#include "nfapi/oai_integration/vendor_ext.h"
int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req) { return(0); }
int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req) { return(0); }
int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req) { return(0); }
......@@ -35,4 +36,5 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
NR_UE_DLSCH_t *dlsch0,
NR_UE_DLSCH_t *dlsch1,
uint16_t n_pdus,
UE_nr_rxtx_proc_t *proc) {}
UE_nr_rxtx_proc_t *proc,
void * typeSpecific ) {}
......@@ -438,6 +438,7 @@ int main(int argc, char **argv)
printf("Initializing gNodeB for mu %d, N_RB_DL %d\n",mu,N_RB_DL);
RC.gNB = (PHY_VARS_gNB**) malloc(sizeof(PHY_VARS_gNB *));
RC.gNB[0] = malloc16_clear(sizeof(*(RC.gNB[0])));
gNB = RC.gNB[0];
......@@ -531,13 +532,13 @@ int main(int argc, char **argv)
s_im = malloc(2*sizeof(double*));
r_re = malloc(2*sizeof(double*));
r_im = malloc(2*sizeof(double*));
txdata = malloc(2*sizeof(int*));
txdata = calloc(2,sizeof(int*));
for (i=0; i<2; i++) {
s_re[i] = malloc16_clear(frame_length_complex_samples*sizeof(double));
s_im[i] = malloc16_clear(frame_length_complex_samples*sizeof(double));
r_re[i] = malloc16_clear(frame_length_complex_samples*sizeof(double));
r_im[i] = malloc16_clear(frame_length_complex_samples*sizeof(double));
printf("Allocating %d samples for txdata\n",frame_length_complex_samples);
......@@ -550,6 +551,7 @@ int main(int argc, char **argv)
//configure UE
UE = malloc16_clear(sizeof(*UE));
memcpy(&UE->frame_parms,frame_parms,sizeof(UE->frame_parms));
//phy_init_nr_top(UE); //called from init_nr_ue_signal
......@@ -722,6 +724,9 @@ int main(int argc, char **argv)
UE_nr_rxtx_proc_t proc={0};
UE->rx_offset=0;
uint8_t ssb_index = 0;
const int estimateSz=7*2*sizeof(int)*frame_parms->ofdm_symbol_size;
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates[frame_parms->nb_antennas_rx][estimateSz];
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_time[frame_parms->nb_antennas_rx][estimateSz];
while (!((SSB_positions >> ssb_index) & 0x01)) ssb_index++; // to select the first transmitted ssb
UE->symbol_offset = nr_get_ssb_start_symbol(frame_parms,ssb_index);
......@@ -732,17 +737,20 @@ int main(int argc, char **argv)
i%frame_parms->symbols_per_slot,
ssb_slot);
nr_pbch_channel_estimation(UE,&proc,0,ssb_slot,i%frame_parms->symbols_per_slot,i-(UE->symbol_offset+1),ssb_index%8,n_hf);
nr_pbch_channel_estimation(UE,estimateSz, dl_ch_estimates, dl_ch_estimates_time, &proc,
0,ssb_slot,i%frame_parms->symbols_per_slot,i-(UE->symbol_offset+1),ssb_index%8,n_hf);
}
fapiPbch_t result;
ret = nr_rx_pbch(UE,
&proc,
estimateSz, dl_ch_estimates,
UE->pbch_vars[0],
frame_parms,
0,
ssb_index%8,
SISO);
SISO,
&result);
if (ret==0) {
//UE->rx_ind.rx_indication_body->mib_pdu.ssb_index; //not yet detected automatically
......@@ -751,9 +759,9 @@ int main(int argc, char **argv)
for (int i=0; i<8; i++)
gNB_xtra_byte |= ((gNB->pbch.pbch_a>>(31-i))&1)<<(7-i);
payload_ret = (UE->pbch_vars[0]->xtra_byte == gNB_xtra_byte);
payload_ret = (result.xtra_byte == gNB_xtra_byte);
for (i=0;i<3;i++){
payload_ret += (UE->pbch_vars[0]->decoded_output[i] == ((msgDataTx.ssb[ssb_index].ssb_pdu.ssb_pdu_rel15.bchPayload>>(8*i)) & 0xff));
payload_ret += (result.decoded_output[i] == ((msgDataTx.ssb[ssb_index].ssb_pdu.ssb_pdu_rel15.bchPayload>>(8*i)) & 0xff));
}
//printf("xtra byte gNB: 0x%02x UE: 0x%02x\n",gNB_xtra_byte, UE->pbch_vars[0]->xtra_byte);
//printf("ret %d\n", payload_ret);
......
......@@ -79,7 +79,9 @@ void nr_fill_nfapi_pucch(module_id_t mod_id,
NR_BWP_UplinkDedicated_t *ubwpd;
ubwpd = cg ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP:NULL;
LOG_D(NR_MAC,"pucch_acknak: %d.%d Calling nr_configure_pucch (ubwpd %p,r_pucch %d) pucch in %d.%d\n",frame,slot,ubwpd,pucch->r_pucch,pucch->frame,pucch->ul_slot);
LOG_D(NR_MAC,"%d.%d Calling nr_configure_pucch (ubwpd %p,r_pucch %d) pucch to be scheduled in %d.%d\n",
frame,slot,ubwpd,pucch->r_pucch,pucch->frame,pucch->ul_slot);
nr_configure_pucch(pucch_pdu,
scc,
UE_info->CellGroup[UE_id],
......@@ -1880,12 +1882,13 @@ void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot)
}
curr_pucch->sr_flag = true;
} else {
NR_sched_pucch_t sched_sr;
memset(&sched_sr, 0, sizeof(sched_sr));
sched_sr.frame = SFN;
sched_sr.ul_slot = slot;
sched_sr.resource_indicator = found;
sched_sr.sr_flag = true;
NR_sched_pucch_t sched_sr = {
.frame = SFN,
.ul_slot = slot,
.sr_flag = true,
.resource_indicator = found,
.r_pucch = -1
};
nr_fill_nfapi_pucch(Mod_idP, SFN, slot, &sched_sr, UE_id);
}
}
......
......@@ -1175,7 +1175,7 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_
(dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.ssb_length,
(dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.ssb_start_subcarrier,
(dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.cell_id)) << FAPI_NR_RX_PDU_TYPE_SSB;
free((dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.pdu);
break;
case FAPI_NR_RX_PDU_TYPE_SIB:
ret_mask |= (handle_bcch_dlsch(dl_info->module_id,
......
......@@ -4297,6 +4297,7 @@ ssize_t do_nrMeasurementReport(uint8_t *buffer,
If we delete this asn1cCalloc statement, eNB will crash in NSA mode.
Please don't delete the following line unless the bug has been found. */
asn1cCalloc(measresulteutra_list->cgi_Info, measresult_cgi2);
(void) measresult_cgi2;
struct LTE_MeasResultEUTRA__measResult* measResult= &measresulteutra_list->measResult;
asn1cCallocOne(measResult->rsrpResult, rsrp_tar);
asn1cCallocOne(measResult->rsrqResult, rsrq_tar);
......
......@@ -905,30 +905,27 @@ rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(
for (pdusession = 0; pdusession < ue_context_pP->ue_context.setup_pdu_sessions; pdusession++) {
// if (xid == ue_context_pP->ue_context.pdusession[pdusession].xid) {
if (ue_context_pP->ue_context.pduSession[pdusession].status == PDU_SESSION_STATUS_DONE) {
NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].pdusession_id = ue_context_pP->ue_context.pduSession[pdusession].param.pdusession_id;
// NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].pdusession_id = 1;
NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].nb_of_qos_flow = ue_context_pP->ue_context.pduSession[pdusession].param.nb_qos;
NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gtp_teid = ue_context_pP->ue_context.gnb_gtp_teid[pdusession];
NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gNB_addr.pdu_session_type = PDUSessionType_ipv4;
NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gNB_addr.length = ue_context_pP->ue_context.gnb_gtp_addrs[pdusession].length;
memcpy(NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gNB_addr.buffer,
ue_context_pP->ue_context.gnb_gtp_addrs[pdusession].buffer, sizeof(uint8_t)*20);
for (qos_flow_index = 0; qos_flow_index < NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].nb_of_qos_flow; qos_flow_index++) {
NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi =
pdusession_setup_t * tmp=&NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession];
tmp->pdusession_id = ue_context_pP->ue_context.pduSession[pdusession].param.pdusession_id;
// tmp->pdusession_id = 1;
tmp->nb_of_qos_flow = ue_context_pP->ue_context.pduSession[pdusession].param.nb_qos;
tmp->gtp_teid = ue_context_pP->ue_context.gnb_gtp_teid[pdusession];
tmp->gNB_addr.pdu_session_type = PDUSessionType_ipv4;
tmp->gNB_addr.length = ue_context_pP->ue_context.gnb_gtp_addrs[pdusession].length;
memcpy(tmp->gNB_addr.buffer,
ue_context_pP->ue_context.gnb_gtp_addrs[pdusession].buffer, tmp->gNB_addr.length);
for (qos_flow_index = 0; qos_flow_index < tmp->nb_of_qos_flow; qos_flow_index++) {
tmp->associated_qos_flows[qos_flow_index].qfi =
ue_context_pP->ue_context.pduSession[pdusession].param.qos[qos_flow_index].qfi;
NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL;
tmp->associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL;
}
ue_context_pP->ue_context.pduSession[pdusession].status = PDU_SESSION_STATUS_ESTABLISHED;
LOG_I (NR_RRC,"gnb_gtp_addr (msg index %d, pdu_sessions index %d, status %d, xid %d): nb_of_pdusessions %d, pdusession_id %d, teid: %u, addr: %d.%d.%d.%d \n ",
LOG_I (NR_RRC,"gnb_gtp_addr (msg index %d, pdu_sessions index %d, status %d, xid %d): nb_of_pdusessions %d, pdusession_id %d, teid: %u \n ",
pdu_sessions_done, pdusession, ue_context_pP->ue_context.pduSession[pdusession].status, xid,
ue_context_pP->ue_context.nb_of_pdusessions,
NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].pdusession_id,
NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gtp_teid,
NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[0],
NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[1],
NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[2],
NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[3]);
NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gtp_teid);
pdu_sessions_done++;
} else if ((ue_context_pP->ue_context.pduSession[pdusession].status == PDU_SESSION_STATUS_NEW) ||
(ue_context_pP->ue_context.pduSession[pdusession].status == PDU_SESSION_STATUS_ESTABLISHED)) {
......
building liblfds
================
Windows (user-mode)
===================
1. Use Microsoft Visual Studio 2008 or Visual C++ 2008 Express Edition (or
later versions) to load "liblfds.sln". The "Win32" platform is x86,
the "x64" platform is x64.
2. Use Microsoft Windows SDK and GNUmake to run makefile.windows (obviously
you'll need to have run setenv.bat or the appropriate vcvars*.bat first;
you can build for x64/64-bit and x86/32-bit - just run the correct batch
file).
Targets are "librel", "libdbg", "dllrel", "dlldbg" and "clean". You need
to clean between switching targets.
Windows (kernel)
================
Use the Windows Driver Kit "build" command. Prior to running "build",
if you wish to build a static library, run the batch file
"runme_before_win_kernel_static_lib_build.bat"; if you wish to
build a dynamic library, instead run "runme_before_win_kernel_dynamic_lib_build.bat".
The Windows kernel build system is rather limited and rather than
really rather messing up the directory/file structure just for the
Windows kernel platform, I've instead arranged it that these batch
files do the necessary work so that "build" will work.
The batch files are idempotent; you can run them as often as you
like, in any order, at any time (before or after builds), and they'll
do the right thing. You need to clean between switching targets.
Linux
=====
Use GNUmake to run "makefile.linux". Targets are "arrel", "ardbg",
"sorel", "sodbg" and "clean". You need to clean between switching
targets.
EXPORTS
lfds611_liblfds_abstraction_test_helper_increment_non_atomic = lfds611_liblfds_abstraction_test_helper_increment_non_atomic @1
lfds611_liblfds_abstraction_test_helper_increment_atomic = lfds611_liblfds_abstraction_test_helper_increment_atomic @2
lfds611_liblfds_abstraction_test_helper_cas = lfds611_liblfds_abstraction_test_helper_cas @3
lfds611_liblfds_abstraction_test_helper_dcas = lfds611_liblfds_abstraction_test_helper_dcas @4
lfds611_freelist_delete = lfds611_freelist_delete @5
lfds611_freelist_get_user_data_from_element = lfds611_freelist_get_user_data_from_element @6
lfds611_freelist_guaranteed_pop = lfds611_freelist_guaranteed_pop @7
lfds611_freelist_new = lfds611_freelist_new @8
lfds611_freelist_new_elements = lfds611_freelist_new_elements @9
lfds611_freelist_pop = lfds611_freelist_pop @10
lfds611_freelist_push = lfds611_freelist_push @11
lfds611_freelist_query = lfds611_freelist_query @12
lfds611_freelist_set_user_data_in_element = lfds611_freelist_set_user_data_in_element @13
lfds611_freelist_use = lfds611_freelist_use @14
lfds611_queue_delete = lfds611_queue_delete @15
lfds611_queue_dequeue = lfds611_queue_dequeue @16
lfds611_queue_enqueue = lfds611_queue_enqueue @17
lfds611_queue_guaranteed_enqueue = lfds611_queue_guaranteed_enqueue @18
lfds611_queue_new = lfds611_queue_new @19
lfds611_queue_query = lfds611_queue_query @20
lfds611_queue_use = lfds611_queue_use @21
lfds611_ringbuffer_delete = lfds611_ringbuffer_delete @22
lfds611_ringbuffer_get_read_element = lfds611_ringbuffer_get_read_element @23
lfds611_ringbuffer_get_write_element = lfds611_ringbuffer_get_write_element @24
lfds611_ringbuffer_new = lfds611_ringbuffer_new @25
lfds611_ringbuffer_put_read_element = lfds611_ringbuffer_put_read_element @26
lfds611_ringbuffer_put_write_element = lfds611_ringbuffer_put_write_element @27
lfds611_ringbuffer_query = lfds611_ringbuffer_query @28
lfds611_ringbuffer_use = lfds611_ringbuffer_use @29
lfds611_slist_delete = lfds611_slist_delete @30
lfds611_slist_get_head = lfds611_slist_get_head @31
lfds611_slist_get_head_and_then_next = lfds611_slist_get_head_and_then_next @32
lfds611_slist_get_next = lfds611_slist_get_next @33
lfds611_slist_get_user_data_from_element = lfds611_slist_get_user_data_from_element @34
lfds611_slist_logically_delete_element = lfds611_slist_logically_delete_element @35
lfds611_slist_new = lfds611_slist_new @36
lfds611_slist_new_head = lfds611_slist_new_head @37
lfds611_slist_new_next = lfds611_slist_new_next @38
lfds611_slist_set_user_data_in_element = lfds611_slist_set_user_data_in_element @39
lfds611_slist_single_threaded_physically_delete_all_elements = lfds611_slist_single_threaded_physically_delete_all_elements @40
lfds611_slist_use = lfds611_slist_use @41
lfds611_stack_clear = lfds611_stack_clear @42
lfds611_stack_delete = lfds611_stack_delete @43
lfds611_stack_guaranteed_push = lfds611_stack_guaranteed_push @44
lfds611_stack_new = lfds611_stack_new @45
lfds611_stack_pop = lfds611_stack_pop @46
lfds611_stack_push = lfds611_stack_push @47
lfds611_stack_query = lfds611_stack_query @48
lfds611_stack_use = lfds611_stack_use @49

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblfds611", "liblfds611.vcproj", "{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug DLL|Win32 = Debug DLL|Win32
Debug DLL|x64 = Debug DLL|x64
Debug Lib|Win32 = Debug Lib|Win32
Debug Lib|x64 = Debug Lib|x64
Release DLL|Win32 = Release DLL|Win32
Release DLL|x64 = Release DLL|x64
Release Lib|Win32 = Release Lib|Win32
Release Lib|x64 = Release Lib|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Debug DLL|Win32.Build.0 = Debug DLL|Win32
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Debug DLL|x64.ActiveCfg = Debug DLL|x64
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Debug DLL|x64.Build.0 = Debug DLL|x64
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Debug Lib|Win32.ActiveCfg = Debug Lib|Win32
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Debug Lib|Win32.Build.0 = Debug Lib|Win32
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Debug Lib|x64.ActiveCfg = Debug Lib|x64
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Debug Lib|x64.Build.0 = Debug Lib|x64
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Release DLL|Win32.ActiveCfg = Release DLL|Win32
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Release DLL|Win32.Build.0 = Release DLL|Win32
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Release DLL|x64.ActiveCfg = Release DLL|x64
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Release DLL|x64.Build.0 = Release DLL|x64
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Release Lib|Win32.ActiveCfg = Release Lib|Win32
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Release Lib|Win32.Build.0 = Release Lib|Win32
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Release Lib|x64.ActiveCfg = Release Lib|x64
{F73AE755-F6D8-4C3A-977D-FBB40DC0ED05}.Release Lib|x64.Build.0 = Release Lib|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
##### paths #####
OUTDIR := .
BINDIR = $(OUTDIR)/bin
OBJDIR = $(OUTDIR)/obj
INCDIR = inc
SRCDIR = src
##### misc #####
QUIETLY = 1>/dev/null 2>/dev/null
##### sources, objects and libraries #####
BINNAME = liblfds611
AR_BINARY = $(BINDIR)/$(BINNAME).a
$(info $(AR_BINARY))
SO_BINARY = $(BINDIR)/$(BINNAME).so
SRCDIRS = lfds611_abstraction lfds611_freelist lfds611_liblfds lfds611_queue lfds611_ringbuffer lfds611_slist lfds611_stack
# TRD : be aware - in the linux makefile, with the one-pass linking behaviour of the GNU linker, the order
# of source files matters! this is because it leads to the ordering of objects in the library and
# that in turn, since the data structures all use the freelist API and the abstraction API, has to be
# correct
# TRD : lfds611_abstraction_cas.c lfds611_abstraction_dcas.c lfds611_abstraction_increment.c are inlined and are compiled by every C file
SOURCES = lfds611_queue_delete.c lfds611_queue_new.c lfds611_queue_query.c lfds611_queue_queue.c \
lfds611_ringbuffer_delete.c lfds611_ringbuffer_get_and_put.c lfds611_ringbuffer_new.c lfds611_ringbuffer_query.c \
lfds611_slist_delete.c lfds611_slist_get_and_set.c lfds611_slist_link.c lfds611_slist_new.c \
lfds611_stack_delete.c lfds611_stack_new.c lfds611_stack_push_pop.c lfds611_stack_query.c \
lfds611_freelist_delete.c lfds611_freelist_get_and_set.c lfds611_freelist_new.c lfds611_freelist_query.c lfds611_freelist_pop_push.c \
lfds611_liblfds_abstraction_test_helpers.c lfds611_liblfds_aligned_free.c lfds611_liblfds_aligned_malloc.c \
lfds611_abstraction_free.c lfds611_abstraction_malloc.c
OBJECTS = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(SOURCES)))
##### CPU variants #####
UNAME = $(shell uname -m)
GCCARCH = -march=$(UNAME)
ifeq ($(UNAME),x86_64)
GCCARCH = -march=core2
endif
ifeq ($(findstring arm,$(UNAME)),arm)
GCCARCH = -march=armv6k -marm
endif
##### tools #####
MAKE = make
MFLAGS =
DG = gcc
DGFLAGS = -MM -std=c99 -I"$(SRCDIR)" -I"$(INCDIR)"
CC = gcc
CBASE = -Wall -Wno-unknown-pragmas -std=c99 $(GCCARCH) -pthread -c -I"$(SRCDIR)" -I"$(INCDIR)"
CFREL = -O2 -finline-functions -Wno-strict-aliasing
CFDBG = -O0 -g
AR = ar
AFLAGS = -rcs
LD = gcc
LFBASE = -Wall -std=c99 -shared
LFREL = -O2 -s
LFDBG = -O0 -g
##### rel/dbg .a/.so variants #####
ifeq ($(findstring so,$(MAKECMDGOALS)),so)
CBASE := $(CBASE) -fpic
endif
CFLAGS = $(CBASE) $(CFDBG)
LFLAGS = $(LFBASE) $(LFDBG)
ifeq ($(findstring rel,$(MAKECMDGOALS)),rel)
CFLAGS = $(CBASE) $(CFREL)
LFLAGS = $(LFBASE) $(LFREL)
endif
##### search paths #####
vpath %.c $(patsubst %,$(SRCDIR)/%:,$(SRCDIRS))
##### implicit rules #####
$(OBJDIR)/%.o : %.c
@echo "Compiling $<"
@$(DG) $(DGFLAGS) $< >$(OBJDIR)/$*.d
@$(CC) $(CFLAGS) -o $@ $<
##### explicit rules #####
$(AR_BINARY) : $(OBJECTS)
@echo "Creating $(AR_BINARY)"
@$(AR) $(AFLAGS) $(AR_BINARY) $(OBJECTS)
$(SO_BINARY) : $(OBJECTS)
@echo "Creating $(SO_BINARY)"
$(LD) $(LFLAGS) $(SYSLIBS) $(OBJECTS) -o $(SO_BINARY)
##### phony #####
.PHONY : clean arrel ardbg sorel sodbg
clean :
@rm -f $(BINDIR)/$(BINNAME).* $(OBJDIR)/*.o $(OBJDIR)/*.d
arrel : $(AR_BINARY)
ardbg : $(AR_BINARY)
sorel : $(SO_BINARY)
sodbg : $(SO_BINARY)
##### dependencies #####
-include $(DEPENDS)
##### notes #####
# TRD : we use -std=c99 purely to permit C++ style comments
##### paths #####
BINDIR = bin
INCDIR = inc
OBJDIR = obj
SRCDIR = src
##### misc #####
QUIETLY = 1>nul 2>nul
##### sources, objects and libraries #####
BINNAME = liblfds611
LIB_BINARY = $(BINDIR)\$(BINNAME).lib
DLL_BINARY = $(BINDIR)\$(BINNAME).dll
SRCDIRS = lfds611_abstraction lfds611_freelist lfds611_liblfds lfds611_queue lfds611_ringbuffer lfds611_slist lfds611_stack
# TRD : lfds611_abstraction_cas.c lfds611_abstraction_dcas.c lfds611_abstraction_increment.c are inlined and are compiled by every C file
SOURCES = lfds611_abstraction_free.c lfds611_abstraction_malloc.c \
lfds611_freelist_delete.c lfds611_freelist_get_and_set.c lfds611_freelist_new.c lfds611_freelist_query.c lfds611_freelist_pop_push.c \
lfds611_liblfds_abstraction_test_helpers.c lfds611_liblfds_aligned_free.c lfds611_liblfds_aligned_malloc.c \
lfds611_queue_delete.c lfds611_queue_new.c lfds611_queue_query.c lfds611_queue_queue.c \
lfds611_ringbuffer_delete.c lfds611_ringbuffer_get_and_put.c lfds611_ringbuffer_new.c lfds611_ringbuffer_query.c \
lfds611_slist_delete.c lfds611_slist_get_and_set.c lfds611_slist_link.c lfds611_slist_new.c \
lfds611_stack_delete.c lfds611_stack_new.c lfds611_stack_push_pop.c lfds611_stack_query.c
OBJECTS = $(patsubst %.c,$(OBJDIR)/%.obj,$(notdir $(SOURCES)))
SYSLIBS = kernel32.lib
##### tools #####
MAKE = make
MFLAGS =
CC = cl
CBASE = /nologo /W4 /WX /c "-I$(SRCDIR)" "-I$(INCDIR)" "/Fd$(BINDIR)\$(BINNAME).pdb" /DUNICODE /D_UNICODE /DWIN32_LEAN_AND_MEAN
CFREL = /Ox /DNDEBUG
CFDBG = /Od /Gm /Zi /D_DEBUG
AR = lib
AFLAGS = /nologo /subsystem:console /wx /verbose
LD = link
LFBASE = /dll /def:$(BINNAME).def /nologo /subsystem:console /wx /nodefaultlib /nxcompat
LFREL = /incremental:no
LFDBG = /debug "/pdb:$(BINDIR)\$(BINNAME).pdb"
##### variants #####
CFLAGS = $(CBASE) $(CFDBG) /MTd
LFLAGS = $(LFBASE) $(LFDBG)
CLIB = libcmtd.lib
ifeq ($(MAKECMDGOALS),librel)
CFLAGS = $(CBASE) $(CFREL) /MT
LFLAGS = $(LFBASE) $(LFREL)
CLIB = libcmt.lib
endif
ifeq ($(MAKECMDGOALS),libdbg)
CFLAGS = $(CBASE) $(CFDBG) /MTd
LFLAGS = $(LFBASE) $(LFDBG)
CLIB = libcmtd.lib
endif
ifeq ($(MAKECMDGOALS),dllrel)
CFLAGS = $(CBASE) $(CFREL) /MD
LFLAGS = $(LFBASE) $(LFREL)
CLIB = msvcrt.lib
endif
ifeq ($(MAKECMDGOALS),dlldbg)
CFLAGS = $(CBASE) $(CFDBG) /MDd
LFLAGS = $(LFBASE) $(LFDBG)
CLIB = msvcrtd.lib
endif
##### search paths #####
vpath %.c $(patsubst %,$(SRCDIR)/%;,$(SRCDIRS))
##### implicit rules #####
$(OBJDIR)/%.obj : %.c
$(CC) $(CFLAGS) "/Fo$@" $<
##### explicit rules #####
$(LIB_BINARY) : $(OBJECTS)
$(AR) $(AFLAGS) $(OBJECTS) /out:$(LIB_BINARY)
$(DLL_BINARY) : $(OBJECTS)
$(LD) $(LFLAGS) $(CLIB) $(SYSLIBS) $(OBJECTS) /out:$(DLL_BINARY)
##### phony #####
.PHONY : clean librel libdbg dllrel dlldbg
clean :
@erase /Q $(BINDIR)\$(BINNAME).* $(OBJDIR)\*.obj $(QUIETLY)
librel : $(LIB_BINARY)
libdbg : $(LIB_BINARY)
dllrel : $(DLL_BINARY)
dlldbg : $(DLL_BINARY)
introduction
============
Welcome to liblfds, a portable, license-free, lock-free data structure library
written in C.
supported platforms
===================
Out-of-the-box ports are provided for;
Operating System CPU Toolchain Choices
================ ============= =================
Windows 64-bit x64 1. Microsoft Visual Studio
2. Microsoft Windows SDK and GNUmake
Windows 32-bit x64, x86 1. Microsoft Visual Studio
2. Visual C++ Express Edition
3. Microsoft Windows SDK and GNUmake
Windows Kernel x64, x86 1. Windows Driver Kit
Linux 64-bit x64 1. GCC and GNUmake
Linux 32-bit ARM, x64, x86 1. GCC and GNUmake
For more information including version requirements, see the building guide (lfds).
data structures
===============
This release of liblfds provides the following;
* Freelist
* Queue
* Ringbuffer (each element read by a single reader)
* Singly-linked list (logical delete only)
* Stack
These are all many-readers, many-writers.
liblfds on-line
===============
On the liblfds home page, you will find the blog, a bugzilla, a forum, a
mediawiki and the current and all historical releases.
The mediawiki contains comprehensive documentation for development, building,
testing and porting.
http://www.liblfds.org
license
=======
There is no license. You are free to use this code in any way.
using
=====
Once built, there is a single header file, /inc/liblfds.h, which you must include
in your source code, and a single library file /bin/liblfds.*, where the suffix
depends on your platform and your build choice (static or dynamic), to which,
if statically built, you must link directly or, if dynamically built, you must
arrange your system such that the library can be found by the loader at run-time.
testing
=======
The library comes with a command line test and benchmark program. This program
requires threads. As such, it is only suitable for platforms which can execute
a command line binary and provide thread support. Currently this means the test
and benchmark program works for all platforms except the Windows Kernel.
For documentation, see the testing and benchmarking guide in the mediawiki.
porting
=======
Both the test program and liblfds provide an abstraction layer which acts to
mask platform differences. Porting is the act of implementing on your platform
the functions which make up the abstraction layers. You do not need to port
the test program to port liblfds, but obviously it is recommended, so you can
test your port.
To support liblfds, your platform MUST support;
* atomic single-word* increment
* atomic single-word compare-and-swap
* atomic contiguous double-word compare-and-swap*
* malloc and free
* compiler directive for alignment of variables declared on the stack
* compiler directives for compiler barriers and processor barriers
* A ''word'' here means a type equal in length to the platform pointer size.
* This requirement excludes the Alpha, IA64, MIPS, PowerPC and SPARC platforms.
Also, your platform MAY support;
* compiler keyword for function inlining
To support the test programme, your platform MUST support;
* determining the number of logical cores
* threads (starting and waiting on for completion)
For documentation, see the porting guide (lfds) in the mediawiki.
release history
===============
release 1, 25th September 2009, svn revision 1574.
- initial release
release 2, 5th October 2009, svn revision 1599.
- added abstraction layer for Windows kernel
- minor code tidyups/fixes
release 3, 25th October 2009, svn revision 1652.
- added singly linked list (logical delete only)
- minor code tidyups/fixes
release 4, 7th December 2009, svn revision 1716.
- added ARM support
- added benchmarking functionality to the test program
- fixed a profound and pervasive pointer
declaration bug; earlier releases of liblfds
*should not be used*
release 5, 19th December 2009, svn revision 1738.
- fixed subtle queue bug, which also affected ringbuffer
and caused data re-ordering under high load
- added benchmarks for freelist, ringbuffer and stack
release 6, 29th December 2009, svn revision 1746.
- fixed two implementation errors, which reduced performance,
spotted by Codeplug from "http://cboard.cprogramming.com".
release 6.0.0, 18th December 2012, svn revision 2537
- introduction of namespaces, e.g. the "lfds600_" prefix
code otherwise COMPLETELY AND WHOLLY UNCHANGED
this release is a stepping-stone to 6.1.0
release 6.0.1, 2nd January 2013, svn revision 3296
- bug fix where an enum wasn't moved into the new namespacing policy
release 6.1.0, 31th December 2012, svn revision 2600
- fixed all existing non-enhancement bugs
- discovered some new bugs and fixed them too
- a very few minor changes/enhancements
release 6.1.1, 2nd January 2013, svn revision 3297
- crucial bug fix where compiler barriers for atomic operations
were not brought over from 7.0.0 during backporting
- minor fix for abstraction tests, two missing store barriers
The Windows kernel build environment is primitive and has a number
of severe limitations; in particular, all source files must be in
one directory and it is not possible to choose the output binary type
(static or dynamic library) from the build command line; rather,
a string has to be modified in a text file used by the build (!)
To deal with these limitations, it is necessary for a Windows kernel
build to run a batch file prior to building.
There are two batch files, one for static library builds and the other
for dynamic library builds.
They are both idempotent; you can run them as often as you like and
switch between them as often as you want. It's all fine; whenever
you run one of them, it will take you from whatever state you were
previously in, into the state you want to be in.
Both batch files copy all the sources file into a single directory,
"/src/single_dir_for_windows_kernel/".
The static library batch file will then copy "/sources.static" into
"/src/single_dir_for_windows_kernel/", which will cause a static
library to be built.
The dynamic library batch file will then copy "/sources.dynamic" into
"/src/single_dir_for_windows_kernel/", which will cause a dynamic
library to be built. It will also copy "src/driver_entry.c" into
"/src/single_dir_for_windows_kernel/", since the linker requires
the DriverEntry function to exist for dynamic libraries, even
though it's not used.
@echo off
rmdir /q /s src\single_dir_for_windows_kernel 1>nul 2>nul
mkdir src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_abstraction\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_freelist\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_liblfds\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_queue\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_ringbuffer\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_slist\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_stack\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y sources.dynamic src\single_dir_for_windows_kernel\sources 1>nul 2>nul
copy /y src\driver_entry.c src\single_dir_for_windows_kernel 1>nul 2>nul
echo Windows kernel dynamic library build directory structure created.
echo (Note the effects of this batch file are idempotent).
@echo off
rmdir /q /s src\single_dir_for_windows_kernel 1>nul 2>nul
mkdir src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_abstraction\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_freelist\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_liblfds\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_queue\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_ringbuffer\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_slist\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y src\lfds611_stack\* src\single_dir_for_windows_kernel 1>nul 2>nul
copy /y sources.static src\single_dir_for_windows_kernel\sources 1>nul 2>nul
erase /f src\single_dir_for_windows_kernel\driver_entry.c 1>nul 2>nul
echo Windows kernel static library build directory structure created.
echo (Note the effects of this batch file are idempotent).
MSC_WARNING_LEVEL = /WX /W4
DLLDEF = ../../liblfds611.def
TARGETNAME = liblfds611
TARGETPATH = ../../bin/
TARGETTYPE = EXPORT_DRIVER
UMTYPE = nt
USER_C_FLAGS = /DWIN_KERNEL_BUILD
INCLUDES = ..;../../inc/
SOURCES = lfds611_abstraction_free.c \
lfds611_abstraction_malloc.c \
lfds611_freelist_delete.c \
lfds611_freelist_get_and_set.c \
lfds611_freelist_new.c \
lfds611_freelist_pop_push.c \
lfds611_freelist_query.c \
lfds611_liblfds_abstraction_test_helpers.c \
lfds611_liblfds_aligned_free.c \
lfds611_liblfds_aligned_malloc.c \
lfds611_queue_delete.c \
lfds611_queue_new.c \
lfds611_queue_query.c \
lfds611_queue_queue.c \
lfds611_ringbuffer_delete.c \
lfds611_ringbuffer_get_and_put.c \
lfds611_ringbuffer_new.c \
lfds611_ringbuffer_query.c \
lfds611_slist_delete.c \
lfds611_slist_get_and_set.c \
lfds611_slist_link.c \
lfds611_slist_new.c \
lfds611_stack_delete.c \
lfds611_stack_new.c \
lfds611_stack_push_pop.c \
lfds611_stack_query.c \
driver_entry.c
MSC_WARNING_LEVEL = /WX /W4
TARGETNAME = liblfds611
TARGETPATH = ../../bin/
TARGETTYPE = DRIVER_LIBRARY
UMTYPE = nt
USER_C_FLAGS = /DWIN_KERNEL_BUILD
INCLUDES = ..;../../inc/
SOURCES = lfds611_abstraction_free.c \
lfds611_abstraction_malloc.c \
lfds611_freelist_delete.c \
lfds611_freelist_get_and_set.c \
lfds611_freelist_new.c \
lfds611_freelist_pop_push.c \
lfds611_freelist_query.c \
lfds611_liblfds_abstraction_test_helpers.c \
lfds611_liblfds_aligned_free.c \
lfds611_liblfds_aligned_malloc.c \
lfds611_queue_delete.c \
lfds611_queue_new.c \
lfds611_queue_query.c \
lfds611_queue_queue.c \
lfds611_ringbuffer_delete.c \
lfds611_ringbuffer_get_and_put.c \
lfds611_ringbuffer_new.c \
lfds611_ringbuffer_query.c \
lfds611_slist_delete.c \
lfds611_slist_get_and_set.c \
lfds611_slist_link.c \
lfds611_slist_new.c \
lfds611_stack_delete.c \
lfds611_stack_new.c \
lfds611_stack_push_pop.c \
lfds611_stack_query.c
#include "liblfds611_internal.h"
/****************************************************************************/
#pragma warning( disable : 4100 )
NTSTATUS DriverEntry( struct _DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath )
{
return( STATUS_SUCCESS );
}
#pragma warning( default : 4100 )
This C file (driver_entry.c) is used when building a dynamic library for
the Windows kernel. It exists to work around one of the limitations of
that build environment. It is not used by any other build; just ignore it.
#include "lfds611_abstraction_internal_body.h"
/****************************************************************************/
#if (defined _WIN32 && defined _MSC_VER)
/* TRD : 64 bit and 32 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler
_WIN32 indicates 64-bit or 32-bit Windows
_MSC_VER indicates Microsoft C compiler
*/
static LFDS611_INLINE lfds611_atom_t lfds611_abstraction_cas( volatile lfds611_atom_t *destination, lfds611_atom_t exchange, lfds611_atom_t compare )
{
lfds611_atom_t
rv;
assert( destination != NULL );
// TRD : exchange can be any value in its range
// TRD : compare can be any value in its range
LFDS611_BARRIER_COMPILER_FULL;
rv = (lfds611_atom_t) _InterlockedCompareExchangePointer( (void * volatile *) destination, (void *) exchange, (void *) compare );
LFDS611_BARRIER_COMPILER_FULL;
return( rv );
}
#endif
/****************************************************************************/
#if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1 && __GNUC_PATCHLEVEL__ >= 0)
/* TRD : any OS on any CPU with GCC 4.1.0 or better
GCC 4.1.0 introduced the __sync_*() atomic intrinsics
__GNUC__ / __GNUC_MINOR__ / __GNUC_PATCHLEVEL__ indicates GCC and which version
*/
static LFDS611_INLINE lfds611_atom_t lfds611_abstraction_cas( volatile lfds611_atom_t *destination, lfds611_atom_t exchange, lfds611_atom_t compare )
{
lfds611_atom_t
rv;
assert( destination != NULL );
// TRD : exchange can be any value in its range
// TRD : compare can be any value in its range
// TRD : note the different argument order for the GCC instrinsic to the MSVC instrinsic
LFDS611_BARRIER_COMPILER_FULL;
rv = (lfds611_atom_t) __sync_val_compare_and_swap( destination, compare, exchange );
LFDS611_BARRIER_COMPILER_FULL;
return( rv );
}
#endif
#include "lfds611_abstraction_internal_body.h"
/****************************************************************************/
#if (defined _WIN64 && defined _MSC_VER)
/* TRD : 64 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler
_WIN64 indicates 64 bit Windows
_MSC_VER indicates Microsoft C compiler
*/
static LFDS611_INLINE unsigned char lfds611_abstraction_dcas( volatile lfds611_atom_t *destination, lfds611_atom_t *exchange, lfds611_atom_t *compare )
{
unsigned char
cas_result;
assert( destination != NULL );
assert( exchange != NULL );
assert( compare != NULL );
LFDS611_BARRIER_COMPILER_FULL;
cas_result = _InterlockedCompareExchange128( (volatile __int64 *) destination, (__int64) *(exchange+1), (__int64) *exchange, (__int64 *) compare );
LFDS611_BARRIER_COMPILER_FULL;
return( cas_result ) ;
}
#endif
/****************************************************************************/
#if (!defined _WIN64 && defined _WIN32 && defined _MSC_VER)
/* TRD : 32 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler
(!defined _WIN64 && defined _WIN32) indicates 32 bit Windows
_MSC_VER indicates Microsoft C compiler
*/
static LFDS611_INLINE unsigned char lfds611_abstraction_dcas( volatile lfds611_atom_t *destination, lfds611_atom_t *exchange, lfds611_atom_t *compare )
{
__int64
original_compare;
assert( destination != NULL );
assert( exchange != NULL );
assert( compare != NULL );
*(__int64 *) &original_compare = *(__int64 *) compare;
LFDS611_BARRIER_COMPILER_FULL;
*(__int64 *) compare = _InterlockedCompareExchange64( (volatile __int64 *) destination, *(__int64 *) exchange, *(__int64 *) compare );
LFDS611_BARRIER_COMPILER_FULL;
return( (unsigned char) (*(__int64 *) compare == *(__int64 *) &original_compare) );
}
#endif
/****************************************************************************/
#if (defined __x86_64__ && defined __GNUC__)
/* TRD : any OS on x64 with GCC
__x86_64__ indicates x64
__GNUC__ indicates GCC
*/
static LFDS611_INLINE unsigned char lfds611_abstraction_dcas( volatile lfds611_atom_t *destination, lfds611_atom_t *exchange, lfds611_atom_t *compare )
{
unsigned char
cas_result;
assert( destination != NULL );
assert( exchange != NULL );
assert( compare != NULL );
// TRD : __asm__ with "memory" in the clobber list is for GCC a full compiler barrier
__asm__ __volatile__
(
"lock;" // make cmpxchg16b atomic
"cmpxchg16b %0;" // cmpxchg16b sets ZF on success
"setz %3;" // if ZF set, set cas_result to 1
// output
: "+m" (*(volatile lfds611_atom_t (*)[2]) destination), "+a" (*compare), "+d" (*(compare+1)), "=q" (cas_result)
// input
: "b" (*exchange), "c" (*(exchange+1))
// clobbered
: "cc", "memory"
);
return( cas_result );
}
#endif
/****************************************************************************/
#if ((defined __i686__ || defined __arm__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1 && __GNUC_PATCHLEVEL__ >= 0)
/* TRD : any OS on x86 or ARM with GCC 4.1.0 or better
GCC 4.1.0 introduced the __sync_*() atomic intrinsics
__GNUC__ / __GNUC_MINOR__ / __GNUC_PATCHLEVEL__ indicates GCC and which version
*/
static LFDS611_INLINE unsigned char lfds611_abstraction_dcas( volatile lfds611_atom_t *destination, lfds611_atom_t *exchange, lfds611_atom_t *compare )
{
unsigned char
cas_result = 0;
unsigned long long int
original_destination;
assert( destination != NULL );
assert( exchange != NULL );
assert( compare != NULL );
LFDS611_BARRIER_COMPILER_FULL;
original_destination = __sync_val_compare_and_swap( (volatile unsigned long long int *) destination, *(unsigned long long int *) compare, *(unsigned long long int *) exchange );
LFDS611_BARRIER_COMPILER_FULL;
if( original_destination == *(unsigned long long int *) compare )
cas_result = 1;
*(unsigned long long int *) compare = original_destination;
return( cas_result );
}
#endif
#include "lfds611_abstraction_internal_wrapper.h"
/****************************************************************************/
#if (!defined WIN_KERNEL_BUILD)
/* TRD : any OS except Windows kernel on any CPU with any compiler
!WIN_KERNEL_BUILD indicates not Windows kernel
*/
void lfds611_abstraction_free( void *memory )
{
free( memory );
return;
}
#endif
/****************************************************************************/
#if (defined WIN_KERNEL_BUILD)
/* TRD : any Windows (kernel) on any CPU with the Microsoft C compiler
WIN_KERNEL_BUILD indicates Windows kernel
*/
void lfds611_abstraction_free( void *memory )
{
ExFreePoolWithTag( memory, 'sdfl' );
return;
}
#endif
#include "lfds611_abstraction_internal_body.h"
/****************************************************************************/
#if (defined _WIN64 && defined _MSC_VER)
/* TRD : 64 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler
_WIN64 indicates 64 bit Windows
_MSC_VER indicates Microsoft C compiler
*/
static LFDS611_INLINE lfds611_atom_t lfds611_abstraction_increment( volatile lfds611_atom_t *value )
{
lfds611_atom_t
rv;
assert( value != NULL );
LFDS611_BARRIER_COMPILER_FULL;
rv = (lfds611_atom_t) _InterlockedIncrement64( (__int64 *) value );
LFDS611_BARRIER_COMPILER_FULL;
return( rv );
}
#endif
/****************************************************************************/
#if (!defined _WIN64 && defined _WIN32 && defined _MSC_VER)
/* TRD : 32 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler
(!defined _WIN64 && defined _WIN32) indicates 32 bit Windows
_MSC_VER indicates Microsoft C compiler
*/
static LFDS611_INLINE lfds611_atom_t lfds611_abstraction_increment( volatile lfds611_atom_t *value )
{
lfds611_atom_t
rv;
assert( value != NULL );
LFDS611_BARRIER_COMPILER_FULL;
rv = (lfds611_atom_t) _InterlockedIncrement( (long int *) value );
LFDS611_BARRIER_COMPILER_FULL;
return( rv );
}
#endif
/****************************************************************************/
#if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1 && __GNUC_PATCHLEVEL__ >= 0)
/* TRD : any OS on any CPU with GCC 4.1.0 or better
GCC 4.1.0 introduced the __sync_*() atomic intrinsics
__GNUC__ / __GNUC_MINOR__ / __GNUC_PATCHLEVEL__ indicates GCC and which version
*/
static LFDS611_INLINE lfds611_atom_t lfds611_abstraction_increment( volatile lfds611_atom_t *value )
{
lfds611_atom_t
rv;
assert( value != NULL );
// TRD : no need for casting here, GCC has a __sync_add_and_fetch() for all native types
LFDS611_BARRIER_COMPILER_FULL;
rv = (lfds611_atom_t) __sync_add_and_fetch( value, 1 );
LFDS611_BARRIER_COMPILER_FULL;
return( rv );
}
#endif
/***** the library wide include file *****/
#include "liblfds611_internal.h"
/***** the internal header body *****/
#include "lfds611_abstraction_internal_body.h"
#include "lfds611_abstraction_internal_wrapper.h"
/****************************************************************************/
#if (!defined WIN_KERNEL_BUILD)
/* TRD : any OS except Windows kernel on any CPU with any compiler
!WIN_KERNEL_BUILD indicates not Windows kernel
*/
void *lfds611_abstraction_malloc( size_t size )
{
return( malloc(size) );
}
#endif
/****************************************************************************/
#if (defined WIN_KERNEL_BUILD)
/* TRD : any Windows (kernel) on any CPU with the Microsoft C compiler
WIN_KERNEL_BUILD indicates Windows kernel
*/
void *lfds611_abstraction_malloc( size_t size )
{
return( ExAllocatePoolWithTag(NonPagedPool, size, 'sdfl') );
}
#endif
#include "lfds611_freelist_internal.h"
/****************************************************************************/
void lfds611_freelist_delete( struct lfds611_freelist_state *fs, void (*user_data_delete_function)(void *user_data, void *user_state), void *user_state )
{
struct lfds611_freelist_element
*fe;
void
*user_data;
assert( fs != NULL );
// TRD : user_data_delete_function can be NULL
// TRD : user_state can be NULL
// TRD : leading load barrier not required as it will be performed by the pop
while( lfds611_freelist_pop(fs, &fe) ) {
if( user_data_delete_function != NULL ) {
lfds611_freelist_get_user_data_from_element( fe, &user_data );
user_data_delete_function( user_data, user_state );
}
lfds611_liblfds_aligned_free( fe );
}
lfds611_liblfds_aligned_free( fs );
return;
}
#include "lfds611_freelist_internal.h"
/****************************************************************************/
void *lfds611_freelist_get_user_data_from_element( struct lfds611_freelist_element *fe, void **user_data )
{
assert( fe != NULL );
// TRD : user_data can be NULL
LFDS611_BARRIER_LOAD;
if( user_data != NULL )
*user_data = fe->user_data;
return( fe->user_data );
}
/****************************************************************************/
void lfds611_freelist_set_user_data_in_element( struct lfds611_freelist_element *fe, void *user_data )
{
assert( fe != NULL );
// TRD : user_data can be NULL
fe->user_data = user_data;
LFDS611_BARRIER_STORE;
return;
}
/***** the library wide include file *****/
#include "liblfds611_internal.h"
/***** defines *****/
#define LFDS611_FREELIST_POINTER 0
#define LFDS611_FREELIST_COUNTER 1
#define LFDS611_FREELIST_PAC_SIZE 2
/***** structures *****/
#pragma pack( push, LFDS611_ALIGN_DOUBLE_POINTER )
struct lfds611_freelist_state {
struct lfds611_freelist_element
*volatile top[LFDS611_FREELIST_PAC_SIZE];
int
(*user_data_init_function)( void **user_data, void *user_state );
void
*user_state;
lfds611_atom_t
aba_counter,
element_count;
};
struct lfds611_freelist_element {
struct lfds611_freelist_element
*next[LFDS611_FREELIST_PAC_SIZE];
void
*user_data;
};
#pragma pack( pop )
/***** private prototypes *****/
lfds611_atom_t lfds611_freelist_internal_new_element( struct lfds611_freelist_state *fs, struct lfds611_freelist_element **fe );
void lfds611_freelist_internal_validate( struct lfds611_freelist_state *fs, struct lfds611_validation_info *vi, enum lfds611_data_structure_validity *lfds611_freelist_validity );
#include "lfds611_freelist_internal.h"
/****************************************************************************/
int lfds611_freelist_new( struct lfds611_freelist_state **fs, lfds611_atom_t number_elements, int (*user_data_init_function)(void **user_data, void *user_state), void *user_state )
{
int
rv = 0;
lfds611_atom_t
element_count;
assert( fs != NULL );
// TRD : number_elements can be any value in its range
// TRD : user_data_init_function can be NULL
*fs = (struct lfds611_freelist_state *) lfds611_liblfds_aligned_malloc( sizeof(struct lfds611_freelist_state), LFDS611_ALIGN_DOUBLE_POINTER );
if( (*fs) != NULL ) {
(*fs)->top[LFDS611_FREELIST_POINTER] = NULL;
(*fs)->top[LFDS611_FREELIST_COUNTER] = 0;
(*fs)->user_data_init_function = user_data_init_function;
(*fs)->user_state = user_state;
(*fs)->aba_counter = 0;
(*fs)->element_count = 0;
element_count = lfds611_freelist_new_elements( *fs, number_elements );
if( element_count == number_elements )
rv = 1;
if( element_count != number_elements ) {
lfds611_liblfds_aligned_free( (*fs) );
*fs = NULL;
}
}
LFDS611_BARRIER_STORE;
return( rv );
}
/****************************************************************************/
//#pragma warning( disable : 4100 )
void lfds611_freelist_use( struct lfds611_freelist_state *fs )
{
assert( fs != NULL );
LFDS611_BARRIER_LOAD;
return;
}
//#pragma warning( default : 4100 )
/****************************************************************************/
lfds611_atom_t lfds611_freelist_new_elements( struct lfds611_freelist_state *fs, lfds611_atom_t number_elements )
{
struct lfds611_freelist_element
*fe;
lfds611_atom_t
loop,
count = 0;
assert( fs != NULL );
// TRD : number_elements can be any value in its range
// TRD : user_data_init_function can be NULL
for( loop = 0 ; loop < number_elements ; loop++ )
if( lfds611_freelist_internal_new_element(fs, &fe) ) {
lfds611_freelist_push( fs, fe );
count++;
}
return( count );
}
/****************************************************************************/
lfds611_atom_t lfds611_freelist_internal_new_element( struct lfds611_freelist_state *fs, struct lfds611_freelist_element **fe )
{
lfds611_atom_t
rv = 0;
assert( fs != NULL );
assert( fe != NULL );
/* TRD : basically, does what you'd expect;
allocates an element
calls the user init function
if anything fails, cleans up,
sets *fe to NULL
and returns 0
*/
*fe = (struct lfds611_freelist_element *) lfds611_liblfds_aligned_malloc( sizeof(struct lfds611_freelist_element), LFDS611_ALIGN_DOUBLE_POINTER );
if( *fe != NULL ) {
if( fs->user_data_init_function == NULL ) {
(*fe)->user_data = NULL;
rv = 1;
}
if( fs->user_data_init_function != NULL ) {
rv = fs->user_data_init_function( &(*fe)->user_data, fs->user_state );
if( rv == 0 ) {
lfds611_liblfds_aligned_free( *fe );
*fe = NULL;
}
}
}
if( rv == 1 )
lfds611_abstraction_increment( (lfds611_atom_t *) &fs->element_count );
return( rv );
}
#include "lfds611_freelist_internal.h"
/****************************************************************************/
struct lfds611_freelist_element *lfds611_freelist_pop( struct lfds611_freelist_state *fs, struct lfds611_freelist_element **fe )
{
LFDS611_ALIGN(LFDS611_ALIGN_DOUBLE_POINTER) struct lfds611_freelist_element
*fe_local[LFDS611_FREELIST_PAC_SIZE];
assert( fs != NULL );
assert( fe != NULL );
LFDS611_BARRIER_LOAD;
fe_local[LFDS611_FREELIST_COUNTER] = fs->top[LFDS611_FREELIST_COUNTER];
fe_local[LFDS611_FREELIST_POINTER] = fs->top[LFDS611_FREELIST_POINTER];
/* TRD : note that lfds611_abstraction_dcas loads the original value of the destination (fs->top) into the compare (fe_local)
(this happens of course after the CAS itself has occurred inside lfds611_abstraction_dcas)
*/
do {
if( fe_local[LFDS611_FREELIST_POINTER] == NULL ) {
*fe = NULL;
return( *fe );
}
} while( 0 == lfds611_abstraction_dcas((volatile lfds611_atom_t *) fs->top, (lfds611_atom_t *) fe_local[LFDS611_FREELIST_POINTER]->next, (lfds611_atom_t *) fe_local) );
*fe = (struct lfds611_freelist_element *) fe_local[LFDS611_FREELIST_POINTER];
return( *fe );
}
/****************************************************************************/
struct lfds611_freelist_element *lfds611_freelist_guaranteed_pop( struct lfds611_freelist_state *fs, struct lfds611_freelist_element **fe )
{
assert( fs != NULL );
assert( fe != NULL );
lfds611_freelist_internal_new_element( fs, fe );
return( *fe );
}
/****************************************************************************/
void lfds611_freelist_push( struct lfds611_freelist_state *fs, struct lfds611_freelist_element *fe )
{
LFDS611_ALIGN(LFDS611_ALIGN_DOUBLE_POINTER) struct lfds611_freelist_element
*fe_local[LFDS611_FREELIST_PAC_SIZE],
*original_fe_next[LFDS611_FREELIST_PAC_SIZE];
assert( fs != NULL );
assert( fe != NULL );
LFDS611_BARRIER_LOAD;
fe_local[LFDS611_FREELIST_POINTER] = fe;
fe_local[LFDS611_FREELIST_COUNTER] = (struct lfds611_freelist_element *) lfds611_abstraction_increment( (lfds611_atom_t *) &fs->aba_counter );
original_fe_next[LFDS611_FREELIST_POINTER] = fs->top[LFDS611_FREELIST_POINTER];
original_fe_next[LFDS611_FREELIST_COUNTER] = fs->top[LFDS611_FREELIST_COUNTER];
/* TRD : note that lfds611_abstraction_dcas loads the original value of the destination (fs->top) into the compare (original_fe_next)
(this happens of course after the CAS itself has occurred inside lfds611_abstraction_dcas)
this then causes us in our loop, should we repeat it, to update fe_local->next to a more
up-to-date version of the head of the lfds611_freelist
*/
do {
fe_local[LFDS611_FREELIST_POINTER]->next[LFDS611_FREELIST_POINTER] = original_fe_next[LFDS611_FREELIST_POINTER];
fe_local[LFDS611_FREELIST_POINTER]->next[LFDS611_FREELIST_COUNTER] = original_fe_next[LFDS611_FREELIST_COUNTER];
} while( 0 == lfds611_abstraction_dcas((volatile lfds611_atom_t *) fs->top, (lfds611_atom_t *) fe_local, (lfds611_atom_t *) original_fe_next) );
return;
}
#include "lfds611_freelist_internal.h"
/****************************************************************************/
void lfds611_freelist_query( struct lfds611_freelist_state *fs, enum lfds611_freelist_query_type query_type, void *query_input, void *query_output )
{
assert( fs != NULL );
// TRD : query type can be any value in its range
// TRD : query_input can be NULL in some cases
assert( query_output != NULL );
LFDS611_BARRIER_LOAD;
switch( query_type ) {
case LFDS611_FREELIST_QUERY_ELEMENT_COUNT:
assert( query_input == NULL );
*(lfds611_atom_t *) query_output = fs->element_count;
break;
case LFDS611_FREELIST_QUERY_VALIDATE:
// TRD : query_input can be NULL
lfds611_freelist_internal_validate( fs, (struct lfds611_validation_info *) query_input, (enum lfds611_data_structure_validity *) query_output );
break;
}
return;
}
/****************************************************************************/
void lfds611_freelist_internal_validate( struct lfds611_freelist_state *fs, struct lfds611_validation_info *vi, enum lfds611_data_structure_validity *lfds611_freelist_validity )
{
struct lfds611_freelist_element
*fe,
*fe_slow,
*fe_fast;
lfds611_atom_t
element_count = 0;
assert( fs != NULL );
// TRD : vi can be NULL
assert( lfds611_freelist_validity != NULL );
*lfds611_freelist_validity = LFDS611_VALIDITY_VALID;
fe_slow = fe_fast = (struct lfds611_freelist_element *) fs->top[LFDS611_FREELIST_POINTER];
/* TRD : first, check for a loop
we have two pointers
both of which start at the top of the lfds611_freelist
we enter a loop
and on each iteration
we advance one pointer by one element
and the other by two
we exit the loop when both pointers are NULL
(have reached the end of the lfds611_freelist)
or
if we fast pointer 'sees' the slow pointer
which means we have a loop
*/
if( fe_slow != NULL )
do {
fe_slow = fe_slow->next[LFDS611_FREELIST_POINTER];
if( fe_fast != NULL )
fe_fast = fe_fast->next[LFDS611_FREELIST_POINTER];
if( fe_fast != NULL )
fe_fast = fe_fast->next[LFDS611_FREELIST_POINTER];
} while( fe_slow != NULL and fe_fast != fe_slow );
if( fe_fast != NULL and fe_slow != NULL and fe_fast == fe_slow )
*lfds611_freelist_validity = LFDS611_VALIDITY_INVALID_LOOP;
/* TRD : now check for expected number of elements
vi can be NULL, in which case we do not check
we know we don't have a loop from our earlier check
*/
if( *lfds611_freelist_validity == LFDS611_VALIDITY_VALID and vi != NULL ) {
fe = (struct lfds611_freelist_element *) fs->top[LFDS611_FREELIST_POINTER];
while( fe != NULL ) {
element_count++;
fe = (struct lfds611_freelist_element *) fe->next[LFDS611_FREELIST_POINTER];
}
if( element_count < vi->min_elements )
*lfds611_freelist_validity = LFDS611_VALIDITY_INVALID_MISSING_ELEMENTS;
if( element_count > vi->max_elements )
*lfds611_freelist_validity = LFDS611_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;
}
return;
}
#include "lfds611_liblfds_internal.h"
/****************************************************************************/
void lfds611_liblfds_abstraction_test_helper_increment_non_atomic( lfds611_atom_t *shared_counter )
{
/* TRD : lfds611_atom_t must be volatile or the compiler
optimizes it away into a single store
*/
volatile lfds611_atom_t
count = 0;
assert( shared_counter != NULL );
while( count++ < 10000000 )
(*(lfds611_atom_t *) shared_counter)++;
return;
}
/****************************************************************************/
void lfds611_liblfds_abstraction_test_helper_increment_atomic( volatile lfds611_atom_t *shared_counter )
{
lfds611_atom_t
count = 0;
assert( shared_counter != NULL );
while( count++ < 10000000 )
lfds611_abstraction_increment( shared_counter );
return;
}
/****************************************************************************/
void lfds611_liblfds_abstraction_test_helper_cas( volatile lfds611_atom_t *shared_counter, lfds611_atom_t *local_counter )
{
lfds611_atom_t
loop = 0,
original_destination;
LFDS611_ALIGN(LFDS611_ALIGN_SINGLE_POINTER) lfds611_atom_t
exchange,
compare;
assert( shared_counter != NULL );
assert( local_counter != NULL );
while( loop++ < 1000000 ) {
do {
compare = *shared_counter;
exchange = compare + 1;
original_destination = lfds611_abstraction_cas( shared_counter, exchange, compare );
} while( original_destination != compare );
(*local_counter)++;
}
return;
}
/****************************************************************************/
void lfds611_liblfds_abstraction_test_helper_dcas( volatile lfds611_atom_t *shared_counter, lfds611_atom_t *local_counter )
{
lfds611_atom_t
loop = 0;
LFDS611_ALIGN(LFDS611_ALIGN_DOUBLE_POINTER) lfds611_atom_t
exchange[2],
compare[2];
assert( shared_counter != NULL );
assert( local_counter != NULL );
while( loop++ < 1000000 ) {
compare[0] = *shared_counter;
compare[1] = *(shared_counter+1);
do {
exchange[0] = compare[0] + 1;
exchange[1] = compare[1];
} while( 0 == lfds611_abstraction_dcas(shared_counter, exchange, compare) );
(*local_counter)++;
}
return;
}
#include "lfds611_liblfds_internal.h"
/****************************************************************************/
void lfds611_liblfds_aligned_free( void *memory )
{
assert( memory != NULL );
// TRD : the "void *" stored above memory points to the root of the allocation
lfds611_abstraction_free( *( (void **) memory - 1 ) );
return;
}
#include "lfds611_liblfds_internal.h"
/****************************************************************************/
void *lfds611_liblfds_aligned_malloc( size_t size, size_t align_in_bytes )
{
void
*original_memory,
*memory;
size_t
offset;
// TRD : size can be any value in its range
// TRD : align_in_bytes can be any value in its range
original_memory = memory = lfds611_abstraction_malloc( size + sizeof(void *) + align_in_bytes );
if( memory != NULL ) {
memory = (void **) memory + 1;
offset = align_in_bytes - (size_t) memory % align_in_bytes;
memory = (unsigned char *) memory + offset;
*( (void **) memory - 1 ) = original_memory;
}
return( memory );
}
/***** the library wide include file *****/
#include "liblfds611_internal.h"
This is not a data structure but rather functions internal to the library.
#include "lfds611_queue_internal.h"
/****************************************************************************/
void lfds611_queue_delete( struct lfds611_queue_state *qs, void (*user_data_delete_function)(void *user_data, void *user_state), void *user_state )
{
void
*user_data;
assert( qs != NULL );
// TRD : user_data_delete_function can be NULL
// TRD : user_state can be NULL
// TRD : leading load barrier not required as it will be performed by the dequeue
while( lfds611_queue_dequeue(qs, &user_data) )
if( user_data_delete_function != NULL )
user_data_delete_function( user_data, user_state );
/* TRD : fully dequeuing will leave us
with a single dummy element
which both qs->enqueue and qs->dequeue point at
we push this back onto the lfds611_freelist
before we delete the lfds611_freelist
*/
lfds611_freelist_push( qs->fs, qs->enqueue[LFDS611_QUEUE_POINTER]->fe );
lfds611_freelist_delete( qs->fs, lfds611_queue_internal_freelist_delete_function, NULL );
lfds611_liblfds_aligned_free( qs );
return;
}
/****************************************************************************/
//#pragma warning( disable : 4100 )
void lfds611_queue_internal_freelist_delete_function( void *user_data, void *user_state )
{
assert( user_data != NULL );
assert( user_state == NULL );
lfds611_liblfds_aligned_free( user_data );
return;
}
//#pragma warning( default : 4100 )
/***** the library wide include file *****/
#include "liblfds611_internal.h"
/***** pragmas *****/
/***** defines *****/
#define LFDS611_QUEUE_STATE_UNKNOWN -1
#define LFDS611_QUEUE_STATE_EMPTY 0
#define LFDS611_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE 1
#define LFDS611_QUEUE_STATE_ATTEMPT_DELFDS611_QUEUE 2
#define LFDS611_QUEUE_POINTER 0
#define LFDS611_QUEUE_COUNTER 1
#define LFDS611_QUEUE_PAC_SIZE 2
/***** structures *****/
#pragma pack( push, LFDS611_ALIGN_DOUBLE_POINTER )
struct lfds611_queue_state {
struct lfds611_queue_element
*volatile enqueue[LFDS611_QUEUE_PAC_SIZE],
*volatile dequeue[LFDS611_QUEUE_PAC_SIZE];
lfds611_atom_t
aba_counter;
struct lfds611_freelist_state
*fs;
};
struct lfds611_queue_element {
// TRD : next in a lfds611_queue requires volatile as it is target of CAS
struct lfds611_queue_element
*volatile next[LFDS611_QUEUE_PAC_SIZE];
struct lfds611_freelist_element
*fe;
void
*user_data;
};
#pragma pack( pop )
/***** externs *****/
/***** private prototypes *****/
int lfds611_queue_internal_freelist_init_function( void **user_data, void *user_state );
void lfds611_queue_internal_freelist_delete_function( void *user_data, void *user_state );
void lfds611_queue_internal_new_element_from_freelist( struct lfds611_queue_state *qs, struct lfds611_queue_element *qe[LFDS611_QUEUE_PAC_SIZE], void *user_data );
void lfds611_queue_internal_guaranteed_new_element_from_freelist( struct lfds611_queue_state *qs, struct lfds611_queue_element * qe[LFDS611_QUEUE_PAC_SIZE], void *user_data );
void lfds611_queue_internal_init_element( struct lfds611_queue_state *qs, struct lfds611_queue_element *qe[LFDS611_QUEUE_PAC_SIZE], struct lfds611_freelist_element *fe, void *user_data );
void lfds611_queue_internal_queue( struct lfds611_queue_state *qs, struct lfds611_queue_element *qe[LFDS611_QUEUE_PAC_SIZE] );
void lfds611_queue_internal_validate( struct lfds611_queue_state *qs, struct lfds611_validation_info *vi, enum lfds611_data_structure_validity *lfds611_queue_validity,
enum lfds611_data_structure_validity *lfds611_freelist_validity );
#include "lfds611_ringbuffer_internal.h"
/****************************************************************************/
void lfds611_ringbuffer_delete( struct lfds611_ringbuffer_state *rs, void (*user_data_delete_function)(void *user_data, void *user_state), void *user_state )
{
assert( rs != NULL );
// TRD : user_data_delete_function can be NULL
// TRD : user_state can be NULL
lfds611_queue_delete( rs->qs, NULL, NULL );
lfds611_freelist_delete( rs->fs, user_data_delete_function, user_state );
lfds611_liblfds_aligned_free( rs );
return;
}
/***** the library wide include file *****/
#include "liblfds611_internal.h"
/***** defines *****/
/***** structures *****/
#pragma pack( push, LFDS611_ALIGN_DOUBLE_POINTER )
struct lfds611_ringbuffer_state {
struct lfds611_queue_state
*qs;
struct lfds611_freelist_state
*fs;
};
#pragma pack( pop )
/***** externs *****/
/***** private prototypes *****/
void lfds611_ringbuffer_internal_validate( struct lfds611_ringbuffer_state *rs, struct lfds611_validation_info *vi, enum lfds611_data_structure_validity *lfds611_queue_validity,
enum lfds611_data_structure_validity *lfds611_freelist_validity );
/***** the library wide include file *****/
#include "liblfds611_internal.h"
/***** defines *****/
#define LFDS611_SLIST_USER_DATA 0
#define LFDS611_SLIST_FLAGS 1
#define LFDS611_SLIST_NO_FLAGS 0x0
#define LFDS611_SLIST_FLAG_DELETED 0x1
/***** structures *****/
#pragma pack( push, LFDS611_ALIGN_SINGLE_POINTER )
struct lfds611_slist_state {
struct lfds611_slist_element
*volatile head;
void
(*user_data_delete_function)( void *user_data, void *user_state ),
*user_state;
};
#pragma pack( pop )
#pragma pack( push, LFDS611_ALIGN_DOUBLE_POINTER )
/* TRD : this pragma pack doesn't seem to work under Windows
if the structure members are the correct way round
(next first), then user_data_and_flags ends up on
a single pointer boundary and DCAS crashes
accordingly, I've moved user_data_and_flags first
*/
struct lfds611_slist_element {
void
*volatile user_data_and_flags[2];
// TRD : requires volatile as is target of CAS
struct lfds611_slist_element
*volatile next;
};
#pragma pack( pop )
/***** private prototypes *****/
void lfds611_slist_internal_init_slist( struct lfds611_slist_state *ss, void (*user_data_delete_function)(void *user_data, void *user_state), void *user_state );
void lfds611_slist_internal_link_element_to_head( struct lfds611_slist_state *lfds611_slist_state, struct lfds611_slist_element *volatile se );
void lfds611_slist_internal_link_element_after_element( struct lfds611_slist_element *volatile lfds611_slist_in_list_element, struct lfds611_slist_element *volatile se );
void lfds611_slist_internal_move_to_first_undeleted_element( struct lfds611_slist_element **se );
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment