1 /***************************************************************************
2 * Copyright 1995, Technion, Israel Institute of Technology
3 * Electrical Eng, Software Lab.
4 * Author: Michael Veksler.
5 ***************************************************************************
7 * Purpose: Data fragments and free list items. Allocate and free blocks.
8 ***************************************************************************
12 #include <stdio.h> /* for debugging only */
13 #include "debugtools.h" /* for "stddeb" */
15 #include "shm_fragment.h"
16 #include "shm_block.h"
18 /******************************************************************************
20 * Free list: all fragments are ordered according to memory location.
21 * new fragments are inserted in this way.
23 ******************************************************************************
26 #define FRAG_PTR(block,ofs) ((struct shm_fragment *) ((char *) block + ofs) )
27 #define NEXT_FRAG(block,ofs) ( FRAG_PTR(block,ofs)->info.next )
29 /* setup first item in the free list */
30 void shm_FragmentInit(struct shm_block *block,int first, int size)
32 struct shm_fragment *fragment;
34 /* round up to nearest 16 byte boundary */
35 first=(first+15)& ~15;
36 block->free_list=first;
38 /* make all the block (exluding the header) free */
39 fragment= FRAG_PTR(block, first);
40 block->free= fragment->size= size-first;
41 fragment->info.next=0;
44 void shm_FragPtrFree(struct shm_block *block, void *ptr)
46 /* ptr points to fragment->info.data, find pointer to fragment,
47 * find the offset of this pointer in block.
50 shm_FragmentFree(block, PTR2REL(block, ptr));
52 void shm_FragmentFree(struct shm_block *block, int fragment_ofs)
54 struct shm_fragment *fragment=NULL;
58 fragment_ofs-=(int )&fragment->info.data;
59 fragment= FRAG_PTR(block, fragment_ofs);
61 block->free+=fragment->size;
62 /* scan free list to find candidates for merging with fragment */
63 for (prev=0, next=block->free_list;
64 (next!=0) && (fragment_ofs > next) ;
65 prev=next, next=NEXT_FRAG(block,next) )
68 /* insert fragment between, prev and next
69 * prev==0: fragment will be the first item in free list
70 * next==0: fragment will be the last item in free list
74 /* update fragment (point to next, or merge with next) */
76 if ( fragment_ofs+fragment->size == next ) {
77 /* merge with the next free block */
78 fragment->size+= FRAG_PTR(block,next)->size;
79 fragment->info.next=FRAG_PTR(block,next)->info.next;
81 /* fragment should be inserted before the next fragment or end of */
82 /* list. (not merged) */
83 fragment->info.next=next;
84 /* now fragment has all the information about the rest of the list */
87 /* upate prev fragment (point or merge with fragment) */
89 if (prev==0) /* first item in free list */
90 block->free_list=fragment_ofs;
91 else if ( prev+FRAG_PTR(block,prev)->size == fragment_ofs ) {
92 /* merge fragment with previous fragment */
93 FRAG_PTR(block,prev)->size+= fragment->size;
94 FRAG_PTR(block,prev)->info.next=fragment->info.next;
96 /* insert fragment after previous fragment */
97 FRAG_PTR(block,prev)->info.next=fragment_ofs;
100 /* use "first fit" algorithm,
101 * return: offset to data in fragment.
103 int shm_FragmentAlloc(struct shm_block *block, int size)
107 struct shm_fragment *fragment;
108 struct shm_fragment *ret_fragment;
112 /* add size of "fragment->size" */
113 size+= (char *)&fragment->info.data - (char *)fragment ;
115 /* round "size" to nearest 16 byte value */
116 size= (size+15) & ~15;
117 if (size > block->free)
119 /* scan free list to find candidates for allocation */
120 for (prev=0, candidate=block->free_list;
122 prev=candidate, candidate= fragment->info.next )
124 fragment=FRAG_PTR(block,candidate);
125 if (fragment->size >= size)
133 if (fragment->size == size) {
135 block->free_list= fragment->info.next;
137 FRAG_PTR(block,prev)->info.next= fragment->info.next;
138 return PTR2REL(block, &fragment->info.data);
141 /* fragment->size > size */
143 /* Split fragment in two, return one part, put the other in free list. */
144 /* The part that starts at the old location - will stay in the free list. */
145 fragment->size -= size;
147 ret_fragment=FRAG_PTR(block, candidate + fragment->size);
148 ret_fragment->size= size;
149 return PTR2REL(block, ret_fragment->info.data);
152 /* like shm_FragmentAlloc, returns pointer instead of offset */
153 char *shm_FragPtrAlloc(struct shm_block *block, int size)
156 ofs= shm_FragmentAlloc(block,size);
160 return (char *) REL2PTR(block, ofs);
162 /* This is used for debugging only */
163 void shm_print_free_list(struct shm_block *block)
165 struct shm_fragment *fragment;
168 item=block->free_list;
170 DUMP("no free fragments");
172 for (; item ; item=fragment->info.next) {
173 fragment=FRAG_PTR(block,item);
174 DUMP("{0x%04x,0x%04x} ",item,fragment->size);
177 DUMP(" [total free=%04x]\n",block->free);
181 #endif /* CONFIG_IPC */