⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/services/
init_system.rs

1//! Init System Implementation
2//!
3//! The init process (PID 1) that starts all system services and manages the
4//! system lifecycle.
5
6#![allow(clippy::if_same_then_else)]
7
8use alloc::{collections::BTreeMap, string::String, vec, vec::Vec};
9use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
10
11use spin::RwLock;
12
13use crate::{error::KernelError, process::ProcessId};
14
15/// Service state
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum ServiceState {
18    Stopped,
19    Starting,
20    Running,
21    Stopping,
22    Failed,
23    Restarting,
24}
25
26/// Service restart policy
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum RestartPolicy {
29    Never,         // Never restart
30    OnFailure,     // Restart only on failure
31    Always,        // Always restart when service stops
32    UnlessStopped, // Restart unless explicitly stopped
33}
34
35/// Service dependency type
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum DependencyType {
38    Requires, // Service must be running
39    Wants,    // Service should be running if possible
40    After,    // Start after this service
41    Before,   // Start before this service
42}
43
44/// Service definition
45#[derive(Debug, Clone)]
46pub struct ServiceDefinition {
47    pub name: String,
48    pub description: String,
49    pub command: String,
50    pub arguments: Vec<String>,
51    pub environment: Vec<String>,
52    pub working_directory: String,
53    pub user: u32,
54    pub group: u32,
55    pub restart_policy: RestartPolicy,
56    pub restart_delay_ms: u32,
57    pub max_restarts: u32,
58    pub timeout_ms: u32,
59    pub dependencies: Vec<(String, DependencyType)>,
60    pub start_level: u32,          // 0-99, lower starts first
61    pub stop_timeout: Option<u32>, // Seconds to wait before SIGKILL (default: 10)
62}
63
64/// Service runtime information
65#[derive(Debug, Clone)]
66pub struct ServiceInfo {
67    pub definition: ServiceDefinition,
68    pub state: ServiceState,
69    pub pid: Option<ProcessId>,
70    pub start_time: u64,
71    pub restart_count: u32,
72    pub exit_code: Option<i32>,
73    pub last_error: Option<String>,
74}
75
76/// Runlevel definition
77#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
78pub enum Runlevel {
79    Halt = 0,      // System halt
80    Single = 1,    // Single user mode
81    Multi = 2,     // Multi-user without networking
82    Network = 3,   // Multi-user with networking
83    Reserved = 4,  // Reserved
84    Graphical = 5, // Multi-user with networking and GUI
85    Reboot = 6,    // System reboot
86}
87
88/// Init system manager
89pub struct InitSystem {
90    /// Registered services
91    services: RwLock<BTreeMap<String, ServiceInfo>>,
92
93    /// Current runlevel
94    current_runlevel: AtomicU32,
95
96    /// Target runlevel
97    target_runlevel: AtomicU32,
98
99    /// System is shutting down
100    shutting_down: AtomicBool,
101
102    /// Init process PID
103    init_pid: AtomicU32,
104
105    /// Service start order (computed from dependencies)
106    start_order: RwLock<Vec<String>>,
107
108    /// Service monitoring thread running
109    monitoring_active: AtomicBool,
110}
111
112impl InitSystem {
113    /// Create a new init system
114    pub fn new() -> Self {
115        Self {
116            services: RwLock::new(BTreeMap::new()),
117            current_runlevel: AtomicU32::new(Runlevel::Halt as u32),
118            target_runlevel: AtomicU32::new(Runlevel::Multi as u32),
119            shutting_down: AtomicBool::new(false),
120            init_pid: AtomicU32::new(1),
121            start_order: RwLock::new(Vec::new()),
122            monitoring_active: AtomicBool::new(false),
123        }
124    }
125}
126
127impl Default for InitSystem {
128    fn default() -> Self {
129        Self::new()
130    }
131}
132
133impl InitSystem {
134    /// Initialize the init system
135    pub fn initialize(&self) -> Result<(), KernelError> {
136        crate::println!("[INIT] Initializing init system...");
137
138        // Register core system services
139        self.register_core_services()?;
140
141        // Compute service start order
142        self.compute_start_order()?;
143
144        // Start service monitoring
145        self.monitoring_active.store(true, Ordering::SeqCst);
146
147        // Switch to runlevel 1 (single user)
148        self.switch_runlevel(Runlevel::Single)?;
149
150        crate::println!("[INIT] Init system initialized");
151        Ok(())
152    }
153
154    /// Register a service
155    pub fn register_service(&self, definition: ServiceDefinition) -> Result<(), KernelError> {
156        let name = definition.name.clone();
157
158        if self.services.read().contains_key(&name) {
159            return Err(KernelError::AlreadyExists {
160                resource: "service",
161                id: 0,
162            });
163        }
164
165        let info = ServiceInfo {
166            definition,
167            state: ServiceState::Stopped,
168            pid: None,
169            start_time: 0,
170            restart_count: 0,
171            exit_code: None,
172            last_error: None,
173        };
174
175        self.services.write().insert(name.clone(), info);
176        crate::println!("[INIT] Registered service: {}", name);
177
178        // Recompute start order
179        self.compute_start_order()?;
180
181        Ok(())
182    }
183
184    /// Start a service
185    pub fn start_service(&self, name: &str) -> Result<(), KernelError> {
186        let mut services = self.services.write();
187
188        let service = services.get_mut(name).ok_or(KernelError::NotFound {
189            resource: "service",
190            id: 0,
191        })?;
192
193        if service.state == ServiceState::Running {
194            return Ok(()); // Already running
195        }
196
197        crate::println!("[INIT] Starting service: {}", name);
198        service.state = ServiceState::Starting;
199
200        // Check dependencies
201        drop(services); // Release lock for dependency check
202        self.check_dependencies(name)?;
203        let mut services = self.services.write();
204        let service = services
205            .get_mut(name)
206            .expect("service disappeared between dependency check and start");
207
208        // Create process for service
209        let process_server = crate::services::process_server::get_process_server();
210
211        let pid = process_server.create_process(
212            ProcessId(self.init_pid.load(Ordering::SeqCst) as u64),
213            service.definition.command.clone(),
214            service.definition.user,
215            service.definition.group,
216            {
217                let mut args = vec![service.definition.command.clone()];
218                args.extend(service.definition.arguments.clone());
219                args
220            },
221            service.definition.environment.clone(),
222        )?;
223
224        service.pid = Some(pid);
225        service.state = ServiceState::Running;
226        service.start_time = self.get_system_time();
227        service.last_error = None;
228
229        crate::println!("[INIT] Service {} started with PID {}", name, pid.0);
230        Ok(())
231    }
232
233    /// Stop a service
234    pub fn stop_service(&self, name: &str) -> Result<(), KernelError> {
235        let mut services = self.services.write();
236
237        let service = services.get_mut(name).ok_or(KernelError::NotFound {
238            resource: "service",
239            id: 0,
240        })?;
241
242        if service.state != ServiceState::Running {
243            return Ok(()); // Not running
244        }
245
246        crate::println!("[INIT] Stopping service: {}", name);
247        service.state = ServiceState::Stopping;
248
249        if let Some(pid) = service.pid {
250            let process_server = crate::services::process_server::get_process_server();
251
252            // Send SIGTERM
253            process_server.send_signal(pid, 15)?;
254
255            // Wait for process to exit with timeout
256            let timeout_secs = service.definition.stop_timeout.unwrap_or(10) as u64;
257            let start = crate::arch::timer::get_timestamp_secs();
258
259            loop {
260                // Check if process has exited
261                if process_server.wait_for_child(pid, None).is_ok() {
262                    break; // Process exited
263                }
264
265                // Check timeout
266                let elapsed = crate::arch::timer::get_timestamp_secs().saturating_sub(start);
267                if elapsed >= timeout_secs {
268                    // Timeout: send SIGKILL
269                    crate::println!(
270                        "[INIT] Service {} did not stop within {}s, sending SIGKILL",
271                        name,
272                        timeout_secs
273                    );
274                    if let Err(_e) = process_server.send_signal(pid, 9) {
275                        crate::println!(
276                            "[INIT] Warning: SIGKILL to PID {} failed: {:?}",
277                            pid.0,
278                            _e
279                        );
280                    }
281                    break;
282                }
283
284                core::hint::spin_loop();
285            }
286
287            service.state = ServiceState::Stopped;
288            service.pid = None;
289
290            crate::println!("[INIT] Service {} stopped", name);
291        }
292
293        Ok(())
294    }
295
296    /// Restart a service
297    pub fn restart_service(&self, name: &str) -> Result<(), KernelError> {
298        self.stop_service(name)?;
299        self.start_service(name)?;
300        Ok(())
301    }
302
303    /// Get service status
304    pub fn get_service_status(&self, name: &str) -> Option<ServiceInfo> {
305        self.services.read().get(name).cloned()
306    }
307
308    /// List all services
309    pub fn list_services(&self) -> Vec<ServiceInfo> {
310        self.services.read().values().cloned().collect()
311    }
312
313    /// Switch runlevel
314    pub fn switch_runlevel(&self, runlevel: Runlevel) -> Result<(), KernelError> {
315        let current = self.current_runlevel.load(Ordering::SeqCst);
316
317        if current == runlevel as u32 {
318            return Ok(()); // Already at target runlevel
319        }
320
321        crate::println!(
322            "[INIT] Switching from runlevel {} to {}",
323            current,
324            runlevel as u32
325        );
326        self.target_runlevel
327            .store(runlevel as u32, Ordering::SeqCst);
328
329        // Stop services not needed in new runlevel
330        let services_to_stop =
331            self.get_services_for_runlevel_transition(current, runlevel as u32, false);
332
333        for service_name in services_to_stop {
334            self.stop_service(&service_name).ok();
335        }
336
337        // Start services needed in new runlevel
338        let services_to_start =
339            self.get_services_for_runlevel_transition(current, runlevel as u32, true);
340
341        for service_name in services_to_start {
342            self.start_service(&service_name).ok();
343        }
344
345        self.current_runlevel
346            .store(runlevel as u32, Ordering::SeqCst);
347        crate::println!("[INIT] Switched to runlevel {}", runlevel as u32);
348
349        Ok(())
350    }
351
352    /// Handle service exit
353    pub fn handle_service_exit(&self, pid: ProcessId, exit_code: i32) {
354        let mut services = self.services.write();
355
356        // Find service by PID
357        for service in services.values_mut() {
358            if service.pid == Some(pid) {
359                crate::println!(
360                    "[INIT] Service {} exited with code {}",
361                    service.definition.name,
362                    exit_code
363                );
364
365                service.state = ServiceState::Stopped;
366                service.pid = None;
367                service.exit_code = Some(exit_code);
368
369                // Check restart policy
370                let should_restart = match service.definition.restart_policy {
371                    RestartPolicy::Never => false,
372                    RestartPolicy::OnFailure => exit_code != 0,
373                    RestartPolicy::Always => !self.shutting_down.load(Ordering::SeqCst),
374                    RestartPolicy::UnlessStopped => {
375                        !self.shutting_down.load(Ordering::SeqCst)
376                            && service.state != ServiceState::Stopped
377                    }
378                };
379
380                if should_restart && service.restart_count < service.definition.max_restarts {
381                    service.state = ServiceState::Restarting;
382                    service.restart_count += 1;
383                    // Exponential backoff: base_delay * 2^min(count, 5)
384                    let base_delay_ms = service.definition.restart_delay_ms as u64;
385                    let exponent = core::cmp::min(service.restart_count, 5);
386                    let delay_ms = base_delay_ms.saturating_mul(1u64 << exponent);
387                    crate::println!(
388                        "[INIT] Scheduling restart for service {} (attempt {}, delay {}ms)",
389                        service.definition.name,
390                        service.restart_count,
391                        delay_ms
392                    );
393                    // Approximate delay via timer-based wait
394                    let target = crate::arch::timer::get_timestamp_ms().saturating_add(delay_ms);
395                    let svc_name = service.definition.name.clone();
396                    drop(services); // Release lock before spinning
397                                    // Wait until delay elapsed
398                    while crate::arch::timer::get_timestamp_ms() < target {
399                        core::hint::spin_loop();
400                    }
401                    // Restart the service
402                    if let Err(_e) = self.start_service(&svc_name) {
403                        crate::println!(
404                            "[INIT] Warning: failed to restart service {}: {:?}",
405                            svc_name,
406                            _e
407                        );
408                    }
409                    return; // services lock was dropped
410                } else if service.restart_count >= service.definition.max_restarts {
411                    service.state = ServiceState::Failed;
412                    service.last_error = Some(String::from("Max restart attempts exceeded"));
413                }
414
415                break;
416            }
417        }
418    }
419
420    /// Shutdown the system
421    pub fn shutdown(&self) -> Result<(), KernelError> {
422        crate::println!("[INIT] System shutdown initiated");
423        self.shutting_down.store(true, Ordering::SeqCst);
424
425        // Stop monitoring
426        self.monitoring_active.store(false, Ordering::SeqCst);
427
428        // Switch to runlevel 0 (halt)
429        self.switch_runlevel(Runlevel::Halt)?;
430
431        // Stop all remaining services in reverse order
432        let services: Vec<String> = self.start_order.read().iter().rev().cloned().collect();
433        for service_name in services {
434            self.stop_service(&service_name).ok();
435        }
436
437        crate::println!("[INIT] System shutdown complete");
438        Ok(())
439    }
440
441    /// Reboot the system
442    pub fn reboot(&self) -> Result<(), KernelError> {
443        crate::println!("[INIT] System reboot initiated");
444
445        // Shutdown first
446        self.shutdown()?;
447
448        // Switch to runlevel 6 (reboot)
449        self.switch_runlevel(Runlevel::Reboot)?;
450
451        crate::println!("[INIT] System rebooting...");
452
453        // Architecture-specific reboot
454        #[cfg(target_arch = "x86_64")]
455        {
456            // Pulse the keyboard controller reset line (port 0xFE to 0x64)
457            // SAFETY: Writing 0xFE to keyboard controller port 0x64 triggers a system
458            // reset.
459            unsafe {
460                use x86_64::instructions::port::Port;
461                let mut port: Port<u8> = Port::new(0x64);
462                port.write(0xFE);
463            }
464        }
465
466        #[cfg(target_arch = "aarch64")]
467        {
468            // PSCI SYSTEM_RESET (function ID 0x84000009)
469            // SAFETY: Invoking PSCI SYSTEM_RESET via HVC; does not return on success.
470            unsafe {
471                core::arch::asm!("ldr x0, =0x84000009", "hvc #0", options(nomem, nostack));
472            }
473        }
474
475        #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
476        {
477            // SBI system reset (SRST extension, function 0)
478            // SAFETY: Invoking SBI SRST ecall to reset the system; does not return on
479            // success.
480            unsafe {
481                core::arch::asm!(
482                    "li a7, 0x53525354", // SRST extension ID
483                    "li a6, 0",          // Function 0: system_reset
484                    "li a0, 0",          // Reset type: shutdown
485                    "li a1, 0",          // Reason: no reason
486                    "ecall",
487                    options(nomem, nostack)
488                );
489            }
490        }
491
492        Ok(())
493    }
494
495    // Helper functions
496
497    fn register_core_services(&self) -> Result<(), KernelError> {
498        // Register console service
499        self.register_service(ServiceDefinition {
500            name: String::from("console"),
501            description: String::from("System Console"),
502            command: String::from("/sbin/getty"),
503            arguments: vec![String::from("tty0")],
504            environment: vec![],
505            working_directory: String::from("/"),
506            user: 0,
507            group: 0,
508            restart_policy: RestartPolicy::Always,
509            restart_delay_ms: 1000,
510            max_restarts: 5,
511            timeout_ms: 5000,
512            dependencies: vec![],
513            start_level: 10,
514            stop_timeout: None,
515        })?;
516
517        // Register logger service
518        self.register_service(ServiceDefinition {
519            name: String::from("logger"),
520            description: String::from("System Logger"),
521            command: String::from("/sbin/syslogd"),
522            arguments: vec![],
523            environment: vec![],
524            working_directory: String::from("/"),
525            user: 0,
526            group: 0,
527            restart_policy: RestartPolicy::Always,
528            restart_delay_ms: 1000,
529            max_restarts: 5,
530            timeout_ms: 5000,
531            dependencies: vec![],
532            start_level: 5,
533            stop_timeout: None,
534        })?;
535
536        // Register device manager
537        self.register_service(ServiceDefinition {
538            name: String::from("devmgr"),
539            description: String::from("Device Manager"),
540            command: String::from("/sbin/devmgr"),
541            arguments: vec![],
542            environment: vec![],
543            working_directory: String::from("/"),
544            user: 0,
545            group: 0,
546            restart_policy: RestartPolicy::OnFailure,
547            restart_delay_ms: 2000,
548            max_restarts: 3,
549            timeout_ms: 10000,
550            dependencies: vec![(String::from("logger"), DependencyType::After)],
551            start_level: 15,
552            stop_timeout: None,
553        })?;
554
555        // Register network service
556        self.register_service(ServiceDefinition {
557            name: String::from("network"),
558            description: String::from("Network Service"),
559            command: String::from("/sbin/netd"),
560            arguments: vec![],
561            environment: vec![],
562            working_directory: String::from("/"),
563            user: 0,
564            group: 0,
565            restart_policy: RestartPolicy::OnFailure,
566            restart_delay_ms: 3000,
567            max_restarts: 3,
568            timeout_ms: 30000,
569            dependencies: vec![
570                (String::from("devmgr"), DependencyType::Requires),
571                (String::from("logger"), DependencyType::After),
572            ],
573            start_level: 20,
574            stop_timeout: None,
575        })?;
576
577        // Register firewall service
578        self.register_service(ServiceDefinition {
579            name: String::from("firewall"),
580            description: String::from("Packet Filter Firewall"),
581            command: String::from("/sbin/fwd"),
582            arguments: vec![],
583            environment: vec![],
584            working_directory: String::from("/"),
585            user: 0,
586            group: 0,
587            restart_policy: RestartPolicy::OnFailure,
588            restart_delay_ms: 3000,
589            max_restarts: 3,
590            timeout_ms: 30000,
591            dependencies: vec![(String::from("network"), DependencyType::After)],
592            start_level: 18,
593            stop_timeout: None,
594        })?;
595
596        // Register DNS resolver service
597        self.register_service(ServiceDefinition {
598            name: String::from("dns-resolver"),
599            description: String::from("DNS Resolver"),
600            command: String::from("/sbin/resolved"),
601            arguments: vec![],
602            environment: vec![],
603            working_directory: String::from("/"),
604            user: 0,
605            group: 0,
606            restart_policy: RestartPolicy::OnFailure,
607            restart_delay_ms: 3000,
608            max_restarts: 3,
609            timeout_ms: 30000,
610            dependencies: vec![(String::from("network"), DependencyType::Requires)],
611            start_level: 22,
612            stop_timeout: None,
613        })?;
614
615        // Register NTP time sync service
616        self.register_service(ServiceDefinition {
617            name: String::from("ntp"),
618            description: String::from("NTP Time Sync"),
619            command: String::from("/sbin/ntpd"),
620            arguments: vec![],
621            environment: vec![],
622            working_directory: String::from("/"),
623            user: 0,
624            group: 0,
625            restart_policy: RestartPolicy::OnFailure,
626            restart_delay_ms: 3000,
627            max_restarts: 3,
628            timeout_ms: 30000,
629            dependencies: vec![(String::from("network"), DependencyType::After)],
630            start_level: 25,
631            stop_timeout: None,
632        })?;
633
634        // Register SSH server service
635        self.register_service(ServiceDefinition {
636            name: String::from("ssh"),
637            description: String::from("SSH Server"),
638            command: String::from("/sbin/sshd"),
639            arguments: vec![],
640            environment: vec![],
641            working_directory: String::from("/"),
642            user: 0,
643            group: 0,
644            restart_policy: RestartPolicy::OnFailure,
645            restart_delay_ms: 3000,
646            max_restarts: 3,
647            timeout_ms: 30000,
648            dependencies: vec![(String::from("network"), DependencyType::After)],
649            start_level: 30,
650            stop_timeout: None,
651        })?;
652
653        Ok(())
654    }
655
656    fn compute_start_order(&self) -> Result<(), KernelError> {
657        let services = self.services.read();
658        let mut order = Vec::new();
659        let mut visited = BTreeMap::new();
660
661        // Topological sort based on dependencies and start levels
662        let mut sorted_services: Vec<_> = services.keys().cloned().collect();
663        sorted_services.sort_by_key(|name| {
664            services
665                .get(name)
666                .map(|s| s.definition.start_level)
667                .unwrap_or(99)
668        });
669
670        for service_name in sorted_services {
671            if !visited.contains_key(&service_name) {
672                self.visit_service(&service_name, &services, &mut visited, &mut order)?;
673            }
674        }
675
676        *self.start_order.write() = order;
677        Ok(())
678    }
679
680    fn visit_service(
681        &self,
682        name: &str,
683        services: &BTreeMap<String, ServiceInfo>,
684        visited: &mut BTreeMap<String, bool>,
685        order: &mut Vec<String>,
686    ) -> Result<(), KernelError> {
687        if let Some(&in_progress) = visited.get(name) {
688            if in_progress {
689                return Err(KernelError::InvalidArgument {
690                    name: "service dependency",
691                    value: "circular dependency detected",
692                });
693            }
694            return Ok(()); // Already visited
695        }
696
697        visited.insert(name.into(), true);
698
699        if let Some(service) = services.get(name) {
700            // Visit dependencies first
701            for (dep_name, dep_type) in &service.definition.dependencies {
702                if matches!(dep_type, DependencyType::Requires | DependencyType::After) {
703                    self.visit_service(dep_name, services, visited, order)?;
704                }
705            }
706        }
707
708        visited.insert(name.into(), false);
709        order.push(name.into());
710        Ok(())
711    }
712
713    fn check_dependencies(&self, name: &str) -> Result<(), KernelError> {
714        let services = self.services.read();
715
716        if let Some(service) = services.get(name) {
717            for (dep_name, dep_type) in &service.definition.dependencies {
718                if *dep_type == DependencyType::Requires {
719                    if let Some(dep_service) = services.get(dep_name) {
720                        if dep_service.state != ServiceState::Running {
721                            return Err(KernelError::InvalidState {
722                                expected: "running",
723                                actual: "not running",
724                            });
725                        }
726                    } else {
727                        return Err(KernelError::NotFound {
728                            resource: "required dependency",
729                            id: 0,
730                        });
731                    }
732                }
733            }
734        }
735
736        Ok(())
737    }
738
739    fn get_services_for_runlevel_transition(
740        &self,
741        _from: u32,
742        to: u32,
743        start: bool,
744    ) -> Vec<String> {
745        let services = self.services.read();
746        let mut result = Vec::new();
747
748        for (name, service) in services.iter() {
749            let should_run = match to {
750                0 => false,                                // Halt - stop everything
751                1 => service.definition.start_level <= 10, // Single user - basic services
752                2 => service.definition.start_level <= 30, // Multi without network
753                3 => service.definition.start_level <= 50, // Multi with network
754                5 => true,                                 // Graphical - everything
755                6 => false,                                // Reboot - stop everything
756                _ => service.definition.start_level <= 30,
757            };
758
759            if start && should_run && service.state != ServiceState::Running {
760                result.push(name.clone());
761            } else if !start && !should_run && service.state == ServiceState::Running {
762                result.push(name.clone());
763            }
764        }
765
766        if start {
767            // Sort by start order
768            let order = self.start_order.read();
769            result.sort_by_key(|name| order.iter().position(|n| n == name).unwrap_or(999));
770        } else {
771            // Reverse order for stopping
772            result.reverse();
773        }
774
775        result
776    }
777
778    fn get_system_time(&self) -> u64 {
779        crate::arch::timer::get_timestamp_secs()
780    }
781}
782
783/// Global init system using OnceLock for safe initialization.
784static INIT_SYSTEM: crate::sync::once_lock::OnceLock<InitSystem> =
785    crate::sync::once_lock::OnceLock::new();
786
787/// Initialize the init system
788pub fn init() {
789    #[allow(unused_imports)]
790    use crate::println;
791
792    println!("[INIT] Creating new InitSystem...");
793    match INIT_SYSTEM.set(InitSystem::new()) {
794        Ok(()) => println!("[INIT] Init system module loaded"),
795        Err(_) => println!("[INIT] Already initialized, skipping..."),
796    }
797}
798
799/// Try to get the global init system without panicking.
800///
801/// Returns `None` if the init system has not been initialized via [`init`].
802pub fn try_get_init_system() -> Option<&'static InitSystem> {
803    INIT_SYSTEM.get()
804}
805
806/// Get the global init system.
807///
808/// Panics if the init system has not been initialized via [`init`].
809/// Prefer [`try_get_init_system`] in contexts where a panic is unacceptable.
810pub fn get_init_system() -> &'static InitSystem {
811    INIT_SYSTEM
812        .get()
813        .expect("Init system not initialized: init() was not called")
814}
815
816/// Run the init process
817pub fn run_init() -> ! {
818    let init_system = get_init_system();
819
820    // Initialize the system
821    init_system
822        .initialize()
823        .expect("Failed to initialize init system");
824
825    // Switch to multi-user mode
826    init_system
827        .switch_runlevel(Runlevel::Multi)
828        .expect("Failed to switch to multi-user mode");
829
830    // Main init loop - wait for child processes and handle events
831    loop {
832        // Check for exited children
833        let process_server = crate::services::process_server::get_process_server();
834
835        // Try to reap any zombie children
836        while let Ok((child_pid, exit_code)) = process_server.wait_for_child(ProcessId(1), None) {
837            init_system.handle_service_exit(child_pid, exit_code);
838        }
839
840        // Clean up any orphaned zombies
841        process_server.reap_zombies();
842
843        // Sleep for ~100ms using timer-based delay then arch halt
844        let wake_time = crate::arch::timer::get_timestamp_ms().saturating_add(100);
845        while crate::arch::timer::get_timestamp_ms() < wake_time {
846            // Use architecture-specific halt/wfi to avoid burning CPU
847            #[cfg(target_arch = "x86_64")]
848            x86_64::instructions::hlt();
849
850            #[cfg(target_arch = "aarch64")]
851            // SAFETY: WFI halts the core until the next interrupt; no memory or state side effects.
852            unsafe {
853                core::arch::asm!("wfi", options(nomem, nostack));
854            }
855
856            #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
857            // SAFETY: WFI halts the core until the next interrupt; no memory or state side effects.
858            unsafe {
859                core::arch::asm!("wfi", options(nomem, nostack));
860            }
861        }
862    }
863}