views:

370

answers:

5

I have some old code written in C for 16-bit using Borland C++ that switches between multiple stacks, using longjmps. It creates a new stack by doing a malloc, and then setting the SS and SP registers to the segment and offset, resp., of the address of the malloc'd area, using inline Assembler. I would like to convert it to Win32, and it looks like the two instructions should be replaced by a single one setting the ESP. The two instructions were surrounded by a CLI/STI pair, but in Win32 these give "privileged instructions", so I have cut them out for now. I am a real innocent when it comes to Windows, so, I was rather surprised that my first test case worked! So, my rather vague question is to ask the experts here if what I am doing is a) too dangerous to continue with, or b) will work if I add some code, take certain precautions, etc.? If the latter, what should be added, and where can I find out about it? Do I have to worry about any other registers, like the SS, EBX, etc.? I am using no optimization... Thanks for any tips people can give me.

+5  A: 

By far the safest way to do this is to port the code to offical Win32 multiprogramming structures, such as threads or fibers. Fibers provide a very lightweight multi-stack paradigm that sounds like it might be suitable for your application.

The Why does Win32 even have fibers? article is an interesting read too.

Greg Hewgill
One of the posts in that article says "they would switch the stack base, but not update the stack limit. Or not switch the exception handler list. Or forget to swap the FP state." Assuming fibers look after those things for me, can I do longjmps between fibers? If I wanted to look after them myself, how complex are they, and where can I find out about them? Thx.
Paul Morrison
I already linked to the MSDN documentation on fibers in my answer. There's a full function reference there, which should answer most of your questions. Note that I don't think you should try to "longjmp between fibers", but instead use the official functions like SwitchToFiber.
Greg Hewgill
Thanks, Greg. The documentation looked a bit offputting, but I will start digging into it.
Paul Morrison
I have spent some time wrestling with Windows fibers, and right now IMO it looks like setjmp and longjmp are in some ways more powerful than SwitchToFiber! Are there any "secret" methods that would (say) do a setjmp without actually switching? That would be really useful for my application. Thanks in advance.
Paul Morrison
The foregoing now seems like a dumb question - what I really need is SetContext(). Is that POSIX only, and if so, can I get a version of that running under Windows? PS Should I raise this as a new question?
Paul Morrison
It looks like setcontext() is POSIX only and there is no direct Windows equivalent of that. And yes you're right, a new question might be appropriate at this point. :)
Greg Hewgill
Thanks, Greg! I have a fibers solution starting to work, but it's awfully clumsy, and probably slow... Unless there really are "secret" methods that I don't know about!
Paul Morrison
+9  A: 

Removing CLI/STI still works due to the differences in the operating environment.

On 16-bit DOS, an interrupt could occur and this interrupt would be initially running on the same stack. If you got interrupted in the middle of the operation, the interrupt could crash because you only updated ss and not sp.

On Windows, and any other modern environment, each user mode thread gets its own stack. If your thread is interrupted for whatever reason, it's stack and context are safely preserved - you don't have to worry about something else running on your thread and your stack. cli/sti in this case would be protecting against something you're already protected against by the OS.

As Greg mentioned, the safe, supported way of swapping stacks like this on Windows is CreateFiber/SwitchToFiber. This does have the side-effect of changing your entire context, so it is not like just switching the stack.

This really raises the question of what you want to do. A lot of times, switching stacks is to get by limited stack space, which was 64k on 16-bit DOS. On Windows, you have a 1 MB stack and you can allocate even larger. Why are you trying to switch stacks?

Michael
This was my first implementation of Flow-Based Programming on a PC. I didn't realize that Win32 has a fibers implementation, but it may be a lot of trouble to convert my code to Fibers - I'll certainly read the article cited by Greg Hewgill, though. Thanks to all of you!
Paul Morrison
A: 

I have done this in user mode, and it appears to have no problems. You do not need cli/sti, theses instructions merely prevent interrupts at that point in code, which should be unnecessary from the limited information you have told us.

Unknown
A: 

Have a look at Mtasker by Bert Hubert. It does simple cooperative multitasking, it might be easy for you to use this to port your code.

piotr
A: 

Don't forget that jumping stacks is going to hose any arguments or stack-resident variables.

Alex Gartrell