- การรองรับ real-time preemption ของ Linux เป็นงานที่รอการเข้าสู่เมนไลน์มาเกือบ 20 ปี และ Thomas Gleixner เปิดเผยในงาน 2023 Linux Plumbers Conference ว่าอุปสรรคใหญ่สุดท้ายคือ
printk() - เป้าหมายคือทำให้โปรเซสที่มีลำดับความสำคัญสูงสุดสามารถทำงานได้ด้วย latency ที่สั้นและคาดการณ์ได้ และเพื่อสิ่งนี้ ส่วนแกนหลักจำนวนมากของเคอร์เนลจึงถูกเขียนใหม่มาเป็นเวลานาน
printk()สามารถถูกเรียกได้ในทุก context จึงซับซ้อนกว่าการพิมพ์ล็อกธรรมดามาก และ การส่งออกแบบ synchronous ในปัจจุบันก็ขัดกับเป้าหมายด้าน latency ของงานเรียลไทม์- ตั้งแต่ปี 2018 มีแพตช์ราว 300 รายการ ที่เข้า upstream แล้วหรือกำลังรออยู่ใน linux-next โดยงานที่ยังเหลือคือการจัดการ handover ของข้อความฉุกเฉินและความปลอดภัยของ console driver
- เมื่อการจัดระเบียบ
printk()เสร็จ และโค้ดเรียลไทม์ส่วนที่เหลือพร้อมใน linux-next ก็อาจรวมเข้าใน merge window เดียวกันได้ แต่ Gleixner บอกว่าจะไม่คาดการณ์ช่วงเวลาที่จะเสร็จอีกแล้ว
งาน real-time preemption ที่ยาวนานเกือบ 20 ปี
- การรองรับเรียลไทม์ของ Linux ปรากฏใน LWN ครั้งแรกเมื่อปี 2004 และเป็นเวลานานที่ดูเหมือนว่า “อีกนิดเดียวก็จะเสร็จ”
- แม้ว่า LWN จะเคยใช้ชื่อ the realtime preemption endgame ตั้งแต่ปี 2009 แต่ในงาน 2023 Linux Plumbers Conference นั้น Gleixner มองว่าคราวนี้จุดจบใกล้เข้ามาจริง ๆ
- สำหรับ Gleixner เอง นี่เป็นงานที่ยาวเกือบ 25 ปี
- เขาเริ่มทำงานด้านการรองรับเรียลไทม์ของ Linux ตั้งแต่ปี 1999
- ตัวโครงการเองก็ดำเนินต่อเนื่องมาเกือบ 20 ปี
- เขาบอกว่าเมื่อทุกอย่างเสร็จจะมี “a big party” แต่ตอนนี้อุปสรรคใหญ่สุดท้ายยังคงเป็น
printk()
latency ที่ real-time preemption พยายามลด
- เป้าหมายของ real-time preemption คือทำให้โปรเซสที่มีลำดับความสำคัญสูงสุดสามารถทำงานได้เสมอด้วย latency ต่ำสุดและคาดการณ์ได้
- เพื่อให้ทำได้ เคอร์เนลต้องสามารถถูก preempt ได้ในสถานการณ์ให้มากที่สุดเท่าที่เป็นไปได้ และข้อยกเว้นต้องถูกจำกัดให้อยู่ในขอบเขตที่แคบและชัดเจน
- แนวทางการทำงานพื้นฐานถูกวางไว้นานแล้ว แต่การแก้ปัญหารายละเอียดใช้เวลายาวนาน
- ระหว่างทางนี้ ส่วนสำคัญหลายส่วนของเคอร์เนลหลักถูกเขียนใหม่ และประโยชน์ของมันก็ขยายไปไกลกว่ากรณีใช้งานแบบเรียลไทม์สู่เคอร์เนลโดยรวม
ทำไม printk() จึงเป็นอุปสรรคสุดท้าย
- เมื่อโค้ดเคอร์เนลต้องส่งข้อความไปยังคอนโซลและล็อก มันจะเรียก
printk()หรือฟังก์ชันที่สร้างอยู่บนมัน - แม้จะดูเหมือนการพิมพ์ข้อความธรรมดา แต่
printk()ต้องทำงานได้ใน แทบทุก context- มันอาจถูกเรียกได้แม้ใน non-maskable interrupt handler
- มันอาจถูกเรียกซ้ำจากภายใน
printk()อื่นได้ - ในสถานการณ์ที่ระบบล่ม ข้อมูลที่พิมพ์ออกมาอาจสำคัญมาก จึงยากที่จะจำกัด context ที่เรียกได้
- ด้วยข้อกำหนดเหล่านี้ ปัญหาเรื่อง concurrency, locking และการจัดการไดรเวอร์จึงพันกันอย่างซับซ้อนใน
printk() printk()ของเคอร์เนลปัจจุบันมีโครงสร้างแบบ synchronous เต็มรูปแบบ- การเรียกจะไม่คืนค่าจนกว่าข้อความจะถูกส่งไปยังทุกปลายทางที่ตั้งไว้
- Gleixner อธิบายโครงสร้างนี้ว่า “stupid”
- โดยเฉพาะระหว่างการบูต แม้ข้อความส่วนใหญ่จะเป็นเพียง noise ธรรมดา ก็ยังต้องรอให้ถูกส่งออกทั้งหมด
- เวลารอคอยนี้ขัดแย้งโดยตรงกับ latency ที่งานเรียลไทม์พยายามลด
- นักพัฒนาเรียลไทม์ย้ายการส่งออกของ
printk()ไปยังเธรดแยกและทำให้เป็นแบบ asynchronous มานานแล้ว แต่โค้ดนั้นใกล้เคียงกับการแฮ็กหลายอย่างมากกว่าจะเป็นวิธีแก้ปัญหาเชิงพื้นฐาน
การปรับปรุง printk() ใหม่ตั้งแต่ปี 2018
- ปัญหา
printk()ถูกจัดการอย่างจริงจังตั้งแต่ปี 2018 และมีแพตช์ราว 300 รายการ ที่เข้า upstream แล้วหรือกำลังรออยู่ใน linux-next - ตอนนี้ยังมีชุดแพตช์สุดท้าย 3 ชุดที่กำลังดำเนินการเพื่อปิดงานนี้
- หนึ่งในรายละเอียดที่ยากที่สุดคือ กลไก handover
- เมื่อเคอร์เนลต้องพิมพ์ข้อความฉุกเฉิน เช่น ตอนระบบล่ม มันอาจต้องแย่งการควบคุมจากคอนโซลที่กำลังพิมพ์ข้อความลำดับความสำคัญต่ำกว่าอยู่
- การทำสิ่งนี้ให้ปลอดภัยในทุก context ไม่ใช่เรื่องง่าย
- อีกงานหนึ่งคือการทำเครื่องหมาย console driver ที่ไม่สามารถใช้งานได้อย่างปลอดภัยในบาง context
- ตัวอย่างเช่น หากต้องพิมพ์ข้อความระหว่าง non-maskable interrupt แต่ต้องมีการตั้งค่าโหมดวิดีโอ ก็จะไม่สามารถทำงานได้
- Gleixner ตอบว่าในช่วงปีที่ผ่านมาไม่มีการเปลี่ยนแนวคิดพื้นฐาน
- ในเคอร์เนลมี console driver ที่ต้องแก้ไขอยู่ 76 ตัว
- โค้ด handover ถูกเปลี่ยนให้สามารถอัปเดตไดรเวอร์ทีละตัวได้ แทนที่จะต้องแก้ทุกไดรเวอร์พร้อมกัน
- การอภิปรายเพิ่มเติมเกี่ยวกับงาน
printk()ล่าสุดอยู่ในบทความนี้
เอาต์พุตแบบ asynchronous และเงื่อนไขการรวมเข้าเมนไลน์
- เมื่อ Masami Hiramatsu ถามว่าข้อความเคอร์เนลใดบ้างที่ควรถูกพิมพ์แบบ synchronous นั้น Gleixner ตอบว่าเกือบทุกอย่างควรถูกทำให้เป็น asynchronous
- เอาต์พุตแบบ asynchronous ช่วยลด latency ที่เกิดจากการเรียก
printk()และยังทำให้สามารถมี kernel thread แยกสำหรับแต่ละคอนโซลได้- คอนโซลที่เร็วสามารถทำงานตามความเร็วของตัวเองได้ โดยไม่ต้องรอคอนโซลที่ช้าที่สุด
- โค้ดถูกเปลี่ยนให้แน่ใจว่าข้อความสำคัญจะถูกคัดลอกลง message buffer อย่างสมบูรณ์ก่อนที่บรรทัดแรกจะเริ่มถูกพิมพ์
- นี่เป็นมาตรการเพื่อรับมือกรณีที่ console driver ที่มีข้อบกพร่องทำให้ทั้งระบบพัง
- เพื่อให้ลำดับการพิมพ์ปลอดภัยขึ้น ระบบจะเขียนไปยังคอนโซลที่รู้ว่าปลอดภัยก่อน
- ตัวอย่างเช่น หากมี persistent-memory store ก็จะบันทึกข้อความก่อนส่งไปยังอุปกรณ์จริง
- นี่เป็นวิธีรักษาเนื้อหาที่พิมพ์ไว้ แม้ไดรเวอร์ที่มีปัญหาจะทำให้ระบบล่ม
- Gleixner บอกว่างานเข้าใกล้ความเสร็จแล้ว แต่เพราะ
printk()คาดเดาได้ยาก เขาจึงจะไม่พูดถึงกำหนดเวลาสำเร็จอีกต่อไป - ถึงอย่างนั้น เขาก็ระบุว่ายังหวังให้โค้ด real-time preemption ส่วนที่เหลือเข้าสู่เมนไลน์ก่อนครบวาระ 20 ปีในช่วงปลายปี 2024
- เมื่อ Clark Williams ถามว่าหลังจากแพตช์
printk()เข้า upstream แล้ว จะใส่โค้ดเรียลไทม์ส่วนที่เหลือใน merge window เดียวกันหรือไม่ Gleixner ตอบว่า “yes” แบบมีเงื่อนไข- หากโค้ดทั้งหมดถูก staged ไว้ใน linux-next และดูพร้อม ก็อาจลองทำได้
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
QNX ทำเรื่องนี้ได้ถูกทางมาตั้งแต่หลายสิบปีก่อนแล้ว ไมโครเคอร์เนลมีขอบเขตสูงสุดสำหรับทุกงานที่ตัวเองทำ และโค้ดก็มีแค่หลักหมื่นบรรทัดเท่านั้น
ไมโครเคอร์เนลทำแค่การจัดสรรหน่วยความจำ, การ dispatch CPU และการส่งข้อความระหว่างโปรเซส ส่วนที่เหลือทั้งหมดรวมถึงไดรเวอร์และ logger อยู่ใน user space และสามารถถูก preempt ได้โดยเธรดที่มี priority สูงกว่า
เคอร์เนล QNX ไม่จัดการสตริง ไม่มีการพาร์ส ไม่มีการฟอร์แมต ไม่มีข้อความ Linux บวมเกินไปสำหรับงานเรียลไทม์ และต้องทำให้โค้ดเคอร์เนลหลายล้านบรรทัดทั้งหมด preempt ได้ โครงสร้างเองจึงไม่เหมาะกับเรียลไทม์ นั่นแหละคือเหตุผลที่ต้องใช้เวลา 20 ปีในการแก้
ผลงานสำคัญที่สุดต่อการออกแบบเคอร์เนลน่าจะเป็นการใช้ capability อย่างทั่วถึง เพื่อส่งมอบอำนาจควบคุมออกไปยัง user space ได้อย่างปลอดภัยแต่ยังยืดหยุ่น
ตัวการบวมของเคอร์เนลเองไม่ได้ทำให้กังวลมากนัก Linux ได้รับเวลาพัฒนาจำนวนมาก และแม้เดสก์ท็อปจะไม่ได้มี priority สูงเท่าเซิร์ฟเวอร์ แต่งานที่ทำเพื่อสร้างเคอร์เนลประสิทธิภาพดีสำหรับอุปกรณ์พกพาอะไรทำนองนั้นก็น่าจะเป็นประโยชน์ต่อผู้ใช้เดสก์ท็อปด้วย
mainที่จัดโครงสร้างดีในภาษา C หรือภาษาตระกูล Cmainแค่ประสานการเรียกฟังก์ชันอื่น ๆ และถึงตรงนี้เคอร์เนล QNX จะทำการ initialize น้อยกว่า แต่แนวคิดใหญ่ ๆ ก็คล้ายกันผมไม่ใช่นักพัฒนาเคอร์เนล แต่แนวทางที่รักษาให้มันเรียบง่ายแบบนี้ดูดี
มีตัวอย่างที่แสดงให้เห็นว่าแม้ระบบกำลังจะตาย เคอร์เนลก็ยังพยายามส่งข้อความ log ออกไปให้ได้ และในสภาพแวดล้อมใช้งานจริงมันถูกใช้กันอย่างไร
https://netflixtechblog.com/kubernetes-and-kernel-panics-ed6...
ถ้าปัญหานี้ถูกแก้ได้ ผมสงสัยว่าจะสามารถแทนที่บางชุดฮาร์ดแวร์/ซอฟต์แวร์ที่สร้างมาเพื่องานเรียลไทม์ได้พอสมควรหรือไม่ ตอนนี้มีตัวเลือกชิป ARM และ x86 ที่ราคาถูก ใช้พลังงานต่ำ และ clock สูงอยู่มาก
เพราะ clock สูงมาก แม้จะมีบางครั้งที่พลาด ก็อาจมี cycle เหลือเยอะจนความเป็นเรียลไทม์แบบสมบูรณ์มีความสำคัญน้อยลงในหลายกรณี ผมรู้ว่ามันไม่หรูและไม่มีประสิทธิภาพนัก แต่บางครั้ง ของสำเร็จรูปทั่วไป ก็ชนะความแม่นยำได้เหมือนกัน
งานที่ทำผิดพลาดเพียงงานเดียวอาจยึดเคอร์เนลไว้จนทำงานที่มีประโยชน์ไม่ได้ แก่นของ hard real-time คือ “ไม่มีอะไรขัดขวางการรันงานสำคัญนี้ได้” ในวงการรถยนต์หรืออากาศยาน ระบบควบคุมต้องทำงานได้ไม่ว่าจะอยู่ในสถานการณ์ใด
ถ้าจำเป็นต้องเรียลไทม์จริง ๆ ก็คือจำเป็นจริง ๆ และไม่มีคำว่า “ใกล้เคียงพอ” ทั้งนี้เป็นเพียงความรู้สึกในฐานะคนนอก
ระบบปฏิบัติการ แม้จะเป็น RTOS ก็รบกวนมากเกินไป ไม่รู้ว่าการเปลี่ยนแปลงนี้จะเปลี่ยนอะไรได้บ้าง แต่ทั้งนี้ขึ้นอยู่กับแอปพลิเคชัน และกรณีที่ต้องการแค่ “เกือบเรียลไทม์” ก็มีมาก จึงอาจมีประโยชน์กับงานแบบนั้น
การถกเถียงตรงนี้เน้นไปที่การแยกแยะระหว่างแอปพลิเคชันเรียลไทม์แบบ “hard” กับ “soft” ใน hard real-time มีแนวโน้มสูงว่าเราไม่อยากใช้ระบบปฏิบัติการทั่วไปอย่าง Linux ตั้งแต่แรก ส่วนใน soft real-time อย่างวิดีโอคอนเฟอเรนซ์หรือการเล่นเสียง ต่อให้กระตุกบ้างหรือเฟรมตกไปไม่กี่เฟรมก็ไม่ใช่เรื่องใหญ่
ตรรกะคือ RT Linux จะเป็นโซลูชันที่ทรงพลังสำหรับงาน soft real-time แบบนั้น แต่กรณีใช้งานแบบ soft ที่เสนอมาก็ทำได้ด้วย embedded Linux อยู่แล้วในตอนนี้ ไม่ใช่ว่าการเล่นวิดีโอหรือเสียงแบบ latency ต่ำด้วยซอฟต์แวร์เคยเป็นไปไม่ได้ และเมื่อ 20 ปีก่อนก็ทำได้แล้ว
ปัญหาเกิดขึ้นเมื่อระบบที่ยุ่งมากมี I/O ที่ preempt ไม่ได้แทรกเข้ามาบ่อย ๆ แต่ในสภาพแวดล้อม embedded กรณีแบบนั้นพบได้ยาก การทำให้เคอร์เนล preempt ได้เต็มรูปแบบและให้การควบคุม scheduling มากขึ้นมีเหตุผลที่น่าเชื่อถือ แต่เหตุผลนั้นไม่ค่อยเกี่ยวกับการที่ Linux ควรแทนที่ระบบปฏิบัติการเรียลไทม์ขนาดเล็กที่สุดหรือโค้ด bare-metal
มันใกล้เคียงกับการดูแลสุขอนามัยที่ดีมากกว่า และทำให้ได้ระบบปฏิบัติการที่ทำงานได้ดีขึ้นเมื่อมีโหลด แม้กับแอปพลิเคชันที่ไม่ใช่เรียลไทม์
เป็นข่าวดี แต่แม้เคอร์เนล Linux จะกลายเป็นแบบเรียลไทม์แล้ว ฮาร์ดแวร์ก็มีโอกาสสูงที่จะยังไม่เป็นเรียลไทม์ เพราะแคชและเวทมนตร์ซับซ้อนภายใน CPU
ฮาร์ดแวร์ขนาดใหญ่และซับซ้อนไม่เหมาะกับเรียลไทม์จริง ๆ ดังนั้น AbsInt และเครื่องมือวิเคราะห์เวลาทำงานกรณีเลวร้ายที่สุด (WCET) จึงมักจัดการกับสถาปัตยกรรม CPU ที่เรียบง่ายเป็นหลัก 8051 น่าจะอยู่ยงคงกระพันไปตลอดจริง ๆ อนึ่ง ยังมี Zephyr RTOS ด้วย
แค่สมมติสถานการณ์อย่างไม่มี cache hit เลยและอยู่ภายใต้โหลดสูงสุด เป็นต้น ถ้ากำหนดขอบเขตบนของเวลาที่ใช้ได้ก็ไม่มีปัญหา
เช่น timer รับอินพุตจาก quadrature encoder แล้วส่ง interrupt เฉพาะตอน wrap หรือเชื่อมระบบ GPIO เข้ากับ DMA เพื่อสตรีมหน่วยความจำไปยังขา output โดยไม่ต้องให้ CPU เข้ามาเกี่ยวข้อง ก็ทำได้ จะสตรีมไป DAC หรือทำ DMA transfer จาก ADC ไปยังหน่วยความจำก็ได้ สิ่งเหล่านี้มักเลี่ยงแคชเพื่อให้ได้ latency ที่คาดการณ์ได้
ในความเป็นจริง ระบบเรียลไทม์จำนวนมากต้องประมวลผลและรวบรวมข้อมูลจากเซนเซอร์ที่เพิ่มขึ้นเรื่อย ๆ จึงทรงพลังขึ้นเรื่อย ๆ
ตอนเป็นมือใหม่ ผมเคยเจอสัมภาษณ์งานน่าหงุดหงิดจำนวนมากที่ผู้สัมภาษณ์ไม่รู้ว่า เรียลไทม์ จริง ๆ แล้วคืออะไร หลายคนพลาดแนวคิดในบทความที่ว่า “และ latency ที่คาดการณ์ได้” และดูเหมือนจะคิดว่าเรียลไทม์แปลว่าแค่ “เร็ว”
ถ้าควบคุมระบบเบรกของรถยนต์ “latency เฉลี่ย 50ms แต่สูงสุด 80ms” อาจยอมรับได้ แต่ “latency เฉลี่ย 1ms แต่ยืดออกไปได้ไม่จำกัด และอาจใช้เวลาหลายวินาที” ยอมรับไม่ได้
การทำ logging แบบ synchronous ก่อปัญหาอีกแล้ว ที่บริษัทเราเคยเจอเรื่องคล้ายกันเพราะ GLOG (ไลบรารี logging ของ Google) เช่น ถ้า stdout เป็นไฟล์ ก็อาจถูก block ที่ disk I/O ได้
ตอนบริการของเราหยุดค้างเกิน 100ms สาเหตุ 90–99% คือ GLOG
“ถ้าเป็นสิ่งที่ต้องบันทึกเป็น log ให้ได้ แต่บันทึก log ไม่ได้ คุณจะทำอย่างไร?” ช่วงหลังผมแค่ชี้ไปที่ CAP theorem แล้วบอกว่า logging ก็เหมือน distributed system อื่น ๆ อาจเพราะมีบทความ Wikipedia ที่มีรูปสามเหลี่ยมกับคำว่า “theorem” คนเลยยอมรับกันมากขึ้น
หลังจากนั้นจึงเปลี่ยนเป็นส่งผ่าน UDP เพราะเสีย log บางส่วนยังดีกว่าเสีย production ทั้งหมด
$MSFTก็เคยมีปัญหาประเภท “ไลบรารี logging ทำทุกอย่างพัง” เช่นกัน ลองนึกภาพว่ามี 100 เธรด แต่ละเธรดมี logging buffer ขนาด 300MBแน่นอนว่ามันถล่มหน่วยความจำ และทำให้เซิร์ฟเวอร์ crash แม้บน SKU ที่แพงที่สุดของ Azure App Service
ทำให้นึกถึงอดีตขึ้นมาทันที ประมาณ 17–18 ปีก่อน ผมเคยคอมไพล์เคอร์เนลสำหรับ Debian ด้วย RT_PREEMPT เพื่อใช้กับอุปกรณ์วิทยาศาสตร์ที่ต้องการ timing ที่แน่นขึ้น
latency และ jitter น่าประทับใจมาก หลังจากนั้นแทบไม่ได้คิดถึงมันอีกเลย แต่ถ้าทำแอปพลิเคชัน embedded ด้วย Raspberry Pi แล้วไม่อยากย้ายไปใช้ไมโครคอนโทรลเลอร์ที่ใช้ RTOS ก็น่าจะมีที่ให้ใช้เยอะ
ผมเคยเห็นข้อเสนอมาก่อนว่าให้รัน Linux เป็น task หนึ่งของ RTOS จึงน่าสนใจเป็นพิเศษ แนวทางคือสิ่งที่ต้องมี deadline แบบ hard real-time ให้รันบน RTOS และไม่ให้ได้รับผลกระทบจาก latency ที่ระบบ virtual memory อาจก่อขึ้น ผมจำไม่ได้ว่านี่เป็นแค่ไอเดียหรือมีการ implement จริง และก็เคยเห็นการกล่าวถึงว่า RpiOS อยู่บน RTOS แค่ครั้งเดียว เลยสงสัยอยู่
สงสัยว่าสิ่งนี้มีความหมายอย่างไรสำหรับผู้ใช้ทั่วไป อยากรู้ว่าเป็นฟีเจอร์ที่เปิดใช้เฉพาะในสถานการณ์ที่เฉพาะเจาะจงมาก ๆ หรือว่าจะช่วยให้คนทั่วไปได้ใช้ ระบบที่ตอบสนองได้ดีกว่าเดิม ด้วยหรือไม่
แต่ละงานจะได้รับงบประมาณ X และต้องไม่เกินนั้น ถ้ากรณีที่ดีที่สุดเร็ว แต่กรณีที่แย่ที่สุดช้า ก็หมายความว่าระบบต้องถือสมมติฐานตามกรณีที่แย่ที่สุดเสมอ
ตัวอย่างของการหลีกเลี่ยงการเรียก
printk()แบบ synchronous นั้นตรงจุดพอดี และแม้ไม่เปิด RT ก็ควรช่วยปรับปรุง latency ภายใต้ภาระโหลดได้ ผมมองว่าเคอร์เนล RT ที่ถูก upstream เต็มรูปแบบจะไม่ทำงานต่างจากเคอร์เนลทั่วไป เว้นแต่จะรันโปรเซส RT จริง ๆ เหตุผลที่ใช้เวลานานในการ upstream คือจำเป็นต้องมีการประนีประนอมเพื่อทำให้ RT เป็นไปได้ และตามบทความบอกว่าตอนนี้การประนีประนอมแบบนั้นเหลือไม่มากแล้วเพราะเมื่อจำเป็นต้องใช้ real-time scheduling ก็จะสามารถใช้เคอร์เนล mainline รุ่นล่าสุดได้
อยากรู้ว่าคิดอย่างไรกับ Xenomai[1] ใช้มาหลายปีโดยไม่มีปัญหา
บน BeagleBone Black ปกติจะได้ jitter ระดับหลายร้อยนาโนวินาที และถือว่าเป็น real-time แบบ “hard” สามารถ schedule งานเป็นคาบในระดับหลายสิบไมโครวินาทีได้โดยไม่เคยพลาดเลย
ต่างจาก Real-Time Linux ที่พยายามทำให้ Linux เอง preempt ได้ Xenomai โดยแก่นแล้วเป็นเคอร์เนลของตัวเอง และรัน Linux เป็นงานหนึ่งที่อยู่ด้านบน มันมี ABI ให้รันงานที่ผู้ใช้สร้างขึ้นขนานกับ Linux หรือที่ priority สูงกว่าได้ ตัวอย่างเช่นสามารถเลี่ยงปัญหา
printk()ได้ เพราะ Xenomai ไม่สนใจและยอม context switch ออกจากprintkเพื่อรันงานของผู้ใช้ข้อเสียคือภายใน context ของ Xenomai จะเรียก system call ทั่วไปไม่ได้ จริง ๆ ก็ทำได้ แต่แน่นอนว่าจะทำลายโมเดล real-time ตัวอย่างเช่นถ้าเรียก
printf()หรือmalloc()ภายในงาน Xenomai มันจะไม่สามารถถูก preempt ได้ ABI ของ Xenomai จำลองสิ่งที่น่าจะจำเป็นในแง่ system call ไว้ให้มากที่สุด และถ้าคุณพอใจที่จะจัดการ heap allocation โดยตรงเอง มันก็ทำงานได้ดีมาก[1]: https://xenomai.org/