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 */
14 #include <debug.h> /* for "stddeb" */
16 #include "shm_fragment.h"
17 #include "shm_block.h"
19 /******************************************************************************
21 * Free list: all fragments are ordered according to memory location.
22 * new fragments are inserted in this way.
24 ******************************************************************************
27 #define FRAG_PTR(block,ofs) ((struct shm_fragment *) ((char *) block + ofs) )
28 #define NEXT_FRAG(block,ofs) ( FRAG_PTR(block,ofs)->info.next )
30 /* setup first item in the free list */
31 void shm_FragmentInit(struct shm_block
*block
,int first
, int size
)
33 struct shm_fragment
*fragment
;
35 /* round up to nearest 16 byte boundary */
36 first
=(first
+15)& ~15;
37 block
->free_list
=first
;
39 /* make all the block (exluding the header) free */
40 fragment
= FRAG_PTR(block
, first
);
41 block
->free
= fragment
->size
= size
-first
;
42 fragment
->info
.next
=0;
45 void shm_FragPtrFree(struct shm_block
*block
, void *ptr
)
47 /* ptr points to fragment->info.data, find pointer to fragment,
48 * find the offset of this pointer in block.
51 shm_FragmentFree(block
, PTR2REL(block
, ptr
));
53 void shm_FragmentFree(struct shm_block
*block
, int fragment_ofs
)
55 struct shm_fragment
*fragment
=NULL
;
59 fragment_ofs
-=(int )&fragment
->info
.data
;
60 fragment
= FRAG_PTR(block
, fragment_ofs
);
62 block
->free
+=fragment
->size
;
63 /* scan free list to find candidates for merging with fragment */
64 for (prev
=0, next
=block
->free_list
;
65 (next
!=0) && (fragment_ofs
> next
) ;
66 prev
=next
, next
=NEXT_FRAG(block
,next
) )
69 /* insert fragment between, prev and next
70 * prev==0: fragment will be the first item in free list
71 * next==0: fragment will be the last item in free list
75 /* update fragment (point to next, or merge with next) */
77 if ( fragment_ofs
+fragment
->size
== next
) {
78 /* merge with the next free block */
79 fragment
->size
+= FRAG_PTR(block
,next
)->size
;
80 fragment
->info
.next
=FRAG_PTR(block
,next
)->info
.next
;
82 /* fragment should be inserted before the next fragment or end of */
83 /* list. (not merged) */
84 fragment
->info
.next
=next
;
85 /* now fragment has all the information about the rest of the list */
88 /* upate prev fragment (point or merge with fragment) */
90 if (prev
==0) /* first item in free list */
91 block
->free_list
=fragment_ofs
;
92 else if ( prev
+FRAG_PTR(block
,prev
)->size
== fragment_ofs
) {
93 /* merge fragment with previous fragment */
94 FRAG_PTR(block
,prev
)->size
+= fragment
->size
;
95 FRAG_PTR(block
,prev
)->info
.next
=fragment
->info
.next
;
97 /* insert fragment after previous fragment */
98 FRAG_PTR(block
,prev
)->info
.next
=fragment_ofs
;
101 /* use "first fit" algorithm,
102 * return: offset to data in fragment.
104 int shm_FragmentAlloc(struct shm_block
*block
, int size
)
108 struct shm_fragment
*fragment
;
109 struct shm_fragment
*ret_fragment
;
113 /* add size of "fragment->size" */
114 size
+= (char *)&fragment
->info
.data
- (char *)fragment
;
116 /* round "size" to nearest 16 byte value */
117 size
= (size
+15) & ~15;
118 if (size
> block
->free
)
120 /* scan free list to find candidates for allocation */
121 for (prev
=0, candidate
=block
->free_list
;
123 prev
=candidate
, candidate
= fragment
->info
.next
)
125 fragment
=FRAG_PTR(block
,candidate
);
126 if (fragment
->size
>= size
)
134 if (fragment
->size
== size
) {
136 block
->free_list
= fragment
->info
.next
;
138 FRAG_PTR(block
,prev
)->info
.next
= fragment
->info
.next
;
139 return PTR2REL(block
, &fragment
->info
.data
);
142 /* fragment->size > size */
144 /* Split fragment in two, return one part, put the other in free list. */
145 /* The part that starts at the old location - will stay in the free list. */
146 fragment
->size
-= size
;
148 ret_fragment
=FRAG_PTR(block
, candidate
+ fragment
->size
);
149 ret_fragment
->size
= size
;
150 return PTR2REL(block
, ret_fragment
->info
.data
);
153 /* like shm_FragmentAlloc, returns pointer instead of offset */
154 char *shm_FragPtrAlloc(struct shm_block
*block
, int size
)
157 ofs
= shm_FragmentAlloc(block
,size
);
161 return (char *) REL2PTR(block
, ofs
);
163 /* This is used for debugging only */
164 void shm_print_free_list(struct shm_block
*block
)
166 struct shm_fragment
*fragment
;
169 item
=block
->free_list
;
171 fprintf(stddeb
,"no free fragments");
173 for (; item
; item
=fragment
->info
.next
) {
174 fragment
=FRAG_PTR(block
,item
);
175 fprintf(stddeb
,"{0x%04x,0x%04x} ",item
,fragment
->size
);
178 fprintf(stddeb
," [total free=%04x]\n",block
->free
);
182 #endif /* CONFIG_IPC */