Release 960805
[wine/multimedia.git] / ipc / shm_fragment.c
blob15c51feec4b8225da2d80432059c39824d9c70fe
1 /***************************************************************************
2 * Copyright 1995, Technion, Israel Institute of Technology
3 * Electrical Eng, Software Lab.
4 * Author: Michael Veksler.
5 ***************************************************************************
6 * File: shm_fragment.c
7 * Purpose: Data fragments and free list items. Allocate and free blocks.
8 ***************************************************************************
9 */
10 #ifdef CONFIG_IPC
12 #include <stdio.h> /* for debugging only */
13 #include <stddebug.h>
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.
50 if (ptr)
51 shm_FragmentFree(block, PTR2REL(block, ptr));
53 void shm_FragmentFree(struct shm_block *block, int fragment_ofs)
55 struct shm_fragment *fragment=NULL;
56 int prev;
57 int next;
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;
81 } else
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;
96 } else
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)
106 int prev;
107 int candidate;
108 struct shm_fragment *fragment;
109 struct shm_fragment *ret_fragment;
111 if (size <= 0)
112 return NIL;
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)
119 return NIL;
120 /* scan free list to find candidates for allocation */
121 for (prev=0, candidate=block->free_list;
122 candidate!=0 ;
123 prev=candidate, candidate= fragment->info.next )
125 fragment=FRAG_PTR(block,candidate);
126 if (fragment->size >= size)
127 break;
130 if (candidate == 0)
131 return NIL;
133 block->free-=size;
134 if (fragment->size == size) {
135 if (prev == 0)
136 block->free_list= fragment->info.next;
137 else
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)
156 int ofs;
157 ofs= shm_FragmentAlloc(block,size);
158 if (ofs == NIL)
159 return NULL;
160 else
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;
167 int item;
169 item=block->free_list;
170 if (item==0) {
171 fprintf(stddeb,"no free fragments");
172 } else {
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);
179 fflush(stddeb);
182 #endif /* CONFIG_IPC */