- ทีม Ghostty ได้เขียน แอปพลิเคชัน GTK ขึ้นใหม่ทั้งหมด พร้อมใช้งาน ระบบชนิดข้อมูล GObject อย่างจริงจัง
- ในกระบวนการนี้ การผสานรวมกับ ภาษา Zig และการตรวจสอบปัญหาหน่วยความจำด้วย Valgrind มีบทบาทสำคัญ
- การนำระบบ GObject มาใช้ช่วยให้ การจัดการหน่วยความจำ และ การพัฒนาวิดเจ็ตแบบกำหนดเอง ง่ายขึ้นกว่าที่ผ่านมา
- จากการใช้ Valgrind ทีมงานพบว่า ความปลอดภัยด้านหน่วยความจำ ของ Ghostty ดีขึ้นอย่างมาก
- Ghostty GTK เวอร์ชันใหม่ได้กลายเป็นค่าเริ่มต้นสำหรับการบิลด์จากซอร์ส และมีกำหนดรวมอยู่ใน รีลีส 1.2
บทนำ
- Ghostty เป็นเทอร์มินัลอีมูเลเตอร์ข้ามแพลตฟอร์มที่รองรับ macOS, Linux, FreeBSD
- แต่ละแพลตฟอร์มมีจุดเด่นจากการใช้เนทีฟ GUI framework ของตนเอง
- macOS: แอปขนาดใหญ่ที่พัฒนาด้วย Swift และ Xcode
- Linux และ BSD: แอปพลิเคชันบน GTK ที่เชื่อมรวมกับ X11/Wayland โดยตรง
- แกนกลางร่วมเขียนด้วย Zig และมี API ที่เข้ากันได้กับ C ABI
- เหตุผลที่เขียนแอป GTK ขึ้นใหม่จากโครงสร้างเดิมสามารถดูได้จาก PR ต้นฉบับ
- บทความนี้เน้นที่ การทำงานร่วมกับระบบชนิดข้อมูล GObject และ ประเด็นด้านหน่วยความจำที่ตรวจสอบด้วย Valgrind
ระบบชนิดข้อมูล GObject และ Zig
- หากใช้ GTK โครงสร้างโดยพื้นฐานจำเป็นต้องทำงานร่วมกับ ระบบชนิดข้อมูล GObject
- ในอดีตทีมพยายามหลีกเลี่ยงระบบ GObject และจัดการ วงจรชีวิตของอ็อบเจ็กต์ Zig ที่ไม่มีการนับอ้างอิงกับอ็อบเจ็กต์ GObject ด้วยตนเอง แต่พบปัญหาซ้ำ ๆ ว่าการคืนหน่วยความจำไม่สมบูรณ์
- ตัวอย่าง: หน่วยความจำฝั่ง Zig ถูกคืนแล้ว แต่หน่วยความจำฝั่ง GTK ยังอยู่ หรือเกิดสถานการณ์ตรงกันข้ามซ้ำ ๆ
- แนวทางนี้ไม่เพียงมีปัญหาเรื่องความถูกต้อง แต่ยังทำให้ใช้งาน ความสามารถเฉพาะของ GTK (event signal, property binding, action) ได้ยาก
- ตัวอย่างที่ชัดเจนคือ เมื่อต้องรีโหลดโครงสร้างการตั้งค่า (config) องค์ประกอบ GUI ทั้งหมดที่เชื่อมอยู่ต้องอัปเดตอย่างสอดคล้องกัน ซึ่งกระบวนการนี้ซับซ้อนและเกิดข้อผิดพลาดบ่อย
- ตอนนี้จัดการผ่าน
GhosttyConfig GObject แบบนับอ้างอิงที่ห่อ Config struct ของ Zig และใช้การแจ้งเตือนการเปลี่ยนแปลงของ property เพื่อกระจายการเปลี่ยนแปลงไปทั่วทั้งแอปอย่างเป็นธรรมชาติ
- การสร้างวิดเจ็ต GObject แบบกำหนดเองก็ง่ายขึ้น ทำให้สามารถใช้เทคโนโลยี UI สมัยใหม่ของ GTK เช่น Blueprint ได้
- เมื่อไม่นานมานี้ การนำ Blueprint มาใช้ช่วยให้เพิ่มฟีเจอร์ใหม่อย่าง แท็บบน title bar ของ GTK และ ขอบกระดิ่งแบบเคลื่อนไหว ได้ง่ายขึ้น
Valgrind กับ GTK และ Zig
- ตลอดกระบวนการพัฒนา มีการใช้ Valgrind เพื่อตรวจสอบปัญหาอย่างเป็นระบบ ทั้ง memory leak และการเข้าถึงหน่วยความจำที่ยังไม่ถูกกำหนด
- การตรวจ Valgrind กับแอป GTK ทำได้ยาก และต้องใช้ ไฟล์ suppression จำนวนมาก (80% เป็นของ GTK เอง ที่เหลือเป็นไลบรารีภายนอกและไดรเวอร์ GPU)
- การตรวจซ้ำอย่างต่อเนื่องทำให้สามารถค้นพบบั๊กหน่วยความจำซับซ้อนที่เกิดเฉพาะในบางกรณีได้ล่วงหน้า
- ตัวอย่าง: หากไม่กำหนดค่าเริ่มต้นให้ GObject
WeakRef อย่างถูกต้อง เมื่ออ็อบเจ็กต์เป้าหมายถูกคืนหน่วยความจำภายหลังจะเกิดการเข้าถึงหน่วยความจำที่ยังไม่ถูกกำหนด ซึ่ง Valgrind ตรวจพบได้ก่อน
- จากประสบการณ์จริง ปัญหาภายใน โค้ดเบส Zig มีเพียง 2 กรณีเท่านั้น (leak 1 ครั้ง, การเข้าถึงที่ยังไม่ถูกกำหนด 1 ครั้ง) และทั้งสองก็เกิดขึ้นระหว่างการเชื่อมกับ 3rd party C API
- ตัวจัดสรรหน่วยความจำสำหรับดีบักของ Zig และความสามารถในการผสานรวมกับ Valgrind ก็พิสูจน์แล้วว่าได้ผลจริง
- ปัญหาหน่วยความจำอื่น ๆ ที่พบส่วนใหญ่เกิดจากขอบเขตของ C API และการจัดการวงจรชีวิตอันซับซ้อนของระบบ GObject
- สรุปคือ หากต้องการใช้ C API ของไลบรารีที่ซับซ้อนอย่างปลอดภัย จำเป็นต้องมีเครื่องมืออย่าง Valgrind
- ฟีเจอร์ช่วยด้านความปลอดภัยหน่วยความจำของ Zig ไม่ได้พิสูจน์ได้แค่ในเชิงทฤษฎี แต่ยังยืนยันได้จาก ประสบการณ์จริงในโครงการ
บทสรุป
- นี่เป็นครั้งที่ ห้า ที่ผู้เขียนสร้างส่วน GUI ของ Ghostty ขึ้นใหม่ตั้งแต่ต้น
- ตามลำดับคือ GLFW, macOS SwiftUI, macOS AppKit+SwiftUI, Linux GTK (เชิงกระบวนวิธี), Linux GTK+ระบบชนิดข้อมูล GObject
- ในแต่ละรอบของการเขียนใหม่ ได้บทเรียนและการเติบโตทางเทคนิคใหม่ ๆ ทุกครั้ง
- มีแผนจะนำบางส่วนของประสบการณ์ครั้งนี้ไปใช้กับโปรเจกต์ macOS ด้วย
- ยังเน้นย้ำถึงความร่วมมืออย่างแข็งขันของทีมดูแลระบบ Ghostty GTK
- แอปพลิเคชัน Ghostty GTK ที่เขียนขึ้นใหม่ได้กลายเป็นค่าเริ่มต้นสำหรับการบิลด์จากซอร์สแล้ว และจะถูกนำไปใช้ใน รีลีสทางการ 1.2
ยังไม่มีความคิดเห็น