exercises

Log | Files | Refs | README

os_abstraction_syscall.rs (1580B)


      1 //! This is the next level of abstraction: instead of calling assembly directly,
      2 //! we use the operating system's API. Instead of `asm` module we use `io`.
      3 
      4 use std::io;
      5 
      6 // This is specific to the Linux operating system and macOS.
      7 // Every Linux (and maxOS) installation comes with a version `libc`, which is
      8 // C library for communicating with the operating system.
      9 //
     10 // Having `libc`, with a consistent API, allows us to program the same way
     11 // without worrying about the underlying platform architecture.
     12 //
     13 // Kernel developers can also make changes to the underlying ABI without
     14 // breaking everyone's program.
     15 #[cfg(target_family = "unix")]
     16 // This flag tells the compiler to link to the "c" library on the system:
     17 #[link(name = "c")]
     18 // This defines what functions in the linked library we want to call:
     19 unsafe extern "C" {
     20     /// This uses Rusts FFI to call external functions
     21     ///
     22     /// The write function takes:
     23     /// - The file descriptor `fd`, which in this case is a handle to `stdout`.
     24     /// - A pointer to an array of u8, `buf` values.
     25     /// - The length of that buffer, `count`.
     26     fn write(fd: u32, buf: *const u8, count: usize) -> i32;
     27 }
     28 
     29 #[cfg(target_family = "unix")]
     30 pub fn syscall(message: String) -> io::Result<()> {
     31     let msg_ptr = message.as_ptr();
     32     let len = message.len();
     33     // This needs to be wrapped in unsafe block, since Rust can't guarantee
     34     // safety when calling external functions:
     35     let res = unsafe { write(1, msg_ptr, len) };
     36 
     37     if res == -1 {
     38         return Err(io::Error::last_os_error());
     39     }
     40     Ok(())
     41 }