The scheduler uses lightweight user threads with an M-to-N scheduler; that is, there are M Java threads mapped across N native threads. Each native thread has its own queue of Java threads. The native threads are periodically preempted, and control changes to the next ready Java thread in the queue. Work is transferred from busy processors to idle processors via transfer queues.

The files for the scheduler are contained in the Scheduler/ subdirectory.

  • jq_Thread - a Java thread, which runs on top of a jq_NativeThread.
  • jq_NativeThread - a native OS thread.
  • jq_RegisterState - register state for a jq_Thread.
  • jq_ThreadQueue - jq_NativeThread-local thread queue.
  • jq_SynchThreadQueue - synchronized thread queue, for transferring jq_Threads between jq_NativeThreads.
  • jq_MainThread - the thread that invokes the main() method of the boot class.
  • jq_InterrupterThread - thread that periodically interrupts another thread. This is used because there are no per-thread timing interrupts available in Windows.

The implementation is still very preliminary. Wait queues, sleeping, interrupting, etc. are not yet implemented.

Thread switch mechanism

The system uses a small piece of assembly code to quickly switch between Java threads. The code is contained in native.cpp/set_current_context. Notice that it currently uses the stack of the Java thread to restore the registers and the program counter! Thus, we have to guarantee that the stack pointer is always valid whenever a thread switch can occur.

Thread-local allocator

The system uses jq_NativeThread-local synchronization-free allocators for fast allocation. Thus, thread switches are disabled while in the allocator. (Note: the current implementation may cause an unfair bias towards allocation-heavy threads. A good solution may be to rewrite the return address in the allocator to call the scheduler after the allocation call has completed.)