implementing threads
Posted: Sat May 22, 2021 4:31 pm
Im having an issue and its implementing threads and basic scheduling, I'm looking for simple code to look at (not to paste), just wondering how they work
The Place to Start for Operating System Developers
http://f.osdev.org/
I think you over-complicate stuff by passing thread create a process context. Any normal usage of thread creation would create the thread in the current process. When you create a process, you also create the first thread, but this should be implicit in the process creation. Typically, initial thread creation for a process will not pass entrypoints (at least not user space entrypoints), rather this is resolved as the application program is loaded and the executable header will indicate the entry-point.neon wrote: To create a thread... Threads must store an execution context (register state). Threads have an associated Process that has an Address Space. You would have a function like CreateThread(process, entry_point, props) that would clear the execution context of the thread and set its context EIP/RIP to entry_point. The thread would be created for "process" and added to the Scheduler. Thread->process should refer to the parent Process object.
Switching process should be as simple as reloading CR3, and the CR3 could be saved in the thread control block so the task switcher doesn't have to know about processes.neon wrote: To switch to a thread... we have to switch to the thread before we can execute it. We call the Scheduler to tell us what thread to switch to. If the thread->process address space is different, we will need to switch to the new address space.
I think saving register state on the stack is a bad approach. It should be saved in the thread control block. That makes it much easier to dump thread state (and change it). There is also FPU state, which also should be saved in the thread control block when needed.neon wrote: To execute a thread... we need to restore the threads execution context (register state.) This is typically done in assembly language: we PUSH the items we need back on the thread-local stack and then use IRET to run it. IRET is used as it supports switching the CPU context to user mode as well as kernel mode.
The scheduler should not rely on iret frames.neon wrote: It can be helpful to experiment with the IRET instruction and consider how we can set whatever the return CS:IP is for it.
Of course. But I do highly recommend already having the framework for multithreading in place first. There is hardware tasks -- and in fact you must always have one for use with user mode -- however due to hardware multitasking being very limited it is typically recommended to implement multithreading in software.is there a way to interface with the CPU to run actual threads?
No worries, please feel free to correct anything that you see: I wrote it very late last night and kept rewriting it thinking how best to describe everything as I wanted to keep things precise and tried to be as clear as possible. My response isn't based on any design: I wanted to focus on the theory rather then design as I believe that is the most important to understanding multithreading. I do have working sample code for threading already on my site so didn't see any benefit of rewriting it here so wanted to focus on just the theory.I think you over-complicate stuff
It is indeed a bad idea: the quote there discusses restoring the thread execution context not storing it. Sorry if this was confusing -- I tried to make it as simple as possible but ironically made some of it sound more complicated ha -- basically I agree with everything you said.I think saving register state on the stack is a bad approach