search tester for ufficial avr scheduler

if you have time to try a porting Ufficial Scheduler.
if work write +1 on Pull Request.

[edit] With this scheduler can run Arduino Due sketch in Arduino uno, mega, Leonardo or others boards With have Avr mcu[/edit]

All 3 example tested on UNO
Result ok
+1

Testato:
I think that it is important try to merge the vbextreme pull request in the official scheduler, and work togheter on the owfficial scheduler.
It only the beginning, but if anyone work on a personal scheduler version we will never have a good official scheduler.

The actual official scheduler is an android porting and work only on DUE.
If all will put a +1 on the vb PR we extend it on all board, and this is important, and after we can start to change all that we want.

porting scheduler for Avr by vbextreme · Pull Request #1 · arduino-libraries/Scheduler · GitHub

This comment seems to belong on this topic?

Cheers!

BW: I recommend that you present this on the Arduino Developers Mailing-list instead. You will get better response. Fishing for +1 on PR is not that efficient.

vbextreme:
I challenge you to find a bug in my version.

Easy! Please run test with thread that uses malloc or String. Does this work when the thread stack is allocated in the heap? Please see avr-libc: Memory Areas and Using malloc().

Cheers!

BW: Test case with malloc/free in thread, Please change start() to startLoop() for your API.

@kowalski, no i can't change a name because the official scheduler use startLoop() for infinite task and start() for "One shot task".
Or i don't understand?

tomorrow try malloc

on setjmp() i founded:

However, there is a major drawback to using these functions: your program, when restored to its previously saved state, will lose its references to any dynamically allocated memory between the longjmp() and the setjmp(). This means you will waste memory for every malloc() or calloc() you have implemented between your longjmp() and setjmp(), and your program will be horribly inefficient. It is highly recommended that you avoid using functions such as longjmp() and setjmp() because they, like the goto statement, are quite often an indication of poor programming practice

Cheers!

The name of your libraries create problem to the Arduino IDE, because you are used the same name of the Official Scheduler, please change it.
This is the error that the people receive if he have already installed the official scheduler

Multiple libraries were found for "Scheduler.h"

I will write to the arduino developer list, but on the PR already is there a positive answer from one of the Team

Cheers!

kowalski:
BW: Test case with malloc/free in thread, Please change start() to startLoop() for your API.

TESTED

your code works perfectly on the vbextreme Pull Request

SchedulerDemo: started
0:setup:alloc:buf=0x1F4
0:setup2
0:setup3
1:loop::i=0
2:loop3:alloc:buf=0x1F4
7:loop2::led off
502:loop:alloc:buf=0x236
1002:loop:free:buf=0x236
1003:loop::i=1
1009:loop2::led on
1504:loop:alloc:buf=0x236
2004:loop:free:buf=0x236
2004:loop::i=2
2010:loop2::led off
2505:loop:alloc:buf=0x236
3006:loop:free:buf=0x236
3006:loop::i=3
3010:loop2::led on
3507:loop:alloc:buf=0x236
4007:loop:free:buf=0x236
4007:loop::i=4
4011:loop2::led off
4508:loop:alloc:buf=0x236
5009:loop:free:buf=0x236
5009:loop::i=5
5011:loop2::led on
5510:loop:alloc:buf=0x236
6010:loop:free:buf=0x236

Cheers!

Yes that is the output generated when running my version! Allocating threads on the heap will give higher buffer addresses (if it works).

SchedulerDemo: started
0:setup:alloc:buf=0x1F4
0:setup2
0:setup3
0:loop::i=0
2:loop3:alloc:buf=0x1F4
7:loop2::led off
502:loop:alloc:buf=0x236
1002:loop:free:buf=0x236
1003:loop::i=1
1009:loop2::led on
1504:loop:alloc:buf=0x236
1779:loop3:nr=42331,buf=free
1780:loop3:free:buf=0x1F4
2003:loop:free:buf=0x236
2004:loop::i=2
2010:loop2::led off
2280:loop3:alloc:buf=0x1F4
2504:loop:alloc:buf=0x236
3005:loop:free:buf=0x236
3006:loop::i=3
3010:loop2::led on
3506:loop:alloc:buf=0x236
4006:loop:free:buf=0x236
4007:loop::i=4

Cheers!

Testato:
However, there is a major drawback to using these functions: your program, when restored to its previously saved state, will lose its references to any dynamically allocated memory between the longjmp() and the setjmp(). This means you will waste memory for every malloc() or calloc() you have implemented between your longjmp() and setjmp(), and your program will be horribly inefficient. It is highly recommended that you avoid using functions such as longjmp() and setjmp() because they, like the goto statement, are quite often an indication of poor programming practice

This quote might need explaining. It is true when jumping though the call stack. The way setjmp/longjmp are used in the Simple Scheduler in yield() there is no jump in the thread call stack. The jump is to another threads call stack. Nothing is dropped. That is the idea behind a context switch.

Cheers!

The issue I am pointing to is that the thread structure and stack are allocated on the heap.

The AVR heap implementation checks that the stack pointer is higher than the heap end on malloc() (when the heap is expanded, brk). Please see the image below from the AVR documentation.

Allocating a thread stack on the heap will make malloc() fail accordingly when the heap needs to expand.

kowalski:
Yes that is the output generated when running my version! Allocating threads on the heap will give higher buffer addresses (if it works).

Cheers!

No, this is the Output generated by vbextreme Scheduler.
Try yourself if you do not believe me.

Cheers!

Ok - that is the same output as when running my version.

Please try the updated test case. It will force allocation from the thread (loop3). The previous version of the demo sketch did malloc/free of a memory block that could be reused by the thread. The test case needs to force the heap to grow towards the stack. The heap free memory block list should be empty or at least not contain a block that could be used.

BW: Why not run the benchmark as well?

Cheers!

@kowalski
We must first try to understand the meaning of porting.
From what I could decipher it means I get a code and run it on a different system.
This means respecting the rules, the first key is not to change what you do not need to edit.
To run the official scheduler on Avr must rewrite the context switch without changing the logic of the program.
I did exactly that.

After this due premise perhaps need to clarify something.
How is the memory in my scheduler?
the design:

As you can see the main task loop () can use all of the stack because it is only he who reside in that area of memory, nor its context switch is close enough to be corrupt.
The task 1 has two distinct areas of memory residing in the heap, the first contains the context and second the stack, the stack size of task 1 can be user-defined or assumes a default value depending on the resources available.
You can always see in the chart where it could go to position a possible call to malloc, in this case you have to trust your libc to play a proper job on the heap.
With this code you can test what I just said.

#include <Scheduler.h>

void loop1()
{
    static char* s = NULL;
    if ( NULL == s )
      s = (char*) malloc(125);

    if ( Serial.available() )
    {
        *s = Serial.read();
        *(s+1) = '\0';
    }
    else
    {
        *s = '\0';
    }
    
    Serial.println("begin1");
    delay(1500);
    Serial.println("loop1");

    if ( '\0' != *s ) Serial.println(s);
    
}

void setup() 
{
    Serial.begin(9600);
    Serial.println("Start");
    delay(3000);
    Scheduler.startLoop(loop1);
}

void loop() 
{
    static char* longstr = NULL;
    if ( NULL == longstr )
      longstr = (char*)malloc(512);

    int i;
    for( i = 0; i < 512; ++i)
    {
        longstr[i] = '\0';
    }

    if ( Serial.available() )
    {
        longstr[0] = Serial.read();
    }
    else
    {
        strcpy(longstr, "Supercalifragilistichespiralidoso");
    }
    
    if ( '\0' != *longstr ) Serial.println(longstr);
    
    Serial.println("begin");
    delay(1500);
    Serial.println("loop");
}

Conclusion:
I'm glad you're trying stability of my code, I suggest you download it and post it in this thread code that can cause bugs.
You must also try to see this code under another point of view:
First forget for a moment to use malloc, I also hate. He thinks he's a student, think of wanting to write a perfect scheduler that performs a specific task, you're not thinking that the proposed code is a perfect base to optimize? a scheduler for generic will have ready to be edited for your needs, it sounds good to me.

And sorry for my English.

Benchmark! no Please!sure you can beat those living near the factory of Ferrari and Lamborghini?
But above all is the purpose of the scheduler be so fast?

and finally
there is a lot of work, to discuss, to learn from each other, but if we really put our must stop creating yet another useless library, we must try to grow Arduino, not our egos.

have a good life

kowalski:
Ok - that is the same output as when running my version.

Please try the updated test case. It will force allocation from the thread (loop3).
Cheers!

I used my time to test your scheduler, now if you need other test on vb scheduler, please do it yourself, and post here the result.

Cheers!

kowalski:
and finally
there is a lot of work, to discuss, to learn from each other, but if we really put our must stop creating yet another useless library, we must try to grow Arduino, not our egos.

YES
this is the most important point of view,

@kowalski not write another personal scheduler, but try to improve the original one, try to change the vbextreme PR if you want, put your name in it, but work together for a goal is the most important thing, and the goal is expand the Official scheduler to all arduino board, and improve it if possible.

Please can you confirm that it is possible to use malloc/free from any thread in this port of the Scheduler. Add at least a test sketch and show that. I have provided information about this issue (see link above) and reference to the AVR clib implementation of malloc/free and how stack-heap boundaries are checked.

Please verify that a preemptive version could be used with the rest of the Arduino core. For instance (again) malloc/free are not reentrant. Using a preemptive version with multi-tasking usage of Serial will require semaphores.

There are other obvious limitations with the current Scheduler API. How does the caller detect that a thread is allocated? If malloc of the thread fails how does the application get to know this?

Last but not least try to be a little professional.

Cheers!

Please verify this test sketch (as described above). Memory allocation will fail even though there is memory available.

#include <Scheduler.h>

void setup()
{
  Serial.begin(9600);
  Scheduler.startLoop(loop2);
}

void loop()
{
  yield();
}

void loop2()
{
  void* buf = malloc(128);
  Serial.print(F("buf=0x"));
  Serial.println((int) buf, HEX);
  Serial.flush();
  if (buf == NULL) {
    Serial.println(F("malloc failed"));
    Serial.flush();
    yield();
    return;
  }
  Serial.println(F("malloc succeeded"));
  Serial.flush();
  yield();
  free(buf);
  buf = NULL;
}

Tested on Arduino Mega and Pro-Mini. It fails due to the thread stack is allocated on the heap. The AVR memory manager (heap) does not allow the stack pointer to be within the heap area.

I checked the malloc and indeed there is a problem .
I solved but not final.
I solved a problem with interrupts .
You also raised an issue on the minimum size of the stack , I have tested up to 100byte without errors , you can show the code?
Surely it will take a minimum size but will also be added to ARM?

I know the problems of a preemptive scheduler , the scheduler Arduino is very far away to be really such.
With my code I just wanted to show that it is possible and perhaps with your help we can get there.