Module process

Module process 

Source
Expand description

§Multithreaded Process

Modern applications increasingly rely on multithreading to achieve responsiveness, scalability, and efficient utilization of multicore processors. By enabling a single process to run multiple threads concurrently, the system can perform I/O and computation in parallel, reduce latency, and better respond to user interactions or real-time events.

To support such workloads, the operating system must provide robust mechanisms for creating, scheduling, and synchronizing threads within a single process. This includes managing shared memory access, ensuring thread-safe operations, and allowing coordination through synchronization primitives such as mutexes, condition variables, and semaphores.

In KeOS, extending the process abstraction to support multithreading is a critical step toward building a realistic and capable system. This enhances your knowledge about how the multithreading, the foundation for concurrent programming models, works in real-world operating system.

§Multithreading in KeOS

Previously, a process in KeOS consisted of a single thread. Your goal is extending the process to run multiple concurrent threads, each with its own execution context but sharing the same address space and resources. Each thread maintains its own register states while sharing the same states.

In earlier projects, each Process owned its own FileStruct and MmStruct. However, on the multi-threaded model, these components are shared across all threads of a process. That is, they become shared resources, requiring proper synchronization. To support shared and mutable access, these resources are wrapped inside an Arc<Mutex<_>>.

  • Arc provides shared ownership with reference counting.
  • Mutex ensures exclusive access to mutable state.

This allows multiple threads to safely access and modify shared structures like file tables and virtual memory mappings.

§Thread Life Cycle

KeOS supports a lightweight threading model within a single process, enabling multiple threads to execute concurrently while sharing the same address space. The life cycle of a thread is managed through four key system calls:

  • thread_create: Creates a new thread within the same process, executing a given function on a user-supplied stack.
  • thread_join: Waits for a specified thread to terminate and retrieves its return value.
  • exit: Terminates the calling thread without affecting other threads in the same process.
  • exit_group: Terminates all threads within the process simultaneously.

When creating a new thread via thread_create, the user must provide a pointer to a valid, writable memory region that will serve as the new thread’s stack. This approach mirrors Linux’s clone() system call and gives userspace full control over stack allocation and reuse. The kernel validates that the provided stack lies within a properly mapped and writable memory region to ensure memory safety.

Threads can be terminated individually using the exit system call, which affects only the calling thread. Other threads in the same process continue executing. To coordinate with thread termination, a thread may invoke thread_join, which blocks until the target thread exits and returns its result. This can be implemented using a Semaphore initialized with zero permits, where the exiting thread signals completion by releasing a permit.

In contrast, exit_group is used when the entire process must be terminated, bringing down all associated threads by calling thread::kill_by_tid. This is necessary in scenarios such as a fatal error in the main thread, unhandled signals, or explicit process termination by the application. Unlike exit, which only marks the calling thread for termination, exit_group ensures that all threads in the process are promptly and safely terminated, and that the process is cleaned up consistently. This behavior aligns with the semantics of multi-threaded processes in modern operating systems and prevents resource leaks or partial process shutdowns.

Together, these mechanisms provide a simple yet robust model for managing thread life cycles in KeOS, balancing fine-grained control with process-wide coordination.

§Implementation Requirements

You need to implement the followings:

By implementing this section, you can move on to the next section with the final form of execution model that widely used in modern OSes:

+========= Process =========+
| Shared States:            |
|  - MmStruct               |
|  - FileStruct             |
|                           |
| Threads:                  |
|  +----- Thread 1 -----+   |
|  |  - Register State  |   |
|  |  - User Stack      |   |
|  +--------------------+   |
|           ...             |
|  +----- Thread N -----+   |
|  |  - Register State  |   |
|  |  - User Stack      |   |
|  +--------------------+   |
+===========================+

Structs§

Thread
A thread state of project 4, which contains file and memory state.