ALLOC.CPP (20263B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /*************************************************************************** 17 ** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S ** 18 *************************************************************************** 19 * * 20 * Project Name : Westwood Library * 21 * * 22 * File Name : ALLOC.CPP * 23 * * 24 * Programmer : Joe L. Bostic * 25 * * 26 * Start Date : February 1, 1992 * 27 * * 28 * Last Update : March 9, 1995 [JLB] * 29 * * 30 *-------------------------------------------------------------------------* 31 * Functions: * 32 * Alloc -- Allocates system RAM. * 33 * Ram_Free -- Determines the largest free chunk of RAM. * 34 * Free -- Free an Alloc'ed block of RAM. * 35 * Resize_Alloc -- Change the size of an allocated block. * 36 * Heap_Size -- Size of the heap we have. * 37 * Total_Ram_Free -- Total amount of free RAM. * 38 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 39 40 #include <malloc.h> 41 #include <string.h> 42 #include <stdlib.h> 43 //#include <dos.h> 44 //#include <bios.h> 45 46 47 #ifndef WWMEM_H 48 #include "wwmem.h" 49 #endif 50 51 52 extern "C" unsigned long Largest_Mem_Block ( void ) ; 53 54 /* 55 ** Define the equates necessary to call a DPMI interrupt. 56 */ 57 #define DPMI_INT 0x0031 58 #define DPMI_LOCK_MEM 0x0600 59 #define DPMI_UNLOCK_MEM 0x0601 60 61 /*=========================================================================*/ 62 /* The following PRIVATE functions are in this file: */ 63 /*=========================================================================*/ 64 65 66 /*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/ 67 68 unsigned long MinRam=0L; // Record of least memory at worst case. 69 unsigned long MaxRam=0L; // Record of total allocated at worst case. 70 static unsigned long TotalRam = 0L; 71 static unsigned long Memory_Calls = 0L; 72 73 void (*Memory_Error)(void) = NULL; 74 extern void (*Memory_Error_Exit)(char *string)=NULL; 75 76 77 //#define MEM_CHECK 78 79 #ifdef MEM_CHECK 80 extern "C"{ 81 extern void __cdecl Int3(void); 82 } 83 #endif //MEM_CHECK 84 85 /*************************************************************************** 86 * DPMI_LOCK -- handles locking a block of DPMI memory * 87 * * 88 * INPUT: * 89 * * 90 * OUTPUT: * 91 * * 92 * WARNINGS: * 93 * * 94 * HISTORY: * 95 * 06/23/1995 PWG : Created. * 96 *=========================================================================*/ 97 #include"mono.h" 98 void DPMI_Lock(VOID const *, long const ) 99 { 100 } 101 102 /*************************************************************************** 103 * DPMI_UNLOCK -- Handles unlocking a locked block of DPMI * 104 * * 105 * INPUT: * 106 * * 107 * OUTPUT: * 108 * * 109 * WARNINGS: * 110 * * 111 * HISTORY: * 112 * 06/23/1995 PWG : Created. * 113 *=========================================================================*/ 114 void DPMI_Unlock(void const *, long const ) 115 { 116 } 117 118 /*************************************************************************** 119 * Alloc -- Allocates system RAM. * 120 * * 121 * This is the basic RAM allocation function. It is used for all * 122 * memory allocations needed by the system or the main program. * 123 * * 124 * INPUT: bytes_to_alloc -- LONG value of the number of bytes to alloc. * 125 * * 126 * flags -- Memory allocation control flags. * 127 * MEM_NORMAL: No special flags. * 128 * MEM_CLEAR: Zero out memory block. * 129 * MEM_NEW: Called by a new. * 130 * * 131 * OUTPUT: Returns with pointer to allocated block. If NULL was returned * 132 * it indicates a failure to allocate. Note: NULL will never be * 133 * returned if the standard library allocation error routine is * 134 * used. * 135 * * 136 * WARNINGS: If you replace the standard memory allocation error routine * 137 * and make it so that Alloc CAN return with a NULL, be sure * 138 * and check for this in your code. * 139 * * 140 * HISTORY: * 141 * 09/03/1991 JLB : Documented. * 142 * 08/09/1993 JLB : Updated with EMS memory support. * 143 * 04/28/1994 JAW : Updated to 32bit Protected mode. * 144 * 03/09/1995 JLB : Fixed * 145 * 09/28/1995 ST : Simplified for win95 * 146 *=========================================================================*/ 147 void *Alloc(unsigned long bytes_to_alloc, MemoryFlagType flags) 148 { 149 150 #ifdef WIN32 151 152 void *mem_ptr; 153 154 #ifdef MEM_CHECK 155 bytes_to_alloc += 32; 156 #endif //MEM_CHECK 157 158 mem_ptr = malloc ( bytes_to_alloc ); 159 160 if ( !mem_ptr && Memory_Error ){ 161 Memory_Error(); 162 } 163 164 if ( mem_ptr && ( flags & MEM_CLEAR ) ){ 165 memset ( mem_ptr , 0 , bytes_to_alloc ); 166 } 167 168 #ifdef MEM_CHECK 169 mem_ptr = (void*)((char*)mem_ptr + 16); 170 unsigned long *magic_ptr =(unsigned long*) ( ((char *)mem_ptr) - 16 ); 171 *magic_ptr++ = (unsigned long)mem_ptr; 172 *magic_ptr++ = (unsigned long)mem_ptr; 173 *magic_ptr++ = (unsigned long)mem_ptr; 174 *magic_ptr = bytes_to_alloc - 32; 175 magic_ptr = (unsigned long*) ( ((char*)mem_ptr) + bytes_to_alloc - 32 ); 176 *magic_ptr++ = (unsigned long)mem_ptr; 177 *magic_ptr++ = (unsigned long)mem_ptr; 178 *magic_ptr++ = (unsigned long)mem_ptr; 179 *magic_ptr = (unsigned long)mem_ptr; 180 #endif //MEM_CHECK 181 182 Memory_Calls++; 183 return ( mem_ptr ); 184 185 #else 186 187 188 189 union REGS regs ; 190 struct SREGS sregs ; 191 unsigned char *retval=NULL; // Pointer to allocated block. 192 unsigned long original_size; // Original allocation size. 193 unsigned long bytesfree; // Number of free bytes. 194 long *longptr=NULL; // Pointer used to store selector 195 196 /* 197 ** Save the original allocated space size so that we can clear the 198 ** exact amount of RAM if they specified MEM_CLEAR. 199 */ 200 original_size = bytes_to_alloc; 201 202 /* 203 ** Reserve one byte for the header of the memory we allocated. 204 ** We will store the flags variable there for later use. 205 */ 206 bytes_to_alloc += (flags & MEM_LOCK) ? 5 : 1; 207 208 /* 209 ** Initialize the total ram available value. 210 */ 211 if (!TotalRam) { 212 TotalRam = Total_Ram_Free(MEM_NORMAL); 213 } 214 215 216 // Try to allocate the memory out of the protected mode memory 217 // chain if we did not require a real mode allocation. If this 218 // fails we will have to try to allocate it out of real mode memory. 219 // Real mode memory is a last resort because some types of applications 220 // require real mode memory. 221 if (!(flags & MEM_REAL)) { 222 retval = (unsigned char*)malloc(bytes_to_alloc); 223 } 224 225 // Try to allocate the memory out of the real mode memory using DPMI 226 // service 0x100. Note that retval will be null if we are requesting 227 // real mode memory so that we do not have to explicitly check for the 228 // real mode flag. Remember we need to reserve room for the dos 229 // selector value at the beginning of our allocated block so rather than 230 // adding fifteen and rounding, we need to add 19 and round. 231 if (!retval) { 232 flags = (MemoryFlagType)(flags | MEM_REAL); 233 regs.x.eax = 0x100; 234 regs.x.ebx = (bytes_to_alloc + 19) >> 4; 235 if (regs.x.ebx & 0xFFFF0000) { 236 retval = NULL; 237 } else { 238 segread ( & sregs ) ; 239 int386x ( 0x31 , & regs, & regs , & sregs ) ; 240 if (regs.x.cflag) 241 retval = NULL; 242 else { 243 longptr = (long *)(((regs.x.eax & 0xFFFF) << 4)+ 1); 244 *longptr++ = regs.x.edx & 0xFFFF; 245 retval = (unsigned char *)longptr; 246 } 247 } 248 } 249 250 // If the alloc failed then we need to signify a memory error. 251 if (retval == NULL) { 252 if(Memory_Error != NULL) 253 Memory_Error(); 254 return NULL; 255 } 256 257 // If the memory needs to be DPMI locked then we should store the 258 // original size in the header before we store the flags. 259 if (flags & MEM_LOCK) { 260 longptr = (long *)retval; 261 *longptr++ = original_size; 262 retval = (unsigned char *)longptr; 263 } 264 265 266 // Now that we know the alloc was sucessful (and for an extra byte 267 // more than the user wanted) we need to stick in the memory flags. 268 *retval++ = flags; 269 270 // If the memory needed to be DPMI locked then set it up so it 271 // is locked. 272 if (flags & MEM_LOCK) { 273 DPMI_Lock(retval, original_size); 274 275 } 276 277 278 /* Clear the space if they wanted it clear */ 279 280 if (flags & MEM_CLEAR) { 281 unsigned char *ptr; // Working memory block pointer. 282 283 ptr = retval; 284 memset(ptr, '\0', original_size); 285 } 286 287 bytesfree = Total_Ram_Free(MEM_NORMAL); 288 if (bytesfree < MinRam) { 289 MinRam = bytesfree; 290 } 291 if (TotalRam-bytesfree > MaxRam) { 292 MaxRam = TotalRam-bytesfree; 293 } 294 295 Memory_Calls++; 296 297 return(retval); 298 299 #endif 300 } 301 302 303 /*************************************************************************** 304 * Free -- Free an Alloc'ed block of RAM. * 305 * * 306 * FUNCTION: * 307 * * 308 * INPUT: A pointer to a block of RAM from Alloc. * 309 * * 310 * OUTPUT: None. * 311 * * 312 * WARNINGS: Don't use this for an Alloc_Block'ed RAM block. * 313 * * 314 * HISTORY: * 315 * 05/25/1990 : Created. * 316 ***************************************************************************/ 317 #ifdef WIN32 318 319 void Free(void const *pointer) 320 { 321 322 if ( pointer ){ 323 324 #ifdef MEM_CHECK 325 326 unsigned long *magic_ptr = (unsigned long*) ( ((char*)pointer) - 16 ); 327 328 if (*magic_ptr++ != (unsigned long)pointer || 329 *magic_ptr++ != (unsigned long)pointer || 330 *magic_ptr++ != (unsigned long)pointer ){ 331 Int3(); 332 } 333 334 magic_ptr = (unsigned long*) ( ((char*)pointer) + *magic_ptr ); 335 336 if (*magic_ptr++ != (unsigned long)pointer || 337 *magic_ptr++ != (unsigned long)pointer || 338 *magic_ptr++ != (unsigned long)pointer || 339 *magic_ptr++ != (unsigned long)pointer ){ 340 Int3(); 341 } 342 343 pointer = (void*) (((char*)pointer)-16); 344 #endif //MEM_CHECK 345 346 free ( (void*)pointer ); 347 Memory_Calls--; 348 } 349 350 #else 351 352 void Free(void const *pointer) 353 { 354 355 union REGS regs ; 356 struct SREGS sregs ; 357 358 359 if (pointer) { 360 /* 361 ** Get a pointer to the flags that we stored off. 362 */ 363 char *byteptr = ((char *)pointer) - 1; 364 365 /* 366 ** Check to see if this was locked me and if it was unlock it. 367 */ 368 if (*byteptr & MEM_LOCK) { 369 long *longptr = ((long *)byteptr) - 1; 370 DPMI_Unlock(pointer, *longptr); 371 pointer = (void *)longptr; 372 } else 373 pointer = (void *)byteptr; 374 375 376 // If the pointer is a real mode pointer than it will point to the 377 // first megabyte of system memory. If it does than we need to 378 // use DPMI to free it. 379 if (*byteptr & MEM_REAL) { 380 regs.x.eax = 0x101; 381 regs.x.edx = *(((long *)pointer) - 1); 382 segread ( & sregs ) ; 383 int386x(0x31, ®s, ®s, &sregs); 384 } else { 385 free((void *)pointer); 386 } 387 Memory_Calls--; 388 } 389 390 #endif 391 } 392 393 394 395 /*************************************************************************** 396 * Resize_Alloc -- Change the size of an allocated block. * 397 * * 398 * This routine will take a previously allocated block and change its * 399 * size without unnecessarily altering its contents. * 400 * * 401 * INPUT: pointer -- Pointer to the original memory allocation. * 402 * * 403 * new_size -- Size in bytes that it will be converted to. * 404 * * 405 * OUTPUT: Returns with a pointer to the new allocation. * 406 * * 407 * WARNINGS: ??? * 408 * * 409 * HISTORY: * 410 * 02/01/1992 JLB : Commented. * 411 *=========================================================================*/ 412 void *Resize_Alloc(void *original_ptr, unsigned long new_size_in_bytes) 413 { 414 415 unsigned long *temp; 416 417 temp = (unsigned long*)original_ptr; 418 419 /* ReAlloc the space */ 420 temp = (unsigned long *)realloc(temp, new_size_in_bytes); 421 if (temp == NULL) { 422 if(Memory_Error != NULL) 423 Memory_Error(); 424 return NULL; 425 } 426 427 return(temp); 428 } 429 430 431 /*************************************************************************** 432 * Ram_Free -- Determines the largest free chunk of RAM. * 433 * * 434 * Use this routine to determine the largest free chunk of available * 435 * RAM for allocation. It also performs a check of the memory chain. * 436 * * 437 * INPUT: none * 438 * * 439 * OUTPUT: Returns with the size of the largest free chunk of RAM. * 440 * * 441 * WARNINGS: This does not return the TOTAL memory free, only the * 442 * largest free chunk. * 443 * * 444 * HISTORY: * 445 * 09/03/1991 JLB : Commented. * 446 *=========================================================================*/ 447 long Ram_Free(MemoryFlagType) 448 { 449 // return(_memmax()); 450 #if(0) 451 MEMORYSTATUS mem_info; 452 mem_info.dwLength=sizeof(mem_info); 453 GlobalMemoryStatus(&mem_info); 454 return ( mem_info.dwAvailPhys ); 455 #endif 456 return ( 64*1024*1024 ); 457 } 458 459 460 /*************************************************************************** 461 * Heap_Size -- Size of the heap we have. * 462 * * 463 * * 464 * * 465 * INPUT: * 466 * * 467 * OUTPUT: * 468 * * 469 * WARNINGS: * 470 * * 471 * HISTORY: * 472 * 06/21/1994 SKB : Created. * 473 *=========================================================================*/ 474 long Heap_Size(MemoryFlagType ) 475 { 476 if (!TotalRam) { 477 TotalRam = Total_Ram_Free(MEM_NORMAL); 478 } 479 return(TotalRam); 480 } 481 482 483 /*************************************************************************** 484 * Total_Ram_Free -- Total amount of free RAM. * 485 * * 486 * * 487 * * 488 * INPUT: * 489 * * 490 * OUTPUT: * 491 * * 492 * WARNINGS: * 493 * * 494 * HISTORY: * 495 * 06/21/1994 SKB : Created. * 496 * 03/09/1995 JLB : Uses prerecorded heap size maximum. * 497 *=========================================================================*/ 498 long Total_Ram_Free(MemoryFlagType ) 499 { 500 #if(0) 501 MEMORYSTATUS mem_info; 502 mem_info.dwLength=sizeof(mem_info); 503 GlobalMemoryStatus(&mem_info); 504 return ( mem_info.dwAvailPhys ); 505 #endif 506 507 return ( 64*1024*1024 ); 508 } 509