Trong hơn 10 năm kể từ khi bắt đầu làm lập trình Linux kernel, đây có lẽ là bug khó nhất mình từng gặp phải. Bug này ảnh hưởng nghiêm trọng đến sản phẩm của khách hàng, nên khi khách hàng tìm đến thì mọi chuyện đã trở lên rất gấp.
Ban đầu khi nhìn vào thông tin của lỗi, mình chỉ nghĩ đơn giản đó là lỗi dead lock trong hệ thống Linux embedded. Tuy nhiên sau khi join dự án, được khách hàng cung cấp thêm thông tin thì mới biết mọi chuyện không đơn giản như vậy.
Để mô tả kỹ hơn thì sản phẩm của khách hàng sử dụng dual-kernel, trong đó Linux kernel chạy song song cùng 1 real-time kernel khác. Real-time kernel bên kia can thiệp sâu vào Linux, ví dụ như thay đổi nguyên lý bộ lập lich, system call, interrupt,… Lỗi dead-lock đó là hệ quả của sự mâu thuẫn xảy ra giữa 2 bộ lập lịch, và tất nhiên còn đến từ lỗi lập trình nào đó từ phía khách hàng. Thật sự mà nói bản thân mình trước đó chưa hề có kinh nghiệm làm về real-time kernel, nên sau khi hiểu rõ về hệ thống, mình cũng không thể ước tính được bao giờ sẽ làm xong. Ít nhất trước khi đi vào sửa bug, mình phải đọc lướt qua toàn bộ source code của real-time kernel kia, để biết nó đã can thiệp những gì sang phía Linux. Đối với những bug khó thứ 2, thứ 3 mà mình gặp trước đây thì thời gian để sửa đâu đó khoảng ba đến bốn tháng. Tuy nhiên, con số này có vẻ khó có được sự chấp nhận từ phía khách hàng.
Vậy mình đã xử lý như thế nào?
- Đầu tiên là mình viết một “báo cáo hàng ngày” lên 1 file word online để share với khách hàng. Trên đó mình liệt kê ra những phỏng đoán về nguyên nhân của lỗi. Mỗi ngày mình sẽ chọn ra 1 nguyên nhân khả thi nhất để điều tra. Nếu ngày hôm đó không xong thì lại tiếp tục điều tra vào hôm sau. Đến khi mình cảm thấy hướng đi đó đã vào ngõ cụt thì mình lựa chọn 1 nguyên nhân khác trong danh sách trên để điều tra tiếp. Trong quá trình điều tra, nếu có thêm ý tưởng về nguyên nhân gây lỗi thì mình sẽ bổ sung thêm vào danh sách. Công việc điều tra hàng ngày mình đã làm những gì, kết quả ra sao, mình nghĩ gì trong đầu đều được ghi ra file báo cáo đó.
- Mình luôn cố gắng giải thích với khách hàng những gì mình đang phân tích ở trong đầu. Đối với 1 bug mà mình biết cách thì thường mình sẽ không làm thế này, vì chuyện giải thích nguyên lý hoạt động của kernel cho những người chỉ làm trên tầng application là rất mất thời gian. Thông thường mình sẽ thông báo luôn là bug đó sửa mất bao nhiêu ngày, sau khi sửa xong thì mình mới giải thích.
Chắc hẳn, đọc đến đây sẽ có không ít người thắc mắc rằng tại sao mình lại làm như vậy.
Thứ nhất, mục tiêu mình hướng đến là tạo sự tin tưởng của khách hàng. Mặc dù hiện tại mình chưa tìm ra được gốc rễ của nguyên nhân nhưng công việc vẫn đang có tiến triển.
Thứ hai, mình muốn khách hàng hiểu việc thuê mình để sửa lỗi này là sự lựa chọn tốt nhất. Việc họ tìm đến một đối tác khác để sửa lỗi chỉ làm vấn đề trầm trọng thêm và tốn thời gian hơn mà thôi.
- Trong quá trình debug, khách hàng đã thúc giục mình liên tục. Việc này tạo ra một áp lực khá lớn đối với bản thân mình. Ngoài ra còn phải điều tra theo một số hướng mà khách yêu cầu, mặc dù mình biết những hướng đó sẽ chẳng đi đến đâu. Thật sự, tâm trạng của mình lúc này rất oải. Tuy nhiên, để có thể đi tiếp, mình đã nghĩ đây là cơ hội để cho mình học cái mới. Ngồi đọc code của 2 bộ lập lịch, xem cách người ta hỗ trợ real-time task trong Linux như thế nào. Kể cả sau 2, 3 tháng bug không sửa được và thất bại trong dự án của khách hàng thì mình cũng học thêm nhiều kiến thức mới.
Cứ như vậy, sau khoảng 3 tuần mình cũng đã nắm được tương đối về nguyên lý hoạt động của cái real-time kernel kia, cách nó và Linux tương tác với nhau. Nguyên nhân của bug dead-lock cũng được khoanh vùng lại. Đâu đó trong hệ thống có khoảng 3 luồng thread thao tác vào chung 1 tài nguyên. 1 luồng trong app của khách, 1 luồng của real-time os và luồng còn lại của Linux kernel. Bug dead-lock này ở dạng ngẫu nhiên, tần suất xuất hiện rất thấp – 1 lần / vài ngày chạy liên tục.
Đối với những bug dead-lock có tần suất xuất hiện thấp như vậy thường sẽ khó debug, nhưng khi khoanh vùng được nguyên nhân thì mẹo fix lại khá đơn giản. Những thread tham gia và việc gây lỗi giống như những bánh răng của 1 cỗ máy. Thông thường chúng sẽ quay với tốc độ ngẫu nhiên, chỉ khi tình cờ chúng kết hợp nhịp nhàng tại 1 thời điểm thì bug dead-lock mới xuất hiện.
Một cách fix tương đối, tạm chấp nhận được là thay đổi thông số của 1 trong số những bánh răng tham gia vào việc gây lỗi. Khiến cho chúng không bao giờ có thể kết hợp nhịp nhàng với nhau được nữa thì bug cũng không xuất hiện.
Sau khi bug được fix xong, nhìn lại thì mình đã học được rất nhiều từ nó. Cho dù có fix được hay không thì những kiến thức mình thu được vẫn giúp bản thân đi được thêm 1 đoạn trong con đường tìm hiểu về lĩnh vực này.