root/gc/AmigaOS.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GC_get_stack_base
  2. GC_get_stack_base
  3. GC_register_data_segments
  4. GC_register_data_segments
  5. GC_amiga_allocwrapper
  6. GC_amiga_free_all_mem
  7. GC_amiga_get_mem
  8. GC_amiga_rec_alloc
  9. GC_amiga_allocwrapper_any
  10. GC_amiga_set_toany
  11. GC_amiga_allocwrapper_fast
  12. GC_amiga_allocwrapper_firsttime
  13. GC_amiga_realloc

   1 
   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 
  43 ptr_t GC_get_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 */
  61 ptr_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 
 214 void *GC_amiga_allocwrapper(size_t size,void *(*AllocFunction)(size_t size2)){
 215         return (*AllocFunction)(size);
 216 }
 217 
 218 void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
 219         =GC_amiga_allocwrapper;
 220 
 221 #else
 222 
 223 
 224 
 225 
 226 void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2));
 227 
 228 void *(*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 
 245 struct GC_Amiga_AllocedMemoryHeader{
 246         ULONG size;
 247         struct GC_Amiga_AllocedMemoryHeader *next;
 248 };
 249 struct 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 
 255 ULONG 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
 260 BOOL GC_amiga_dontalloc=FALSE;
 261 #endif
 262 
 263 #ifdef GC_AMIGA_PRINTSTATS
 264 int succ=0,succ2=0;
 265 int nsucc=0,nsucc2=0;
 266 int nullretries=0;
 267 int numcollects=0;
 268 int chipa=0;
 269 int allochip=0;
 270 int allocfast=0;
 271 int cur0=0;
 272 int cur1=0;
 273 int cur10=0;
 274 int cur50=0;
 275 int cur150=0;
 276 int cur151=0;
 277 int ncur0=0;
 278 int ncur1=0;
 279 int ncur10=0;
 280 int ncur50=0;
 281 int ncur150=0;
 282 int ncur151=0;
 283 #endif
 284 
 285 /* Free everything at program-end. */
 286 
 287 void 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 
 330 char *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  */
 338 size_t latestsize;
 339 
 340 #endif
 341 
 342 
 343 /*
 344  * The actual function that is called with the GET_MEM macro.
 345  *
 346  */
 347 
 348 void *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
 393 void *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 
 437 void *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 
 517 void (*GC_amiga_toany)(void)=NULL;
 518 
 519 void GC_amiga_set_toany(void (*func)(void)){
 520         GC_amiga_toany=func;
 521 }
 522 
 523 #endif // !GC_AMIGA_ONLYFAST
 524 
 525 
 526 void *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 
 561 void *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  */
 577 void *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 

/* [<][>][^][v][top][bottom][index][help] */