Dagens program Sanntidsprogrammering med Linux TTK4155 Sanntidsprogrammering Gjesteforelesning 28. september 2004 Håvard Skinnemoen Grunner til å velge Linux Linux i dedikerte systemer (sanntid eller ikke) Linux og sanntid: Status Hva kan ødelegge responstiden? RTLinux og RTAI Hvorfor Linux? Mulig å tilpasse kildekoden Support Robust, velprøvd platform Relativt enkelt å bytte platform Ingen royalties Støtte for mange CPU-arkitekturer: alpha arm26 h8300 ia64 m68knommu parisc ppc64 sh sparc64 v850 arm cris i386 m68k mips ppc s390 sparc um x86_64 Embedded Linux: Begrensninger Lite minne og lagringsplass Uvanlige lagringsmedier (f.eks. flash) Pålitelighet Tidskrav Uerfarne sluttbrukere
Embedded Linux: Hvordan lage små systemer? Embedded Linux: Qt/Embedded Tilpasning av Linux-kjernen: Velg kun den funksjonaliteten du trenger Valg av run-time bibliotek: uclibc, dietlibc, etc. vs. GNU libc Statisk vs. dynamisk linking busybox Qt/Embedded har (nesten) samme API som andre Qt-versjoner Mye mindre footprint enn Qt/X11 Samme kildekoden kan kompileres på Windows, Mac OS X og X11 Linux og sanntid: Status POSIX: Tråder, delt minne, message queues Nye synkroniseringsprimitiver i kjernen NPTL: Native Posix Thread Library O(1) scheduler Betydelig bedre responstid i 2.6 enn 2.4 Scheduling av Linuxprosesser Tre scheduling-policies: First In-First Out (SCHED_FIFO) Round Robin (SCHED_RR) Dynamisk prioritet (SCHED_OTHER) Default: SCHED_OTHER Statisk prioritet 1 99 for SCHED_FIFO og SCHED_RR, 0 for SCHED_OTHER
Andre mekanismer Native POSIX Thread Library!NPTL" 32 sanntidssignaler (SIGRTMIN.. SIGRTMAX) POSIX Shared Memory (mmap) Låsing av minne (mlock og mlockall) Svært viktig siden page faults kan ta lang tid POSIX Message Queues Raskere og nærmere POSIX-standarden enn LinuxThreads 1:1 modell (1 kerneltråd per applikasjonstråd) Futex: Fast Userspace Mutex Hva påvirker responstiden i Linux-kjernen? Interrupt Latency vs. Scheduling Latency Maskering av avbrudd Linux-kjernen er i utgangspunktet ikke preemptiv Tidkrevende operasjoner i kjernen kan være svært ødeleggende for responstiden Hva skjer under et avbrudd? Avbruddshåndtereren kjøres. NEED_RESCHED blir satt dersom en ny tråd vekkes Evt. softirq kjøres når alle avbrudd er håndtert Ved retur til brukerprogram: Kjør scheduleren dersom NEED_RESCHED er satt Ved retur til kjernen kan ikke alltid scheduleren kjøres umiddelbart
Preemptible Kernel En teller forteller når kjernen kan avbrytes preempt_enable() dekrementerer telleren preempt_disable() inkrementerer telleren Dersom telleren er 0 ved retur fra interrupt kan scheduleren kjøres selv om prosessen er i kjernemodus spinlock-primitiver styrer også preemptivitet Kernel Preemption: Eksempler void thatfunc(struct some_card *card) spin_lock_irq(&card->lock); card->users += 1; spin_unlock_irq(&card->lock); void thisfunc(struct some_card *card) spin_lock(&card->lock); thatfunc(card); spin_unlock(&card->lock); Low-Latency Low-Latency: Eksempel Linux 2.4.22 Linux 2.6.7 Prinsipp: Identifiser kode som kjører lenge uten å tillate scheduling Legg inn kall til cond_resched() på strategiske steder cond_resched() kaller schedule() dersom NEED_RESCHED er satt static int move_page_tables(struct mm_struct * mm, unsigned long new_addr, unsigned long old_addr, unsigned long new_addr, unsigned long old_addr, unsigned long while len) (offset) unsigned long len) offset -= PAGE_SIZE; unsigned long offset = len; unsigned long offset; if (move_one_page(mm, old_addr + offset, new_addr + offset)) flush_cache_range(mm, old_addr, old_addr goto + oops_we_failed; len); flush_cache_range(vma, old_addr, old_addr + len); /* /* * This is not the clever way to do this, but we're taking the * easy way out on the assumption that most remappings will be * only a few pages.. This also makes error recovery easier. */ while (offset) offset -= PAGE_SIZE; if (move_one_page(mm, old_addr + offset, new_addr + offset)) goto oops_we_failed; flush_tlb_range(mm, old_addr, old_addr + len); return 0; oops_we_failed: /*... */ static unsigned long move_page_tables(struct vm_area_struct *vma, * This is not the clever way to do this, but we're taking the * easy way out on the assumption that most remappings will be * only a few pages.. This also makes error recovery easier. */ for (offset = 0; offset < len; offset += PAGE_SIZE) return offset; if (move_one_page(vma, old_addr+offset, new_addr+offset) < 0) break; cond_resched(); for (offset = 0; offset < len; offset += PAGE_SIZE) if (move_one_page(vma, old_addr+offset, new_addr+offset) < 0) break; cond_resched();
RTLinux og RTAI Hvordan RTLinux fungerer Prinsipp: 100% preemptibel kjerne Linux kjøres som en lavprioritets-tråd under en nanokjerne Linux-kjernen kan ikke maskere avbrudd direkte Mekanismer under RTLinux POSIX med noen utvidelser (_np suffiks) RTLinux-spesifikke tidsfunksjoner Real-Time FIFOs for kommunikasjon med Linux-prosesser Minnemappet I/O: /dev/mem eller ioremap() Port I/O: inb(), inw(), inl(), outb(), outw(), outl(), eventuelt med pause Myke og harde avbrudd Fordeler med RTLinux og RTAI Svært lav worst-case latency Vanlige Linux-applikasjoner kjører side om side uten å forstyrre Nesten-standard POSIX API Mulig å kommunisere med lav-prioritets Linuxprosesser: brukergrensesnitt, web-server, etc.
Ulemper med RTLinux og RTAI En RTLinux-applikasjon er ikke en Linuxapplikasjon Trenger eget sett med drivere Applikasjonskode kjøres med mer privilegier enn nødvendig (kjerne-modus) Spørsmål? Mindre brukerbase enn Linux