Synopsis - Cross-Reference

File: /src/Synopsis/gc/AmigaOS.c
  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
 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