/*************************************************************************** * Copyright 1995, Technion, Israel Institute of Technology * Electrical Eng, Software Lab. * Author: Michael Veksler. *************************************************************************** * File: shm_fragment.c * Purpose: Data fragments and free list items. Allocate and free blocks. *************************************************************************** */ #ifdef CONFIG_IPC #include /* for debugging only */ #include /* for "stddeb" */ #include "shm_fragment.h" #include "shm_block.h" /****************************************************************************** * * Free list: all fragments are ordered according to memory location. * new fragments are inserted in this way. * ****************************************************************************** */ #define FRAG_PTR(block,ofs) ((struct shm_fragment *) ((char *) block + ofs) ) #define NEXT_FRAG(block,ofs) ( FRAG_PTR(block,ofs)->info.next ) /* setup first item in the free list */ void shm_FragmentInit(struct shm_block *block,int first, int size) { struct shm_fragment *fragment; /* round up to nearest 16 byte boundary */ first=(first+15)& ~15; block->free_list=first; /* make all the block (exluding the header) free */ fragment= FRAG_PTR(block, first); block->free= fragment->size= size-first; fragment->info.next=0; } void shm_FragPtrFree(struct shm_block *block, void *ptr) { /* ptr points to fragment->info.data, find pointer to fragment, * find the offset of this pointer in block. */ if (ptr) shm_FragmentFree(block, PTR2REL(block, ptr)); } void shm_FragmentFree(struct shm_block *block, int fragment_ofs) { struct shm_fragment *fragment=NULL; int prev; int next; fragment_ofs-=(int )&fragment->info.data; fragment= FRAG_PTR(block, fragment_ofs); block->free+=fragment->size; /* scan free list to find candidates for merging with fragment */ for (prev=0, next=block->free_list; (next!=0) && (fragment_ofs > next) ; prev=next, next=NEXT_FRAG(block,next) ) ; /* insert fragment between, prev and next * prev==0: fragment will be the first item in free list * next==0: fragment will be the last item in free list */ /* update fragment (point to next, or merge with next) */ if ( fragment_ofs+fragment->size == next ) { /* merge with the next free block */ fragment->size+= FRAG_PTR(block,next)->size; fragment->info.next=FRAG_PTR(block,next)->info.next; } else /* fragment should be inserted before the next fragment or end of */ /* list. (not merged) */ fragment->info.next=next; /* now fragment has all the information about the rest of the list */ /* upate prev fragment (point or merge with fragment) */ if (prev==0) /* first item in free list */ block->free_list=fragment_ofs; else if ( prev+FRAG_PTR(block,prev)->size == fragment_ofs ) { /* merge fragment with previous fragment */ FRAG_PTR(block,prev)->size+= fragment->size; FRAG_PTR(block,prev)->info.next=fragment->info.next; } else /* insert fragment after previous fragment */ FRAG_PTR(block,prev)->info.next=fragment_ofs; } /* use "first fit" algorithm, * return: offset to data in fragment. */ int shm_FragmentAlloc(struct shm_block *block, int size) { int prev; int candidate; struct shm_fragment *fragment; struct shm_fragment *ret_fragment; if (size <= 0) return NIL; /* add size of "fragment->size" */ size+= (char *)&fragment->info.data - (char *)fragment ; /* round "size" to nearest 16 byte value */ size= (size+15) & ~15; if (size > block->free) return NIL; /* scan free list to find candidates for allocation */ for (prev=0, candidate=block->free_list; candidate!=0 ; prev=candidate, candidate= fragment->info.next ) { fragment=FRAG_PTR(block,candidate); if (fragment->size >= size) break; } if (candidate == 0) return NIL; block->free-=size; if (fragment->size == size) { if (prev == 0) block->free_list= fragment->info.next; else FRAG_PTR(block,prev)->info.next= fragment->info.next; return PTR2REL(block, &fragment->info.data); } /* fragment->size > size */ /* Split fragment in two, return one part, put the other in free list. */ /* The part that starts at the old location - will stay in the free list. */ fragment->size -= size; ret_fragment=FRAG_PTR(block, candidate + fragment->size); ret_fragment->size= size; return PTR2REL(block, ret_fragment->info.data); } /* like shm_FragmentAlloc, returns pointer instead of offset */ char *shm_FragPtrAlloc(struct shm_block *block, int size) { int ofs; ofs= shm_FragmentAlloc(block,size); if (ofs == NIL) return NULL; else return (char *) REL2PTR(block, ofs); } /* This is used for debugging only */ void shm_print_free_list(struct shm_block *block) { struct shm_fragment *fragment; int item; item=block->free_list; if (item==0) { DUMP("no free fragments"); } else { for (; item ; item=fragment->info.next) { fragment=FRAG_PTR(block,item); DUMP("{0x%04x,0x%04x} ",item,fragment->size); } } DUMP(" [total free=%04x]\n",block->free); fflush(stddeb); } #endif /* CONFIG_IPC */