Im working on a VHDL compiler/simulator. The VHDL language based on
using processes. I have a C++ scheduler, and when a process scheduled,
the code for this process is executed. This code is in x86 asm. I have
problem some wait constructs which suspends processes. For example
there is a 'wait on <sig>' construct which suspends the process until
there is some event on 'sig'. I can implement it on the following way:
the EIP is remembered after executing wait on, then a 'ret' executed.
When this process newly scheduled there is a jump at the start of the
process, which jumps to this IP. The problem this wait constructs can
be used in a subprograms. For example 'proc1' process calls 'subp1'
subprogram, 'subp1' suprogram calls 'subp2' subprogram, and there is a
'wait on' in 'subp2'. How could I implement it? It is a context
switching? There will be more than 1000 VHDL process also.
Thanks
Look for synchronization and message passing primitives in your OS.
You may make your code block until it gets a message/event or somebody
releases a mutex it's waiting on.
Alex
John> Hi,
John> Im working on a VHDL compiler/simulator. The VHDL language
John> based on using processes. I have a C++ scheduler, and when a
John> process scheduled, the code for this process is executed. This
John> code is in x86 asm. I have problem some wait constructs which
John> suspends processes. For example there is a 'wait on <sig>'
John> construct which suspends the process until there is some event
John> on 'sig'. I can implement it on the following way: the EIP is
John> remembered after executing wait on, then a 'ret' executed.
John> When this process newly scheduled there is a jump at the start
John> of the process, which jumps to this IP. The problem this wait
John> constructs can be used in a subprograms. For example 'proc1'
John> process calls 'subp1' subprogram, 'subp1' suprogram calls
John> 'subp2' subprogram, and there is a 'wait on' in 'subp2'. How
John> could I implement it? It is a context switching? There will be
John> more than 1000 VHDL process also.
You typically have separate, heap-allocated, stacks. When
context-switching, you save EIP, ESP and a bunch of registers. If you
make sure wait() is not-inlined all you need to save are the
callee-saved registers defined by your ABI.
Once that done, the fact that wait is called from a deeply nested chain
of subroutine calls become immaterial.
OTH,
Maurizio
You presumably already have a separate stack for each process that
will record the call chain. The normal next step is to record *all*
used registers when descheduling the process. You can add these to the
existing stack or save them elsewhere in spaces (one per process)
reserved for the purpose. Either will do.
These will include all the general purpose registers and if you use
MMX or SSE instructions you need to save those registers too. See the
pusha, fsave and fxsave instructions.
James
How could I have separate stacks for each processes? Now Im working
with a single stack.
In principle just allocate memory for the stacks and switch them as
part of your task switching. In practice the answer depends on what
operating system you are running under and which x86 mode you are in.
If in real mode switch SS and SP. In protected mode switch SS and ESP.
If you are operating with paging you can allocate guard pages at top
and bottom of each stack address range to prevent stack overflow and
underflow. If not using paging or you don't have access to it you may
want to check the stack pointers for range from time to time - perhaps
on task switch.
Finally, you may not be able to change SS due to OS restrictions or
due to running under x86-64. If so I guess you'll need to see what
your OS provides in terms of stack allocation and switching or process
switching or thread switching or fiber switching.
James
>> You presumably already have a separate stack for each process
>> that will record the call chain. The normal next step is to
>> record *all* used registers when descheduling the process. You
>> can add these to the existing stack or save them elsewhere in
>> spaces (one per process) reserved for the purpose. Either will
>> do.
>>
>> These will include all the general purpose registers and if you
>> use MMX or SSE instructions you need to save those registers
>> too. See the pusha, fsave and fxsave instructions.
>>
>> James
John> How could I have separate stacks for each processes? Now Im
John> working with a single stack.
The stack is simply memory that is pointed to by a special purpose
register (the stack pointer). Many architecture (not all) have some
instructions (noticeably CALL/JSR, PUSH, POP and RET) implicitly
operating on the stack pointer.
In order to have multiple stacks you just allocate (typically on the
heap) multiple regions. Before yielding control to a thread you load the
machine stack pointer so that it points to the thread's own "stack"
rather than the system stack. Your thread's code won't know the
difference.
You can learn everything about this by looking at the code for any of
the user space thread libraries available as open source.
oth,
Maurizio
--
I could allocate stacks on the main stack, by remembering the
resulting ESP-s
sub ESP, my_stack_size ; store ESP in the process data structure
When switching I would change ESP to this stored ESP....