Replace some magic numbers with symbols.
[wine] / memory / local.c
1 /*
2  * Local heap functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  * Copyright 1996 Huw Davies
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /*
23  * Note:
24  * All local heap functions need the current DS as first parameter
25  * when called from the emulation library, so they take one more
26  * parameter than usual.
27  */
28
29 #include "config.h"
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include "wine/winbase16.h"
34 #include "instance.h"
35 #include "local.h"
36 #include "module.h"
37 #include "stackframe.h"
38 #include "toolhelp.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(local);
42
43 typedef struct
44 {
45 /* Arena header */
46     WORD prev;          /* Previous arena | arena type */
47     WORD next;          /* Next arena */
48 /* Start of the memory block or free-list info */
49     WORD size;          /* Size of the free block */
50     WORD free_prev;     /* Previous free block */
51     WORD free_next;     /* Next free block */
52 } LOCALARENA;
53
54 #define ARENA_HEADER_SIZE      4
55 #define ARENA_HEADER( handle) ((handle) - ARENA_HEADER_SIZE)
56
57   /* Arena types (stored in 'prev' field of the arena) */
58 #define LOCAL_ARENA_FREE       0
59 #define LOCAL_ARENA_FIXED      1
60
61 #include "pshpack1.h"
62
63 typedef struct
64 {
65     WORD check;                 /* 00 Heap checking flag */
66     WORD freeze;                /* 02 Heap frozen flag */
67     WORD items;                 /* 04 Count of items on the heap */
68     WORD first;                 /* 06 First item of the heap */
69     WORD pad1;                  /* 08 Always 0 */
70     WORD last;                  /* 0a Last item of the heap */
71     WORD pad2;                  /* 0c Always 0 */
72     BYTE ncompact;              /* 0e Compactions counter */
73     BYTE dislevel;              /* 0f Discard level */
74     DWORD distotal;             /* 10 Total bytes discarded */
75     WORD htable;                /* 14 Pointer to handle table */
76     WORD hfree;                 /* 16 Pointer to free handle table */
77     WORD hdelta;                /* 18 Delta to expand the handle table */
78     WORD expand;                /* 1a Pointer to expand function (unused) */
79     WORD pstat;                 /* 1c Pointer to status structure (unused) */
80     FARPROC16 notify WINE_PACKED; /* 1e Pointer to LocalNotify() function */
81     WORD lock;                  /* 22 Lock count for the heap */
82     WORD extra;                 /* 24 Extra bytes to allocate when expanding */
83     WORD minsize;               /* 26 Minimum size of the heap */
84     WORD magic;                 /* 28 Magic number */
85 } LOCALHEAPINFO;
86
87 #include "poppack.h"
88
89 #define LOCAL_HEAP_MAGIC  0x484c  /* 'LH' */
90
91   /* All local heap allocations are aligned on 4-byte boundaries */
92 #define LALIGN(word)          (((word) + 3) & ~3)
93
94 #define ARENA_PTR(ptr,arena)       ((LOCALARENA *)((char*)(ptr)+(arena)))
95 #define ARENA_PREV(ptr,arena)      (ARENA_PTR((ptr),(arena))->prev & ~3)
96 #define ARENA_NEXT(ptr,arena)      (ARENA_PTR((ptr),(arena))->next)
97 #define ARENA_FLAGS(ptr,arena)     (ARENA_PTR((ptr),(arena))->prev & 3)
98
99
100 /***********************************************************************
101  *           LocalInit   (KERNEL.4)
102  */
103 BOOL16 WINAPI LocalInit16( HANDLE16 selector, WORD start, WORD end )
104 {
105     char *ptr;
106     WORD heapInfoArena, freeArena, lastArena;
107     LOCALHEAPINFO *pHeapInfo;
108     LOCALARENA *pArena, *pFirstArena, *pLastArena;
109     NE_MODULE *pModule;
110     BOOL16 ret = FALSE;
111
112       /* The initial layout of the heap is: */
113       /* - first arena         (FIXED)      */
114       /* - heap info structure (FIXED)      */
115       /* - large free block    (FREE)       */
116       /* - last arena          (FREE)       */
117
118     TRACE("%04x %04x-%04x\n", selector, start, end);
119     if (!selector) selector = CURRENT_DS;
120
121     if (start == 0)
122     {
123         /* start == 0 means: put the local heap at the end of the segment */
124
125         DWORD size = GlobalSize16( GlobalHandle16( selector ) );
126         start = (WORD)(size > 0xffff ? 0xffff : size) - 1;
127         if ( end > 0xfffe ) end = 0xfffe;
128         start -= end;
129         end += start;
130
131         /* Paranoid check */
132
133         if ((pModule = NE_GetPtr( GlobalHandle16( selector ) )))
134         {
135             SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule );
136             int segNr;
137
138             for ( segNr = 0; segNr < pModule->seg_count; segNr++, pSeg++ )
139                 if ( GlobalHandleToSel16(pSeg->hSeg) == selector )
140                     break;
141
142             if ( segNr < pModule->seg_count )
143             {
144                 WORD minsize = pSeg->minsize;
145                 if ( pModule->ss == segNr+1 )
146                     minsize += pModule->stack_size;
147
148                 TRACE(" new start %04x, minstart: %04x\n", start, minsize);
149             }
150         }
151     }
152     ptr = MapSL( MAKESEGPTR( selector, 0 ) );
153
154     start = LALIGN( max( start, sizeof(INSTANCEDATA) ) );
155     heapInfoArena = LALIGN(start + sizeof(LOCALARENA) );
156     freeArena = LALIGN( heapInfoArena + ARENA_HEADER_SIZE
157                         + sizeof(LOCALHEAPINFO) );
158     lastArena = (end - sizeof(LOCALARENA)) & ~3;
159
160       /* Make sure there's enough space.       */
161
162     if (freeArena + sizeof(LOCALARENA) >= lastArena) goto done;
163
164       /* Initialise the first arena */
165
166     pFirstArena = ARENA_PTR( ptr, start );
167     pFirstArena->prev      = start | LOCAL_ARENA_FIXED;
168     pFirstArena->next      = heapInfoArena;
169     pFirstArena->size      = LALIGN(sizeof(LOCALARENA));
170     pFirstArena->free_prev = start;  /* this one */
171     pFirstArena->free_next = freeArena;
172
173       /* Initialise the arena of the heap info structure */
174
175     pArena = ARENA_PTR( ptr, heapInfoArena );
176     pArena->prev = start | LOCAL_ARENA_FIXED;
177     pArena->next = freeArena;
178
179       /* Initialise the heap info structure */
180
181     pHeapInfo = (LOCALHEAPINFO *) (ptr + heapInfoArena + ARENA_HEADER_SIZE );
182     memset( pHeapInfo, 0, sizeof(LOCALHEAPINFO) );
183     pHeapInfo->items   = 4;
184     pHeapInfo->first   = start;
185     pHeapInfo->last    = lastArena;
186     pHeapInfo->htable  = 0;
187     pHeapInfo->hdelta  = 0x20;
188     pHeapInfo->extra   = 0x200;
189     pHeapInfo->minsize = lastArena - freeArena;
190     pHeapInfo->magic   = LOCAL_HEAP_MAGIC;
191
192       /* Initialise the large free block */
193
194     pArena = ARENA_PTR( ptr, freeArena );
195     pArena->prev      = heapInfoArena | LOCAL_ARENA_FREE;
196     pArena->next      = lastArena;
197     pArena->size      = lastArena - freeArena;
198     pArena->free_prev = start;
199     pArena->free_next = lastArena;
200
201       /* Initialise the last block */
202
203     pLastArena = ARENA_PTR( ptr, lastArena );
204     pLastArena->prev      = freeArena | LOCAL_ARENA_FREE;
205     pLastArena->next      = lastArena;  /* this one */
206     pLastArena->size      = LALIGN(sizeof(LOCALARENA));
207     pLastArena->free_prev = freeArena;
208     pLastArena->free_next = lastArena;  /* this one */
209
210       /* Store the local heap address in the instance data */
211
212     ((INSTANCEDATA *)ptr)->heap = heapInfoArena + ARENA_HEADER_SIZE;
213     ret = TRUE;
214
215  done:
216     CURRENT_STACK16->ecx = ret;  /* must be returned in cx too */
217     return ret;
218 }
219
220
221 /***********************************************************************
222  *           LocalAlloc   (KERNEL32.@)
223  * RETURNS
224  *      Handle: Success
225  *      NULL: Failure
226  */
227 HLOCAL WINAPI LocalAlloc(
228                 UINT flags, /* [in] Allocation attributes */
229                 SIZE_T size /* [in] Number of bytes to allocate */
230 ) {
231     return (HLOCAL)GlobalAlloc( flags, size );
232 }
233
234
235 /***********************************************************************
236  *           LocalCompact   (KERNEL32.@)
237  */
238 SIZE_T WINAPI LocalCompact( UINT minfree )
239 {
240     return 0;  /* LocalCompact does nothing in Win32 */
241 }
242
243
244 /***********************************************************************
245  *           LocalFlags   (KERNEL32.@)
246  * RETURNS
247  *      Value specifying allocation flags and lock count.
248  *      LMEM_INVALID_HANDLE: Failure
249  */
250 UINT WINAPI LocalFlags(
251               HLOCAL handle /* [in] Handle of memory object */
252 ) {
253     return GlobalFlags( (HGLOBAL)handle );
254 }
255
256
257 /***********************************************************************
258  *           LocalFree   (KERNEL32.@)
259  * RETURNS
260  *      NULL: Success
261  *      Handle: Failure
262  */
263 HLOCAL WINAPI LocalFree(
264                 HLOCAL handle /* [in] Handle of memory object */
265 ) {
266     return (HLOCAL)GlobalFree( (HGLOBAL)handle );
267 }
268
269
270 /***********************************************************************
271  *           LocalHandle   (KERNEL32.@)
272  * RETURNS
273  *      Handle: Success
274  *      NULL: Failure
275  */
276 HLOCAL WINAPI LocalHandle(
277                 LPCVOID ptr /* [in] Address of local memory object */
278 ) {
279     return (HLOCAL)GlobalHandle( ptr );
280 }
281
282
283 /***********************************************************************
284  *           LocalLock   (KERNEL32.@)
285  * Locks a local memory object and returns pointer to the first byte
286  * of the memory block.
287  *
288  * RETURNS
289  *      Pointer: Success
290  *      NULL: Failure
291  */
292 LPVOID WINAPI LocalLock(
293               HLOCAL handle /* [in] Address of local memory object */
294 ) {
295     return GlobalLock( (HGLOBAL)handle );
296 }
297
298
299 /***********************************************************************
300  *           LocalReAlloc   (KERNEL32.@)
301  * RETURNS
302  *      Handle: Success
303  *      NULL: Failure
304  */
305 HLOCAL WINAPI LocalReAlloc(
306                 HLOCAL handle, /* [in] Handle of memory object */
307                 SIZE_T size,   /* [in] New size of block */
308                 UINT flags     /* [in] How to reallocate object */
309 ) {
310     return (HLOCAL)GlobalReAlloc( (HGLOBAL)handle, size, flags );
311 }
312
313
314 /***********************************************************************
315  *           LocalShrink   (KERNEL32.@)
316  */
317 SIZE_T WINAPI LocalShrink( HGLOBAL handle, UINT newsize )
318 {
319     return 0;  /* LocalShrink does nothing in Win32 */
320 }
321
322
323 /***********************************************************************
324  *           LocalSize   (KERNEL32.@)
325  * RETURNS
326  *      Size: Success
327  *      0: Failure
328  */
329 SIZE_T WINAPI LocalSize(
330               HLOCAL handle /* [in] Handle of memory object */
331 ) {
332     return GlobalSize( (HGLOBAL)handle );
333 }
334
335
336 /***********************************************************************
337  *           LocalUnlock   (KERNEL32.@)
338  * RETURNS
339  *      TRUE: Object is still locked
340  *      FALSE: Object is unlocked
341  */
342 BOOL WINAPI LocalUnlock(
343               HLOCAL handle /* [in] Handle of memory object */
344 ) {
345     return GlobalUnlock( (HGLOBAL)handle );
346 }