memalign.c 4.39 KB
/*
=============================================================================
        Copyright (C) 1997-1999 NINTENDO Co.,Ltd.
        
        $RCSfile: memalign.c,v $
        $Revision: 1.1.1.1 $
        $Date: 2002/10/30 02:07:09 $
=============================================================================
関数名:memalign
-----------------------------------------------------------------------------
書式:  #include <malloc.h>
        void *memalign(int alignment, size_t size);
引数:  alignment アライメント値
        size 確保するサイズ
戻り値:確保した領域の先頭ポインタ。
        確保に失敗したら NULL を返す。
説明:  InitHeap で確保した領域に alignment でアライメントを
        調整した領域から、size 以上のメモリブロックを確保する。
        アライメント値が 16 以下の場合は、アライメント値を 16 として、
        処理される。
-----------------------------------------------------------------------------
*/
#include    <ultra64.h>
#include    "string.h"
#include    "malloc.h"
#include    "_malloc.h"

void *memalign(int alignment, size_t size)
{
    int size2;
    unsigned int    *next2, *p, *r;
    unsigned char   *c;
    struct mallocST *malloc_st_ptr;

    if ((int)malloc_ptr == -1)  return  NULL;

    if (!size)  return  NULL;

    if( alignment <= 16 ){
	return _malloc( malloc_ptr, size ) ;
    }

    malloc_st_ptr = (struct mallocST *)malloc_ptr;
    size += 15;
    size &= (~15);

    size2 = 0;
    next2 = 0;
    while(1)    {
        if (!malloc_st_ptr->flag)   {
            c = (unsigned char *)malloc_st_ptr;
            c += (MALLOC_HEADSIZE + alignment - 1);
            c = (unsigned char *)((int)c & (~(alignment-1)));
            if (c >= (unsigned char *)malloc_st_ptr+MALLOC_HEADSIZE && c+size<(unsigned char *)malloc_st_ptr+malloc_st_ptr->size) {
                //  アライメント後のアドレスがブロック内?
                if ((size2 > malloc_st_ptr->size) || !size2)    {
                    r = (unsigned int *)c;
                    p = (unsigned int *)malloc_st_ptr;
                    size2 = malloc_st_ptr->size;
                    next2 = malloc_st_ptr->next;
                }
            }
        }
        if (!(malloc_st_ptr->next)) break;
        malloc_st_ptr = (struct mallocST *)malloc_st_ptr->next;
    }

    if (size2)  {
        if (p != (unsigned int *)malloc_ptr)    {
            if ((int)r - (int)p<= 32)    {   //  アライメントのために前に空くメモリが16バイト以下なら前の容量を増やす。
                if (r-p >15)    {
                    malloc_st_ptr = (struct mallocST *)malloc_ptr;
                    while(1)    {
                        if (malloc_st_ptr->next == 0)   break;
                        if (malloc_st_ptr->next == p)   {
                            malloc_st_ptr->next = r-MALLOC_HEADSIZE;
                            malloc_st_ptr->size += 16;
                            break;
                        }
                        malloc_st_ptr = (struct mallocST *)malloc_st_ptr->next;
                    }
                }
            }   else    {           //  アライメント後の前に16バイト以上の大きな空きメモリが出来たのでブロックを作成
                malloc_st_ptr = (struct mallocST *)p;
                malloc_st_ptr->next = r -(MALLOC_HEADSIZE/sizeof(unsigned int *));
                malloc_st_ptr->size = (int)r - (int)p - MALLOC_HEADSIZE * 2;
                malloc_st_ptr->flag = 0;
            }
        }   else    {
            malloc_st_ptr = (struct mallocST *)p;
            malloc_st_ptr->next = r - (MALLOC_HEADSIZE / sizeof(int *));
            malloc_st_ptr->size = (r - p)*sizeof(int) - MALLOC_HEADSIZE * 2;
            malloc_st_ptr->flag = 0;
        }
        c = (char *)r;
        c -= MALLOC_HEADSIZE;
        malloc_st_ptr = (struct mallocST *)c;

        if (size2>=size+MALLOC_HEADSIZE+16) {
            malloc_st_ptr->next = (unsigned int *)((unsigned int)r + size);         /*  メモリ確保  */
            malloc_st_ptr->size = size;
            malloc_st_ptr->flag = 1;

            malloc_st_ptr = (struct mallocST *)malloc_st_ptr->next;                     /*  あまりメモリ開放    */
            malloc_st_ptr->next = next2;
            malloc_st_ptr->size = size2 - size - (r - p) * sizeof(int);

            malloc_st_ptr->flag = 0;
        }   else    {
            malloc_st_ptr->next = next2;
            malloc_st_ptr->size = (int)(next2 - r);
            malloc_st_ptr->flag = 1;
        }
        return  (unsigned char *)r;
    }
    return  NULL;
}