base/malloc/malloc.c

Go to the documentation of this file.
00001 /*!\file malloc.c 00002 * \brief Dynamic memory allocation services. 00003 * \author Philippe Gerum 00004 * 00005 * Copyright (C) 2001,2002,2003,2004 Philippe Gerum <rpm@xenomai.org>. 00006 * 00007 * RTAI is free software; you can redistribute it and/or modify it 00008 * under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 2 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * RTAI is distributed in the hope that it will be useful, but WITHOUT 00013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 00014 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 00015 * License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with RTAI; if not, write to the Free Software Foundation, 00019 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00020 * 00021 * Dynamic memory allocation services lifted and adapted from the 00022 * Xenomai nucleus. 00023 * 00024 * This file implements the RTAI dynamic memory allocator based on the 00025 * algorithm described in "Design of a General Purpose Memory 00026 * Allocator for the 4.3BSD Unix Kernel" by Marshall K. McKusick and 00027 * Michael J. Karels. 00028 * 00029 * \ingroup shm 00030 */ 00031 00032 /*! 00033 * @addtogroup shm 00034 *@{*/ 00035 00036 #include <linux/module.h> 00037 #include <linux/kernel.h> 00038 #include <linux/version.h> 00039 #include <rtai_config.h> 00040 #include <asm/rtai.h> 00041 #ifdef CONFIG_RTAI_MALLOC_VMALLOC 00042 #include <rtai_shm.h> 00043 #else /* !CONFIG_RTAI_MALLOC_VMALLOC */ 00044 #include <linux/slab.h> 00045 #endif /* CONFIG_RTAI_MALLOC_VMALLOC */ 00046 #include <rtai_malloc.h> 00047 00048 MODULE_PARM(rtai_global_heap_size,"i"); 00049 00050 int rtai_global_heap_size = RTHEAP_GLOBALSZ; 00051 00052 void *rtai_global_heap_adr = NULL; 00053 00054 rtheap_t rtai_global_heap; /* Global system heap */ 00055 00056 static void *alloc_extent (u_long size) 00057 { 00058 caddr_t p; 00059 #ifdef CONFIG_RTAI_MALLOC_VMALLOC 00060 caddr_t _p; 00061 00062 p = _p = (caddr_t)vmalloc(size); 00063 if (p) { 00064 printk("RTAI[malloc]: vmalloced extent %p, size %lu.\n", p, size); 00065 for (; size > 0; size -= PAGE_SIZE, _p += PAGE_SIZE) { 00066 mem_map_reserve(virt_to_page(__va(kvirt_to_pa((u_long)_p)))); 00067 } 00068 } 00069 #else /* !CONFIG_RTAI_MALLOC_VMALLOC */ 00070 p = (caddr_t)kmalloc(size,GFP_KERNEL); 00071 printk("RTAI[malloc]: kmalloced extent %p, size %lu.\n", p, size); 00072 #endif /* CONFIG_RTAI_MALLOC_VMALLOC */ 00073 if (p) { 00074 memset(p, 0, size); 00075 } 00076 return p; 00077 } 00078 00079 static void free_extent (void *p, u_long size) 00080 { 00081 #ifdef CONFIG_RTAI_MALLOC_VMALLOC 00082 caddr_t _p = (caddr_t)p; 00083 00084 printk("RTAI[malloc]: vfreed extent %p, size %lu.\n", p, size); 00085 for (; size > 0; size -= PAGE_SIZE, _p += PAGE_SIZE) { 00086 mem_map_unreserve(virt_to_page(__va(kvirt_to_pa((u_long)_p)))); 00087 } 00088 vfree(p); 00089 #else /* !CONFIG_RTAI_MALLOC_VMALLOC */ 00090 printk("RTAI[malloc]: kfreed extent %p, size %lu.\n", p, size); 00091 kfree(p); 00092 #endif /* CONFIG_RTAI_MALLOC_VMALLOC */ 00093 } 00094 00095 static void init_extent (rtheap_t *heap, rtextent_t *extent) 00096 { 00097 caddr_t freepage; 00098 int n, lastpgnum; 00099 00100 INIT_LIST_HEAD(&extent->link); 00101 00102 /* The page area starts right after the (aligned) header. */ 00103 extent->membase = (caddr_t)extent + heap->hdrsize; 00104 lastpgnum = heap->npages - 1; 00105 00106 /* Mark each page as free in the page map. */ 00107 for (n = 0, freepage = extent->membase; n < lastpgnum; n++, freepage += heap->pagesize) { 00108 *((caddr_t *)freepage) = freepage + heap->pagesize; 00109 extent->pagemap[n] = RTHEAP_PFREE; 00110 } 00111 *((caddr_t *)freepage) = NULL; 00112 extent->pagemap[lastpgnum] = RTHEAP_PFREE; 00113 extent->memlim = freepage + heap->pagesize; 00114 00115 /* The first page starts the free list of a new extent. */ 00116 extent->freelist = extent->membase; 00117 } 00118 00119 /*! 00120 * \fn int rtheap_init(rtheap_t *heap, 00121 void *heapaddr, 00122 u_long heapsize, 00123 u_long pagesize); 00124 * \brief Initialize a memory heap. 00125 * 00126 * Initializes a memory heap suitable for dynamic memory allocation 00127 * requests. The heap manager can operate in two modes, whether 00128 * time-bounded if the heap storage area and size are statically 00129 * defined at initialization time, or dynamically extendable at the 00130 * expense of a less deterministic behaviour. 00131 * 00132 * @param heap The address of a heap descriptor the memory manager 00133 * will use to store the allocation data. This descriptor must always 00134 * be valid while the heap is active therefore it must be allocated in 00135 * permanent memory. 00136 * 00137 * @param heapaddr The address of a statically-defined heap storage 00138 * area. If this parameter is non-zero, all allocations will be made 00139 * from the given area in fully time-bounded mode. In such a case, the 00140 * heap is non-extendable. If a null address is passed, the heap 00141 * manager will attempt to extend the heap each time a memory 00142 * starvation is encountered. In the latter case, the heap manager 00143 * will request additional chunks of core memory to Linux when needed, 00144 * voiding the real-time guarantee for the caller. 00145 * 00146 * @param heapsize If heapaddr is non-zero, heapsize gives the size in 00147 * bytes of the statically-defined storage area. Otherwise, heapsize 00148 * defines the standard length of each extent that will be requested 00149 * to Linux when a memory starvation is encountered for the heap. 00150 * heapsize must be a multiple of pagesize and lower than 16 00151 * Mbytes. Depending on the Linux allocation service used, requests 00152 * for extent memory might be limited in size. For instance, heapsize 00153 * must be lower than 128Kb for kmalloc()-based allocations. In the 00154 * current implementation, heapsize must be large enough to contain an 00155 * internal header. The following formula gives the size of this 00156 * header: hdrsize = (sizeof(rtextent_t) + ((heapsize - 00157 * sizeof(rtextent_t))) / (pagesize + 1) + 15) & ~15; 00158 * 00159 * @param pagesize The size in bytes of the fundamental memory page 00160 * which will be used to subdivide the heap internally. Choosing the 00161 * right page size is important regarding performance and memory 00162 * fragmentation issues, so it might be a good idea to take a look at 00163 * http://docs.FreeBSD.org/44doc/papers/kernmalloc.pdf to pick the 00164 * best one for your needs. In the current implementation, pagesize 00165 * must be a power of two in the range [ 8 .. 32768] inclusive. 00166 * 00167 * @return 0 is returned upon success, or one of the following 00168 * error codes: 00169 * - RTHEAP_PARAM is returned whenever a parameter is invalid. 00170 * - RTHEAP_NOMEM is returned if no initial extent can be allocated 00171 * for a dynamically extendable heap (i.e. heapaddr == NULL). 00172 * 00173 * Side-effect: This routine does not call the rescheduling procedure. 00174 * 00175 * Context: This routine must be called on behalf of a thread context. 00176 */ 00177 00178 int rtheap_init (rtheap_t *heap, void *heapaddr, u_long heapsize, u_long pagesize) 00179 { 00180 u_long hdrsize, pmapsize, shiftsize, pageshift; 00181 rtextent_t *extent; 00182 int n; 00183 00184 /* 00185 * Perform some parametrical checks first. 00186 * Constraints are: 00187 * PAGESIZE must be >= 2 ** MINLOG2. 00188 * PAGESIZE must be <= 2 ** MAXLOG2. 00189 * PAGESIZE must be a power of 2. 00190 * HEAPSIZE must be large enough to contain the static part of an 00191 * extent header. 00192 * HEAPSIZE must be a multiple of PAGESIZE. 00193 * HEAPSIZE must be lower than RTHEAP_MAXEXTSZ. 00194 */ 00195 if ((pagesize < (1 << RTHEAP_MINLOG2)) || 00196 (pagesize > (1 << RTHEAP_MAXLOG2)) || 00197 (pagesize & (pagesize - 1)) != 0 || 00198 heapsize <= sizeof(rtextent_t) || 00199 heapsize > RTHEAP_MAXEXTSZ || 00200 (heapsize & (pagesize - 1)) != 0) { 00201 return RTHEAP_PARAM; 00202 } 00203 00204 /* Determine the page map overhead inside the given extent 00205 size. We need to reserve a byte in a page map for each page 00206 which is addressable into this extent. The page map is itself 00207 stored in the extent space, right after the static part of its 00208 header, and before the first allocatable page. */ 00209 pmapsize = ((heapsize - sizeof(rtextent_t)) * sizeof(u_char)) / (pagesize + sizeof(u_char)); 00210 00211 /* The overall header size is: static_part + page_map rounded to 00212 the minimum alignment size. */ 00213 hdrsize = (sizeof(rtextent_t) + pmapsize + RTHEAP_MINALIGNSZ - 1) & ~(RTHEAP_MINALIGNSZ - 1); 00214 00215 /* An extent must contain at least two addressable pages to cope 00216 with allocation sizes between pagesize and 2 * pagesize. */ 00217 if (hdrsize + 2 * pagesize > heapsize) { 00218 return RTHEAP_PARAM; 00219 } 00220 00221 /* Compute the page shiftmask from the page size (i.e. log2 value). */ 00222 for (pageshift = 0, shiftsize = pagesize; shiftsize > 1; shiftsize >>= 1, pageshift++); 00223 00224 heap->pagesize = pagesize; 00225 heap->pageshift = pageshift; 00226 heap->hdrsize = hdrsize; 00227 #ifdef CONFIG_RTAI_MALLOC_VMALLOC 00228 heap->extentsize = heapsize; 00229 #else /* !CONFIG_RTAI_MALLOC_VMALLOC */ 00230 heap->extentsize = heapsize > KMALLOC_LIMIT ? KMALLOC_LIMIT : heapsize; 00231 #endif /* CONFIG_RTAI_MALLOC_VMALLOC */ 00232 heap->npages = (heap->extentsize - hdrsize) >> pageshift; 00233 heap->maxcont = heap->npages*pagesize; 00234 heap->flags = 00235 heap->ubytes = 0; 00236 INIT_LIST_HEAD(&heap->extents); 00237 spin_lock_init(&heap->lock); 00238 00239 for (n = 0; n < RTHEAP_NBUCKETS; n++) { 00240 heap->buckets[n] = NULL; 00241 } 00242 00243 if (heapaddr) { 00244 extent = (rtextent_t *)heapaddr; 00245 init_extent(heap, extent); 00246 list_add_tail(&extent->link, &heap->extents); 00247 } else { 00248 u_long init_size = 0; 00249 while (init_size < heapsize) { 00250 if (!(extent = (rtextent_t *)alloc_extent(heap->extentsize))) { 00251 struct list_head *holder, *nholder; 00252 list_for_each_safe(holder, nholder, &heap->extents) { 00253 extent = list_entry(holder, rtextent_t, link); 00254 free_extent(extent, heap->extentsize); 00255 } 00256 return RTHEAP_NOMEM; 00257 } 00258 init_extent(heap, extent); 00259 list_add_tail(&extent->link, &heap->extents); 00260 init_size += heap->extentsize; 00261 } 00262 } 00263 return 0; 00264 } 00265 00266 /*! 00267 * \fn void rtheap_destroy(rtheap_t *heap); 00268 * \brief Destroys a memory heap. 00269 * 00270 * Destroys a memory heap. Dynamically allocated extents are returned 00271 * to Linux. 00272 * 00273 * @param heap The descriptor address of the destroyed heap. 00274 * 00275 * Side-effect: This routine does not call the rescheduling procedure. 00276 * 00277 * Context: This routine must be called on behalf of a thread context. 00278 */ 00279 00280 void rtheap_destroy (rtheap_t *heap) 00281 { 00282 struct list_head *holder, *nholder; 00283 00284 list_for_each_safe(holder, nholder, &heap->extents) { 00285 free_extent(list_entry(holder, rtextent_t, link), heap->extentsize); 00286 } 00287 } 00288 00289 /* 00290 * get_free_range() -- Obtain a range of contiguous free pages to 00291 * fulfill an allocation of 2 ** log2size. Each extent is searched, 00292 * and a new one is allocated if needed, provided the heap is 00293 * extendable. Must be called with the heap lock set. 00294 */ 00295 00296 static caddr_t get_free_range (rtheap_t *heap, 00297 u_long bsize, 00298 int log2size, 00299 int mode) 00300 { 00301 caddr_t block, eblock, freepage, lastpage, headpage, freehead = NULL; 00302 u_long pagenum, pagecont, freecont; 00303 struct list_head *holder; 00304 rtextent_t *extent; 00305 00306 list_for_each(holder,&heap->extents) { 00307 00308 extent = list_entry(holder,rtextent_t,link); 00309 freepage = extent->freelist; 00310 00311 while (freepage != NULL) 00312 { 00313 headpage = freepage; 00314 freecont = 0; 00315 00316 /* Search for a range of contiguous pages in the free page 00317 list of the current extent. The range must be 'bsize' 00318 long. */ 00319 do 00320 { 00321 lastpage = freepage; 00322 freepage = *((caddr_t *)freepage); 00323 freecont += heap->pagesize; 00324 } 00325 while (freepage == lastpage + heap->pagesize && freecont < bsize); 00326 00327 if (freecont >= bsize) 00328 { 00329 /* Ok, got it. Just update the extent's free page 00330 list, then proceed to the next step. */ 00331 00332 if (headpage == extent->freelist) 00333 extent->freelist = *((caddr_t *)lastpage); 00334 else 00335 *((caddr_t *)freehead) = *((caddr_t *)lastpage); 00336 00337 goto splitpage; 00338 } 00339 00340 freehead = lastpage; 00341 } 00342 } 00343 00344 /* No available free range in the existing extents so far. If we 00345 cannot extend the heap, we have failed and we are done with 00346 this request. */ 00347 00348 return NULL; 00349 00350 splitpage: 00351 00352 /* At this point, headpage is valid and points to the first page 00353 of a range of contiguous free pages larger or equal than 00354 'bsize'. */ 00355 00356 if (bsize < heap->pagesize) 00357 { 00358 /* If the allocation size is smaller than the standard page 00359 size, split the page in smaller blocks of this size, 00360 building a free list of free blocks. */ 00361 00362 for (block = headpage, eblock = headpage + heap->pagesize - bsize; 00363 block < eblock; block += bsize) 00364 *((caddr_t *)block) = block + bsize; 00365 00366 *((caddr_t *)eblock) = NULL; 00367 } 00368 else 00369 *((caddr_t *)headpage) = NULL; 00370 00371 pagenum = (headpage - extent->membase) >> heap->pageshift; 00372 00373 /* Update the extent's page map. If log2size is non-zero 00374 (i.e. bsize <= 2 * pagesize), store it in the first page's slot 00375 to record the exact block size (which is a power of 00376 two). Otherwise, store the special marker RTHEAP_PLIST, 00377 indicating the start of a block whose size is a multiple of the 00378 standard page size, but not necessarily a power of two. In any 00379 case, the following pages slots are marked as 'continued' 00380 (PCONT). */ 00381 00382 extent->pagemap[pagenum] = log2size ? log2size : RTHEAP_PLIST; 00383 00384 for (pagecont = bsize >> heap->pageshift; pagecont > 1; pagecont--) 00385 extent->pagemap[pagenum + pagecont - 1] = RTHEAP_PCONT; 00386 00387 return headpage; 00388 } 00389 00390 /*! 00391 * \fn void *rtheap_alloc(rtheap_t *heap, u_long size, int flags); 00392 * \brief Allocate a memory block from a memory heap. 00393 * 00394 * Allocates a contiguous region of memory from an active memory heap. 00395 * Such allocation is guaranteed to be time-bounded if the heap is 00396 * non-extendable (see rtheap_init()). Otherwise, it might trigger a 00397 * dynamic extension of the storage area through an internal request 00398 * to the Linux allocation service (kmalloc/vmalloc). 00399 * 00400 * @param heap The descriptor address of the heap to get memory from. 00401 * 00402 * @param size The size in bytes of the requested block. Sizes lower 00403 * or equal to the page size are rounded either to the minimum 00404 * allocation size if lower than this value, or to the minimum 00405 * alignment size if greater or equal to this value. In the current 00406 * implementation, with MINALLOC = 16 and MINALIGN = 16, a 15 bytes 00407 * request will be rounded to 16 bytes, and a 17 bytes request will be 00408 * rounded to 32. 00409 * 00410 * @param flags A set of flags affecting the operation. Unless 00411 * RTHEAP_EXTEND is passed and the heap is extendable, this service 00412 * will return NULL without attempting to extend the heap dynamically 00413 * upon memory starvation. 00414 * 00415 * @return The address of the allocated region upon success, or NULL 00416 * if no memory is available from the specified non-extendable heap, 00417 * or no memory can be obtained from Linux to extend the heap. 00418 * 00419 * Side-effect: This routine does not call the rescheduling procedure. 00420 * 00421 * Context: This routine can always be called on behalf of a thread 00422 * context. It can also be called on behalf of an IST context if the 00423 * heap storage area has been statically-defined at initialization 00424 * time (see rtheap_init()). 00425 */ 00426 00427 void *rtheap_alloc (rtheap_t *heap, u_long size, int mode) 00428 00429 { 00430 u_long bsize, flags; 00431 caddr_t block; 00432 int log2size; 00433 00434 if (size == 0) 00435 return NULL; 00436 00437 if (size <= heap->pagesize) 00438 /* Sizes lower or equal to the page size are rounded either to 00439 the minimum allocation size if lower than this value, or to 00440 the minimum alignment size if greater or equal to this 00441 value. In other words, with MINALLOC = 15 and MINALIGN = 00442 16, a 15 bytes request will be rounded to 16 bytes, and a 00443 17 bytes request will be rounded to 32. */ 00444 { 00445 if (size <= RTHEAP_MINALIGNSZ) 00446 size = (size + RTHEAP_MINALLOCSZ - 1) & ~(RTHEAP_MINALLOCSZ - 1); 00447 else 00448 size = (size + RTHEAP_MINALIGNSZ - 1) & ~(RTHEAP_MINALIGNSZ - 1); 00449 } 00450 else 00451 /* Sizes greater than the page size are rounded to a multiple 00452 of the page size. */ 00453 size = (size + heap->pagesize - 1) & ~(heap->pagesize - 1); 00454 00455 /* It becomes more space efficient to directly allocate pages from 00456 the free page list whenever the requested size is greater than 00457 2 times the page size. Otherwise, use the bucketed memory 00458 blocks. */ 00459 00460 if (size <= heap->pagesize * 2) 00461 { 00462 /* Find the first power of two greater or equal to the rounded 00463 size. The log2 value of this size is also computed. */ 00464 00465 for (bsize = (1 << RTHEAP_MINLOG2), log2size = RTHEAP_MINLOG2; 00466 bsize < size; bsize <<= 1, log2size++) 00467 ; /* Loop */ 00468 00469 flags = rt_spin_lock_irqsave(&heap->lock); 00470 00471 block = heap->buckets[log2size - RTHEAP_MINLOG2]; 00472 00473 if (block == NULL) 00474 { 00475 block = get_free_range(heap,bsize,log2size,mode); 00476 00477 if (block == NULL) 00478 goto release_and_exit; 00479 } 00480 00481 heap->buckets[log2size - RTHEAP_MINLOG2] = *((caddr_t *)block); 00482 heap->ubytes += bsize; 00483 } 00484 else 00485 { 00486 if (size > heap->maxcont) 00487 return NULL; 00488 00489 flags = rt_spin_lock_irqsave(&heap->lock); 00490 00491 /* Directly request a free page range. */ 00492 block = get_free_range(heap,size,0,mode); 00493 00494 if (block) 00495 heap->ubytes += size; 00496 } 00497 00498 release_and_exit: 00499 00500 rt_spin_unlock_irqrestore(flags,&heap->lock); 00501 00502 return block; 00503 } 00504 00505 /*! 00506 * \fn int rtheap_free(rtheap_t *heap, void *block); 00507 * \brief Release a memory block to a memory heap. 00508 * 00509 * Releases a memory region to the memory heap it was previously 00510 * allocated from. 00511 * 00512 * @param heap The descriptor address of the heap to release memory 00513 * to. 00514 * 00515 * @param block The address of the region to release returned by a 00516 * previous call to rtheap_alloc(). 00517 * 00518 * @return 0 is returned upon success, or RTHEAP_PARAM is returned 00519 * whenever the block is not a valid region of the specified heap. 00520 * 00521 * Side-effect: This routine does not call the rescheduling procedure. 00522 * 00523 * Context: This routine can be called on behalf of a thread or IST 00524 * context 00525 */ 00526 00527 int rtheap_free (rtheap_t *heap, void *block) 00528 00529 { 00530 u_long pagenum, pagecont, boffset, bsize, flags; 00531 caddr_t freepage, lastpage, nextpage, tailpage; 00532 rtextent_t *extent = NULL; 00533 struct list_head *holder; 00534 int log2size, npages; 00535 00536 flags = rt_spin_lock_irqsave(&heap->lock); 00537 00538 /* Find the extent from which the returned block is 00539 originating. If the heap is non-extendable, then a single 00540 extent is scanned at most. */ 00541 00542 list_for_each(holder,&heap->extents) { 00543 00544 extent = list_entry(holder,rtextent_t,link); 00545 00546 if ((caddr_t)block >= extent->membase && 00547 (caddr_t)block < extent->memlim) 00548 break; 00549 } 00550 00551 if (!holder) 00552 goto unlock_and_fail; 00553 00554 /* Compute the heading page number in the page map. */ 00555 pagenum = ((caddr_t)block - extent->membase) >> heap->pageshift; 00556 boffset = ((caddr_t)block - (extent->membase + (pagenum << heap->pageshift))); 00557 00558 switch (extent->pagemap[pagenum]) 00559 { 00560 case RTHEAP_PFREE: /* Unallocated page? */ 00561 case RTHEAP_PCONT: /* Not a range heading page? */ 00562 00563 unlock_and_fail: 00564 00565 rt_spin_unlock_irqrestore(flags,&heap->lock); 00566 return RTHEAP_PARAM; 00567 00568 case RTHEAP_PLIST: 00569 00570 npages = 1; 00571 00572 while (npages < heap->npages && 00573 extent->pagemap[pagenum + npages] == RTHEAP_PCONT) 00574 npages++; 00575 00576 bsize = npages * heap->pagesize; 00577 00578 /* Link all freed pages in a single sub-list. */ 00579 00580 for (freepage = (caddr_t)block, 00581 tailpage = (caddr_t)block + bsize - heap->pagesize; 00582 freepage < tailpage; freepage += heap->pagesize) 00583 *((caddr_t *)freepage) = freepage + heap->pagesize; 00584 00585 /* Mark the released pages as free in the extent's page map. */ 00586 00587 for (pagecont = 0; pagecont < npages; pagecont++) 00588 extent->pagemap[pagenum + pagecont] = RTHEAP_PFREE; 00589 00590 /* Return the sub-list to the free page list, keeping 00591 an increasing address order to favor coalescence. */ 00592 00593 for (nextpage = extent->freelist, lastpage = NULL; 00594 nextpage != NULL && nextpage < (caddr_t)block; 00595 lastpage = nextpage, nextpage = *((caddr_t *)nextpage)) 00596 ; /* Loop */ 00597 00598 *((caddr_t *)tailpage) = nextpage; 00599 00600 if (lastpage) 00601 *((caddr_t *)lastpage) = (caddr_t)block; 00602 else 00603 extent->freelist = (caddr_t)block; 00604 00605 break; 00606 00607 default: 00608 00609 log2size = extent->pagemap[pagenum]; 00610 bsize = (1 << log2size); 00611 00612 if ((boffset & (bsize - 1)) != 0) /* Not a block start? */ 00613 goto unlock_and_fail; 00614 00615 /* Return the block to the bucketed memory space. */ 00616 00617 *((caddr_t *)block) = heap->buckets[log2size - RTHEAP_MINLOG2]; 00618 heap->buckets[log2size - RTHEAP_MINLOG2] = block; 00619 00620 break; 00621 } 00622 00623 heap->ubytes -= bsize; 00624 00625 rt_spin_unlock_irqrestore(flags,&heap->lock); 00626 00627 return 0; 00628 } 00629 00630 int __rtai_heap_init (void) 00631 { 00632 rtai_global_heap_size = (rtai_global_heap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); 00633 if (rtheap_init(&rtai_global_heap, NULL, rtai_global_heap_size, PAGE_SIZE)) { 00634 printk(KERN_INFO "RTAI[malloc]: failed to initialize the global heap (size=%d bytes).\n", rtai_global_heap_size); 00635 return 1; 00636 } 00637 rtai_global_heap_adr = rtai_global_heap.extents.next; 00638 printk(KERN_INFO "RTAI[malloc]: loaded (global heap size=%d bytes).\n", rtai_global_heap_size); 00639 return 0; 00640 } 00641 00642 void __rtai_heap_exit (void) 00643 { 00644 rtheap_destroy(&rtai_global_heap); 00645 printk("RTAI[malloc]: unloaded.\n"); 00646 } 00647 00648 /* 00649 * IMPLEMENTATION NOTES: 00650 * 00651 * The implementation follows the algorithm described in a USENIX 00652 * 1988 paper called "Design of a General Purpose Memory Allocator for 00653 * the 4.3BSD Unix Kernel" by Marshall K. McKusick and Michael 00654 * J. Karels. You can find it at various locations on the net, 00655 * including http://docs.FreeBSD.org/44doc/papers/kernmalloc.pdf. 00656 * A minor variation allows this implementation to have 'extendable' 00657 * heaps when needed, with multiple memory extents providing autonomous 00658 * page address spaces. When the non-extendable form is used, the heap 00659 * management routines show bounded worst-case execution time. 00660 * 00661 * The data structures hierarchy is as follows: 00662 * 00663 * HEAP { 00664 * block_buckets[] 00665 * extent_queue -------+ 00666 * } | 00667 * V 00668 * EXTENT #1 { 00669 * <static header> 00670 * page_map[npages] 00671 * page_array[npages][pagesize] 00672 * } -+ 00673 * | 00674 * | 00675 * V 00676 * EXTENT #n { 00677 * <static header> 00678 * page_map[npages] 00679 * page_array[npages][pagesize] 00680 * } 00681 */ 00682 00683 /*@}*/ 00684 00685 #ifndef CONFIG_RTAI_MALLOC_BUILTIN 00686 module_init(__rtai_heap_init); 00687 module_exit(__rtai_heap_exit); 00688 #endif /* !CONFIG_RTAI_MALLOC_BUILTIN */ 00689 00690 #ifdef CONFIG_KBUILD 00691 EXPORT_SYMBOL(rtheap_init); 00692 EXPORT_SYMBOL(rtheap_destroy); 00693 EXPORT_SYMBOL(rtheap_alloc); 00694 EXPORT_SYMBOL(rtheap_free); 00695 EXPORT_SYMBOL(rtai_global_heap); 00696 EXPORT_SYMBOL(rtai_global_heap_adr); 00697 EXPORT_SYMBOL(rtai_global_heap_size); 00698 #endif /* CONFIG_KBUILD */

Generated on Thu Nov 20 11:49:51 2008 for RTAI API by doxygen 1.3.8