Vai al contenuto
Ridgun
Italiano

Riferimento

Ridgun — Specifica del livello di astrazione della piattaforma (PAL) e delle librerie di sistema (posix.rglib, io.rglib)

Questa specifica definisce il contratto tra il compilatore di Ridgun (ridgunc) e le librerie di sistema di Ridgun (posix.rglib, io.rglib, unix-tools) su tutti i sistemi operativi di destinazione supportati e previsti (Linux, MacOS, Windows) e su tutte le architetture di CPU (X86_64, Arm64).


1. Panoramica dell'architettura: PAL a 2 livelli + ADT somma di destinazione

Ridgun evita di esporre nelle librerie portabili numeri di syscall esclusivi di Linux o maschere di bit specifiche di un sistema operativo. Per farlo divide l'interazione con il sistema in due livelli del compilatore, più alcuni ADT di destinazione fortemente tipizzati:

  1. ADT somma della piattaforma di destinazione predichiarati (sys os => SysOs, sys arch => SysArch):
  • Invece di restituire valori String non tipizzati (soggetti a refusi e che il type checker non può verificare), ridgunc predichiara due ADT somma estensibili:
     type SysOs   = Linux | MacOS | Windows
     type SysArch = X86_64 | Arm64
  • sys os => SysOs e sys arch => SysArch vengono risolti dal backend in fase di compilazione in costanti NLoadAdt0 a costo zero (Linux / X86_64 su x86_64-linux, Linux / Arm64 su arm64-linux).
  • Le librerie possono fare dispatch in modo pulito con il pattern matching tabellare su SysOs / SysArch, confrontare con == ((sys os) == Linux) oppure estenderli per destinazioni BSD o bare-metal personalizzate con expand type SysOs = FreeBSD | BareMetal (FR-COMP-005).
  1. Livello 1 — Primitive PAL multipiattaforma (sys open mode, sys open, sys close, sys read fd, sys write fd, sys poll, sys terminate, sys kill, sys call):
  • Tutte le maschere di flag e di eventi di polling passate alle primitive del livello 1 usano le costanti normalizzate della PAL di Ridgun.
  • Ogni backend (x86_64.rg ELF64, arm64.rg ELF64 e i futuri backend Mach-O per macOS e PE64 per Windows) traduce queste costanti normalizzate nell'ABI nativa del kernel del sistema operativo (openat/poll/kill su Linux, open/poll/kill su macOS, CreateFileW/WaitForSingleObject/WSAPoll/TerminateProcess su Windows).
  • La sintassi naturale separata da spazi (sys open mode path "r") e quella separata da underscore (sys open mode path "r") sono accettate allo stesso modo.
  1. Livello 2 — Quote di esecuzione dichiarative (with timeout <duration> do):
  • I letterali interi accettano suffissi di durata: _ms (* 1), _s (* 1000) e _min (* 60000).
  • with timeout 500_ms do <body> (e la forma combinata with region 64_KB, timeout 500_ms do <body>) inserisce una scadenza lessicale (sys time ms + duration_ms) nello stack delle scadenze PAL locale al thread, la limita a un'eventuale scadenza esterna più stringente (min(outer, new)) e ripristina la scadenza esterna all'uscita.
  • All'interno di un blocco with timeout, sys deadline ms => Int restituisce la scadenza attiva in tempo epoch (0 se illimitata), sys remaining ms => Int restituisce i millisecondi rimanenti (-1 se illimitata, 0 se scaduta) e sys poll fd events -1 limita automaticamente il proprio tempo di attesa a sys remaining ms.

2. Riferimento della PAL integrata nel compilatore (FR-COMP-007)

2.1 Introspezione della piattaforma di destinazione

PrimitivaFirmaDescrizione
sys os=> SysOsSistema operativo di destinazione in fase di compilazione (Linux | MacOS | Windows).
sys arch=> SysArchArchitettura di CPU di destinazione in fase di compilazione (X86_64 | Arm64).

Esempio di dispatch idiomatico tra più sistemi operativi in una libreria .rglib, senza catene di if/else:

fn :: path separator SysOs   => String
      path separator Linux   =  "/"
      path separator MacOS   =  "/"
      path separator Windows =  "\\"

fn :: null device => String
      null device =  null device for (sys os)

fn :: null device for SysOs   => String
      null device for Windows =  "NUL"
      null device for _       =  "/dev/null"

2.2 I/O tramite descrittore o handle e polling di disponibilità

PrimitivaFirmaContratto PAL normalizzato
sys open modeString String => IntApre path con la stringa di modalità portabile "r", "w", "a", "rw", "w+" o "a+" (permesso predefinito 0644 / 420 in creazione). Restituisce un descrittore o handle >= 0 oppure un codice di errore negativo (-errno).
sys openString Int Int => IntApre path con i flags normalizzati della PAL di Ridgun (0 = sola lettura, 1 = sola scrittura, 2 = lettura e scrittura, 64 = crea, 512 = tronca, 1024 = accoda, 2048 = non bloccante) e il permesso mode (ad esempio 420 per 0644).
sys closeInt => IntChiude fd o l'handle. Restituisce 0 in caso di successo oppure il valore negativo -errno.
sys read fdInt Int => StringLegge fino a max_bytes da fd o dall'handle (0 = stdin, 1 = stdout, 2 = stderr, oppure un file, una pipe o una FIFO aperti). Restituisce "" a EOF (0 byte) o in caso di errore.
sys write fdInt String => IntScrive data su fd o sull'handle. Restituisce i byte scritti (>= 0) oppure il valore negativo -errno.
sys pollInt Int Int => IntInterroga fd in attesa degli events normalizzati (1 = POLLIN leggibile, 4 = POLLOUT scrivibile, 8 = POLLERR, 16 = POLLHUP) con timeout_ms (-1 = infinito, oppure limitato a sys remaining ms all'interno di with timeout; 0 = polling non bloccante; > 0 = attesa massima in ms). Restituisce > 0 con la maschera di bit degli eventi pronti, 0 allo scadere del timeout oppure < 0 con -errno.

2.3 Orologi, scadenze, segnali e via di fuga di basso livello

PrimitivaFirmaContratto PAL normalizzato
sys time ms=> IntOrologio monotono in millisecondi (CLOCK_MONOTONIC).
sys sleep msInt => ()Sospende l'esecuzione per ms millisecondi (nanosleep / Sleep).
sys deadline ms=> IntScadenza lessicale attiva in ms monotoni (0 fuori da with timeout).
sys remaining ms=> IntMillisecondi che mancano alla scadenza lessicale attiva (-1 fuori da with timeout, 0 se scaduta).
sys getpid=> IntID del processo corrente (> 0).
sys terminateInt Bool => IntTerminazione dei processi multipiattaforma: force = False invia una richiesta di terminazione ordinata (SIGTERM su POSIX), force = True forza la terminazione immediata (SIGKILL su POSIX, TerminateProcess su Windows). Restituisce 0 oppure -errno.
sys killInt Int => IntInvia un segnale normalizzato (0 = verifica di esistenza, 2 = SIGINT, 9 = SIGKILL, 15 = SIGTERM) a pid (o al gruppo di processi se pid < 0). Restituisce 0 oppure -errno.
sys pipe=> Int IntCrea una pipe del sistema operativo (__NR_pipe = 22) e restituisce (read_fd, write_fd) (oppure (-1, -1) in caso di errore).
sys waitpidInt Int => Int IntAttende il processo figlio pid con options (0 = bloccante, 1 = WNOHANG) tramite __NR_wait4 = 61 e restituisce (ret_pid, exit_status), decodificato con WIFEXITED/WEXITSTATUS (0..255) e WIFSIGNALED (128 + WTERMSIG).
sys callInt Int... => IntSyscall grezza di basso livello secondo l'ABI di destinazione (nr più 0..6 argomenti a1..a6) per driver specifici di un sistema operativo. Se la usi, proteggila con sys os / sys arch.

3. Superficie consigliata delle librerie .rglib (io.rglib e posix.rglib)

3.1 io.rglib — Wrapper di I/O di alto livello che rispettano i timeout

type IoResult = IoOk String | IoTimeout | IoEof | IoError Int

fn :: io read with timeout String Int     => IoResult
      io read with timeout path   wait_ms =
        with timeout wait_ms do
          -- Open non-blocking (0 + 2048 = O_RDONLY | O_NONBLOCK) so FIFO/device open never hangs
          fd = sys open path 2048 0
          io read poll step fd

fn :: io read poll step Int => IoResult
      io read poll step fd
        | fd < 0 = IoError fd
        | otherwise =
          -- timeout_ms = -1 automatically uses `sys remaining ms` from the active `with timeout` block
          ev = sys poll fd 1 (0 - 1)
          io read after poll fd ev

fn :: io read after poll Int Int => IoResult
      io read after poll fd  ev
        | ev == 0 =
          sys close fd -> ()
          IoTimeout
        | ev < 0 =
          sys close fd -> ()
          IoError ev
        | otherwise =
          chunk = sys read fd fd 65536
          sys close fd -> ()
          io wrap chunk chunk

fn :: io wrap chunk String => IoResult
      io wrap chunk ""     =  IoEof
      io wrap chunk s      =  IoOk s

3.2 posix.rglib — Costanti simboliche e funzioni di supporto per i processi

-- Normalized PAL Open Flags
fn :: o rdonly   => Int
      o rdonly   =  0

fn :: o wronly   => Int
      o wronly   =  1

fn :: o rdwr     => Int
      o rdwr     =  2

fn :: o creat    => Int
      o creat    =  64

fn :: o trunc    => Int
      o trunc    =  512

fn :: o append   => Int
      o append   =  1024

fn :: o nonblock => Int
      o nonblock =  2048

-- Normalized PAL Poll Events
fn :: poll in  => Int
      poll in  =  1

fn :: poll out => Int
      poll out =  4

fn :: poll err => Int
      poll err =  8

fn :: poll hup => Int
      poll hup =  16

-- Normalized Signals
fn :: sig int  => Int
      sig int  =  2

fn :: sig kill => Int
      sig kill =  9

fn :: sig term => Int
      sig term =  15

fn :: process exists Int => Bool
      process exists pid =  (sys kill pid 0) == 0

4. Compilare e distribuire librerie .rglib e .so

Compila qualsiasi modulo di libreria senza bisogno di main:

# Emit portable Ridgun library bundle (.rglib)
./bin/ridgunc build --lib src/main/ridgun/lib/io.rg -o target/io.rglib

# Emit native ELF64 shared object (.so)
./bin/ridgunc build --so src/main/ridgun/lib/io.rg -o target/libio.so

# Or via stable in a library project (`stable new --lib io`):
./bin/stable built lib