Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

MultiTasking Help needed

4 views
Skip to first unread message

Das

unread,
Apr 13, 2010, 12:16:12 PM4/13/10
to
Hi,
I have some confusion,
I saw there are Hobby OSs implemented Multi Tasking(task switching)
either Using TSS or Stack.

My question
1) Is it good to do multi tasking by switching register values of 2
Tasks
as an example
void switch(regs *r)
{
memcpy(current_task.r,r,sizeof(regs));
memcpy(r,next_task.r,sizeof(regs));
}
The switch() is called from timer interrupt handler in C code.
(task struct has a pointer to regs.as a member)

Please suggest me If it is good then what should I do to pass argument
to the task.

Please refere the task.cpp file under code.google.com/p/nanoos/

Thanks
Ashok.

Maxim S. Shatskih

unread,
Apr 14, 2010, 1:35:01 AM4/14/10
to
> 1) Is it good to do multi tasking by switching register values of 2
> Tasks

Yes.

You only need to switch nonvolatile regs in this. Volatile regs are spoiled by calling the SwitchAway function anyway, according to the calling convention.

But, on hardware interrupt prolog, you need to save _all_ registers.

--
Maxim S. Shatskih
Windows DDK MVP
ma...@storagecraft.com
http://www.storagecraft.com

Das

unread,
Apr 14, 2010, 8:11:45 AM4/14/10
to
On Apr 14, 10:35 am, "Maxim S. Shatskih"

<ma...@storagecraft.com.no.spam> wrote:
> > 1) Is it good to do multi tasking by switching register values of 2
> > Tasks
>
> Yes.
>
> You only need to switch nonvolatile regs in this. Volatile regs are spoiled by calling the SwitchAway function anyway, according to the calling convention.
>
> But, on hardware interrupt prolog, you need to save _all_ registers.
>

Yes I am doing the same, But assume I want to pass parameters to the
task, How I will do it?

I tried to populate a stack and assign it to esp, The contenet of the
stack is as follows
top> argument
top-1> entry
top-2---sizeof(regs) > register values
regs->eip =entry

but the Invalid OPCODE exception happens

Ashok.

Das

unread,
Apr 17, 2010, 12:52:49 PM4/17/10
to

any more thought/Help???

Well I followed the geek-os and tryed the task_switch mechanism from
it with the specified
stack structure still I am unable to pass the parameter to the task
function.
I am inspecting why it is happening, In the mean time I also need some
thought or scheme
how to achieve will be help full.

Thanks
Ashok.
------------------
http://code.google.com/p/nanoos/

James Harris

unread,
Apr 17, 2010, 7:04:22 PM4/17/10
to
On 13 Apr, 17:16, Das <ashok.s....@gmail.com> wrote:
> Hi,
> I have some confusion,
> I saw there are Hobby OSs implemented Multi Tasking(task switching)
> either Using TSS or Stack.
>
> My question
> 1) Is it good to do multi tasking by switching register values of 2
> Tasks
>     as an example
>     void switch(regs *r)
>     {
>          memcpy(current_task.r,r,sizeof(regs));
>          memcpy(r,next_task.r,sizeof(regs));
>     }

It's probably more normal to just switch a pointer. Save and restore
would work with the current pointer.

> The switch() is called from timer interrupt handler in C code.
> (task struct has a pointer to regs.as a member)
>
> Please suggest me If it is good then what should I do to pass argument
> to the task.

You only pass arguments when you start a task, not when switching
between tasks. For switch() code and some good explanations see

http://webcast.berkeley.edu/media/common/rss/Computer_Science_162__001_Fall_2009_Video__webcast.rss

and look at lectures 4 and 5. I think lecture 5 contains the actual
thread switching you need and how to approach it.

James

Rod Pemberton

unread,
Apr 17, 2010, 7:16:28 PM4/17/10
to
"James Harris" <james.h...@googlemail.com> wrote in message
news:b162ad7d-3076-4a89...@h27g2000yqm.googlegroups.com...

> On 13 Apr, 17:16, Das <ashok.s....@gmail.com> wrote:
> > I saw there are Hobby OSs implemented Multi Tasking(task switching)
> > either Using TSS or Stack.
> >
> > My question
> > 1) Is it good to do multi tasking by switching register values of 2
> > Tasks
> > as an example
> > void switch(regs *r)
> > {
> > memcpy(current_task.r,r,sizeof(regs));
> > memcpy(r,next_task.r,sizeof(regs));
> > }
>
> It's probably more normal to just switch a pointer. Save and restore
> would work with the current pointer.
>

It looks to me like he's just switching register sets for each task. I
think he needs to switch stacks too. Doesn't he? Otherwise the stack gets
corrupted, or the data on the stack gets out-of-sequence for the appropriate
task.


RP


James Harris

unread,
Apr 18, 2010, 5:36:03 PM4/18/10
to
On 18 Apr, 00:16, "Rod Pemberton" <do_not_h...@havenone.cmm> wrote:
> "James Harris" <james.harri...@googlemail.com> wrote in message

Aha! I can't remember where the discussion ended but weren't you
previously arguing for using *one* stack for multiple tasks?
(Rhetorical question. No need to reply!)

In fact I'm not clear what the OP's plans are but copying register
values using memcpy doesn't seem right. Registers should, IMHO, be
saved when switching out of the old task. Many of them are saved
anyway when switching to the interrupt handler. Then they can be
restored on return. It's just that the return may go back to a
different task or thread.

That just leaves the problem of how to initialise the thread saved
state and any parameters that the OP mentioned. IIRC the video
lectures I linked to show a good way to deal with that.

Either way I agree with what you mentioned - that the stack is part of
the per-task state that needs to be saved and restored.

James

Das

unread,
Apr 19, 2010, 2:13:06 AM4/19/10
to
On Apr 18, 4:16 am, "Rod Pemberton" <do_not_h...@havenone.cmm> wrote:
> "James Harris" <james.harri...@googlemail.com> wrote in message

RP,
I guess You are right, But i am creating a stack and my esp in the reg
set points to that.
after i populate the stack, i switch the registers.
I guess by some means I'm corrupting the stack.

Das
-----------------------
http://code.google.com/p/nanoos/

Das

unread,
Apr 19, 2010, 2:28:28 AM4/19/10
to
On Apr 19, 2:36 am, James Harris <james.harri...@googlemail.com>
wrote:

I will look into those tutorials.
Well copying the register set is just not sufficient, but it is ok for
context saving and restoring. But it never
Ok for returning from interrupt( IRET ). Hence i'm now in my current
code following the stack change.

e.g
*--stack_top -> args
*--stack_top-> entry
*--stack_top-> 0 // should be a thread/task exit
after this I am copying all the register set

now when I am switching task I now change only the task pointer i
already have stored.
Might be I am doing things in Wrong way.
If I don't succeed then I will definitely poke the group again... :)

Das
--------------
http://code.google.com/p/nanoos/

s_dub...@yahoo.com

unread,
Apr 19, 2010, 3:42:32 PM4/19/10
to

These articles might be a help to you...

http://www.embedded.com/columns/technicalinsights/55301875?_requestid=231663
Managing Tasks on x86 Processors

http://www.embedded.com/columns/significantbits/22104365?_requestid=280086
Helping underprivileged code

http://www.embedded.com/columns/significantbits/18400795?_requestid=287915
Taming the x86 beast

In Helping underprivileged code, it says:

"
It's amazing to me that all of this happens in hardware. There's not a
lick of code involved in this process, just a lot of data tables.
Granted, it takes the processor about 100 clock cycles (less than a
microsecond at 500MHz) to do all this, but it's entirely automatic and
mechanical. For some small real-time kernels, privilege protection and
task switching is all they do; now that work can be done entirely in
hardware.

Where code goes, so goes the stack
When you change privilege levels, you change the addressable domain of
your program. For example, when your code is running at privilege
level 2 (PL2), you can access PL2 and PL3 data segments and a PL2
stack segment. If you make a successful call through a call gate to a
PL1 code segment, your privilege level increases to PL1 and you can
access PL1, PL2, and PL3 data segments. But what about your stack?

When you change privilege levels, your stack changes automatically.
Your old SS segment and stack pointer are abandoned and replaced with
new ones that correspond to the new, higher privilege level. Where
does this new stack come from? Hmmm, I feel a new data structure
coming on.

Believe it or not, there's still one more magical data structure you
need to create if you're going to use privilege protection on x86
processors. This new one is called the task state segment (TSS). We'll
save the gory details for another day, but in brief, the TSS includes
four different sets of stack pointers, one for each privilege level.
And, of course, you get to (read: have to) define where each of these
stacks will go. Obviously, the PL1 stack should be in a PL1 stack
segment, and so forth. You might never need all four of these stacks;
your code might never call a subroutine through a PL1 call gate. But
leaving these stacks undefined is a really bad idea. You'll have an
awfully tough time figuring out why your code suffered a sudden stack
failure after a routine function call.

Defensive programming
Sharp-eyed readers will notice that we glossed over one of the bit
fields in the call gate. Bits 32 through 36 define the number of 32-
bit parameters that will be passed from the calling routine into the
called routine. The chip will automatically copy this many bytes
(times four) from your stack to the called routine's stack.

After every FAR CALL there should be a matching FAR RET (return)
instruction that pops the correct number of parameters off the stack.
Just to make things tricky, call gates define the number of parameters
as 32-bit words, while the FAR RET instruction counts bytes. Be sure
to multiply by four before punching your return ticket.

This automatic parameter passing makes it awkward to write a routine
that accepts a variable number of arguments. The call gate will copy a
fixed number of bytes onto the called routine's stack, and the FAR RET
must remove exactly that many at the end. A single function will
either need several call gates, each with a different parameter count
(and with a matching exit point), or it will have to be coded for a
worst-case payload.

If 31 words (124 bytes) isn't enough space, you might want to pass
parameters by reference, rather than by value. In other words, push a
pointer to a data structure rather than the data itself. After all,
the called routine can access any data memory that the calling routine
could possibly have used, by virtue of its higher privilege level.

Each FAR RET executes one final step to aid security. Just before
control returns to the old, less-privileged code, the data segment
registers DS, ES, FS, and GS are all checked to see if the called
procedure might have left indexes to more privileged segments in them.
If so, the offending segment registers are zeroed. This keeps high-
level procedures that are sloppy with their segment registers from
unwittingly giving less-privileged procedures access to memory that
would otherwise be off-limits.

Oh, and you can't return values on the stack. Both the caller's stack
and the called routine's stack will shrink by the number of bytes
specified in the call gate and the FAR RET instruction, respectively.
When the caller regains control, it looks as though no parameters were
ever on the stack. (Besides, the two routines use physically separate
stacks.) You've got to return values in registers.

Finally, you should save and restore all segment registers in your
called functions. This is more to protect the caller than the callee.
If the called function changes any of the data segment registers to
point to segments the caller doesn't have permission to access, the
processor will zero those segment registers to prevent you from
passing on ownership of a privileged segment. The caller might regain
control with one or more of its segment registers cleared, which can
be a miserable bug to track. If the caller doesn't use, say, the GS
register frequently it can be hard to track down why it generates
General Protection Faults later on.
"

I'm not sure what NANOOS strategy is, but it seems to point in the
above direction.

According to what he says above, the caller can specify and pass
parameters on the stack to the new task throught the callgate, but can
only expect values returned in the registers.

However, I think if a shared descriptor is used as a 'common data
block'.. well the caller&callee would need to be at the same privilege
level.

The way I understand privilege, less privilege can call in to more
privilege 'conforming' code, and more privilege code can dereference
out to the less privileged data.

I'm not sure about your memcpy design. Even with all ring0 sections,
you need the correct descriptors as part of the function call, likely
they are not 'in common'. TSS's are separate memory spaces, no?

hth,

Steve

Rod Pemberton

unread,
Apr 19, 2010, 2:51:54 PM4/19/10
to
"James Harris" <james.h...@googlemail.com> wrote in message
news:5fb2944c-5b2f-4756...@c21g2000yqk.googlegroups.com...

>
> Aha! I can't remember where the discussion ended but weren't you
> previously arguing for using *one* stack for multiple tasks?
>

That's probably not what the OP wants to attempt, ever...

Yes, I said that could be done. I wasn't arguing for it... A stack per
process or task is probably a better choice for most.

A single stack can be used for multiple processes/tasks. It's not optimal.
It has "lock up" issues. The stack can't always be unrolled with multiple
users. E.g., a stackframe can't be removed until a loop exits, so the
previously running app is halted... So, some app's will "halt" until
another app has exited or popped off certain stackframes. IIRC, it also
required a bit of logic in the epilog to unroll the stack correctly. I.e.,
a task switch and/or unrolling of the stack need to selectively occur in the
epilog.


Rod Pemberton


Das

unread,
Apr 20, 2010, 4:09:08 AM4/20/10
to
On Apr 20, 12:42 am, s_dubrov...@yahoo.com wrote:
> On Apr 13, 11:16 am, Das <ashok.s....@gmail.com> wrote:
>
>
>
> > Hi,
> > I have some confusion,
> > I saw there are Hobby OSs implemented Multi Tasking(task switching)
> > either Using TSS or Stack.
>
> > My question
> > 1) Is it good to do multi tasking by switching register values of 2
> > Tasks
> >     as an example
> >     void switch(regs *r)
> >     {
> >          memcpy(current_task.r,r,sizeof(regs));
> >          memcpy(r,next_task.r,sizeof(regs));
> >     }
> > The switch() is called from timer interrupt handler in C code.
> > (task struct has a pointer to regs.as a member)
>
> > Please suggest me If it is good then what should I do to pass argument
> > to the task.
>
> > Please refere the task.cpp file under code.google.com/p/nanoos/
>
> > Thanks
> > Ashok.
>
> These articles might be a help to you...
>
> http://www.embedded.com/columns/technicalinsights/55301875?_requestid...

> Managing Tasks on x86 Processors
>
> http://www.embedded.com/columns/significantbits/22104365?_requestid=2...
> Helping underprivileged code
>
> http://www.embedded.com/columns/significantbits/18400795?_requestid=2...

> Taming the x86 beast
>
> In Helping underprivileged code, it says:
>
> "
----------------snipped----------------

> I'm not sure what NANOOS strategy is, but it seems to point in the
> above direction.
>

Currently There is
1)only kernel(ring 0) no user tasks.
2)No TSS based task switching. (only software based task switching)
3)No plans for user land soon
4)When Kernel is done Then User land (ring 3) will be designed.
5)initially one-to-one thread mapping
6)many-to-many
7) I cant think of ( as it is a hobby kernel sorry :) )

> According to what he says above, the caller can specify and pass
> parameters on the stack to the new task throught the callgate, but can
> only expect values returned in the registers.
>

only a single task/thread parameter passed by reference in kernel
thread

> However, I think if a shared descriptor is used as a 'common data
> block'.. well the caller&callee would need to be at the same privilege
> level.

Yes they are as all code belong to kernel only.

>
> The way I understand privilege, less privilege can call in to more
> privilege 'conforming' code, and more privilege code can dereference
> out to the less privileged data.
>

> I'm not sure about your memcpy design.  Even with all ring0 sections,
> you need the correct descriptors as part of the function call, likely
> they are not 'in common'.  TSS's are separate memory spaces, no?
>
> hth,
>

Yes definitely it helped me ;) As i am learning how to implement multi
tasking.

> Steve

Das
--------------------
http://code.google.com/p/nanoos/

Das

unread,
May 19, 2010, 12:41:53 AM5/19/10
to
On Apr 20, 1:09 pm, Das <ashok.s....@gmail.com> wrote:
> On Apr 20, 12:42 am, s_dubrov...@yahoo.com wrote:
>
> > On Apr 13, 11:16 am, Das <ashok.s....@gmail.com> wrote:
------snipped---------

>
> Yes definitely it helped me ;) As i am learning how to implement multi
> tasking.
>
> > Steve
>

Well Now the multitasking is working, that is i can create different
tasks can pass parameters to it, switch between tasks on timer
interrupts, can remove a task if it finished.

Now I will try to implement parent task *waiting* for a child task and
similar associated functions.

Well again: is it necessary to implement fork() and similar things as
in Unix clones?
I mean in fork child inherit all properties of parent do I need to
implement similar things?
\these questions may sound odd :) but ...

Das
--------------------
http://code.google.com/p/nanoos/


Alexei A. Frounze

unread,
May 19, 2010, 2:37:41 AM5/19/10
to
On May 18, 9:41 pm, Das <ashok.s....@gmail.com> wrote:
> On Apr 20, 1:09 pm, Das <ashok.s....@gmail.com> wrote:> On Apr 20, 12:42 am, s_dubrov...@yahoo.com wrote:
>
> > > On Apr 13, 11:16 am, Das <ashok.s....@gmail.com> wrote:
>
> ------snipped---------
>
>
>
> > Yes definitely it helped me ;) As i am learning how to implement multi
> > tasking.
>
> > > Steve
>
> Well Now the multitasking is working, that is i can create  different
> tasks can pass parameters to it, switch between tasks on timer
> interrupts, can remove a task if it finished.
>
> Now I will try to implement parent task *waiting* for a child task and
> similar associated functions.
>
> Well again: is it necessary to implement fork() and similar things as
> in Unix clones?

If you intend to support some of that Unix functionality or more or
less easily port existing applications to your OS, you'll need fork()
and the co. However, if you don't, the details of the API and
implementation are up to you.

> I mean in fork child inherit all properties of parent do I need to
> implement similar things?

Think of what you actually need. You may not need to inherit
everything, but there are some useful properties like the user and
access rights. If you want to share the memory between the two
processes via copy-on-write (COW) and some other things, then you want
some more. If you just want to execute another task w/o much implicit
data sharing, you don't need to implement many things.

> \these questions may sound odd :) but ...

We all learn by trial and error, asking questions and receiving
advice.

Alex

Das

unread,
May 20, 2010, 10:15:29 PM5/20/10
to
On May 19, 11:37 am, "Alexei A. Frounze" <alexfrun...@gmail.com>
wrote:

> On May 18, 9:41 pm, Das <ashok.s....@gmail.com> wrote:
>
>
>
> > On Apr 20, 1:09 pm, Das <ashok.s....@gmail.com> wrote:> On Apr 20, 12:42 am, s_dubrov...@yahoo.com wrote:
>
> > > > On Apr 13, 11:16 am, Das <ashok.s....@gmail.com> wrote:
>
> > ------snipped---------
>
> > > Yes definitely it helped me ;) As i am learning how to implement multi
> > > tasking.
>
> > > > Steve
>
> > Well Now the multitasking is working, that is i can create  different
> > tasks can pass parameters to it, switch between tasks on timer
> > interrupts, can remove a task if it finished.
>
> > Now I will try to implement parent task *waiting* for a child task and
> > similar associated functions.
>
> > Well again: is it necessary to implement fork() and similar things as
> > in Unix clones?
>
> If you intend to support some of that Unix functionality or more or
> less easily port existing applications to your OS, you'll need fork()
> and the co. However, if you don't, the details of the API and
> implementation are up to you.
>

Well No clone, till now it is in my mind that it should be as simple
as possible.
With concept of programming the hardware.
1) it should be able to provide a mechanism for drivers,
2) atleast some games ( tic-tac-toe, if i can be too ambitious then a
PACMAN )
3) ping like network utility

s_dub...@yahoo.com

unread,
May 21, 2010, 12:02:51 AM5/21/10
to
> > Alex- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -

This might interest you for ideas, esp. section 1.4 Real Time Monitor.

http://www.cpm.z80.de/manuals/mpm86sg.pdf

My understanding is this method follows the DEC VMS school of
multitasking.

hth,

Steve

Das

unread,
May 22, 2010, 1:03:20 PM5/22/10
to

Hi Steve,
Nice Document. Well ... let me see how much efficient I am to put few
of these.

das.
------------------
http://code.google.com/p/nanoos/

0 new messages