- Nhóm Ghostty đã viết lại hoàn toàn ứng dụng GTK và tích cực tận dụng hệ thống kiểu GObject
- Trong quá trình này, việc tích hợp với ngôn ngữ Zig và kiểm tra vấn đề bộ nhớ bằng Valgrind đóng vai trò quan trọng
- Việc áp dụng hệ thống GObject giúp quản lý bộ nhớ và triển khai widget tùy chỉnh trở nên đơn giản hơn trước
- Kết quả từ việc sử dụng Valgrind cho thấy độ an toàn bộ nhớ của Ghostty đã được cải thiện đáng kể
- Ghostty GTK mới đã trở thành mặc định cho các bản dựng từ mã nguồn và sẽ được đưa vào bản phát hành 1.2
Giới thiệu
- Ghostty là một trình giả lập terminal đa nền tảng hỗ trợ macOS, Linux, FreeBSD
- Mỗi nền tảng sử dụng framework GUI native riêng để tạo khác biệt
- macOS: ứng dụng quy mô lớn dựa trên Swift và Xcode
- Linux và BSD: ứng dụng dựa trên GTK, tích hợp trực tiếp với X11/Wayland
- Phần lõi dùng chung được viết bằng Zig và cung cấp API tương thích C ABI
- Có thể tham khảo PR gốc để biết lý do viết lại ứng dụng GTK trong cấu trúc cũ
- Bài viết này tập trung vào việc tích hợp với hệ thống kiểu GObject và các vấn đề bộ nhớ được xác minh bằng Valgrind
Hệ thống kiểu GObject và Zig
- Khi sử dụng GTK, về cơ bản phải tương tác với hệ thống kiểu GObject
- Trước đây, dự án cố tránh dùng hệ thống GObject và tự đồng bộ vòng đời của đối tượng Zig không có reference counting với đối tượng GObject, nhưng liên tục gặp vấn đề giải phóng bộ nhớ không đúng cách
- Ví dụ: bộ nhớ phía Zig đã được giải phóng nhưng bộ nhớ phía GTK vẫn còn tồn tại, hoặc ngược lại
- Cách tiếp cận này không chỉ gặp vấn đề về tính đúng đắn mà còn khiến việc sử dụng các tính năng đặc thù của GTK (event signal, property binding, action) trở nên khó khăn
- Một ví dụ cụ thể là khi reload struct cấu hình (config), mọi phần tử GUI liên quan đều phải được cập nhật nhất quán, nhưng quá trình này phức tạp và dễ lỗi
- Hiện tại, dự án quản lý nó bằng
GhosttyConfig GObject có reference counting bao bọc struct Config của Zig, và các thông báo thay đổi thuộc tính giúp thay đổi được lan truyền tự nhiên trong toàn bộ ứng dụng
- Việc tạo widget GObject tùy chỉnh cũng trở nên dễ dàng hơn, cho phép dùng các công nghệ UI GTK hiện đại như Blueprint
- Gần đây, nhờ đưa vào Blueprint, việc bổ sung các tính năng mới như tab trên thanh tiêu đề GTK và viền chuông có hiệu ứng động đã trở nên dễ dàng hơn
Valgrind với GTK và Zig
- Trong toàn bộ quá trình phát triển, nhóm đã dùng Valgrind để kiểm chứng một cách có hệ thống các vấn đề như rò rỉ bộ nhớ và truy cập bộ nhớ chưa được định nghĩa
- Việc kiểm tra ứng dụng GTK bằng Valgrind khá khó khăn và cần tới các tệp suppression dung lượng lớn (80% là từ chính GTK, phần còn lại là thư viện bên thứ ba và driver GPU)
- Nhờ kiểm tra lặp đi lặp lại, nhóm có thể phát hiện sớm những lỗi bộ nhớ phức tạp chỉ xuất hiện trong một số trường hợp nhất định
- Ví dụ: nếu không khởi tạo đúng GObject
WeakRef, khi đối tượng đích được giải phóng về sau sẽ xảy ra truy cập bộ nhớ chưa được định nghĩa, và Valgrind đã phát hiện điều này từ trước
- Trong trải nghiệm thực tế, bên trong codebase Zig chỉ có tổng cộng 2 vấn đề (1 rò rỉ, 1 truy cập chưa được định nghĩa), và cả hai đều phát sinh trong quá trình tích hợp với C API của bên thứ ba
- Allocator debug của Zig và khả năng tích hợp với Valgrind cũng đã chứng minh được hiệu quả thực tế
- Các vấn đề bộ nhớ khác được phát hiện hầu hết xuất phát từ ranh giới C API và việc quản lý vòng đời phức tạp của hệ thống GObject
- Kết luận là, để sử dụng an toàn C API của các thư viện phức tạp, cần những công cụ như Valgrind
- Các tính năng hỗ trợ an toàn bộ nhớ của Zig không chỉ hiệu quả trên lý thuyết mà còn được xác nhận qua trải nghiệm dự án thực tế
Kết luận
- Đây là lần thứ năm phần GUI của Ghostty được xây lại từ đầu
- Theo thứ tự: GLFW, macOS SwiftUI, macOS AppKit+SwiftUI, Linux GTK (thủ tục), Linux GTK + hệ thống kiểu GObject
- Qua mỗi lần viết lại lặp đi lặp lại, nhóm đều thu được bài học mới và sự trưởng thành về kỹ thuật
- Họ cũng có kế hoạch áp dụng một phần kinh nghiệm này cho dự án macOS
- Bài viết cũng nhấn mạnh sự hợp tác tích cực từ đội duy trì hệ thống Ghostty GTK
- Ứng dụng Ghostty GTK được viết lại nay đã trở thành mặc định cho các bản dựng từ mã nguồn và sẽ được áp dụng trong bản phát hành chính thức 1.2
Chưa có bình luận nào.