I am new to FreeRTOS and learning queues at the moment.
I have a Task_3 who send 5 integers to the queue and Task 4 who reads the queue and prints the values read. Problem is that i write 0..4 to the queue but the Task 4 reads on all 5 positions of the queue the value 5. Why not 0..4 ?
The send task 3
void task_3(void *args)
{
uint32_t count = 0;
uint32_t *Value;
Value = &count;
ESP_EARLY_LOGI(TAG, "Task 3 entered..");
if (myQueue_2 == NULL)
{
printf("myQueue_2 could not be created !\n");
}
ESP_EARLY_LOGI("TASK 3", "Data waiting in myQueue_2_1 : %d, Space available : %d", uxQueueMessagesWaiting(myQueue_2), uxQueueSpacesAvailable(myQueue_2));
for (count = 0; count < 5;count++)
{
ESP_EARLY_LOGI("TASK 3", "Value = %d\n", *Value);
xQueueSend(myQueue_2, (void*)&Value, (TickType_t)0);
}
ESP_EARLY_LOGI("TASK 3", "Data waiting in myQueue_2_1 : %d, Space available : %d",
uxQueueMessagesWaiting(myQueue_2), uxQueueSpacesAvailable(myQueue_2));
while (1)
{
vTaskDelay(pdMS_TO_TICKS(500));
}
}
Output of Task 3
I (0) TASK 3: Data waiting in myQueue_2_1 : 0, Space available : 5
I (10) TASK 3: Value = 0
I (10) TASK 3: Value = 1
I (20) TASK 3: Value = 2
I (20) TASK 3: Value = 3
I (20) TASK 3: Value = 4
The read task 4
void task_4(void *args)
{
uint32_t *RxValue = NULL;
while (1)
{
vTaskDelay(pdMS_TO_TICKS(500));
if (uxQueueMessagesWaiting(myQueue_2) > 0)
{
xQueueReceive(myQueue_2, &RxValue, (TickType_t)5);
ESP_EARLY_LOGI("TASK 4", "Received from myQueue_2 = %d\n", *RxValue);
ESP_EARLY_LOGI("TASK 4", "Data waiting in myQueue_2 : %d, Space available : %d",
uxQueueMessagesWaiting(myQueue_2), uxQueueSpacesAvailable(myQueue_2));
}
}
}
Output of task 4
I (30) TASK 3: Data waiting in myQueue_2_1 : 5, Space available : 0
I (1300) TASK 4: Received from myQueue_2 = 5
I (1300) TASK 4: Data waiting in myQueue_2 : 4, Space available : 1
I (1800) TASK 4: Received from myQueue_2 = 5
I (1800) TASK 4: Data waiting in myQueue_2 : 3, Space available : 2
I (2300) TASK 4: Received from myQueue_2 = 5
I (2300) TASK 4: Data waiting in myQueue_2 : 2, Space available : 3
I (2800) TASK 4: Received from myQueue_2 = 5
I (2800) TASK 4: Data waiting in myQueue_2 : 1, Space available : 4
I (3300) TASK 4: Received from myQueue_2 = 5
I (3300) TASK 4: Data waiting in myQueue_2 : 0, Space available : 5
xQueueSend() sends a pointer to a value, not the value itself. It doesn't make a copy of what's being pointed to. If the value that's pointed to changes before the queue is read, the reader will see the new value.
Your code enqueues the same five pointers to the variable count, not five copies of the value of count. By the time task_4 runs, count is equal to 5. So task_4 reads 5 each time.
The correct way to do this is to pass a different pointer each time. You might malloc() the value each time and free it:
for (count = 0; count < 5;count++)
{
uint32_t *value = (uint32_t *)malloc(sizeof(uint32_t));
if (value) {
*value = count;
ESP_EARLY_LOGI("TASK 3", "Value = %d\n", *value);
xQueueSend(myQueue_2, (void*)&Value, (TickType_t)0);
} else {
ESP_EARLY_LOGI("TASK 3", "malloc failed");
}
}
and
while (1)
{
vTaskDelay(pdMS_TO_TICKS(500));
if (uxQueueMessagesWaiting(myQueue_2) > 0)
{
xQueueReceive(myQueue_2, &RxValue, (TickType_t)5);
ESP_EARLY_LOGI("TASK 4", "Received from myQueue_2 = %d\n", *RxValue);
ESP_EARLY_LOGI("TASK 4", "Data waiting in myQueue_2 : %d, Space available : %d",
uxQueueMessagesWaiting(myQueue_2), uxQueueSpacesAvailable(myQueue_2));
free(RxValue);
}
}
The first code fragment allocates storage and enqueues it each time, so each item queued will be different. It's extremely important that the second code fragment free the storage, otherwise the program will leak memory and eventually run out of it.
Since a pointer is large enough to store uint32_t, you could also just cast the counter to be void * and cast it back to uint32_t in the receiving task. If you want to pass anything larger than a pointer you'll need to malloc() it and initialize it or do your own memory management of the objects you want to pass.
Related
I have encountered a pretty strange problem while I was exploring the capabilities of FreeRtos on a ESP32 Wrover module. Currently, I have two tasks in my program. The first task will be used to collect some data, and the second one will be dedicated to print out debug messages to the serial monitor. These task use a queue to exchange data. Since I want to create a few more tasks in the system, the data collector task recieves the queue as part of a parameter struct. Here is my problem: if the data collector task sends only one message to the queue, the program works perfectly. But if I tried to add another message to the queue (as shown in the last piece of code), it forced the CPU to encounter a "LoadProhibited" exception. From what I have read in other topics, this problem is usually caused by accessing a NULL pointer somewhere in the program. But as you can see in the code below, I tried to add some protection by checking the pointers before adding anything to the queue. I also tried to raise the amount of allocated memory of the tasks, and pinning both task to core 1. I still got the same result.
Here is the main:
static QueueHandle_t debugMsgQueue = NULL;
static QueueHandle_t sensorDataBufQueue = NULL;
TaskHandle_t debugTaskHandle = NULL;
TaskHandle_t sensorTaskHandle = NULL;
uint32_t sensorTaskWatchdog;
ESP32Time rtc;
void StreamDebugger(void* pvParameters) {
char debugMsg[_debugDataLength];
while (1) {
if (debugMsgQueue != NULL) {
if (xQueueReceive(debugMsgQueue, (void*)debugMsg, portMAX_DELAY) == pdPASS) {
Serial.print(debugMsg);
}
}
}
}
void setup(){
Serial.begin(115200);
EEPROM.begin(_eepromSize);
/*CREATING GLOBAL DATA BUFFERS*/
debugMsgQueue = xQueueCreate(5, sizeof(char[_debugDataLength]));
sensorDataBufQueue = xQueueCreate(2, sizeof(char*));
if (debugMsgQueue == NULL || sensorDataBufQueue == NULL) {
Serial.print("\r\nCouldn't create dataBuffers. Aborting operation.");
}
BaseType_t xReturned;
/*DEBUG MESSAGE HANDLER TASK*/
xReturned = xTaskCreate(StreamDebugger, "DEBUG", 2048, NULL, 1, &debugTaskHandle);
if (xReturned != pdPASS) {
Serial.print("\r\nCouldn't create DEBUGTASK. Aborting operation.");
}
/*MEASURMENT HANDLER TASK*/
const ReadSensorsParameters sensorTaskDescriptor{ &debugMsgQueue,&sensorDataBufQueue,&sensorTaskWatchdog,rtc};
xReturned = xTaskCreate(ReadSensors, "GETDATA", 4096, (void*)&sensorTaskDescriptor, 1, &sensorTaskHandle);
if (xReturned != pdPASS) {
Serial.print("\r\nCouldn't create GETDATATASK. Aborting operation.");
}
}
void loop(){
}
This is the struct which is used by the sensor data collector task:
typedef struct READSENTASKPARAMETERS {
QueueHandle_t* debugQueue;
QueueHandle_t* dataQueue;
uint32_t* watchdog;
ESP32Time &systemClock;
}ReadSensorsParameters;
This is the data collector task, the one that works:
void ReadSensors(void* pvParameters) {
ReadSensorsParameters* handlers = (ReadSensorsParameters*) pvParameters;
char debugMsg[_debugDataLength];
char dataMsg[_msgDataMaxLength];
strcpy(debugMsg, "READSENSORTASK");
if (debugMsg != NULL && *handlers->debugQueue != NULL) {
xQueueSend(*handlers->debugQueue, (void*)debugMsg, portMAX_DELAY);
}
vTaskDelete(NULL);
}
And here is the modified task, which, for some reason does not work at all:
void ReadSensors(void* pvParameters) {
ReadSensorsParameters* handlers = (ReadSensorsParameters*) pvParameters;
char debugMsg[_debugDataLength];
char dataMsg[_msgDataMaxLength];
strcpy(debugMsg, "READSENSORTASK");
if (debugMsg != NULL && *handlers->debugQueue != NULL) {
xQueueSend(*handlers->debugQueue, (void*)debugMsg, portMAX_DELAY);
}
if (debugMsg != NULL && *handlers->debugQueue != NULL) {
xQueueSend(*handlers->debugQueue, (void*)debugMsg, portMAX_DELAY);
}
vTaskDelete(NULL);
}
And here is the error message I recieve:
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5816
entry 0x400806ac
READSENSORTASKGuru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400d0e5c PS : 0x00060d30 A0 : 0x800889dc A1 : 0x3ffb2f80
A2 : 0x00000000 A3 : 0x3f400fad A4 : 0x3ffc07b8 A5 : 0x3ffb8058
A6 : 0x00000000 A7 : 0x00000000 A8 : 0x800d0e5a A9 : 0x3ffb2f70
A10 : 0x3ffb2f8a A11 : 0x3f400fbc A12 : 0x000000ff A13 : 0x0000ff00
A14 : 0x00ff0000 A15 : 0xff000000 SAR : 0x00000010 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000 LBEG : 0x4000142d LEND : 0x4000143a LCOUNT : 0xfffffff3
Backtrace: 0x400d0e5c:0x3ffb2f80 0x400889d9:0x3ffb2fe0
Does anyone have any idea?
SOLVED! Turned out (after a few sleepless nights) that
static const MyTaskParameters sensorTaskDescriptor{
&debugMsgQueue,
&sensorDataBufQueue,
&sensorTaskWatchdog,
rtc,
&sensorTaskWatchdogSemaphore,
&rtcSemaphore
};
had to be declared as a static variable. What I think had happened was that when READSENSORTASK was created, it immediately started running and was able to place data into the output buffer. After the first context switch the SETUP task was deleted automatically, and therefore this sensorTaskDescriptor variable was also deleted that is why next message placement invoked the LoadProhibited message. What is still weird for me is that I was trying to check all to pointers not to be NULL. I guess the faulty call was somewhere inside the xQueueSend function.
Anyways, I hope this thread helps someone.
Here is TAS code
boolean TAS(*target)
{
boolean rv = *target; //Save the initial value
*target = true; //Set lock
return rv; //Return initial value
}
The following codes means two different tries for the increment operation on a thread safe counter using tas to maintain the counter value consistency.
code 1.
Counter::Increment() {
while (TAS(&lock)) ;
value++;
lock = FREE;
memory_barrier();
}
code 2.
Counter::Increment() {
while (lock == BUSY && TAS(&lock)) ;
value++;
lock = FREE;
memory_barrier();
}
What will be the issue of each codes that cannot handle consistency
Assuming that FREE == false and BUSY == true, here is a flow which breaks mutual exclusion:
Start thread 1:
Increment
TAS
rv = *lock; // FREE
Switch to thread 2:
Increment
TAS
rv = *lock; // FREE
*lock = BUSY;
return rv; // FREE
Load value 0 from memory and push it into the stack
Switch to thread 1:
*lock = BUSY;
return rv; // FREE
Load value 0 from memory and push it into the stack
Push 1 into the stack
Pop two integers from the stack and add them
Store the result (0 + 1) into value
Switch to thread 2:
Push 1 into the stack
Pop two integers from the stack and add them
Store the result (0 + 1) into value
I'm learning about osdev and looking up xv6 code, currently - the console code in particular. Basically, I don't get how the console launches a process.
in console.c there is a function:
void consoleintr(int (*getc)(void)) {
....
while((c = getc()) >= 0) {
switch(c) {
....
default:
....
if(c == '\n' || c == C('D') || input.rightmost == input.r + INPUT_BUF) {
wakeup(&input.r);
}
}
}
So I get it, when the line ends (or the length of the buffer exceeds maximum), it launches wakeup(&input.r)
Then there is this in proc.c:
// Wake up all processes sleeping on chan.
// The ptable lock must be held.
static void wakeup1(void *chan)
{
struct proc *p;
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
if(p->state == SLEEPING && p->chan == chan)
p->state = RUNNABLE;
}
// Wake up all processes sleeping on chan.
void wakeup(void *chan)
{
acquire(&ptable.lock);
wakeup1(chan);
release(&ptable.lock);
}
What is happening here? Why is it comparing address of a console buffer and proc's chan? What is this chan?
It is for processes who waiting (sleeps) for console input. See here:
235 int
236 consoleread(struct inode *ip, char *dst, int n)
...
251 sleep(&input.r, &cons.lock);
The code you have mentioned wakeups this sleeping processes, because data have came from console and is available now for processing.
chan - is a channel. You can wait (sleep) for different things. This channel is for console input data.
Hello Dear participants of stackoverflow,
I'm new to kernel space development and still in the beginning of the road.
I developed a basic char device driver that can read open close etc . But couldn't find a proper source and how to tutorial for Poll/select mechanism sample.
I've written the sample code for poll function below:
static unsigned int dev_poll(struct file * file, poll_table *wait)
{
poll_wait(file,&dev_wait,wait);
if (size_of_message > 0 ){
printk(KERN_INFO "size_of_message > 0 returning POLLIN | POLLRDNORM\n");
return POLLIN | POLLRDNORM;
}
else {
printk(KERN_INFO "dev_poll return 0\n");
return 0;
}
}
It works fine but couldn't undestand a few things.
When I call select from user space program as
struct timeval time = {5,0 } ;
select(fd + 1 , &readfs,NULL,NULL,&time);
the dev_poll function in driver called once and return zero or POLLIN in order to buffer size . And then never called again. In user space , after 5 seconds the program continue if dev_poll returned 0.
What I couldn't understand is here , How the driver code will decide and let user space program if there is something in buffer that is readable withing this 5 seconds , if it's called once and returned immediately.
Is there anyway in kernel module to gather information of timeval parameter that comes from userspace ?
Thank you from now on.
Regards,
Call poll_wait() actually places some wait object into a waitqueue, specified as a second parameter. When wait object is fired (via waitqueue's wake_up or similar function), the poll function is evaluated again.
Kernel driver needn't to bother about timeouts: when time is out, the wait object will be removed from the waitqueue automatically.
Hello dear curious people like me about poll . I came up with a solution.
From another topic on stackowerflow a guy said that the poll_function is called multiple times if kernel need to last situation. So basically I implement that code .
when poll called call wait_poll(wait_queue_head);
when device have buffered data(this is usually in driver write function).
call wake_up macro with wait_queue_head paramater.
So after this step poll function of driver is called again .
So here you can return whatever you want to return. In this case POLLIN | POLLRDNORM..
Here is my sample code for write and poll in the driver.
static unsigned int dev_poll(struct file * file, poll_table *wait)
{
static int dev_poll_called_count = 0 ;
dev_poll_called_count ++;
poll_wait(file,&dev_wait,wait);
read_wait_queue_length++;
printk(KERN_INFO "Inside dev_poll called time is : %d read_wait_queue_length %d\n",dev_poll_called_count,read_wait_queue_length);
printk(KERN_INFO "After poll_wait wake_up called\n");
if (size_of_message > 0 ){
printk(KERN_INFO "size_of_message > 0 returning POLLIN | POLLRDNORM\n");
return POLLIN | POLLRDNORM;
}
else {
printk(KERN_INFO "dev_poll return 0\n");
return 0;
}
}
static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
printk(KERN_INFO "Inside write \n");;
int ret;
ret = copy_from_user(message, buffer, len);
size_of_message = len ;
printk(KERN_INFO "EBBChar: Received %zu characters from the user\n", size_of_message);
if (ret)
return -EFAULT;
message[len] = '\0';
printk(KERN_INFO "gelen string %s", message);
if (read_wait_queue_length)
{
wake_up(&dev_wait);
read_wait_queue_length = 0;
}
return len;
}
I am in need to use /dev/input/event0 to be watched for key events.I have used inotify_add_watch(), but the read() call hangs.But If I cat /dev/input/event0 I can see some events.Please let me know what is wrong.Below is my code snippet
/creating the INOTIFY instance/
fd = inotify_init();
/*checking for error*/
if ( fd < 0 ) {
perror( "inotify_init" );
}
/*adding the /dev/input/event0 to watch list.*/
wd = inotify_add_watch(fd, "/dev/input/event0", IN_ALL_EVENTS);
if (wd < 0){
perror("inotify_add_watch");
exit(-1);
}
for (;;) {
length = read(fd, buffer,EVENT_BUF_LEN);
printf("length = %d",length);
if (length == 0)
perror("read() from inotify fd returned 0!");
if (length < 0)
perror("read");
printf("Read %ld bytes from inotify fd\n", (long) numRead);
You haven't explained why you think you need to use inotify for this.
I'm assuming that you just want to programmatically test whether an event is ready.
You can do something like:
int fd = open("/dev/input/event0", O_RDONLY|O_NONBLOCK);
struct pollfd pfd; // see man 2 poll
pfd.fd = fd;
pfd.events = POLLIN;
if (poll(&pfd, 1, &ts, 1000 /* milliseconds */) > 0) {
// reading from fd now will not block
}
This will wait for up to 1 second (1000 milliseconds) for an event to be ready to read. You can change the timeout to whatever you need. You can also use 0 to test whether there is data available immediately without waiting.
read() is a blocking function and waits for file update, unless specifically mentioned.
If you want it to be non-blocking, simply add a flag.
file_descriptor = inotify_init1(IN_NONBLOCK);
https://linux.die.net/man/2/inotify_init1