����15-7 linux/lib/malloc.c


  1 /*

  2  * malloc.c --- a general purpose kernel memory allocator for Linux.

  3  *

  4  * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91

  5  *

  6  * This routine is written to be as fast as possible, so that it

  7  * can be called from the interrupt level.

  8  *

  9  * Limitations: maximum size of memory we can allocate using this routine

 10  *      is 4k, the size of a page in Linux.

 11  *

 12  * The general game plan is that each page (called a bucket) will only hold

 13  * objects of a given size.  When all of the object on a page are released,

 14  * the page can be returned to the general free pool.  When malloc() is

 15  * called, it looks for the smallest bucket size which will fulfill its

 16  * request, and allocate a piece of memory from that bucket pool.

 17  *

 18  * Each bucket has as its control block a bucket descriptor which keeps

 19  * track of how many objects are in use on that page, and the free list

 20  * for that page.  Like the buckets themselves, bucket descriptors are

 21  * stored on pages requested from get_free_page().  However, unlike buckets,

 22  * pages devoted to bucket descriptor pages are never released back to the

 23  * system.  Fortunately, a system should probably only need 1 or 2 bucket

 24  * descriptor pages, since a page can hold 256 bucket descriptors (which

 25  * corresponds to 1 megabyte worth of bucket pages.)  If the kernel is using

 26  * that much allocated memory, it's probably doing something wrong.  :-)

 27  *

 28  * Note: malloc() and free() both call get_free_page() and free_page()

 29  *      in sections of code where interrupts are turned off, to allow

 30  *      malloc() and free() to be safely called from an interrupt routine.

 31  *      (We will probably need this functionality when networking code,

 32  *      particularily things like NFS, is added to Linux.)  However, this

 33  *      presumes that get_free_page() and free_page() are interrupt-level

 34  *      safe, which they may not be once paging is added.  If this is the

 35  *      case, we will need to modify malloc() to keep a few unused pages

 36  *      "pre-allocated" so that it can safely draw upon those pages if

 37  *      it is called from an interrupt routine.

 38  *

 39  *      Another concern is that get_free_page() should not sleep; if it

 40  *      does, the code is carefully ordered so as to avoid any race

 41  *      conditions.  The catch is that if malloc() is called re-entrantly,

 42  *      there is a chance that unecessary pages will be grabbed from the

 43  *      system.  Except for the pages for the bucket descriptor page, the

 44  *      extra pages will eventually get released back to the system, though,

 45  *      so it isn't all that bad.

 46  */

 47

    /*

     *     malloc.c - Linux��ͨ���ں��ڴ���亯����

     *

     * ��Theodore Ts'o���� (tytso@mit.edu), 11/29/91

     *

     * �ú�������д�ɾ����ܵؿ죬�Ӷ����Դ��жϲ���ô˺�����

     *

     * ���ƣ�ʹ�øú���һ�����ܷ��������ڴ���4k��Ҳ��Linux���ڴ�ҳ��Ĵ�С��

     *

     * ��д�ú�������ѭ��һ�������ÿҳ(����Ϊһ���洢Ͱ)��������Ҫ���ɶ���Ĵ�С��

     * ��һҳ�ϵ����ж����ͷź󣬸�ҳ�Ϳ��Է���ͨ�ÿ����ڴ�ء���malloc()������

     * ʱ������Ѱ������Ҫ�����С�Ĵ洢Ͱ�����Ӹô洢Ͱ�з���һ���ڴ档

     *

     * ÿ���洢Ͱ����һ����Ϊ������õĴ洢Ͱ�����������м�¼��ҳ�����ж��ٶ�������

     * ʹ���Լ���ҳ�Ͽ����ڴ���б�������洢Ͱ����һ�����洢Ͱ������Ҳ�Ǵ洢��ʹ��

     * get_free_page()���뵽��ҳ���ϵģ�������洢Ͱ��ͬ���ǣ�Ͱ��������ռ�õ�ҳ��

     * �����ٻ��ͷŸ�ϵͳ�����˵���һ��ϵͳ��Լֻ��Ҫ1��2ҳ��Ͱ������ҳ�棬��Ϊһ

     * ��ҳ����Դ��256��Ͱ������(��Ӧ1MB�ڴ�Ĵ洢Ͱҳ��)�����ϵͳΪͰ��������

     * ���������ڴ棬��ô�϶�ϵͳʲô�ط���������J��

     *

     * ע�⣡malloc()��free()���߹ر����жϵĴ��벿�ֶ�������get_free_page()��

     *       free_page()��������ʹmalloc()��free()���԰�ȫ�ر����жϳ����е���

     *       (��������룬������NFS�ȱ����뵽Linux��ʱ�Ϳ�����Ҫ���ֹ���)����ǰ

     *       ���Ǽ���get_free_page()��free_page()�ǿ��԰�ȫ�����жϼ�������ʹ�õģ�

     *       ����һ�������˷�ҳ����֮��Ϳ��ܲ��ǰ�ȫ�ġ�������������������ô����

     *       ����Ҫ�޸�malloc()����Ԥ�ȷ��䡱��ҳ���õ��ڴ棬���malloc()��free()

     *       �����жϳ����е���ʱ�Ϳ��԰�ȫ��ʹ����Щҳ�档

     *

     *       ������Ҫ���ǵ�����get_free_page()��Ӧ��˯�ߣ������˯�ߵĻ�����Ϊ�˷�ֹ

     *       �κξ���������������Ҫ��ϸ�ذ���˳�� �ؼ��������malloc()�ǿ��������

     *       �����õĻ�����ô�ͻ���ڲ���Ҫ��ҳ�汻��ϵͳ��ȡ�ߵĻ��ᡣ��������Ͱ����

     *       ����ҳ�棬��Щ�����ҳ�����ջ��ͷŸ�ϵͳ�����Բ�������������������á�

     */

 

 48 #include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣

 49 #include <linux/mm.h>     // �ڴ����ͷ�ļ�������ҳ���С�����һЩҳ���ͷź���ԭ�͡�

 50 #include <asm/system.h>   // ϵͳͷ�ļ������������û��޸�������/�ж��ŵȵ�Ƕ��ʽ���ꡣ

 51

    // �洢Ͱ�������ṹ��

 52 struct bucket_desc {    /* 16 bytes */

 53         void                    *page;          // ��Ͱ��������Ӧ���ڴ�ҳ��ָ�롣

 54         struct bucket_desc      *next;          // ��һ��������ָ�롣

 55         void                    *freeptr;       // ָ��Ͱ�п����ڴ�λ�õ�ָ�롣

 56         unsigned short          refcnt;         // ���ü�����

 57         unsigned short          bucket_size;    // ����������Ӧ�洢Ͱ�Ĵ�С��

 58 };

 59

    // �洢Ͱ������Ŀ¼�ṹ��

 60 struct _bucket_dir {    /* 8 bytes */

 61         int                     size;      // �ô洢Ͱ�Ĵ�С(�ֽ���)��

 62         struct bucket_desc      *chain;    // �ô洢ͰĿ¼���Ͱ����������ָ�롣

 63 };

 64

 65 /*

 66  * The following is the where we store a pointer to the first bucket

 67  * descriptor for a given size. 

 68  *

 69  * If it turns out that the Linux kernel allocates a lot of objects of a

 70  * specific size, then we may want to add that specific size to this list,

 71  * since that will allow the memory to be allocated more efficiently.

 72  * However, since an entire page must be dedicated to each specific size

 73  * on this list, some amount of temperance must be exercised here.

 74  *

 75  * Note that this list *must* be kept in order.

 76  */

    /*

     * ���������Ǵ�ŵ�һ��������С�洢Ͱ������ָ��ĵط���

     *

     * ���Linux�ں˷���������ָ����С�Ķ�����ô���Ǿ�ϣ������ָ���Ĵ�С�ӵ�

     * ���б�(����)�У���Ϊ��������ʹ�ڴ�ķ������Ч�����ǣ���Ϊһҳ�����ڴ�ҳ��

     * ���������б���ָ����С�����ж���������Ҫ����������IJ��Բ�����

     */

    // �洢ͰĿ¼�б�(����)��

 77 struct _bucket_dir bucket_dir[] = {

 78         { 16,   (struct bucket_desc *) 0},    // 16�ֽڳ��ȵ��ڴ�顣

 79         { 32,   (struct bucket_desc *) 0},    // 32�ֽڳ��ȵ��ڴ�顣

 80         { 64,   (struct bucket_desc *) 0},    // 64�ֽڳ��ȵ��ڴ�顣

 81         { 128,  (struct bucket_desc *) 0},    // 128�ֽڳ��ȵ��ڴ�顣

 82         { 256,  (struct bucket_desc *) 0},    // 256�ֽڳ��ȵ��ڴ�顣

 83         { 512,  (struct bucket_desc *) 0},    // 512�ֽڳ��ȵ��ڴ�顣

 84         { 1024, (struct bucket_desc *) 0},    // 1024�ֽڳ��ȵ��ڴ�顣

 85         { 2048, (struct bucket_desc *) 0},    // 2048�ֽڳ��ȵ��ڴ�顣

 86         { 4096, (struct bucket_desc *) 0},    // 4096�ֽ�(1ҳ)�ڴ档

 87         { 0,    (struct bucket_desc *) 0}};   /* End of list marker */

 88

 89 /*

 90  * This contains a linked list of free bucket descriptor blocks

 91  */

    /*

     * �����Ǻ��п���Ͱ�������ڴ���������

     */

 92 struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0;

 93

 94 /*

 95  * This routine initializes a bucket description page.

 96  */

    /*

     * ������ӳ������ڳ�ʼ��һҳͰ������ҳ�档

     */

    //// ��ʼ��Ͱ��������

    // ��������Ͱ����������������free_bucket_descָ���һ������Ͱ��������

 97 static inline void init_bucket_desc()

 98 {

 99         struct bucket_desc *bdesc, *first;

100         int     i;

101        

    // ����һҳ�ڴ棬���ڴ��Ͱ�����������ʧ�ܣ�����ʾ��ʼ��Ͱ������ʱ�ڴ治��������Ϣ��������

102         first = bdesc = (struct bucket_desc *) get_free_page();

103         if (!bdesc)

104                 panic("Out of memory in init_bucket_desc()");

    // ���ȼ���һҳ�ڴ��пɴ�ŵ�Ͱ������������Ȼ����佨����������ָ�롣

105         for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) {

106                 bdesc->next = bdesc+1;

107                 bdesc++;

108         }

109         /*

110          * This is done last, to avoid race conditions in case

111          * get_free_page() sleeps and this routine gets called again....

112          */

            /*

             * ������������ģ�Ŀ����Ϊ�˱�����get_free_page()˯��ʱ���ӳ����ֱ�

             * ���ö�����ľ���������

             */

    // ������Ͱ������ָ��free_bucket_desc���������С�

113         bdesc->next = free_bucket_desc;

114         free_bucket_desc = first;

115 }

116

    //// ���䶯̬�ڴ溯����

    // ������len - ������ڴ�鳤�ȡ�

    // ���أ�ָ�򱻷����ڴ��ָ�롣���ʧ���򷵻�NULL��

117 void *malloc(unsigned int len)

118 {

119         struct _bucket_dir      *bdir;

120         struct bucket_desc      *bdesc;

121         void                    *retval;

122

123         /*

124          * First we search the bucket_dir to find the right bucket change

125          * for this request.

126          */

            /*

             * �������������洢ͰĿ¼bucket_dir��Ѱ���ʺ������Ͱ��С��

             */

    // �����洢ͰĿ¼��Ѱ���ʺ������ڴ���С��Ͱ���������������Ŀ¼���Ͱ�ֽ�������������ֽ�

    // �������ҵ��˶�Ӧ��ͰĿ¼�

127         for (bdir = bucket_dir; bdir->size; bdir++)

128                 if (bdir->size >= len)

129                         break;

    // �������������Ŀ¼��û���ҵ����ʴ�С��Ŀ¼��������������ڴ���С̫�󣬳����˸�

    // ����ķ�������(�Ϊ1��ҳ��)��������ʾ������Ϣ��������

130         if (!bdir->size) {

131                 printk("malloc called with impossibly large argument (%d)\n",

132                         len);

133                 panic("malloc: bad arg");

134         }

135         /*

136          * Now we search for a bucket descriptor which has free space

137          */

            /*

             * �����������������п��пռ��Ͱ��������

             */

138         cli();  /* Avoid race conditions */   /* Ϊ�˱�����־������������ȹ��ж� */

    // ������ӦͰĿ¼�������������������Ҿ��п��пռ��Ͱ�����������Ͱ�������Ŀ����ڴ�ָ��

    // freeptr��Ϊ�գ����ʾ�ҵ�����Ӧ��Ͱ��������

139         for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next)

140                 if (bdesc->freeptr)

141                         break;

142         /*

143          * If we didn't find a bucket with free space, then we'll

144          * allocate a new one.

145          */

            /*

             * ���û���ҵ����п��пռ��Ͱ����������ô���Ǿ�Ҫ�½���һ����Ŀ¼�����������

             */

146         if (!bdesc) {

147                 char            *cp;

148                 int             i;

149

    // ��free_bucket_desc��Ϊ��ʱ����ʾ��һ�ε��øó��򣬻������������п�Ͱ�������������ꡣ

    // ��ʱ����Ҫ����һ��ҳ�沢�����Ͻ�������ʼ������������������free_bucket_desc��ָ���һ

    // ������Ͱ��������

150                 if (!free_bucket_desc

151                         init_bucket_desc();

    // ȡfree_bucket_descָ��Ŀ���Ͱ������������free_bucket_descָ����һ������Ͱ��������

152                 bdesc = free_bucket_desc;

153                 free_bucket_desc = bdesc->next;

    // ��ʼ�����µ�Ͱ������������������������0��Ͱ�Ĵ�С���ڶ�ӦͰĿ¼�Ĵ�С������һ�ڴ�ҳ�棬

    // ����������ҳ��ָ��pageָ���ҳ�棻�����ڴ�ָ��Ҳָ���ҳ��ͷ����Ϊ��ʱȫΪ���С�

154                 bdesc->refcnt = 0;

155                 bdesc->bucket_size = bdir->size;

156                 bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();

    // ��������ڴ�ҳ�����ʧ�ܣ�����ʾ������Ϣ��������

157                 if (!cp)

158                         panic("Out of memory in kernel malloc()");

159                 /* Set up the chain of free objects */

                    /* �ڸ�ҳ�����ڴ��н������ж������� */

    // �Ը�ͰĿ¼��ָ����Ͱ��СΪ���󳤶ȣ��Ը�ҳ�ڴ���л��֣���ʹÿ������Ŀ�ʼ4�ֽ�����

    // ��ָ����һ�����ָ�롣

160                 for (i=PAGE_SIZE/bdir->size; i > 1; i--) {

161                         *((char **) cp) = cp + bdir->size;

162                         cp += bdir->size;

163                 }

    // ���һ������ʼ����ָ������Ϊ0(NULL)��

    // Ȼ���ø�Ͱ����������һ������ָ���ֶ�ָ���ӦͰĿ¼��ָ��chain��ָ������������ͰĿ¼��

    // chainָ���Ͱ��������Ҳ���������������뵽����������ͷ����

164                 *((char **) cp) = 0;

165                 bdesc->next = bdir->chain; /* OK, link it in! */   /* OK���������룡*/

166                 bdir->chain = bdesc;

167         }

    // ����ָ�뼴���ڸ���������Ӧҳ��ĵ�ǰ����ָ�롣Ȼ������ÿ��пռ�ָ��ָ����һ�����ж���

    // ��ʹ�������ж�Ӧҳ���ж������ü�����1��

168         retval = (void *) bdesc->freeptr;

169         bdesc->freeptr = *((void **) retval);

170         bdesc->refcnt++;

    // ��󿪷��жϣ�������ָ������ڴ�����ָ�롣

171         sti();  /* OK, we're safe again */   /* OK�����������ְ�ȫ��*/

172         return(retval);

173 }

174

175 /*

176  * Here is the free routine.  If you know the size of the object that you

177  * are freeing, then free_s() will use that information to speed up the

178  * search for the bucket descriptor.

179  *

180  * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)"

181  */

    /*

     * �������ͷ��ӳ��������֪���ͷŶ���Ĵ�С����free_s()��ʹ�ø���Ϣ����

     * ��Ѱ��ӦͰ���������ٶȡ�

     *

     * ���ǽ�����һ���꣬ʹ��"free(x)"��Ϊ"free_s(x, 0)"��

     */

    //// �ͷŴ洢Ͱ����

    // ������obj - ��Ӧ����ָ�룻size - ��С��

182 void free_s(void *obj, int size)

183 {

184         void            *page;

185         struct _bucket_dir      *bdir;

186         struct bucket_desc      *bdesc, *prev;

187

188         /* Calculate what page this object lives in */

            /* ����ö������ڵ�ҳ�� */

189         page = (void *)  ((unsigned long) obj & 0xfffff000);

190         /* Now search the buckets looking for that page */

            /* ���������洢ͰĿ¼�������ӵ�Ͱ��������Ѱ�Ҹ�ҳ�� */

    //

191         for (bdir = bucket_dir; bdir->size; bdir++) {

192                 prev = 0;

193                 /* If size is zero then this conditional is always false */

                    /* �������size��0�������������϶���false */

194                 if (bdir->size < size)

195                         continue;

    // ������ӦĿ¼�������ӵ����������������Ҷ�Ӧҳ�档���ij������ҳ��ָ�����page���ʾ�ҵ�

    // ����Ӧ������������ת��found����������������ж�Ӧpage������������ָ��prevָ�����������

196                 for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) {

197                         if (bdesc->page == page)

198                                 goto found;

199                         prev = bdesc;

200                 }

201         }

    // �������˶�ӦĿ¼���������������û���ҵ�ָ����ҳ�棬����ʾ������Ϣ��������

202         panic("Bad address passed to kernel free_s()");

203 found:

    // �ҵ���Ӧ��Ͱ�����������ȹ��жϡ�Ȼ�󽫸ö����ڴ��������п���������У���ʹ��������

    // �Ķ������ü�����1��

204         cli(); /* To avoid race conditions */   /* Ϊ�˱��⾺������ */

205         *((void **)obj) = bdesc->freeptr;

206         bdesc->freeptr = obj;

207         bdesc->refcnt--;

    // ������ü����ѵ���0�������ǾͿ����ͷŶ�Ӧ���ڴ�ҳ��͸�Ͱ��������

208         if (bdesc->refcnt == 0) {

209                 /*

210                  * We need to make sure that prev is still accurate.  It

211                  * may not be, if someone rudely interrupted us....

212                  */

                    /*

                     * ������Ҫȷ��prev��Ȼ����ȷ�ģ���ij�����³���ж�������

                     * ���п��ܲ����ˡ�

                     */

    // ���prev�Ѿ���������������������ǰһ����������������������ǰ��������ǰһ����������

213                 if ((prev && (prev->next != bdesc)) ||

214                     (!prev && (bdir->chain != bdesc)))

215                         for (prev = bdir->chain; prev; prev = prev->next)

216                                 if (prev->next == bdesc)

217                                         break;

    // ����ҵ���ǰһ�����������������������ɾ����ǰ��������

218                 if (prev)

219                         prev->next = bdesc->next;

    // ���prev==NULL����˵����ǰһ���������Ǹ�Ŀ¼���׸���������Ҳ��Ŀ¼����chainӦ��ֱ��

    // ָ��ǰ������bdesc�������ʾ���������⣬����ʾ������Ϣ����������ˣ�Ϊ�˽���ǰ������

    // ��������ɾ����Ӧ����chainָ����һ����������

220                 else {

221                         if (bdir->chain != bdesc)

222                                 panic("malloc bucket chains corrupted");

223                         bdir->chain = bdesc->next;

224                 }

    // �ͷŵ�ǰ���������������ڴ�ҳ�棬�������������������������������ʼ����

225                 free_page((unsigned long) bdesc->page);

226                 bdesc->next = free_bucket_desc;

227                 free_bucket_desc = bdesc;

228         }

    // ���жϣ����ء�

229         sti();

230         return;

231 }

232

233