printing the stack of a task in FreeRTOS - freertos

I am working on a STM32F4-discovery board, i installed FreeRTOS on the board and was able to run two tasks created by main function.
Now i want task 1 to access the local variables of task 2 with any passing of variable by reference or by value.
I thought it would be good to print the stack content of task 2 and then locate the local variables and use that in task1
Can somebody guide me with this?
I tried to print the address of each variable and tried to use in task1, but my program did not compile and returned -1.

It is not clear to me what you are trying to achieve, or what you mean by the program returning -1 because it didn't compile, but it would not be normal for one task to access a stack variable of another task.
Each task has its own stack, and the stack is private to the task. There are lots of ways tasks can communicate with each other though, without the need to access each other's stack. The simplest way is just to make the variable global, although global variables are rarely a good thing. Other than that you could send the value from one task to another on a queue (http://www.freertos.org/Inter-Task-Communication.html), or even using a task notification as a mailbox (http://www.freertos.org/RTOS_Task_Notification_As_Mailbox.html).

First, a cautionary note: what you're trying to do -- access local variables of one task from another -- can be error-prone. Particularly if the local is declared in Task A and goes out of scope before Task B accesses it. Since stack memory can be reused for different variables in different functions, Task B might be accessing some other variable.
But I've actually used this pattern in practice -- specifically, to allow one task to stack-allocate a buffer for communication serviced by another task.
So I'll just assume that you know what you're doing. :-)
It's difficult to compute the address of a local variable ahead of time. If you derive it today, it's likely to change if you change the code or compiler version. What you probably want to do is to capture its address at runtime and somehow make it available to the other task. This can be be tricky, however: it's possible for the other task to try to use the local before your task starts up, and nothing prevents other tasks from getting to it.
A slightly cleaner approach would be to provide the address to the other task through a queue shard by the two tasks.
QueueHandle_t shared_queue;
void common_startup() {
// This code might go in main, or wherever you initialize things.
shared_queue = xQueueCreate(1, sizeof(unsigned *));
}
void task_a() {
// This task wants to share the address of 'local' with task_b.
unsigned local;
// Stuff the address of our local in the queue. We use a
// non-blocking send here because the queue will be empty (nobody
// else puts things in it). In real code you'd probably do some
// error checking!
unsigned * ptr = &local;
xQueueSend(shared_queue, &ptr, 0);
while (1) {
do_stuff();
}
}
void task_b() {
// This task wants to use task_a's 'local'.
// Real code would do error checking!
unsigned * ptr;
xQueueReceive(shared_queue, &ptr, portMAX_DELAY);
while (1) {
// Just increment the shared variable
(*ptr)++;
}
}

Related

FreeRTOS - creating a task in place of another task?

I am using heap_1 memory allocation. There is an initialization task Task_ini, from which 2 tasks Task_1 and Task_2 are launched. Then I delete Task_ini. At some point in time from Task_1 I need to create a new task Task_3. How can I create Task_3 in the FreeRTOS heap in place of Task_ini which has already been deleted by that time, knowing only its TaskHandle_t?
int main(void){
xTaskCreate(Task_ini, "Task_ini", configMINIMAL_STACK_SIZE, NULL, 1, &htask_ini);
vTaskStartScheduler();
for(;;);
}
void Task_ini(void *pParams){
xTaskCreate(Task_function, "Task_1", configMINIMAL_STACK_SIZE, &param1, 1, &htask1);
xTaskCreate(Task_function, "Task_2", configMINIMAL_STACK_SIZE, &param2, 1, &htask2);
vTaskDelete(NULL);
}
void Task_function(void *pParams){
for(;;){
//task code
//...
//end task code
if(create == true){
create = false;
//Here I need to create a task at the address where the "Task_ini" task was.
//My code creates a task in a new heap section, and if there is no space it will cause a memory allocation error.
xTaskCreate(Task_function, "Task_3", configMINIMAL_STACK_SIZE, &param3, 1, &htask3);
}
}
}
The main idea of heap_1 is that you can't free memory. It is simply not capable of doing so. If you want to delete tasks, you need to use other heap_n methods. Even in that case, you should let the kernel to do its job: It's kernels job to manage memory for FreeRTOS objects, not yours.
Actually, deleting tasks isn't considered as a good practice in general. Unless you are really low on heap space, you can simply suspend the task. In this way, you can wake it up again without any cost in case its services are required again.
It's true that an init task will become useless after the system initialization. But there is a well known solution for your init task problem: It can evolve into another task after it completes the initialization sequence. For example, Task_ini can create only Task_2, and instead of creating a Task_1, it can do the Task_1's job itself.
Update:
It's kernels job to manage memory for FreeRTOS objects, not yours.
Actually, FreeRTOS allows you to manage the memory manually, if you prefer to do so. There are static versions of object creation functions, like xTaskCreateStatic(). When using these static versions, you pass two statically allocated buffers to the function for the task stack and the task control block (TCB). Then you will literally be able to place one task onto another (provided that it's deleted). To be able to use these functions, configSUPPORT_STATIC_ALLOCATION must be defined as 1.
But I suggest you to avoid manual memory management unless you have a specific reason to do so.

How to pass native void pointers to a Dart Isolate - without copying?

I am working on exposing an audio library (C library) for Dart. To trigger the audio engine, it requires a few initializations steps (non blocking for UI), then audio processing is triggered with a perform function, which is blocking (audio processing is a heavy task). That is why I came to read about Dart isolates.
My first thought was that I only needed to call the performance method in the isolate, but it doesn't seem possible, since the perform function takes the engine state as first argument - this engine state is an opaque pointer ( Pointer in dart:ffi ). When trying to pass engine state to a new isolate with compute function, Dart VM returns an error - it cannot pass C pointers to an isolate.
I could not find a way to pass this data to the isolate, I assume this is due to the separate memory of main isolate and the one I'm creating.
So, I should probably manage the entire engine state in the isolate which means :
Create the engine state
Initialize it with some options (strings)
trigger the perform function
control audio at runtime
I couldn't find any example on how to perform this actions in the isolate, but triggered from main thread/isolate. Neither on how to manage isolate memory (keep the engine state, and use it). Of course I could do
Here is a non-isolated example of what I want to do :
Pointer<Void> engineState = createEngineState();
initEngine(engineState, parametersString);
startEngine(engineState);
perform(engineState);
And at runtime, triggered by UI actions (like slider value changed, or button clicked) :
setEngineControl(engineState, valueToSet);
double controleValue = getEngineControl(engineState);
The engine state could be encapsulated in a class, I don't think it really matters here.
Whether it is a class or an opaque datatype, I can't find how to manage and keep this state, and perform triggers from main thread (processed in isolate). Any idea ?
In advance, thanks.
PS: I notice, while writing, that my question/explaination may not be precise, I have to say I'm a bit lost here, since I never used Dart Isolates. Please tell me if some information is missing.
EDIT April 24th :
It seems to be working with creating and managing object state inside the Isolate. But the main problem isn't solved. Because the perform method is actually blocking while it is not completed, there is no way to still receive messages in the isolate.
An option I thought first was to use the performBlock method, which only performs a block of audio samples. Like this :
while(performBlock(engineState)) {
// listen messages, and do something
}
But this doesn't seem to work, process is still blocked until audio performance finishes. Even if this loop is called in an async method in the isolate, it blocks, and no message are read.
I now think about the possibility to pass the Pointer<Void> managed in main isolate to another, that would then be the worker (for perform method only), and then be able to trigger some control methods from main isolate.
The isolate Dart package provides a registry sub library to manage some shared memory. But it is still impossible to pass void pointer between isolates.
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Invalid argument(s): Native objects (from dart:ffi) such as Pointers and Structs cannot be passed between isolates.
Has anyone already met this kind of situation ?
It is possible to get an address which this Pointer points to as a number and construct a new Pointer from this address (see Pointer.address and Pointer.fromAddress()). Since numbers can freely be passed between isolates, this can be used to pass native pointers between them.
In your case that could be done, for example, like this (I used Flutter's compute to make the example a bit simpler but that would apparently work with explicitly using Send/ReceivePorts as well)
// Callback to be used in a backround isolate.
// Returns address of the new engine.
int initEngine(String parameters) {
Pointer<Void> engineState = createEngineState();
initEngine(engineState, parameters);
startEngine(engineState);
return engineState.address;
}
// Callback to be used in a backround isolate.
// Does whichever processing is needed using the given engine.
void processWithEngine(int engineStateAddress) {
final engineState = Pointer<Void>.fromAddress(engineStateAddress);
process(engineState);
}
void main() {
// Initialize the engine in a background isolate.
final address = compute(initEngine, "parameters");
final engineState = Pointer<Void>.fromAddress(address);
// Do some heavy computation in a background isolate using the engine.
compute(processWithEngine, engineState.address);
}
I ended up doing the processing of callbacks inside the audio loop itself.
while(performAudio())
{
tasks.forEach((String key, List<int> value) {
double val = getCallback(key);
value.forEach((int element) {
callbackPort.send([element, val]);
});
});
}
Where the 'val' is the thing you want to send to callback. The list of int 'value' is a list of callback index.
Let's say you audio loop performs with vector size of 512 samples, you will be able to pass your callbacks after every 512 audio samples are processed, which means 48000 / 512 times per second (assuming you sample rate is 48000). This method is not the best one but it works, I still have to see if it works in very intensive processing context though. Here, it has been thought for realtime audio, but it could work the same for audio rendering.
You can see the full code here : https://framagit.org/johannphilippe/csounddart/-/blob/master/lib/csoundnative.dart

Resart a task in FreeRTOS

I have a specific task routine which performs some operations in a specific order, and these operations handle few volatile variables. There is a specific interrupt which updates these volatile variables asynchronously. Hence, the task routine should restart if such an interrupt occurs. Normally FreeRTOS will resume the task, but this will result in wrong derived values, hence the requirement for restarting the routine. I also cannot keep the task routine under critical section, because I should not be missing any interrupts.
Is there a way in FreeRTOS with which I can achieve this? Like a vtaskRestart API. I could have deleted the task and re-created it, but this adds a lot of memory management complications, which I would like to avoid. Currently my only option is to add checks in the routine on a flag to see if a context switch have occured and if yes, restart, else continue.
Googling did not fetch any clue on this. Seems like people never faced such a problem or may be its that this design is poor. In FreeRTOS forum, few who asked for a task-restart didn't seem to have this same problem. stackOverflow didn't have a result on freertos + task + restart. So, this could be the first post with this tag combination ;)
Can someone please tell me if this is directly possible in FreeRTOS?
You can use semaphore for this purpose. If you decide using semaphore, you should do the steps below.
Firstly, you should create a binary semaphore.
The semaphore must be given in the interrupt routine with
xSemaphoreGiveFromISR( Example_xSemaphore, &xHigherPriorityTaskWoken
);
And, you must check taking semaphore in the task.
void vExample_Task( void * pvParameters )
{
for( ;; )
{
if (xSemaphoreTake( Example_xSemaphore, Example_PROCESS_TIME)==pdTRUE)
{
}
}
}
For this purpose you should use a queue and use the queue peek function to yield at your volatile data.
I'm using it as I have a real time timer and this way I make the time available to all my task, without any blocking.
Here it how it goes:
Declare the queue:
xQueueHandle RTC_Time_Queue;
Create the queue of 1 element:
RTC_Time_Queue = xQueueCreate( 1, sizeof(your volatile struct) );
Overwrite the queue everytime your interrupt occurs:
xQueueOverwriteFromISR(RTC_Time_Queue, (void*) &time);
And from other task peek the queue:
xQueuePeek(RTC_GetReadQueue(), (void*) &TheTime, 0);
The 0 at the end of xQueuePeek means you don't want to wait if the queue is empty. The queue peek won't delete the value in the queue so it will be present every time you peek and the code will never stop.
Also you should avoid having variable being accessed from ISR and the RTOS code as you may get unexpected corruption.

One thread showing interest in another thread (consumer / producer)

I would like to have to possibility to make thread (consumer) express interest in when another thread (producer) makes something. But not all the time.
Basically I want to make a one-shot consumer. Ideally the producer through would go merrily about its business until one (or many) consumers signal that they want something, in which case the producer would push some data into a variable and signal that it has done so. The consumer will wait until the variable has become filled.
It must also be so that the one-shot consumer can decide that it has waited too long and abandon the wait (a la pthread_cond_timedwait)
I've been reading many articles and SO questions about different ways to synchronize threads. Currently I'm leaning towards a condition variable approach.
I would like to know if this is a good way to go about it (being a novice at thread programming I probably have quite a few bugs in there), or if it perhaps would be better to (ab)use semaphores for this situation? Or something else entirely? Just an atomic assign to a pointer variable if available? I currently don't see how these would work safely, probably because I'm trying to stay on the safe side, this application is supposed to run for months, without locking up. Can I do without the mutexes in the producer? i.e.: just signal a condition variable?
My current code looks like this:
consumer {
pthread_mutex_lock(m);
pred = true; /* signal interest */
while (pred) {
/* wait a bit and hopefully get an answer before timing out */
pthread_cond_timedwait(c, m, t);
/* it is possible that the producer never produces anything, in which
case the pred will stay true, we must "designal" interest here,
unfortunately the also means that a spurious wake could make us miss
a good answer, no? How to combat this? */
pred = false;
}
/* if we got here that means either an answer is available or we timed out */
//... (do things with answer if not timed out, otherwise assign default answer)
pthread_mutex_unlock(m);
}
/* this thread is always producing, but it doesn't always have listeners */
producer {
pthread_mutex_lock(m);
/* if we have a listener */
if (pred) {
buffer = "work!";
pred = false;
pthread_cond_signal(c);
}
pthread_mutex_unlock(m);
}
NOTE: I'm on a modern linux and can make use of platform-specific functionality if necessary
NOTE2: I used the seemingly global variables m, c, and t. But these would be different for every consumer.
High-level recap
I want a thread to be able to register for an event, wait for it for a specified time and then carry on. Ideally it should be possible for more than one thread to register at the same time and all threads should get the same events (all events that came in the timespan).
What you want is something similar to a std::future in c++ (doc). A consumer requests a task to be performed by a producer using a specific function. That function creates a struct called future (or promise), holding a mutex, a condition variable associated with the task as well as a void pointer for the result, and returns it to the caller. It also put that struct, the task id, and the parameters (if any) in a work queue handled by the producer.
struct future_s {
pthread_mutex_t m;
pthread_cond_t c;
int flag;
void *result;
};
// basic task outline
struct task_s {
struct future_s result;
int taskid;
};
// specific "mytask" task
struct mytask_s {
struct future_s result;
int taskid;
int p1;
float p2;
};
future_s *do_mytask(int p1, float p2){
// allocate task data
struct mytask_s * t = alloc_task(sizeof(struct mytask_s));
t->p1 = p1;
t->p2 = p2;
t->taskid = MYTASK_ID;
task_queue_add(t);
return (struct future_s *)t;
}
Then the producer pull the task out of the queue, process it, and once terminated, put the result in the future and trigger the variable.
The consumer may wait for the future or do something else.
For a cancellable futures, include a flag in the struct to indicate that the task is cancelled. The future is then either:
delivered, the consumer is the owner and must deallocate it
cancelled, the producer remains the owner and disposes of it.
The producer must therefore check that the future has not been cancelled before triggering the condition variable.
For a "shared" future, the flag turns into a number of subscribers. If the number is above zero, the order must be delivered. The consumer owning the result is left to be decided between all consumers (First come first served? Is the result passed along to all consumers?).
Any access to the future struct must be mutexed (which works well with the condition variable).
Regarding the queues, they may be implemented using a linked list or an array (for versions with limited capacity). Since the functions creating the futures may be called concurrently, they have to be protected with a lock, which is usually implemented with a mutex.

trouble reading from __global memory after atom_inc in OpenCL

OpenCL doesn't have a global barrier that will stop all threads, so I'm trying to create a work around with the following code:
void barrier(__global uint* scratch) {
uint nThreads = get_global_size(0);
atom_inc(scratch);
/* this loop never terminates */
while(scratch[0] < nThreads) {
continue;
}
}
The idea is that each thread loops until all of them increment that one piece of memory.
However, the value read from scratch[0] never changes for the threads once it's been read, and it loops forever. I know it's being incremented because it's the correct value when I read it back to the host.
Is the global memory being locally cached? What's going on here?
Found the problem: the order in which work groups are executed is implementation defined. This means that some threads might start only after others have finished.
In the code I gave, the work groups that are started first will loop forever waiting on the the others to hit the 'barrier'. And the work groups that would be started later won't ever start because they're waiting for the first ones to finish.
If the implementation (I'm on a Radeon 5750, using Stream SDK 2.2) executes all work groups concurrently, then it probably wouldn't be an issue. But that's not the case for my setup.

Resources