How SharpEmu Handles Fiber Exports: PS4 Fiber API Implementation in C#
SharpEmu implements the PlayStation 4 Fiber API (libSceFiber) through a static FiberExports class that manages fiber initialization, context switching, and lifecycle operations in pure managed C#.
The par274/sharpemu repository provides a complete managed implementation of Sony's fiber-based concurrency primitives. All fiber-related system calls route through the FiberExports static class in src/SharpEmu.Libs/Fiber/FiberExports.cs, which emulates the PS4 ABI while maintaining thread-safe execution within the emulator's runtime.
Overview of FiberExports Architecture
The FiberExports class serves as the central dispatch point for all libSceFiber operations. Unlike traditional thread-based concurrency, fibers (or "user-mode scheduling" contexts) require explicit management of execution state, stack ranges, and continuation chains.
The implementation maintains a thread-static _currentFiberAddress field that tracks which fiber is currently executing on each host thread. When a fiber transfer occurs, the FiberRunCore method updates both this thread-local storage and the global GuestThreadExecution.CurrentFiberAddress property. This dual-tracking mechanism allows other kernel modules—such as KernelRuntimeCompatExports and KernelEventFlagCompatExports—to query fiber state for diagnostic logging without disrupting execution.
Fiber Lifecycle Implementation
Initialization via FiberInitializeCore
Fiber creation begins with sceFiberInitialize or sceFiberInitializeWithInternalOption, both of which delegate to FiberInitializeCore.
In src/SharpEmu.Libs/Fiber/FiberExports.cs (lines 34-61), this method performs the following operations:
- Validates the supplied stack address and size (minimum 512 bytes)
- Writes a signature to the fiber structure for integrity checking
- Stores the entry point, fiber name, and optional argument
- Registers the fiber's stack range with the memory subsystem
// Example: Initialize a fiber with a guest-allocated stack
ulong entryPoint = 0x100000000; // Guest function address
ulong stackAddr = 0x7ff00000; // Guest stack pointer
ulong stackSize = 0x20000; // 128KB stack (>= 512 minimum)
int result = FiberExports.FiberInitialize(ctx);
if (result != 0)
throw new Exception($"Fiber init failed: 0x{result:X8}");
Execution and Context Switching via FiberRunCore
All fiber execution paths—sceFiberRun, sceFiberSwitch, sceFiberAttachContextAndRun, and sceFiberAttachContextAndSwitch—funnel into the FiberRunCore method (lines 38-60).
This routine handles the complex state transitions required by the PS4 ABI:
- Validates the target fiber structure and signature
- Verifies the caller's current fiber state matches the requested operation (run vs. switch)
- Creates or restores a continuation context
- Updates the previous fiber's state to "suspended"
- Transfers execution via
GuestThreadExecution.RequestCurrentContextTransfer
The optional "context attachment" variants (sceFiberAttachContextAndRun and sceFiberAttachContextAndSwitch) allow callers to pass additional context buffers that the emulator validates and stores alongside the fiber state.
// Example: Run a fiber (transfers execution to guest entry point)
int result = FiberExports.FiberRun(ctx);
if (result != 0)
throw new Exception($"Fiber run failed: 0x{result:X8}");
// Example: Switch to an already-running fiber
ulong targetFiber = 0x8ff00000; // Address of target fiber structure
int switchResult = FiberExports.FiberSwitch(ctx);
if (switchResult != 0)
Console.WriteLine($"Switch error: 0x{switchResult:X8}");
Finalization via FiberFinalize
When a fiber completes execution, sceFiberFinalize (lines 24-48) performs cleanup:
- Verifies the fiber is in an idle state
- Removes continuation chains and return-target entries
- Unregisters the stack range
- Marks the fiber structure as terminated
Current Fiber Tracking and Diagnostics
SharpEmu provides diagnostic visibility into fiber execution through GetCurrentFiberAddressForDiagnostics. This method forwards to ResolveCurrentFiberAddress, which implements a three-tier lookup strategy:
- Checks the thread-static
_currentFiberAddress - Falls back to the global
GuestThreadExecution.CurrentFiberAddress - Performs a stack scan as last resort
Other kernel modules consume this API for debugging purposes. In src/SharpEmu.Libs/Kernel/KernelRuntimeCompatExports.cs, the emulator prints the current fiber when handling runtime-related calls. Similarly, KernelEventFlagCompatExports.cs logs the fiber address during event-flag wait operations.
// Example: Query current fiber for debugging
ulong current = FiberExports.GetCurrentFiberAddressForDiagnostics(ctx);
Console.WriteLine($"Current fiber address: 0x{current:X16}");
Error Handling and Validation
The implementation returns PS4-style error codes (0 for success, 0x8059xxxx for specific failures). Validation helpers such as TryValidateFiber and TryReadFiberFields centralize checks for:
- Structure alignment requirements
- Magic signature verification
- Valid state transitions (e.g., preventing run on an already-running fiber)
- Stack size minimums (512 bytes)
These validation routines ensure that malformed fiber operations fail before corrupting emulator state, matching the defensive behavior of the actual PS4 kernel.
Summary
- SharpEmu Fiber exports are implemented in the static
FiberExportsclass atsrc/SharpEmu.Libs/Fiber/FiberExports.cs - Fiber lifecycle moves through initialization (
FiberInitializeCore), execution (FiberRunCore), and finalization (FiberFinalize) - Context switching uses
GuestThreadExecution.RequestCurrentContextTransferto transfer control between fibers - Thread-local tracking via
_currentFiberAddressenables diagnostic queries from other kernel modules - PS4-compliant error codes (
0x8059xxxx) provide accurate compatibility for games relying onlibSceFiber
Frequently Asked Questions
How does SharpEmu track which fiber is currently executing?
SharpEmu uses a thread-static _currentFiberAddress field that is updated whenever FiberRunCore enters a new fiber. The GetCurrentFiberAddressForDiagnostics method first checks this thread-local value, then falls back to a global variable, and finally performs a stack scan if necessary. This hierarchy allows other kernel modules to query fiber state without synchronization overhead.
What is the difference between FiberRun and FiberSwitch in SharpEmu?
Both methods delegate to FiberRunCore, but they enforce different state validation rules. FiberRun expects the target fiber to be uninitialized or finalized, while FiberSwitch expects an active fiber that is currently suspended. The distinction ensures that games cannot accidentally launch a fiber twice or switch to a terminated context.
Which files handle the actual fiber context transfer?
While FiberExports.cs manages the high-level fiber logic, the actual CPU context transfer occurs in src/SharpEmu.Core/GuestThreadExecution.cs through the RequestCurrentContextTransfer method. This separation keeps the fiber state machine in the HLE (High-Level Emulation) layer while delegating low-level execution to the core runtime.
What error codes does SharpEmu return for invalid fiber operations?
SharpEmu returns standard PS4 error codes in the 0x8059xxxx range. Common failures include invalid alignment, signature mismatches, incorrect fiber states (e.g., attempting to run an already-running fiber), and stack size violations below the 512-byte minimum. These codes match the actual libSceFiber implementation to ensure game compatibility.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →