Page 1 of 1

User threads, kernel threads and everything in between

Posted: Tue May 19, 2020 10:13 am
by sunnysideup
I've been doing a bit of OsDev, and as I'm moving to process management and so on, I got to thinking about user threads and kernel threads that I've read about in OS books.

So the question is this: Is the number of KERNEL threads equal to the number of kernel stacks that I have? That is, there is a complete correspondence between the two. To me, it makes sense because, after all, the kernel is only called when there is an interrupt (trap, exception, hw, etc.). So having multiple kernel stacks = having multiple kernel threads?

And user-level threads are something managed by a user-space thread library?

So I'm guessing that an OS is one-to-one when each user-level thread has its own kernel stack (and thus a kernel thread).
If the kernel had only one stack, that is, it had a global kernel stack, then the user-space thread library can expose only one user thread to "join" the kernel stack, and this would be a many to one model.

Is this right? If so, what is a many to many model?

Re: User threads, kernel threads and everything in between

Posted: Tue May 19, 2020 10:38 am
by nexos
User threads do have a kernel and user stack. The kernel stack is in the Task State Segment. When an exception, IRQ, or ISR occur, you will go into kernel mode, and esp and the segment registers will be loaded from the TSS. You could have one kernel stack for the system, but it would soon overflow as more tasks ran.

Re: User threads, kernel threads and everything in between

Posted: Tue May 19, 2020 10:46 am
by sunnysideup
Here I am not concerned with any specific underlying hardware (TSS, etc.). I want to understand the concept of many to many, many to one, and one to one threading models.

Re: User threads, kernel threads and everything in between

Posted: Tue May 19, 2020 11:55 am
by AndrewAPrice
sunnysideup wrote:And user-level threads are something managed by a user-space thread library?
The kernel knows about user-thread threads, unless you have some esoteric microkernel that has a thread manager runing in userspace (essentially a thread is a bunch of registers (one being a stack pointer), so a userspace thread manager could tell the kernel "switch to these bunch of registers.") This would be a little extreme, and performance would suffer a little (3 context switches instead of 1 when your timer fires), so many microkernels do keep threading and scheduling in the kernel.

With that being said, a user-space thread library could just be a wrapper over your system calls to create a thread, wake a thread, etc.
sunnysideup wrote:So I'm guessing that an OS is one-to-one when each user-level thread has its own kernel stack (and thus a kernel thread).
I only have one kernel stack that I switch to for entering syscalls and interrupts.

Being a microkernel, I have no "kernel threads" only interrupt and syscall handlers. When I support multiple CPU cores, I will have one stack per core.

Re: User threads, kernel threads and everything in between

Posted: Tue May 19, 2020 12:57 pm
by sunnysideup
Take a look at this article: https://www.tutorialspoint.com/operatin ... eading.htm

It describes multi threading models, which is also described in almost all standard OS books (dinosaur book, AST, etc. ) And the article says this while describing user threads: "In this case, the thread management kernel is not aware of the existence of threads. The thread library contains code for creating and destroying threads, for passing message and data between threads, for scheduling thread execution and for saving and restoring thread contexts. The application starts with a single thread."

This clearly says that the kernel doesn't know about threads. Perhaps this model isn't used nowadays, but still... This is a forum for OS theory after all.

Re: User threads, kernel threads and everything in between

Posted: Tue May 19, 2020 1:09 pm
by sunnysideup
In your microkernel system, how do you do syscalls (traps - not necessarily the syscall instruction)? I'm not sure how it'd work on a microkernel, especially blocking syscalls.

Re: User threads, kernel threads and everything in between

Posted: Tue May 19, 2020 2:37 pm
by AndrewAPrice
sunnysideup wrote:In your microkernel system, how do you do syscalls (traps - not necessarily the syscall instruction)? I'm not sure how it'd work on a microkernel, especially blocking syscalls.
My microkernel runs in long-mode, so what I say might not apply for real and protected mode:

In the TSS, you can select what stack to use for syscalls and interrupts (and you can even specify multiple stacks if you want to handle nested interrupts, such as catching if your interrupt handler code segfaults.)

For me, I have one kernel stack, which I share between syscalls and interrupts.

There is a bit in the FLAGS register (bit 9) that tells the CPU if interrupts are enabled. When you use syscall/sysret, the kernel masks FLAGS with SFMASK. So if you set bit 9 in SFMASK, interrupts will be disabled upon entering a syscall, and re-enabled upon sysret.

Being a micro-kernel, my kernel is limited to scheduling, memory management, and messaging. I don't have any need for kernel threads, so the only way kernel code gets triggered is via an interrupt or syscall, and since interrupts won't trigger syscalls, and syscalls disable interrupts, kernel code won't interrupt kernel code and I only need one kernel stack.

When I implement multi-core support in the future, my plan is to have one TSS and kernel stack per processor, and use spin-locks around my data structures.

Re: User threads, kernel threads and everything in between

Posted: Tue May 19, 2020 6:59 pm
by sunnysideup
So how do you deal with blocking syscalls? For example, a syscall that waits for some hardware interrupt like a key press. Or you don't have blocking syscalls at all?

Re: User threads, kernel threads and everything in between

Posted: Wed May 20, 2020 1:06 am
by AndrewAPrice
I do have blocking syscalls but you can implement them by putting the caller to sleep (unscheduling the user thread) and returning from the syscall into the next scheduled thread.

You context switch by returning from the syscall loading in a different set of registers than what the syscall was called with.