I am trying to pass a large amount of data between threads in C (Raspberry with Debian).
I want to create 32 queues. I need to pass messages of 105 bytes each one. I want to pass 105 bytes each 4 ms to anothe thread for about 20 seconds (30 seconds top).
What I found with posix queues is that I cannot modify mq_msgsize parameter. I can modify mq_maxmsg but if I try to modify the other, queue does not work. It just work with 1024 bytes.
I think I have not understood mq_maxmsg and mq_msgsize parameters. I thought that mq_maxmsg is the number of messages I can store in the queue and mq_msgsize the size of each parameter.
In mq_send function I should pass the buffer I have with a value of 105 bytes.
In mq_receive function I should read 105 bytes each time.
Is this right?
If I try this, send/received does not work. Only with 1024.
This is how I am declaring the queues (I have 32 right now, but all of them are created equally):
#define Q_MOTOR_SIZE 1024
struct mq_attr mq_motor_attr;
mq_motor_attr.mq_flags = 0;
mq_motor_attr.mq_maxmsg = 10000;
mq_motor_attr.mq_msgsize = Q_MOTOR_SIZE; #I tried to change this value by 105
mq_motor_attr.mq_curmsgs = 0;
PR_mq_motor[0] = mq_open(MOTOR_0_Q_NAME, O_CREAT| O_RDONLY| O_NONBLOCK, 0644, &mq_motor_attr);
PR_mq_motor[1] = mq_open(MOTOR_1_Q_NAME, O_CREAT| O_RDONLY| O_NONBLOCK, 0644, &mq_motor_attr);
...
PR_mq_motor[31] = mq_open(MOTOR_31_Q_NAME, O_CREAT| O_RDONLY| O_NONBLOCK, 0644, &mq_motor_attr);
Every time I send a bunch of frames (105 bytes), should I send 1024 or it should work with 105 as packet size?
mq_send(PR_mq_motor[motor_counter], PR_queue_buffer, 1024, 0);
vs
mq_send(PR_mq_motor[motor_counter], PR_queue_buffer, 105, 0);
Same happens in the recevie part. If I try to read 105 instead of 1024, it crashes somewhere during the operation.
What should I do here? In case something needs to be modified on the raspi configuration, it is not a problem.
As #Shawn suggested. I implemented a linked list in order to have the 32 queues I wanted in the beggining.
I created some arrays to keep track of all the mutex to control access and the header of each list.
I think push is working fine but I have some kind of issue while popping elements.
As I said, I want to storage buffers of 8 bytes each one so I created the struct with buffers of 10 to be sure.
int16_t LL_M_Push(uint8_t LL_M_motor, uint8_t *LL_M_frame, uint16_t LL_M_size) {
pthread_mutex_lock(&PR_LL_M_lock[LL_M_motor]);
PR_LL_M_node_t *current = PR_LL_M_head[LL_M_motor];
if (current != NULL) {
while (current->next != NULL) {
current = current->next;
}
/* now we can add a new variable */
current->next = malloc(sizeof(PR_LL_M_node_t));
memcpy(current->next->val, LL_M_frame, LL_M_size);
current->next->next = NULL;
} else {
PR_LL_M_head[LL_M_motor] = malloc(sizeof(PR_LL_M_node_t));
memcpy(PR_LL_M_head[LL_M_motor]->val, LL_M_frame, LL_M_size);
PR_LL_M_head[LL_M_motor]->next = NULL;
}
PR_LL_M_counter[LL_M_motor]++;
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_motor]);
return PR_LL_M_counter[LL_M_motor];
}
int16_t LL_M_Pop(uint8_t LL_M_motor, uint8_t *LL_M_element) {
uint8_t *retval;
PR_LL_M_node_t *next_node = NULL;
pthread_mutex_lock(&PR_LL_M_lock[LL_M_motor]);
if ((PR_LL_M_head[LL_M_motor] == NULL) || (PR_LL_M_counter[LL_M_motor] == 0)) {
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_motor]);
return -1;
}
next_node = PR_LL_M_head[LL_M_motor]->next;
retval = PR_LL_M_head[LL_M_motor]->val;
memcpy(LL_M_element, retval, 10);
PR_LL_M_counter[LL_M_motor]--;
free(PR_LL_M_head[LL_M_motor]);
PR_LL_M_head[LL_M_motor] = next_node;
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_motor]);
return PR_LL_M_counter[LL_M_motor];
}
Do you see something wrong here? Do you need something else?
Related
I am doing a project where I want to write some info to the MT25Q (MT25QL512ABB1EW9-0SIT) flash device from Micron Technology. But when I try to write and read from the first few pages (0-13) I get trash data back. I thought there might be a protected area in the flash so I checked the value of the corresponding bits in the status register and the value corresponds to none of the sectors being protected. Plus none of possible ranges for protected sector correspond to this value either.
I am using zephyr-os which supports the flash device. Here is my code:
#include "MT25Q.h"
#include <flash.h>
struct device *dev = device_get_binding("MT25Q");
struct flash_pages_info myflash;
flash_get_page_info_by_idx(dev, 0, &myflash);
char *test_line = malloc(5);
char *buf = malloc(5);
strcpy(test_line, "test");
size_t page_count = flash_get_page_count(dev);
flash_write_protection_set(dev, false);
for(long i = 0; i < total_pages; i++) {
returnval = flash_get_page_info_by_idx(dev, i, &myflash);
flash_write(dev, myflash.start_offset, test_line, 5);
flash_read(dev, myflash.start_offset, buf, 5);
printk("%s\n", buf);
}
flash_write_protection_set(dev, true);
free(buf);
free(test_line);
return 0;
}
For the the first 15 iterations of the loop I read back some garbage string. And afterwards it works as expected. The device is byte-writeable.
Can someone help me understand why this is happening ? I hope I posted all the required info but just in case:
total_pages = 256
myflash.size = 131072
I'm writing a porting of an emulator to SDL. There is a method, called at each frame, that passes a buffer with new audio samples for next frame.
I opened a device with SDL_OpenAudioDevice and at each frame the SDL callback method reproduces samples from audio buffer.
It works but the sound is not perfect, some tic, some metallic noise and so on.
Sound is 16 bit signed.
EDIT: Ok, I found a solution!
With the code of the opening post I was playing samples for next frame at the current frame in real time. It was wrong!
So, I implemented a circular buffer where I put samples for next frame that underlying code passes to me at each (current) frame.
In that buffer there are 2 pointers, one for read point and the other one for write point. SDL calls callback function when on its audio stream there are no more data to play; so when callback function is called I play audio samples from read point on the circular buffer then update the read pointer.
When underlying code gives me audio samples data for next frame I write them in the circular buffer at write point, then update the write pointer.
Read and write pointers are shifted by the amount of samples to be played at each frame.
Code updated, needs some adjustment when samplesPerFrame is not an int but it works ;-)
Circular buffer structure:
typedef struct circularBufferStruct
{
short *buffer;
int cells;
short *readPoint;
short *writePoint;
} circularBuffer;
This method is called at initialization:
int initialize_audio(int stereo)
{
if (stereo)
channel = 2;
else
channel = 1;
// Check if sound is disabled
if (sampleRate != 0)
{
// Initialize SDL Audio
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
{
SDL_Log("SDL fails to initialize audio subsystem!\n%s", SDL_GetError());
return 1;
}
// Number of samples per frame
samplesPerFrame = (double)sampleRate / (double)framesPerSecond * channel;
audioSamplesSize = samplesPerFrame * bytesPerSample; // Bytes
audioBufferSize = audioSamplesSize * 10; // Bytes
// Set and clear circular buffer
audioBuffer.buffer = malloc(audioBufferSize); // Bytes, must be a multiple of audioSamplesSize
memset(audioBuffer.buffer, 0, audioBufferSize);
audioBuffer.cells = (audioBufferSize) / sizeof(short); // Cells, not Bytes!
audioBuffer.readPoint = audioBuffer.buffer;
audioBuffer.writePoint = audioBuffer.readPoint + (short)samplesPerFrame;
}
else
samplesPerFrame = 0;
// First frame
return samplesPerFrame;
}
This is the SDL method callback from want.callback:
void audioCallback(void *userdata, uint8_t *stream, int len)
{
SDL_memset(stream, 0, len);
if (audioSamplesSize == 0)
return;
if (len > audioSamplesSize)
{
len = audioSamplesSize;
}
SDL_MixAudioFormat(stream, (const Uint8 *)audioBuffer.readPoint, AUDIO_S16SYS, len, SDL_MIX_MAXVOLUME);
audioBuffer.readPoint += (short)samplesPerFrame;
if (audioBuffer.readPoint >= audioBuffer.buffer + audioBuffer.cells)
audioBuffer.readPoint = audioBuffer.readPoint - audioBuffer.cells;
}
This method is called at each frame (after first pass we require only the amount of samples):
int update_audio(short *buffer)
{
// Check if sound is disabled
if (sampleRate != 0)
{
memcpy(audioBuffer.writePoint, buffer, audioSamplesSize); // Bytes
audioBuffer.writePoint += (short)samplesPerFrame; // Cells
if (audioBuffer.writePoint >= audioBuffer.buffer + audioBuffer.cells)
audioBuffer.writePoint = audioBuffer.writePoint - audioBuffer.cells;
if (firstTime)
{
// Set required audio specs
want.freq = sampleRate;
want.format = AUDIO_S16SYS;
want.channels = channel;
want.samples = samplesPerFrame / channel; // total samples divided by channel count
want.padding = 0;
want.callback = audioCallback;
want.userdata = NULL;
device = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(0, 0), 0, &want, &have, 0);
SDL_PauseAudioDevice(device, 0);
firstTime = 0;
}
}
else
samplesPerFrame = 0;
// Next frame
return samplesPerFrame;
}
I expect that this question/answer will be useful for others in the future because I didn't find almost nothing on the net for SDL Audio
Ok, I found a solution!
With the code of the opening post I was playing samples for next frame at the current frame in real time. It was wrong!
So, I implemented a circular buffer where I put samples for next frame that underlying code passes to me at each (current) frame. From that buffer I read and write in different position, see opening post
My AF-XDP userspace program is based on this tutorial: https://github.com/xdp-project/xdp-tutorial/tree/master/advanced03-AF_XDP
I am currently trying to parse ~360.000 RTP-packets per second (checking for continuous sequence numbers) but I loose around 25 per second (this means that for 25 packets the statement previous_rtp_sqnz_nmbr + 1 == current_rtp_sqnz_nmbr doesn't hold true).
So I tried to increase the number of allocated packets NUM_FRAMES from 228.000 to 328.000. With default FRAME_SIZE of XSK_UMEM__DEFAULT_FRAME_SIZE = 4096 this results in 1281Mbyte being allocated (no problem because I have 32GB of RAM) but for whatever reason, this function call:
static struct xsk_umem_info *configure_xsk_umem(void *buffer, uint64_t size)
{
printf("Try to allocate %lu\n", size);
struct xsk_umem_info *umem;
int ret;
umem = calloc(1, sizeof(*umem));
if (!umem)
return NULL;
ret = xsk_umem__create(&umem->umem, buffer, size, &umem->fq, &umem->cq,
NULL);
if (ret) {
errno = -ret;
return NULL;
}
umem->buffer = buffer;
return umem;
}
fails with
Try to allocate 1343488000
ERROR: Can't create umem "Cannot allocate memory"
I don't know why? But because I know that my RTP-packets are not larger than 1500bytes, I set FRAME_SIZE 3072 so I am now at around 960Mbyte (which works without an error).
However, I am now loosing half of the received packets (this means that for 180.000 packets the previous sequence number doesn't line up with the current sequence number).
Because of this I ask the question: What is the relationship between FRAME_SIZE and the actual size of a packet? Because obviously it can not be the same.
Edit: I am using 5.4.0-4-amd64 #1 SMP Debian 5.4.19-1 (2020-02-13) x86_64 GNU/Linux and just copied the libbpf-repository from here into my code-base: https://github.com/libbpf/libbpf
So I don't know whether the error mentioned here: https://github.com/xdp-project/xdp-tutorial/issues/76 is still valid?
I am struggling my head with this problem.
If I check my application with top command in Linux, I get that VIRT is always the same (running for a couple of days) while RES is increasing a bit (between 4 bytes and 32 bytes) after an operation. I perform an operation once each 60 minutes.
An operation consists in reading some frames by SPI, adding them to several linked lists and after a while, extracting them in another thread.
I executed Valgrind with the following options:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes -v ./application
Once I close it (My app would run forever if everything goes well) I check leaks and I see nothing but the threads I haven't closed. Only possibly lost bytes in threads. No definitely and no indirectly.
I do not know if this is normal. I have used Valgrind in the past to find some leaks and it always worked well, I am pretty sure it is working well right now too but the RES issue I can't explain.
I have checked the linked list to see if I was leaving some nodes without free but, to me, it seems to be right.
I have 32 linked lists in one array. I have done this to make the push/pop operations easier without having 32 separate lists. I don't know if this could be causing the problem. If this is the case, I will split them:
typedef struct PR_LL_M_node {
uint8_t val[60];
struct PR_LL_M_node *next;
} PR_LL_M_node_t;
pthread_mutex_t PR_LL_M_lock[32];
PR_LL_M_node_t *PR_LL_M_head[32];
uint16_t PR_LL_M_counter[32];
int16_t LL_M_InitLinkedList(uint8_t LL_M_number) {
if (pthread_mutex_init(&PR_LL_M_lock[LL_M_number], NULL) != 0) {
printf("Mutex LL M %d init failed\n", LL_M_number);
return -1;
}
PR_LL_M_ready[LL_M_number] = 0;
PR_LL_M_counter[LL_M_number] = 0;
PR_LL_M_head[LL_M_number] = NULL;
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return PR_LL_M_counter[LL_M_number];
}
int16_t LL_M_Push(uint8_t LL_M_number, uint8_t *LL_M_frame, uint16_t LL_M_size) {
pthread_mutex_lock(&PR_LL_M_lock[LL_M_number]);
PR_LL_M_node_t *current = PR_LL_M_head[LL_M_number];
if (current != NULL) {
while (current->next != NULL) {
current = current->next;
}
/* now we can add a new variable */
current->next = malloc(sizeof(PR_LL_M_node_t));
memset(current->next->val, 0x00, 60);
/* Clean buffer before using it */
memcpy(current->next->val, LL_M_frame, LL_M_size);
current->next->next = NULL;
} else {
PR_LL_M_head[LL_M_number] = malloc(sizeof(PR_LL_M_node_t));
memcpy(PR_LL_M_head[LL_M_number]->val, LL_M_frame, LL_M_size);
PR_LL_M_head[LL_M_number]->next = NULL;
}
PR_LL_M_counter[LL_M_number]++;
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return PR_LL_M_counter[LL_M_number];
}
int16_t LL_M_Pop(uint8_t LL_M_number, uint8_t *LL_M_frame) {
PR_LL_M_node_t *next_node = NULL;
pthread_mutex_lock(&PR_LL_M_lock[LL_M_number]);
if ((PR_LL_M_head[LL_M_number] == NULL)) {
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return -1;
}
if ((PR_LL_M_counter[LL_M_number] == 0)) {
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return -1;
}
next_node = PR_LL_M_head[LL_M_number]->next;
memcpy(LL_M_frame, PR_LL_M_head[LL_M_number]->val, 60);
free(PR_LL_M_head[LL_M_number]);
PR_LL_M_counter[LL_M_number]--;
PR_LL_M_head[LL_M_number] = next_node;
pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
return PR_LL_M_counter[LL_M_number];
}
This way I pass the number of the linked list I want to manage and I operate over it. What do you think? Is RES a real problem? I think it could be related to other parts of the application but I have commented out most of it and it always happens if the push/pop operation is used. If I leave push/pop out, RES maintains its number.
When I extract the values I use a do/while until I get -1 as response of the pop operation.
Your observations do not seem to indicate a problem:
VIRT and RES are expressed in KiB (units of 1024 bytes). Depending on how virtual memory works on your system, the numbers should always be multiples of the page size, which is most likely 4KiB.
RES is the amount of resident memory, in other words the amount of RAM actually mapped for your program at a given time.
If the program goes to sleep for 60 minutes at a time, the system (Linux) may determine that some of its pages are good candidates for discarding or swapping should it need to map memory for other processes. RES will diminish accordingly. Note incidentally that top is one such process that needs memory and thus can disturb your process while observing it, a computing variant of Heisenberg's Principle.
When the process wakes up, whatever memory is accessed by the running thread is mapped back into memory, either from the executable file(s) if it was discarded or from the swap file, or from nowhere if the discarded page was all null bytes or an unused part of the stack. This causes RES to increase again.
There might be other problems in the code, especially in code that you did not post, but if VIRT does not change, you do not seem to have a memory leak.
I'm trying to access a SPI sensor using the SPIDEV driver but my code gets stuck on IOCTL.
I'm running embedded Linux on the SAM9X5EK (mounting AT91SAM9G25). The device is connected to SPI0. I enabled CONFIG_SPI_SPIDEV and CONFIG_SPI_ATMEL in menuconfig and added the proper code to the BSP file:
static struct spi_board_info spidev_board_info[] {
{
.modalias = "spidev",
.max_speed_hz = 1000000,
.bus_num = 0,
.chips_select = 0,
.mode = SPI_MODE_3,
},
...
};
spi_register_board_info(spidev_board_info, ARRAY_SIZE(spidev_board_info));
1MHz is the maximum accepted by the sensor, I tried 500kHz but I get an error during Linux boot (too slow apparently). .bus_num and .chips_select should correct (I also tried all other combinations). SPI_MODE_3 I checked the datasheet for it.
I get no error while booting and devices appear correctly as /dev/spidevX.X. I manage to open the file and obtain a valid file descriptor. I'm now trying to access the device with the following code (inspired by examples I found online).
#define MY_SPIDEV_DELAY_USECS 100
// #define MY_SPIDEV_SPEED_HZ 1000000
#define MY_SPIDEV_BITS_PER_WORD 8
int spidevReadRegister(int fd,
unsigned int num_out_bytes,
unsigned char *out_buffer,
unsigned int num_in_bytes,
unsigned char *in_buffer)
{
struct spi_ioc_transfer mesg[2] = { {0}, };
uint8_t num_tr = 0;
int ret;
// Write data
mesg[0].tx_buf = (unsigned long)out_buffer;
mesg[0].rx_buf = (unsigned long)NULL;
mesg[0].len = num_out_bytes;
// mesg[0].delay_usecs = MY_SPIDEV_DELAY_USECS,
// mesg[0].speed_hz = MY_SPIDEV_SPEED_HZ;
mesg[0].bits_per_word = MY_SPIDEV_BITS_PER_WORD;
mesg[0].cs_change = 0;
num_tr++;
// Read data
mesg[1].tx_buf = (unsigned long)NULL;
mesg[1].rx_buf = (unsigned long)in_buffer;
mesg[1].len = num_in_bytes;
// mesg[1].delay_usecs = MY_SPIDEV_DELAY_USECS,
// mesg[1].speed_hz = MY_SPIDEV_SPEED_HZ;
mesg[1].bits_per_word = MY_SPIDEV_BITS_PER_WORD;
mesg[1].cs_change = 1;
num_tr++;
// Do the actual transmission
if(num_tr > 0)
{
ret = ioctl(fd, SPI_IOC_MESSAGE(num_tr), mesg);
if(ret == -1)
{
printf("Error: %d\n", errno);
return -1;
}
}
return 0;
}
Then I'm using this function:
#define OPTICAL_SENSOR_ADDR "/dev/spidev0.0"
...
int fd;
fd = open(OPTICAL_SENSOR_ADDR, O_RDWR);
if (fd<=0) {
printf("Device not found\n");
exit(1);
}
uint8_t buffer1[1] = {0x3a};
uint8_t buffer2[1] = {0};
spidevReadRegister(fd, 1, buffer1, 1, buffer2);
When I run it, the code get stuck on IOCTL!
I did this way because, in order to read a register on the sensor, I need to send a byte with its address in it and then get the answer back without changing CS (however, when I tried using write() and read() functions, while learning, I got the same result, stuck on them).
I'm aware that specifying .speed_hz causes a ENOPROTOOPT error on Atmel (I checked spidev.c) so I commented that part.
Why does it get stuck? I though it can be as the device is created but it actually doesn't "feel" any hardware. As I wasn't sure if hardware SPI0 corresponded to bus_num 0 or 1, I tried both, but still no success (btw, which one is it?).
UPDATE: I managed to have the SPI working! Half of it.. MOSI is transmitting the right data, but CLK doesn't start... any idea?
When I'm working with SPI I always use an oscyloscope to see the output of the io's. If you have a 4 channel scope ypu can easily debug the issue, and find out if you're axcessing the right io's, using the right speed, etc. I usually compare the signal I get to the datasheet diagram.
I think there are several issues here. First of all SPI is bidirectional. So if yo want to send something over the bus you also get something. Therefor always you have to provide a valid buffer to rx_buf and tx_buf.
Second, all members of the struct spi_ioc_transfer have to be initialized with a valid value. Otherwise they just point to some memory address and the underlying process is accessing arbitrary data, thus leading to unknown behavior.
Third, why do you use a for loop with ioctl? You already tell ioctl you haven an array of spi_ioc_transfer structs. So all defined transaction will be performed with one ioctl call.
Fourth ioctl needs a pointer to your struct array. So ioctl should look like this:
ret = ioctl(fd, SPI_IOC_MESSAGE(num_tr), &mesg);
You see there is room for improvement in your code.
This is how I do it in a c++ library for the raspberry pi. The whole library will soon be on github. I'll update my answer when it is done.
void SPIBus::spiReadWrite(std::vector<std::vector<uint8_t> > &data, uint32_t speed,
uint16_t delay, uint8_t bitsPerWord, uint8_t cs_change)
{
struct spi_ioc_transfer transfer[data.size()];
int i = 0;
for (std::vector<uint8_t> &d : data)
{
//see <linux/spi/spidev.h> for details!
transfer[i].tx_buf = reinterpret_cast<__u64>(d.data());
transfer[i].rx_buf = reinterpret_cast<__u64>(d.data());
transfer[i].len = d.size(); //number of bytes in vector
transfer[i].speed_hz = speed;
transfer[i].delay_usecs = delay;
transfer[i].bits_per_word = bitsPerWord;
transfer[i].cs_change = cs_change;
i++
}
int status = ioctl(this->fileDescriptor, SPI_IOC_MESSAGE(data.size()), &transfer);
if (status < 0)
{
std::string errMessage(strerror(errno));
throw std::runtime_error("Failed to do full duplex read/write operation "
"on SPI Bus " + this->deviceNode + ". Error message: " +
errMessage);
}
}