Synopsis - Cross-Reference
File: /src/Synopsis/gc/AmigaOS.c1 2 3/****************************************************************** 4 5 AmigaOS-spesific routines for GC. 6 This file is normally included from os_dep.c 7 8******************************************************************/ 9 10 11#if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM) 12# include "gc_priv.h" 13# include <stdio.h> 14# include <signal.h> 15# define GC_AMIGA_DEF 16# define GC_AMIGA_SB 17# define GC_AMIGA_DS 18# define GC_AMIGA_AM 19#endif 20 21 22#ifdef GC_AMIGA_DEF 23 24# ifndef __GNUC__ 25# include <exec/exec.h> 26# endif 27# include <proto/exec.h> 28# include <proto/dos.h> 29# include <dos/dosextens.h> 30# include <workbench/startup.h> 31 32#endif 33 34 35 36 37#ifdef GC_AMIGA_SB 38 39/****************************************************************** 40 Find the base of the stack. 41******************************************************************/ 42 43ptr_t GC_get_main_stack_base() 44{ 45 struct Process *proc = (struct Process*)SysBase->ThisTask; 46 47 /* Reference: Amiga Guru Book Pages: 42,567,574 */ 48 if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS 49 && proc->pr_CLI != NULL) { 50 /* first ULONG is StackSize */ 51 /*longPtr = proc->pr_ReturnAddr; 52 size = longPtr[0];*/ 53 54 return (char *)proc->pr_ReturnAddr + sizeof(ULONG); 55 } else { 56 return (char *)proc->pr_Task.tc_SPUpper; 57 } 58} 59 60#if 0 /* old version */ 61ptr_t GC_get_stack_base() 62{ 63 extern struct WBStartup *_WBenchMsg; 64 extern long __base; 65 extern long __stack; 66 struct Task *task; 67 struct Process *proc; 68 struct CommandLineInterface *cli; 69 long size; 70 71 if ((task = FindTask(0)) == 0) { 72 GC_err_puts("Cannot find own task structure\n"); 73 ABORT("task missing"); 74 } 75 proc = (struct Process *)task; 76 cli = BADDR(proc->pr_CLI); 77 78 if (_WBenchMsg != 0 || cli == 0) { 79 size = (char *)task->tc_SPUpper - (char *)task->tc_SPLower; 80 } else { 81 size = cli->cli_DefaultStack * 4; 82 } 83 return (ptr_t)(__base + GC_max(size, __stack)); 84} 85#endif 86 87 88#endif 89 90 91#ifdef GC_AMIGA_DS 92/****************************************************************** 93 Register data segments. 94******************************************************************/ 95 96 void GC_register_data_segments() 97 { 98 struct Process *proc; 99 struct CommandLineInterface *cli; 100 BPTR myseglist; 101 ULONG *data; 102 103 int num; 104 105 106# ifdef __GNUC__ 107 ULONG dataSegSize; 108 GC_bool found_segment = FALSE; 109 extern char __data_size[]; 110 111 dataSegSize=__data_size+8; 112 /* Can`t find the Location of __data_size, because 113 it`s possible that is it, inside the segment. */ 114 115# endif 116 117 proc= (struct Process*)SysBase->ThisTask; 118 119 /* Reference: Amiga Guru Book Pages: 538ff,565,573 120 and XOper.asm */ 121 if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) { 122 if (proc->pr_CLI == NULL) { 123 myseglist = proc->pr_SegList; 124 } else { 125 /* ProcLoaded 'Loaded as a command: '*/ 126 cli = BADDR(proc->pr_CLI); 127 myseglist = cli->cli_Module; 128 } 129 } else { 130 ABORT("Not a Process."); 131 } 132 133 if (myseglist == NULL) { 134 ABORT("Arrrgh.. can't find segments, aborting"); 135 } 136 137 /* xoper hunks Shell Process */ 138 139 num=0; 140 for (data = (ULONG *)BADDR(myseglist); data != NULL; 141 data = (ULONG *)BADDR(data[0])) { 142 if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) || 143 ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) { 144# ifdef __GNUC__ 145 if (dataSegSize == data[-1]) { 146 found_segment = TRUE; 147 } 148# endif 149 GC_add_roots_inner((char *)&data[1], 150 ((char *)&data[1]) + data[-1], FALSE); 151 } 152 ++num; 153 } /* for */ 154# ifdef __GNUC__ 155 if (!found_segment) { 156 ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library"); 157 } 158# endif 159 } 160 161#if 0 /* old version */ 162 void GC_register_data_segments() 163 { 164 extern struct WBStartup *_WBenchMsg; 165 struct Process *proc; 166 struct CommandLineInterface *cli; 167 BPTR myseglist; 168 ULONG *data; 169 170 if ( _WBenchMsg != 0 ) { 171 if ((myseglist = _WBenchMsg->sm_Segment) == 0) { 172 GC_err_puts("No seglist from workbench\n"); 173 return; 174 } 175 } else { 176 if ((proc = (struct Process *)FindTask(0)) == 0) { 177 GC_err_puts("Cannot find process structure\n"); 178 return; 179 } 180 if ((cli = BADDR(proc->pr_CLI)) == 0) { 181 GC_err_puts("No CLI\n"); 182 return; 183 } 184 if ((myseglist = cli->cli_Module) == 0) { 185 GC_err_puts("No seglist from CLI\n"); 186 return; 187 } 188 } 189 190 for (data = (ULONG *)BADDR(myseglist); data != 0; 191 data = (ULONG *)BADDR(data[0])) { 192# ifdef AMIGA_SKIP_SEG 193 if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) || 194 ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) { 195# else 196 { 197# endif /* AMIGA_SKIP_SEG */ 198 GC_add_roots_inner((char *)&data[1], 199 ((char *)&data[1]) + data[-1], FALSE); 200 } 201 } 202 } 203#endif /* old version */ 204 205 206#endif 207 208 209 210#ifdef GC_AMIGA_AM 211 212#ifndef GC_AMIGA_FASTALLOC 213 214void *GC_amiga_allocwrapper(size_t size,void *(*AllocFunction)(size_t size2)){ 215 return (*AllocFunction)(size); 216} 217 218void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2)) 219 =GC_amiga_allocwrapper; 220 221#else 222 223 224 225 226void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)); 227 228void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2)) 229 =GC_amiga_allocwrapper_firsttime; 230 231 232/****************************************************************** 233 Amiga-spesific routines to obtain memory, and force GC to give 234 back fast-mem whenever possible. 235 These hacks makes gc-programs go many times faster when 236 the amiga is low on memory, and are therefore strictly necesarry. 237 238 -Kjetil S. Matheussen, 2000. 239******************************************************************/ 240 241 242 243/* List-header for all allocated memory. */ 244 245struct GC_Amiga_AllocedMemoryHeader{ 246 ULONG size; 247 struct GC_Amiga_AllocedMemoryHeader *next; 248}; 249struct GC_Amiga_AllocedMemoryHeader *GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(int)~(NULL); 250 251 252 253/* Type of memory. Once in the execution of a program, this might change to MEMF_ANY|MEMF_CLEAR */ 254 255ULONG GC_AMIGA_MEMF = MEMF_FAST | MEMF_CLEAR; 256 257 258/* Prevents GC_amiga_get_mem from allocating memory if this one is TRUE. */ 259#ifndef GC_AMIGA_ONLYFAST 260BOOL GC_amiga_dontalloc=FALSE; 261#endif 262 263#ifdef GC_AMIGA_PRINTSTATS 264int succ=0,succ2=0; 265int nsucc=0,nsucc2=0; 266int nullretries=0; 267int numcollects=0; 268int chipa=0; 269int allochip=0; 270int allocfast=0; 271int cur0=0; 272int cur1=0; 273int cur10=0; 274int cur50=0; 275int cur150=0; 276int cur151=0; 277int ncur0=0; 278int ncur1=0; 279int ncur10=0; 280int ncur50=0; 281int ncur150=0; 282int ncur151=0; 283#endif 284 285/* Free everything at program-end. */ 286 287void GC_amiga_free_all_mem(void){ 288 struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM)); 289 struct GC_Amiga_AllocedMemoryHeader *temp; 290 291#ifdef GC_AMIGA_PRINTSTATS 292 printf("\n\n" 293 "%d bytes of chip-mem, and %d bytes of fast-mem where allocated from the OS.\n", 294 allochip,allocfast 295 ); 296 printf( 297 "%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n", 298 chipa 299 ); 300 printf("\n"); 301 printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects); 302 printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries); 303 printf("\n"); 304 printf("Succeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2); 305 printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2); 306 printf("\n"); 307 printf( 308 "Number of retries before succeding a chip->fast force:\n" 309 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n", 310 cur0,cur1,cur10,cur50,cur150,cur151 311 ); 312 printf( 313 "Number of retries before giving up a chip->fast force:\n" 314 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n", 315 ncur0,ncur1,ncur10,ncur50,ncur150,ncur151 316 ); 317#endif 318 319 while(gc_am!=NULL){ 320 temp=gc_am->next; 321 FreeMem(gc_am,gc_am->size); 322 gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp)); 323 } 324} 325 326#ifndef GC_AMIGA_ONLYFAST 327 328/* All memory with address lower than this one is chip-mem. */ 329 330char *chipmax; 331 332 333/* 334 * Allways set to the last size of memory tried to be allocated. 335 * Needed to ensure allocation when the size is bigger than 100000. 336 * 337 */ 338size_t latestsize; 339 340#endif 341 342 343/* 344 * The actual function that is called with the GET_MEM macro. 345 * 346 */ 347 348void *GC_amiga_get_mem(size_t size){ 349 struct GC_Amiga_AllocedMemoryHeader *gc_am; 350 351#ifndef GC_AMIGA_ONLYFAST 352 if(GC_amiga_dontalloc==TRUE){ 353// printf("rejected, size: %d, latestsize: %d\n",size,latestsize); 354 return NULL; 355 } 356 357 // We really don't want to use chip-mem, but if we must, then as little as possible. 358 if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL; 359#endif 360 361 gc_am=AllocMem((ULONG)(size + sizeof(struct GC_Amiga_AllocedMemoryHeader)),GC_AMIGA_MEMF); 362 if(gc_am==NULL) return NULL; 363 364 gc_am->next=GC_AMIGAMEM; 365 gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader); 366 GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am)); 367 368// printf("Allocated %d (%d) bytes at address: %x. Latest: %d\n",size,tot,gc_am,latestsize); 369 370#ifdef GC_AMIGA_PRINTSTATS 371 if((char *)gc_am<chipmax){ 372 allochip+=size; 373 }else{ 374 allocfast+=size; 375 } 376#endif 377 378 return gc_am+1; 379 380} 381 382 383 384 385#ifndef GC_AMIGA_ONLYFAST 386 387/* Tries very hard to force GC to find fast-mem to return. Done recursively 388 * to hold the rejected memory-pointers reachable from the collector in an 389 * easy way. 390 * 391 */ 392#ifdef GC_AMIGA_RETRY 393void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const int rec){ 394 void *ret; 395 396 ret=(*AllocFunction)(size); 397 398#ifdef GC_AMIGA_PRINTSTATS 399 if((char *)ret>chipmax || ret==NULL){ 400 if(ret==NULL){ 401 nsucc++; 402 nsucc2+=size; 403 if(rec==0) ncur0++; 404 if(rec==1) ncur1++; 405 if(rec>1 && rec<10) ncur10++; 406 if(rec>=10 && rec<50) ncur50++; 407 if(rec>=50 && rec<150) ncur150++; 408 if(rec>=150) ncur151++; 409 }else{ 410 succ++; 411 succ2+=size; 412 if(rec==0) cur0++; 413 if(rec==1) cur1++; 414 if(rec>1 && rec<10) cur10++; 415 if(rec>=10 && rec<50) cur50++; 416 if(rec>=50 && rec<150) cur150++; 417 if(rec>=150) cur151++; 418 } 419 } 420#endif 421 422 if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))){ 423 ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1); 424// GC_free(ret2); 425 } 426 427 return ret; 428} 429#endif 430 431 432/* The allocating-functions defined inside the amiga-blocks in gc.h is called 433 * via these functions. 434 */ 435 436 437void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){ 438 void *ret,*ret2; 439 440 GC_amiga_dontalloc=TRUE; // Pretty tough thing to do, but its indeed necesarry. 441 latestsize=size; 442 443 ret=(*AllocFunction)(size); 444 445 if(((char *)ret) <= chipmax){ 446 if(ret==NULL){ 447 //Give GC access to allocate memory. 448#ifdef GC_AMIGA_GC 449 if(!GC_dont_gc){ 450 GC_gcollect(); 451#ifdef GC_AMIGA_PRINTSTATS 452 numcollects++; 453#endif 454 ret=(*AllocFunction)(size); 455 } 456#endif 457 if(ret==NULL){ 458 GC_amiga_dontalloc=FALSE; 459 ret=(*AllocFunction)(size); 460 if(ret==NULL){ 461 WARN("Out of Memory! Returning NIL!\n", 0); 462 } 463 } 464#ifdef GC_AMIGA_PRINTSTATS 465 else{ 466 nullretries++; 467 } 468 if(ret!=NULL && (char *)ret<=chipmax) chipa+=size; 469#endif 470 } 471#ifdef GC_AMIGA_RETRY 472 else{ 473 /* We got chip-mem. Better try again and again and again etc., we might get fast-mem sooner or later... */ 474 /* Using gctest to check the effectiviness of doing this, does seldom give a very good result. */ 475 /* However, real programs doesn't normally rapidly allocate and deallocate. */ 476// printf("trying to force... %d bytes... ",size); 477 if( 478 AllocFunction!=GC_malloc_uncollectable 479#ifdef ATOMIC_UNCOLLECTABLE 480 && AllocFunction!=GC_malloc_atomic_uncollectable 481#endif 482 ){ 483 ret2=GC_amiga_rec_alloc(size,AllocFunction,0); 484 }else{ 485 ret2=(*AllocFunction)(size); 486#ifdef GC_AMIGA_PRINTSTATS 487 if((char *)ret2<chipmax || ret2==NULL){ 488 nsucc++; 489 nsucc2+=size; 490 ncur0++; 491 }else{ 492 succ++; 493 succ2+=size; 494 cur0++; 495 } 496#endif 497 } 498 if(((char *)ret2)>chipmax){ 499// printf("Succeeded.\n"); 500 GC_free(ret); 501 ret=ret2; 502 }else{ 503 GC_free(ret2); 504// printf("But did not succeed.\n"); 505 } 506 } 507#endif 508 } 509 510 GC_amiga_dontalloc=FALSE; 511 512 return ret; 513} 514 515 516 517void (*GC_amiga_toany)(void)=NULL; 518 519void GC_amiga_set_toany(void (*func)(void)){ 520 GC_amiga_toany=func; 521} 522 523#endif // !GC_AMIGA_ONLYFAST 524 525 526void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){ 527 void *ret; 528 529 ret=(*AllocFunction)(size); 530 531 if(ret==NULL){ 532 // Enable chip-mem allocation. 533// printf("ret==NULL\n"); 534#ifdef GC_AMIGA_GC 535 if(!GC_dont_gc){ 536 GC_gcollect(); 537#ifdef GC_AMIGA_PRINTSTATS 538 numcollects++; 539#endif 540 ret=(*AllocFunction)(size); 541 } 542#endif 543 if(ret==NULL){ 544#ifndef GC_AMIGA_ONLYFAST 545 GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR; 546 if(GC_amiga_toany!=NULL) (*GC_amiga_toany)(); 547 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any; 548 return GC_amiga_allocwrapper_any(size,AllocFunction); 549#endif 550 } 551#ifdef GC_AMIGA_PRINTSTATS 552 else{ 553 nullretries++; 554 } 555#endif 556 } 557 558 return ret; 559} 560 561void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){ 562 atexit(&GC_amiga_free_all_mem); 563 chipmax=(char *)SysBase->MaxLocMem; // For people still having SysBase in chip-mem, this might speed up a bit. 564 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast; 565 return GC_amiga_allocwrapper_fast(size,AllocFunction); 566} 567 568 569#endif //GC_AMIGA_FASTALLOC 570 571 572 573/* 574 * The wrapped realloc function. 575 * 576 */ 577void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){ 578#ifndef GC_AMIGA_FASTALLOC 579 return GC_realloc(old_object,new_size_in_bytes); 580#else 581 void *ret; 582 latestsize=new_size_in_bytes; 583 ret=GC_realloc(old_object,new_size_in_bytes); 584 if(ret==NULL && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){ 585 /* Out of fast-mem. */ 586#ifdef GC_AMIGA_GC 587 if(!GC_dont_gc){ 588 GC_gcollect(); 589#ifdef GC_AMIGA_PRINTSTATS 590 numcollects++; 591#endif 592 ret=GC_realloc(old_object,new_size_in_bytes); 593 } 594#endif 595 if(ret==NULL){ 596#ifndef GC_AMIGA_ONLYFAST 597 GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR; 598 if(GC_amiga_toany!=NULL) (*GC_amiga_toany)(); 599 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any; 600 ret=GC_realloc(old_object,new_size_in_bytes); 601#endif 602 } 603#ifdef GC_AMIGA_PRINTSTATS 604 else{ 605 nullretries++; 606 } 607#endif 608 } 609 if(ret==NULL){ 610 WARN("Out of Memory! Returning NIL!\n", 0); 611 } 612#ifdef GC_AMIGA_PRINTSTATS 613 if(((char *)ret)<chipmax && ret!=NULL){ 614 chipa+=new_size_in_bytes; 615 } 616#endif 617 return ret; 618#endif 619} 620 621#endif //GC_AMIGA_AM 622 623