Skip to main content
Topic: Pico-Os... a silly dangerous little coroutine kernel :o) (Read 7275 times) previous topic - next topic

Pico-Os... a silly dangerous little coroutine kernel :o)

:o)
i allready publish than in the web platform forum, but i thought it can be helpful to more people here...
and i might be working on it in a near future...

so ... it is a dusted off, of an old silly pico-os (smaller than micro) of coroutines from one on my old projects.  this is not fancy or complete like other os or RTOS but it is very small and can be useful...

right now it is written for  the  PIC p33FJ128GP204, but it can be easily adapted to anything !

so 3 files
osp.c --- c source
osp.h --- prototype
main.c --- an example from some dangerous examples code.

i think of that has a "DangerousPrototype"  so feel free to use and abuse :o)

:o)

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #1
Thanks for sharing.

If anyone has a project based on this they'd like to share, please post it. I can include a examples in the SVN, and start a wiki page if needed.
Got a question? Please ask in the forum for the fastest answers.

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #2
I am trying to implement this on an ARM platform, but somehow it gets stuck. Any details on how to port it? Especially with the function pointer and the stack when it is created?

I tested setjmp() and longjmp() to work without any issue on the platform. But modifying the jmp_buff seems the issue here since I don't know how to point to the new stack for each created task.

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #3
[quote author="ekawahyu"]I tested setjmp() and longjmp() to work without any issue on the platform. But modifying the jmp_buff seems the issue here since I don't know how to point to the new stack for each created task.[/quote]

Every architecture has its own specific layout of the jump buffer. You need to look at the setjmp/longjmp source code to see what gets stored where and act accordingly.

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #4
Thanks for the clue Bertho! I manage to make it work by now after looking at the newlib source code!

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #5
[quote author="ekawahyu"]I am trying to implement this on an ARM platform, but somehow it gets stuck. Any details on how to port it? Especially with the function pointer and the stack when it is created?
I tested setjmp() and longjmp() to work without any issue on the platform. But modifying the jmp_buff seems the issue here since I don't know how to point to the new stack for each created task.[/quote]

I never work with ARM ( soon maybe i will ) so you will have to check few stuff ... 
So this is the current Magic Code (or Ugly Hack )  :oP

  tasks.regs[14] = (unsigned int)&tasks.stack[0];
  tasks.regs[15] = (unsigned int)&tasks.stack[0]; 
  tasks.regs[16] = (unsigned int)taskPtr;
  tasks.regs[17] = 0; 


- find how the stack is manage in an ARM on that PIC  the stack grows from small addresses to bigger addresses so the current task stack start at stack[0].
ARM stack might grows from big addresses to small addresses, so might have to adjust where to put the task stack bottom
- you have to consider and adjust if the stack need to be align on 8 bits, 16bits or 32 bits addresses.
- you have to consider and adjust for the Endianness of your ARM, how does it save it values and pointers.
- von Neuman or Harvard Architecture ?  some small pic (Harvard Architecture) has special hardware stack and you cannot easily manipulate the stack and frame pointer...

So
you usually  have to tweak 3 values,  the saved  return value  from a longjump  so here  regs[16]  and regs[17]
the saved stack pointer  and the saved stack frame pointer ,  regs[14]  and regs[15]  (I don't remember witch one is witch of those).
You have to adjust those values in the setjump registers buffer.

so a good start is by tracing  few procedure calls and setjump  longjump and look how stack  and frame pointer are managed.
and turn compiler optimization off (at least for your test)  :oP

beware of your compiler  it can also make weird things when optimization is on !!!

I hope this will help :o)  ( and post your code if you succeed :o) )

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #6
Hmmm... not sure if it was due to the optimization level or not, only declaring local variable as static is the only way to make it work. I cannot reproduce the issue anymore since I cleaned the whole project and rebuilt it.

My project on ARM is a bare metal system with some function stubs for newlib. I am trying to provide the simplest threading-like environment and Pico-OS coroutine is the closest and cleanest implementation I could find so far. I would say that Pico-OS coroutine as a clever hack instead of an ugly hack :)

I will provide the modification of the source code under BSD style license, but I need to fork the project from you if such project exists. That way I can do some attribution to the original creator and pay some respect to the license attached.

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #7
[quote author="ekawahyu"]Hmmm... not sure if it was due to the optimization level or not, only declaring local variable as static is the only way to make it work. I cannot reproduce the issue anymore since I cleaned the whole project and rebuilt it.[/quote]

Did you miss a "volatile" keyword in there? Optimization will kill you if you do not declare your variables correctly.

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #8
[quote author="ekawahyu"]Hmmm... not sure if it was due to the optimization level or not, only declaring local variable as static is the only way to make it work. I cannot reproduce the issue anymore since I cleaned the whole project and rebuilt it.

My project on ARM is a bare metal system with some function stubs for newlib. I am trying to provide the simplest threading-like environment and Pico-OS coroutine is the closest and cleanest implementation I could find so far. I would say that Pico-OS coroutine as a clever hack instead of an ugly hack :)

I will provide the modification of the source code under BSD style license, but I need to fork the project from you if such project exists. That way I can do some attribution to the original creator and pay some respect to the license attached.[/quote]

So did you answer all first questions ? ;oP
On your ARM ,  which one are you using ?
Is your stack growing up or down ? 
is  your cpu 32bits , does it need to be aligned on 32 bits addresses ?
Endianness ?
etc ( see prev post) all thoses info are need to have that running fine !

You can used my sources to do everything you want the concept are pretty old  :o)
I think I wrote my first little thing like that in 1990 :oP
And at that time I was implementing try and catch style macros in C  (using set and longjumg)  and table of function pointers :op
I was reading an article in Byte Magazine if I remember where the author  implement something like that in Turbo Pascal :o)
so i played with the concept and adapted it in C :-)

So since that time i wrote few of those with different target goals. 
Simple coroutine kernel can be very nice to used :o)
Someone remember the first MacFinder  :oP

:-)

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #9
It seems to be fixed after removing an extra (mistakenly initialized) semaphore. I think that was the issue. If you notice in the main.c, the semaphore init is initializing more than the defined SEM_SIZE.

I want to implement a simple osSleep() which blocks task from running until a certain time is met. I know that this can be easily done with a hardware timer or attach it to the time tick. But for the sake of portability issue, I would like to use something that is already available with the C library such as signal() and alarm(). Unfortunately, alarm() can only be used for one task, anyone has a better idea?

 

Re: Pico-Os... a silly dangerous little coroutine kernel :o)

Reply #10
That main.c is in fact a mess :oP
I never had/took the time to make it nice :)
:o/

There is many ways to implement timers ...
A really easy one is the have an hardware timer maintaining a counter
something like found in many libs returning  a millisec count.

so basic principle will be that

you task will get get the current time,
add the delay it want to go to sleep
in a loop wait for this value to match the current time.
if it is not the time to continue the task do a  taskpreempt(), so letting other tasks do something while you are sleeping ...
:o)
you can of course build that into few more generic functions...

there is many other ways to implement timers, but those may involve coding something that is
not really cross platform...

:-)