malloc/free
id:higepon が malloc/free のことを日記で書いていたので、BayOS で使っているものを紹介します。といっても自前実装ではなく、MonaWiki/MonaDat にある Mona-20050620-MonaDat.tar.bz2 を改良して使っています。割り当てが早いらしいのと、なによりソースコードがすごく小さいのが採用の理由です。new / delete がこれだけで使えるようになりますので、C++ で OS を書きたいと思っている人におすすめです(アプリプログラマには関係ないですが、メモリの割り当てと解放は OS やライブリーの仕事なので、OS を書く人はこれも自前でやらないとインスタンス1つさえ生成できません)。あと、MonaWiki にある sms_gc を組み合わせるとすごくコンパクトな GC が作れるので、D言語や Java などで OS を書きたいと思っている人にもおすすめです(笑)。ちなみに、メモリ割り当て時にゼロクリアしていないので、危険だとおもったら、g_km.allocate 後にゼロクリアして使ってください。
memory.h
#ifndef _MEMORY_H_ #define _MEMORY_H_ #include "types.h" typedef struct MemoryInfo { dword total, free; }; class Memory { private: dword start, end, used, firstFree; public: void init(dword size, dword end); void* allocate(dword size); void free(void* address); void get_status(MemoryInfo* minfo); private: dword search_fit(dword size); bool check_address(dword ptr, dword* prev); void set_next(dword ptr, dword next); dword get_next(dword ptr); }; // カーネルメモリ extern Memory g_km; // // ここから下は C++言語の new / delete サポート // および C言語の malloc / free サポート // void* operator new(size_t size); void operator delete(void* address); #ifdef __cplusplus extern "C" { #endif void* malloc(size_t size); void free(void * address); #ifdef __cplusplus } #endif void __builtin_delete(void* address); void* __builtin_new(size_t size); void* __builtin_vec_new(size_t size); void __builtin_vec_delete(void* address); inline void* operator new(size_t, void* __p) { return __p; } #endif
memory.cpp
#include "Memory.h" class MemoryEntry { public: int Size; dword Prev, Next; inline static void write_used(dword ptr, dword size) { *(dword*)ptr = *(dword*)(ptr + size - sizeof(dword)) = size; } inline static void write_free(dword ptr, dword size, dword prev, dword next) { dword* p = (dword*)ptr; *(p++) = *(dword*)(ptr + size - sizeof(dword)) = size | 0x80000000; *(p++) = prev; *p = next; } inline static void write_last(dword ptr, dword prev) { dword* p = (dword*)ptr; *(p++) = 0; *p = prev; } }; void Memory::init(dword start, dword end) { this->start = this->firstFree = start; this->end = end; this->used = 0; MemoryEntry::write_last(this->start, 0); } void* Memory::allocate(dword size) { dword sz = (sizeof(dword) + size + sizeof(dword) + 15) & 0xfffffff0; // align16 dword ptr = this->search_fit(sz); if (ptr == 0 || ptr + sz > this->end) return NULL; this->used += sz; MemoryEntry* h = (MemoryEntry*)ptr; dword sz_old = h->Size & 0x7fffffff; dword nptr = ptr + sz, prev = h->Prev, next = nptr; if (sz_old == 0) { MemoryEntry::write_last(nptr, prev); } else { if (sz < sz_old) { MemoryEntry::write_free(nptr, sz_old - sz, prev, h->Next); ((MemoryEntry*)h->Next)->Prev = nptr; } else { next = h->Next; ((MemoryEntry*)next)->Prev = prev; } } MemoryEntry::write_used(ptr, sz); this->set_next(prev, next); return (void*)(ptr + sizeof(dword)); } dword Memory::search_fit(dword size) { for (dword p = this->firstFree; p <= this->end; p = ((MemoryEntry*)p)->Next) { int sz = ((MemoryEntry*)p)->Size; if (sz == 0) { return p; } else if (sz > 0) { break; } sz &= 0x7fffffff; if (size <= (dword)sz) return p; } return 0; } void Memory::free(void* address) { dword ptr = ((dword)address) - sizeof(dword), prev = 0; if (!this->check_address(ptr, &prev)) return; this->used -= ((MemoryEntry*)ptr)->Size; dword sz = *(int*)ptr, next = this->get_next(prev); if (ptr > this->start) { int psz = *(int*)(ptr - sizeof(int)); if (psz < 0) { psz &= 0x7fffffff; ptr -= psz; sz += psz; prev = ((MemoryEntry*)ptr)->Prev; } } dword nptr = ptr + sz, nsz = *(dword*)nptr; if (nsz < 0) { sz += nsz & 0x7fffffff; next = ((MemoryEntry*)nptr)->Next; } if (nsz == 0) { MemoryEntry::write_last(ptr, prev); } else { MemoryEntry::write_free(ptr, sz, prev, next); ((MemoryEntry*)next)->Prev = ptr; } this->set_next(prev, ptr); } bool Memory::check_address(dword ptr, dword* prev) { if (ptr < this->start || ptr > this->end) return false; int psz1 = *(int*)ptr; if (psz1 < 16 || (psz1 & 15) != 0 || ptr + psz1 > this->end) return false; int psz2 = *(int*)(ptr + psz1 - sizeof(int)); if (psz1 != psz2) return false; for (dword p = this->firstFree; p <= ptr; p = ((MemoryEntry*)p)->Next) { if (((MemoryEntry*)p)->Size >= 0) return false; *prev = p; } return true; } void Memory::set_next(dword ptr, dword next) { if (ptr == 0) { this->firstFree = next; } else { ((MemoryEntry*)ptr)->Next = next; } } dword Memory::get_next(dword ptr) { return ptr == 0 ? this->firstFree : ((MemoryEntry*)ptr)->Next; } void Memory::get_status(MemoryInfo* minfo) { minfo->total = this->end - this->start; minfo->free = minfo->total - this->used; } // // ここから下は C++言語の new / delete サポート // および C言語の malloc / free サポート // void* operator new(size_t size) { void* p = g_km.allocate(size); return p; } void operator delete(void* address) { g_km.free(address); return; } void* operator new[](size_t size) { void* p = g_km.allocate(size); return p; } void operator delete[](void* address) { g_km.free(address); return; } void* malloc(size_t size) { void* p = g_km.allocate(size); return p; } void free(void * address) { g_km.free(address); return; }
使い方
#include "memory.h" /* カーネルメモリの初期化 */ Memory g_km; dword km_start = 0x000200000; dword km_end = 0x0007fffff; g_km.init(km_start, km_end); /* new / delete */ Test* test = new Test(); delete(test); /* malloc / free */ char* buff = (char*)malloc(1024); free(buff);