Hi everyone,
I'm writing a VM for my high-level language which is to be JIT-compiled to native code before execution. To be able to take advantage of multiple cores, I plan to use POSIX "VM" threads (I'm working with Linux and GCC), and each VM thread will manage multiple language threads for light-weight multithreading (but also so that if/when it becomes a standalone OS, each CPU core can be assigned a VM thread).
I'm fine with writing some assembly to switch from VM code to JITed code, but exiting out again is puzzling me. Ideally, I'd like to have a timer go off after a language thread's quantum expires and do a longjmp to the "restore the stack, return to VM" code. I've found that alarm()/sigaction() can act as a timer, but they seem to expect the signal handler to return. So could I longjmp out of a signal handler reliably, with possibly only needing to re-enable signals for the thread? That sounds kind of dirty...
Since polling the system time or constantly decrementing a "quantum remaining" register is inefficient and not needing to clutter the compiler with such code would be nice, is there another way to implement my own preempting in user-land?
Another problem is a language thread overflowing its (private) stack; is it possible to trap a stack overflow in a child POSIX thread separately from other invalid memory writes? From what I can find, SIGSTKFLT doesn't seem to be well supported at all. Even if the thread dies, that wouldn't be too much of a problem, as long as it's traceable back to overflowing the stack, and where. (Methods could check the remaining stack size in their prologues but that sounds slow, maybe it's the most stable way though.)
Thanks in advance! Certain things are so much easier when you have access to the PIT and IDT...
Preemptive multithreading, stack checking in Linux user-land
-
- Posts: 12
- Joined: Sat Oct 23, 2004 11:00 pm
- Location: In ur gcc, watchin' you compile.
- Contact:
Preemptive multithreading, stack checking in Linux user-land
khumba.net - prototype capability language and operating environment
"Lose your questions and you will find your answers" -D'ni Proverb
"Lose your questions and you will find your answers" -D'ni Proverb
Re: Preemptive multithreading, stack checking in Linux user-land
Hi,
Personally in that situation I'd have a 1:1 relationship between language threads and POSIX threads. POSIX threads provide preemption and also a many:many mapping onto kernel threads so they're not as expensive as you think.
The alternative as far as I can see is to have a per-thread memory location that gets polled at the start of every Basic Block, whether the thread should exit to your C code or not.
As to other alternatives, my lips are sealed by my contract with my current employer - sorry!
James
Personally in that situation I'd have a 1:1 relationship between language threads and POSIX threads. POSIX threads provide preemption and also a many:many mapping onto kernel threads so they're not as expensive as you think.
The alternative as far as I can see is to have a per-thread memory location that gets polled at the start of every Basic Block, whether the thread should exit to your C code or not.
As to other alternatives, my lips are sealed by my contract with my current employer - sorry!
James
-
- Posts: 12
- Joined: Sat Oct 23, 2004 11:00 pm
- Location: In ur gcc, watchin' you compile.
- Contact:
Re: Preemptive multithreading, stack checking in Linux user-land
That makes sense, I think I'll go with 1:1. It'll perform better in competition with other threaded applications running too. I'm planning on using a deferred reference-counting garbage collector, so each thread will need its own inc/dec buffer; if it provides a significant speed improvement, I'll keep a pool of buffers to avoid lots of repeated allocations (I imagine it will).
If I were going to go with the polling strategy, the code would be something simple (dec <quantumLeft>; jz return_to_c), but then <quantumLeft> would need to be able to hold a word large enough to allow a decent amount of time. Plus, like you say, inserting the code in lots of places (in the message-send code, after jump targets, and after every Nth statement of a long function ought to do it). Meh.
On the other hand, the language is image-based with resumable threads, so the VM will need some way to tell its threads to move to a saveable state, and this may come down to polling a signal buffer as well. So many things high on the priority list right now.
Thanks! Cheers,
Khumba
If I were going to go with the polling strategy, the code would be something simple (dec <quantumLeft>; jz return_to_c), but then <quantumLeft> would need to be able to hold a word large enough to allow a decent amount of time. Plus, like you say, inserting the code in lots of places (in the message-send code, after jump targets, and after every Nth statement of a long function ought to do it). Meh.
On the other hand, the language is image-based with resumable threads, so the VM will need some way to tell its threads to move to a saveable state, and this may come down to polling a signal buffer as well. So many things high on the priority list right now.
Interesting, I'll keep that in the back of my mind .http://forum.osdev.org/viewtopic.php?p=128332#p128332 wrote:Another example is a JIT compiler. These programs will deliberately cause illegal reads and writes in order to trap an exception condition, also known as "lazy compiling". It will leave an area of memory unmapped, and point pointers at it so that if those pointers are followed, a trap occurs. This means that the JIT compiler doesn't actually have to compute everything at once, rather it can wait until it's needed.
Thanks! Cheers,
Khumba
khumba.net - prototype capability language and operating environment
"Lose your questions and you will find your answers" -D'ni Proverb
"Lose your questions and you will find your answers" -D'ni Proverb