Skip to content

📦 صندوق الألعاب: تشريح mm/heap.rs (مدير الحجز الديناميكي) ​

في لغة Rust، العيش بدون ذاكرة ديناميكية (Dynamic Allocation) هو جحيم حقيقي! لن تستطيع استخدام String، ولا Vec، ولا Box. في الأنظمة العادية، لغة Rust تطلب الذاكرة من نظام التشغيل (عبر malloc في C). ولكن هنا، نحن نظام التشغيل! يجب أن نبرمج مدير الـ Heap الخاص بنا لنطعم لغة Rust!

1. تحقيق واجهة GlobalAlloc ​

يجب أن نقوم ببناء كائن، ثم نضع فوقه وسم #[global_allocator] ليقوم المترجم بتوجيه جميع استدعاءات Box و String إليه تلقائياً.

rust
#[global_allocator]
static ALLOCATOR: Spinlock<HeapAllocator> = Spinlock::new(HeapAllocator::empty());

unsafe impl GlobalAlloc for Spinlock<HeapAllocator> {
    unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
        // عندما تكتب Box::new(5) سيتم استدعاء هذا السطر!
        self.lock().allocate(layout).unwrap_or(core::ptr::null_mut())
    }

    unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
        // وعندما ينتهي عمر المتغير، يُستدعى هذا السطر لتحرير الذاكرة
        self.lock().deallocate(ptr, layout);
    }
}

2. هندسة الـ Bump Allocator (أو غيره) ​

الـ Heap هو ببساطة قطعة أرض ضخمة (مثلاً 1MB) نحجزها للنواة عند بدء التشغيل.

  • الـ Allocator يحتفظ بمؤشر (Pointer) يدل على أول مساحة فارغة.
  • كلما طُلب حجز جديد، يُحرَّك المؤشر للأمام بمقدار الحجم المطلوب.
  • إذا امتلأت مساحة الـ Heap، يستعين الـ Allocator بـ الـ VMM (map_page) لجلب صفحات جديدة وضمها لأرض الـ Heap!

⚠️ ملاحظة أمنية قوية: الـ Heap الذي بُرمج هنا هو للنواة فقط (Ring 0). البرامج التي تعمل في وضع المستخدم (Ring 3) تمتلك مدير Heap منفصل خاص بها تماماً، ولا تشارك النواة في هذا الـ Heap قط. هذا يمنع أي عملية خبيثة من استهلاك (استنفاد) ذاكرة النواة (OOM)!

تم تطويره بحب بواسطة مجتمع Qtoom.