How is proactive scheduling implemented for user-level threads in Linux?

With user-level threads, there are N user-level threads running on top of one kernel thread. This is in contrast to pthreads, where only one user thread runs on the kernel thread.

User level N threads are pre-scheduled on a single core thread. But what are the details of how it's done.

I've heard something that suggested that the streaming library dictates everything for a signal to be sent by the kernel, and that is a mechanism to do execution from a separate user-level thread to a signal handler, which can then pre-schedule.

But what are the details of how state, such as registers and stream structures, is stored and / or mutated to make it all work? Maybe a very simple user level flow that is useful for learning the details?

+2


source to share


1 answer


Use the source to get the correct information! But this is what I remember when I read ...

There are two ways in which you can schedule user-level flows: voluntarily and proactively.

  • Voluntary scheduling : threads must call a function periodically to transfer CPU usage to another thread. This function is called yield()

    or schedule()

    or something like that.
  • Pre-scheduling : The library forcibly removes the processor from one thread and transfers it to another. This is usually done using timer signals such as SIGALARM

    (see for details man ualarm

    ).

How to make a real switch if your OS is friendly and provides the functionality you need is easy. In Linux, you have makecontext()

/ functions swapcontext()

that make it easy to switch between one task to another. Again, see the man pages for details.

Unfortunately, these features have been removed from POSIX, so other UNIXs may not have them. If that's the case, there are other tricks you can do. Most popular was the one who called sigaltstack()

to set up an alternate stack to manage signals, then kill()

himself to go to the alternate stack, and longjmp()

from the signal function to the actual user mode thread. want to run. Smart, mm?

As a side note, in Windows user modes, streams are referred to as fibers and are also fully supported (see docs CreateFiber()

).



The latter uses an assembler that can be made to work almost anywhere, but is completely system dependent. The steps to create a UMT will be as follows:

  • Allocate a stack.
  • Allocate and initialize the UMT context: a structure for storing the values โ€‹โ€‹of the corresponding registers of the CPU.

And to switch from one UMT to another:

  • Save the current context.
  • Switch stack.
  • Restore the next context to the CPU and move on to the next instruction.

These steps are relatively easy to do in assembler, but completely impossible in plain C without supporting some of the tricks mentioned above.

+2


source







All Articles