# How SharpEmu Manages CPU Context Switching in Guest Threads

> Discover how SharpEmu masterfully handles CPU context switching. Learn how it saves and loads guest thread register states for seamless execution.

- Repository: [Berk/sharpemu](https://github.com/par274/sharpemu)
- Tags: internals
- Published: 2026-07-13

---

**SharpEmu performs CPU context switching by saving the complete register state of a guest thread into a `CpuContext` object, then loading that state into the execution engine when the thread resumes.**

SharpEmu is an open-source emulator designed to replicate PlayStation®-style environments, and it implements multi-threaded execution entirely in software. Because the emulator does not rely on hardware virtualization, **CPU context switching** becomes a matter of swapping structured data between managed objects rather than triggering processor-level task switches.

## The CpuContext Data Structure

At the heart of SharpEmu’s threading model lies the **`CpuContext`** class defined in [`src/SharpEmu.HLE/CpuContext.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/CpuContext.cs). This object encapsulates the complete architectural state of a guest CPU, including general-purpose registers (`R0` through `R15`), SIMD registers (`XMM`/`YMM`), the instruction pointer (`RIP`), flags (`RFLAGS`), and segment bases (`FSBASE` and `GSBASE`).

### Register Storage and Access

The `CpuContext` exposes registers through an indexer that maps enum values to an internal array. When SharpEmu performs CPU context switching, it uses this indexer to rapidly copy values between the active execution state and the saved thread state.

```csharp
public ulong this[CpuRegister register]
{
    get => _registers[(int)register];
    set
    {
        _registers[(int)register] = value;
        if (register == CpuRegister.Rax) _raxWritten = true;
    }
}

```

The setter logic includes a special flag for `RAX` writes, which the emulator uses to detect return values after function calls.

### Stack Operations

Before the emulator can safely switch threads, it must ensure the stack state is consistent. The `CpuContext` provides atomic push and pop operations that adjust `RSP` and perform memory writes in a single call:

```csharp
public bool PushUInt64(ulong value)
{
    var rsp = this[CpuRegister.Rsp];
    rsp -= sizeof(ulong);
    this[CpuRegister.Rsp] = rsp;
    return TryWriteUInt64(rsp, value);
}

```

These methods guarantee that when a thread resumes after CPU context switching, its stack pointer and memory contents match the exact state at the point of suspension.

## The Context Switching Workflow

When the `CpuExecutionEngine` needs to move execution from one guest thread to another, it follows a strict four-step sequence:

1. **Save the current thread’s state** – The active `CpuContext` is captured and stored in the current `GuestThreadExecution` instance.
2. **Load the target thread’s state** – The `CpuContext` from the next `GuestThreadExecution` is installed as the active context.
3. **Restore registers and stack** – General-purpose registers, `RIP`, `RSP`, and flags are re-populated from the saved context.
4. **Resume execution** – The engine fetches the next instruction using the restored `RIP` and continues interpreting with the newly loaded registers.

Because the emulator runs as a pure interpreter, no hardware context switch instructions are involved; the operation is simply a structured memory copy between managed objects.

## Thread State Management

The **`GuestThreadExecution`** class (found in [`src/SharpEmu.HLE/GuestThreadExecution.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/GuestThreadExecution.cs)) maintains a dedicated `CpuContext` per thread and exposes explicit methods for state transitions.

### Saving State

Before a thread yields or blocks, `SaveState()` clones the current CPU state into the thread’s private storage:

```csharp
public void SaveState()
{
    _savedContext = new CpuContext(Memory, Generation)
    {
        Rip = this[CpuRegister.Rip],
        Rflags = this[CpuRegister.Rflags],
        Rsp = this[CpuRegister.Rsp],
        // copy remaining registers...
    };
}

```

This captures the exact snapshot required for later restoration.

### Loading State

When the scheduler selects a thread to run, `LoadState()` reverse the process:

```csharp
public void LoadState()
{
    this[CpuRegister.Rip]    = _savedContext.Rip;
    this[CpuRegister.Rflags] = _savedContext.Rflags;
    this[CpuRegister.Rsp]    = _savedContext.Rsp;
    // restore remaining registers...
    ClearRaxWriteFlag();                 // reset RAX-written tracking
}

```

The `ClearRaxWriteFlag()` call ensures that stale return-value flags from previous executions do not interfere with the new context.

## Execution Engine Integration

The **`CpuExecutionEngine`** (located in [`src/SharpEmu.Core/Cpu/CpuExecutionEngine.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Cpu/CpuExecutionEngine.cs)) orchestrates the actual switch by invoking the save and load methods when a thread yields, blocks on a synchronization primitive, or is pre-empted by the scheduler.

```csharp
public void SwitchThread(GuestThreadExecution current, GuestThreadExecution next)
{
    current.SaveState();    // snapshot current CPU registers
    next.LoadState();       // load registers for the next thread
    // execution will continue with next thread's RIP
}

```

After `LoadState()` completes, the `CpuDispatcher` (in [`src/SharpEmu.Core/Cpu/CpuDispatcher.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Cpu/CpuDispatcher.cs)) routes the next decoded instruction using the freshly loaded `CpuContext`, ensuring seamless continuity for the guest application.

## Summary

- SharpEmu implements **CPU context switching** purely in software through the `CpuContext` class, avoiding hardware virtualization requirements.
- The `CpuContext` indexer in [`CpuContext.cs`](https://github.com/par274/sharpemu/blob/main/CpuContext.cs) provides fast register access while tracking `RAX` writes for return-value handling.
- `GuestThreadExecution` manages per-thread state with `SaveState()` and `LoadState()` methods that capture and restore full CPU snapshots.
- Stack consistency is maintained through atomic `PushUInt64` and `PopUInt64` operations that update `RSP` and memory simultaneously.
- The `CpuExecutionEngine` coordinates switches by calling these methods during thread yields, blocks, or pre-emption events.

## Frequently Asked Questions

### What registers are preserved during a context switch in SharpEmu?

SharpEmu preserves all general-purpose registers (`R0` through `R15`), SIMD registers (`XMM`/`YMM`), the instruction pointer (`RIP`), the flags register (`RFLAGS`), and segment bases (`FSBASE` and `GSBASE`). These values are stored in the `CpuContext` object and restored when the thread resumes execution.

### How does SharpEmu handle the stack pointer during CPU context switching?

The stack pointer (`RSP`) is treated as a standard register within the `CpuContext`. During a context switch, the current value is saved via the `SaveState()` method and restored via `LoadState()`. Additionally, the `PushUInt64` and `PopUInt64` helpers ensure that stack memory contents remain synchronized with the pointer value before any switch occurs.

### Why does SharpEmu track RAX writes separately during context switching?

The emulator tracks `RAX` writes using the `_raxWritten` flag to detect when a function return value has been placed in the `RAX` register. This is critical for emulating calling conventions correctly after a context switch, as the `SetReturn` method uses this flag to determine whether the guest thread has completed a function call and produced a result.

### Is hardware assistance used for CPU context switching in SharpEmu?

No. SharpEmu operates as a pure software interpreter. CPU context switching is implemented entirely by copying `CpuContext` objects between threads in managed code. This design choice allows the emulator to run on platforms without hardware virtualization support while maintaining precise control over the guest CPU state.