223 lines
23 KiB
Markdown
223 lines
23 KiB
Markdown
# Native service architecture
|
|
|
|
This document defines the intended user-mode service model for nt-lite. It is an architectural contract, not a description of every detail of the current implementation. Code should move toward this model without introducing temporary service boundaries that are not meant to survive.
|
|
|
|
## Process roles
|
|
|
|
`init.exe` is the kernel-selected bootstrap user process and user-mode service supervisor. Its process identifier is deliberately not an ABI: it happens to be allocated early today, but code, configuration, diagnostics, and personalities must not assume a particular PID for init.
|
|
|
|
`init.exe` is not a UNIX init process: it does not imply a kernel process hierarchy, it does not adopt orphaned processes, and it does not provide reparenting semantics. Holding a process handle for supervision does not make the supervised process a child in a UNIX sense.
|
|
|
|
The intended user-mode system plane has four roles:
|
|
|
|
- `init.exe` owns service lifecycle and authority delegation.
|
|
- `rssrv.exe` is the critical native system server.
|
|
- Session-owned infrastructure such as `dwm.exe` is noncritical and owns bulky policy that should not make RSSRV monolithic.
|
|
- Subsystem-specific personality servers, such as `posixsrv.exe`, are optional and noncritical to the native system.
|
|
|
|
Do not split native input, resource naming, display authority, or console ownership into one service process per subsystem merely to isolate components. nt-lite is a hybrid kernel. RSSRV is intentionally a substantial native server, but it is not the desktop compositor: the desktop window manager and composition engine belong in a separate `dwm.exe` process so window-tree, z-order, damage, decoration, and composition policy can evolve without expanding RSSRV into the whole graphical environment.
|
|
|
|
## Kernel and RSSRV ownership
|
|
|
|
The kernel owns mechanisms that require kernel authority or hardware access. The bootstrap service manager receives explicit manager capabilities for the native resource plane and delegates attenuated input, display, volume, and namespace authority to RSSRV; this authority must not depend on init's PID. This includes:
|
|
|
|
- process and thread execution;
|
|
- virtual memory and sections;
|
|
- object handles and capabilities;
|
|
- ports and other IPC primitives;
|
|
- filesystem and storage drivers;
|
|
- physical input drivers and raw input-device objects;
|
|
- display miniports, low-level display devices, framebuffer or VRAM mappings, and hardware presentation primitives;
|
|
- kernel surfaces and other graphics primitives whose implementation belongs below user-mode policy.
|
|
|
|
RSSRV owns shared native user-mode policy and system-visible logical resources. Its intended responsibilities include:
|
|
|
|
- the global native object namespace;
|
|
- namespace directories, bindings, enumeration, and symbolic links;
|
|
- publication of mounted volumes and other native resources;
|
|
- logical keyboard and mouse ownership above raw device input;
|
|
- keyboard state and layout policy where it does not belong in the hardware driver;
|
|
- logical pointer state, input focus, capture, and routing;
|
|
- native console objects, console buffers, console input, and active-console policy;
|
|
- interactive-session state;
|
|
- the session's display metadata, modeset policy, and transitional console authority;
|
|
- authority and routing used by the session desktop/window manager, without owning the window tree or compositor.
|
|
|
|
RSSRV owns the logical object and its policy; it does not replace the kernel driver or hardware object. For example, a keyboard driver remains a kernel component, while RSSRV consumes normalized key events and owns the logical keyboard state exposed to native user mode.
|
|
|
|
RSSRV should remain internally modular even though its native resource facilities share one process and failure domain. Separate namespace, volume, input, console, session, and display components are preferred over separate user-mode services. Desktop/window/composition policy is the exception: it has enough independent bulk and failure behavior to live in `dwm.exe`.
|
|
|
|
The implemented RSSRV foundation uses one root `RSSRV_STATE` and passes explicit component state to worker threads instead of relying on subsystem globals. The namespace tree lives in `namespace.c`, mounted-volume publication in `volume.c`, resource protocol/listener handling in `resource_service.c`, Session 0 policy in `session.c`, and `rssrv.c` is limited to bootstrap, service control, and component lifetime. RSSRV receives attenuated kernel input-manager and display-manager capabilities in dedicated input/display component state rather than relying on ambient process privilege.
|
|
|
|
Logical input is now an RSSRV-owned facility. The kernel input manager exposes a capability-scoped stream of normalized physical key make/break and relative mouse events. RSSRV consumes that stream, owns key-down/modifier/lock state, performs the initial keyboard-layout character mapping, and owns logical pointer position and mouse-button/wheel state. Session 0 owns routing policy above that logical state: one active target, keyboard focus, ordinary pointer focus, and optional pointer capture. Keyboard and pointer dispatch snapshot the selected target before calling it, so target-specific queues do not share or race the raw logical-input queue. Session 0 owns logical pointer state and routing, while DWM mirrors that authoritative position to the visible hardware cursor through its separately delegated display-manager capability. RSSRV publishes the raw logical listener at `/Services/Input`; normal native applications and the current POSIX/Win32 personality bindings may consume that service through the `NtlInput*` client API, while the console receives a separately routed focused-input queue. The old global input syscalls remain a transitional native ABI for existing callers and contract tests, but they are no longer the canonical interactive input path and should be deleted after those callers migrate.
|
|
|
|
RSSRV owns logical typematic timing for the Session 0 input path. Repeated physical make events are treated as idempotent there so PS/2 hardware repeat and USB HID share one logical repeat policy. The legacy kernel-global input path retains its existing kernel repeat timer only for legacy consumers that have not moved to RSSRV routing.
|
|
|
|
## Desktop window manager
|
|
|
|
`dwm.exe` is the Session 0 desktop window manager and compositor. It is not a personality server and it is not a replacement for RSSRV. RSSRV remains the authority broker for the interactive session: it owns Session 0, logical input routing, console ownership, and the namespace objects through which the session is named. init owns bootstrap delegation of the display-manager capability and splits its rights between RSSRV and DWM.
|
|
|
|
DWM owns graphical policy that would otherwise make RSSRV monolithic:
|
|
|
|
- the desktop and window tree;
|
|
- z-order and visibility;
|
|
- window bounds and decorations;
|
|
- dirty-region aggregation and composition scheduling;
|
|
- composition of client surfaces into the desktop surface;
|
|
- later animation and graphical effects.
|
|
|
|
DWM must not receive ambient display privilege. init delegates an attenuated display-manager capability carrying query, physical-present, and cursor rights only; RSSRV receives the disjoint mode-setting and transitional-console authority it still needs. Mode-setting remains outside DWM unless a later design gives it a concrete reason to own that policy. A DWM crash must not take RSSRV down; native namespace, input, console, and session authority remain alive even if the graphical desktop disappears. DWM becomes eligible for `restart=on-failure` only after its session reconstruction protocol is defined, and then it is subject to the same three-restarts-in-any-sliding-five-minute-window rule as every other restartable managed process.
|
|
|
|
DWM also owns visible pointer presentation policy independently from RSSRV input routing. The native desktop model must support a free cursor, a cursor confined to a desktop/window rectangle, and a relative-pointer lock suitable for games. Relative lock hides and pins the hardware cursor while preserving RSSRV's relative mouse deltas for the captured input target; it must not synthesize motion by repeatedly warping the logical pointer. Cursor visibility is an explicit DWM policy bit rather than a side effect of focus or capture. RSSRV pointer capture chooses the input recipient, while DWM confinement/relative-lock controls only presentation. The later desktop/window protocol will authorize focused clients to request these transitions without granting them DisplayManager cursor authority.
|
|
|
|
## Personality servers
|
|
|
|
A personality server exists only for state or policy that is specific to one application personality and must be shared between processes.
|
|
|
|
Personality servers are not the owners of generic hardware or native session resources. They consume native facilities exposed by the kernel and RSSRV.
|
|
|
|
`posixsrv.exe` may eventually own POSIX-specific shared state such as:
|
|
|
|
- POSIX credentials and supplementary groups;
|
|
- POSIX process-group and session identifiers;
|
|
- cross-process POSIX signal state and routing;
|
|
- the synthetic POSIX filesystem metadata overlay;
|
|
- POSIX FIFO metadata;
|
|
- passwd and group database state.
|
|
|
|
POSIX does not cause the kernel to acquire a UNIX process hierarchy. A POSIX launch relationship may be tracked by the POSIX subsystem when required by an exposed API, but there is no reparenting to a distinguished process and no orphan adoption. In particular, POSIX must not infer special semantics from whatever PID the kernel assigned to `init.exe`.
|
|
|
|
A Win32 personality server should not be created merely for symmetry. If shared Win32-only state eventually requires a server, `winsrv.exe` is the preferred role name. Native console, input, session, and display ownership remains in RSSRV rather than moving into a Win32 server.
|
|
|
|
## Service discovery
|
|
|
|
The numeric kernel system-service registry is bootstrap infrastructure, not the general service namespace.
|
|
|
|
`SYS_SERVICE_RESOURCE` exists so processes can find RSSRV before a higher-level namespace is available. New ordinary services should not receive additional numeric kernel service identifiers merely for discovery.
|
|
|
|
Once RSSRV is available, named services and logical system resources should be published through the RSSRV namespace. A future namespace may contain entries such as:
|
|
|
|
```text
|
|
/
|
|
├── Device
|
|
│ ├── Keyboard0
|
|
│ ├── Mouse0
|
|
│ ├── Display0
|
|
│ └── HarddiskVolume1
|
|
├── Services
|
|
│ ├── Input
|
|
│ ├── Console
|
|
│ └── Posix
|
|
├── Sessions
|
|
│ └── 0
|
|
│ ├── Console
|
|
│ └── Desktop
|
|
├── SystemRoot -> /Device/HarddiskVolume1
|
|
└── Console -> /Sessions/0/Console
|
|
```
|
|
|
|
The current namespace foundation materializes `/Device`, `/Services`, and `/Sessions` as real RSSRV namespace directories. `/SystemRoot` is a real RSSRV symbolic link to the independently published `/Device/HarddiskVolumeN` object for the bootstrap system volume. `/Device/Display0` is a query-only display-manager child capability: init delegates mode-setting and transitional console authority to RSSRV while physical-present and cursor authority are delegated separately to DWM. `/Services/Input` and `/Services/Console` are bound RSSRV listener capabilities for the raw logical-input and native-console protocols. Session 0 is materialized as `/Sessions/0`, with `/Sessions/0/Desktop` reserved for the userspace desktop/window-manager object and `/Sessions/0/Console` bound to the current console listener. `/Console` is a symbolic link to `/Sessions/0/Console`. Namespace directories are enumerable through the resource protocol; native shell `dir` and tab completion use that enumeration rather than synthesizing names from filesystem paths.
|
|
|
|
Names added later are not ABI until code deliberately makes them so. The important rule is that RSSRV is the canonical named namespace after bootstrap.
|
|
|
|
## Service configuration and supervision
|
|
|
|
`init.exe` owns service lifecycle. The mandatory `system/services.ini` file, packaged next to `settings.ini`, defines stable service policy. The kernel does not parse this file. `init.exe` reads it directly through the bootstrap system-volume capability before RSSRV starts, so locating RSSRV never depends on RSSRV itself.
|
|
|
|
The configuration uses case-sensitive `[service.<id>]` sections. Every service section must define all of these keys:
|
|
|
|
```ini
|
|
[service.rssrv]
|
|
type=resource
|
|
image=system/rssrv.exe
|
|
start=auto
|
|
critical=true
|
|
restart=never
|
|
ready_timeout_ms=5000
|
|
stop_timeout_ms=5000
|
|
requires=
|
|
```
|
|
|
|
The parser is deliberately strict. Unknown or duplicate keys, duplicate service identifiers, malformed values, missing required keys, missing dependencies, dependency cycles, and an automatic service depending on a disabled service are fatal configuration errors. The file has no includes, quoting language, environment expansion, continuation lines, or implicit fallback descriptor. A missing or malformed `services.ini` is fatal rather than causing init to fall back to a compiled duplicate of service policy.
|
|
|
|
`type` selects an audited service adapter whose bootstrap authority remains compiled into init. Configuration is not a capability language. In particular, the resource adapter owns the restricted security context and startup capabilities required by RSSRV; `services.ini` cannot grant arbitrary privileges or handles. The generic adapter is intentionally narrow: the service receives only its private service-control listener, runs under the shared unprivileged service context, exports exactly one public Port listener in READY, and init publishes that listener at `/Services/<id>` through RSSRV. Automatic generic services must be noncritical, `restart=never`, and explicitly depend on RSSRV. `posixsrv.exe` is the first consumer of this adapter.
|
|
|
|
Exactly one resource service must be configured. While resource-server reconstruction is unsupported it must be automatic, critical, dependency-free, and `restart=never`. A future implementation may relax only the restart restriction once recovery semantics exist.
|
|
|
|
Managed services use the parsed descriptor and a runtime record. The runtime record owns the current process handle, control connection, and lifecycle state. Service dependencies are resolved to descriptor indices and dependency-first startup order is computed while validating the configuration.
|
|
|
|
The private service-control READY protocol is generic. A READY notification reports a status and the number of transferred export handles; the meaning and expected count of those handles come from the compiled service adapter. RSSRV exports its init-only administrative resource listener plus the Session 0 control listener delegated onward to DWM. DWM exports one desktop listener for init to publish at `/Sessions/0/Desktop`. A generic service exports one public listener for `/Services/<id>`. The protocol does not encode service-specific READY flags.
|
|
|
|
The configured interactive session process is not a managed service. It is launched and observed separately from the service table. `dwm.exe`, by contrast, is an explicit noncritical `[service.dwm]`: it is launched by init in dependency order after RSSRV, receives no ambient security privilege, and exports no machine-global endpoint. Its initial bootstrap owns the visible hardware cursor; later compositor/window protocol work remains session policy inside that same service process.
|
|
|
|
The service manager should remain small. Restart accounting, additional startup capabilities, and recovery policy should be added only where they have a concrete consumer.
|
|
|
|
A service is expected to move through a small set of states such as:
|
|
|
|
```text
|
|
stopped -> starting -> ready -> stopping -> stopped
|
|
\-> failed
|
|
```
|
|
|
|
A service becomes ready only after its authoritative state and exported capabilities are usable. Process creation alone is not readiness.
|
|
|
|
A normal requested stop is not a crash and must not consume restart budget.
|
|
|
|
## Automatic restart policy
|
|
|
|
Automatic restart is opt-in for each service. A service must not be marked restartable until its authoritative state, exported capabilities, and dependent clients have a defined recovery model.
|
|
|
|
When automatic restart is enabled for a failed or crashed service, `init.exe` applies a sliding five-minute restart window:
|
|
|
|
1. Remove recorded automatic-restart timestamps that are at least five minutes old.
|
|
2. If three automatic restarts remain in the window, suppress another automatic restart and leave the service in the failed state.
|
|
3. Otherwise record the new restart attempt and restart the service.
|
|
|
|
This permits at most three automatic restart attempts in any sliding five-minute interval. It is not a fixed five-minute bucket and it does not reset on wall-clock boundaries.
|
|
|
|
A restart attempt is counted when `init.exe` commits to an automatic restart after a failure, not merely when the failed process is observed. Startup failure of the replacement still consumes that attempt.
|
|
|
|
Dependency-driven recovery caused by a service failure counts against the failed service's restart budget. A deliberate stop, shutdown, or explicit administrative start does not count as an automatic restart.
|
|
|
|
The default policy is no automatic restart until reconstruction semantics are defined. In particular, RSSRV is critical and must not be blindly restarted as though its namespace and session state survived. If RSSRV is ever made restartable, recovery must explicitly rebuild the native service plane and any user session state that cannot survive the loss of RSSRV.
|
|
|
|
The three-restarts-in-five-minutes rule is an invariant of `restart=on-failure`, not a configurable knob. The current shipped service set contains no automatically restartable service, so init does not yet need runtime restart accounting. RSSRV is `restart=never`; an unexpected RSSRV exit is a terminal critical-service failure. The interactive session process is not a service and its separate restart behavior is outside this service restart budget.
|
|
|
|
## Failure domains
|
|
|
|
RSSRV is a critical native service because it is intended to own authoritative namespace and session state. Loss of RSSRV is therefore a native service-plane failure, not an ordinary personality failure. If a critical service reaches an unrecoverable failed state, init emits a fatal diagnostic and exits; the kernel already treats unexpected init termination as fatal.
|
|
|
|
Personality servers are noncritical to the native system. Failure of `posixsrv.exe`, for example, may invalidate POSIX shared state and require affected POSIX processes to fail or be terminated, but it must not make native RSSRV facilities unavailable.
|
|
|
|
Clients must not silently treat a newly started service instance as the same stateful server unless the protocol explicitly supports reconstruction. A restarted service instance has a new generation of authoritative state unless a future design specifies otherwise.
|
|
|
|
## Design constraints
|
|
|
|
When extending this model:
|
|
|
|
- keep hardware mechanism in the kernel and shared native user-mode policy in RSSRV;
|
|
- do not create a service merely because a subsystem can be isolated behind IPC;
|
|
- do not duplicate a native resource owner inside multiple personality servers;
|
|
- keep the numeric kernel service registry bootstrap-only;
|
|
- keep service authority capability-based rather than identity checks against process names;
|
|
- define recovery semantics before enabling automatic restart;
|
|
- prefer one canonical path to a service or resource and remove transitional aliases once the real model works.
|
|
|
|
## Native console ownership
|
|
|
|
RSSRV owns the one logical native console used before multi-session support exists. The console is an RSSRV component, not a separate service process. It is published as `/Services/Console` so native clients and personality libraries use one canonical console protocol.
|
|
|
|
The console component currently serializes output, cursor movement, fills, explicit glyph drawing, clear operations, and logical keyboard input. It owns a monotonically increasing content generation and a focused key queue populated by Session 0 routing. The input service remains available for applications that need the raw logical keyboard or pointer stream rather than console semantics.
|
|
|
|
The kernel text console remains a transitional rendering backend. RSSRV reaches it only through the delegated display-manager capability and `SYS_DISPLAY_MANAGER_RIGHT_CONSOLE`; RSSRV does not receive `SYS_PRIV_CONSOLE_ACCESS`. The capability-scoped console bridge exists so normal user applications can migrate away from ambient console syscalls before the kernel text-buffer implementation is removed or reduced to early-boot/panic use.
|
|
|
|
Normal native and personality console code should use `NtlConsole*`. The old `SysWriteConsole`, `SysGetConsoleInfo`, `SysSetConsoleCursor`, fill, clear, and direct glyph syscalls remain supported temporarily for bootstrapping, diagnostics, and regression tests. Their existence is not a commitment to keep two console APIs. Once DWM session/window composition can replace the kernel's interactive text-console path, remaining ordinary callers should move and the stale ambient syscalls should be deleted.
|
|
|
|
Session 0 now exists as explicit RSSRV state. The console registers a stable in-process input target with that session and is the initial active target, keyboard focus, and pointer focus. Pointer capture is represented separately so the later userspace window manager can capture pointer delivery without changing the raw input service or console protocol. The console owns its own focused key queue; `/Services/Input` remains a raw logical observer queue rather than competing with console reads for the same records.
|
|
|
|
`/Services/Console` names the process-independent console protocol, `/Sessions/0/Console` names the Session 0 instance, and `/Console` is the convenience symbolic link to the current session console. `/Sessions/0/Desktop` is currently only a namespace directory; the later DWM phase will replace that placeholder with the first real desktop policy object.
|
|
|
|
Display authority is split explicitly at bootstrap. RSSRV retains mode-setting and transitional console rights, while init delegates physical-present and hardware-cursor rights to the noncritical DWM service. The published `/Device/Display0` capability remains intentionally query-only. Neither RSSRV nor ordinary applications need ambient `SYS_PRIV_DISPLAY_ACCESS` for the normal path.
|
|
|
|
Kernel surfaces are now shareable capability-backed pixel storage rather than process-private presentation objects. A surface may have multiple independent VAD mappings in one or more processes; mapping rights distinguish read-only compositor access from client write access. `SysCommitSurface` records clipped damage, increments a content generation, and signals the waitable surface object without touching physical scanout. Surface wakeups are deliberately coalescing: consumers use the generation to detect skipped commits, and `LastDamageBounds` describes only the most recent commit rather than an acknowledged damage queue. The later DWM window protocol will carry the compositor's authoritative dirty-region submission. `SysPresentDisplayManagerSurface` is the capability-scoped physical-present path intended for DWM. The old ambient `SysPresentSurface` API and its handle right are deleted. Ordinary clients can create, map, share, wait on, and commit surfaces but cannot touch physical scanout. `SysPresentDisplayManagerSurface` is the only surface-to-scanout path and requires an explicitly delegated DisplayManager PRESENT capability.
|