AmigaOS.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /******************************************************************
  2. AmigaOS-specific routines for GC.
  3. This file is normally included from os_dep.c
  4. ******************************************************************/
  5. #if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM)
  6. # include "private/gc_priv.h"
  7. # include <stdio.h>
  8. # include <signal.h>
  9. # define GC_AMIGA_DEF
  10. # define GC_AMIGA_SB
  11. # define GC_AMIGA_DS
  12. # define GC_AMIGA_AM
  13. #endif
  14. #ifdef GC_AMIGA_DEF
  15. # ifndef __GNUC__
  16. # include <exec/exec.h>
  17. # endif
  18. # include <proto/exec.h>
  19. # include <proto/dos.h>
  20. # include <dos/dosextens.h>
  21. # include <workbench/startup.h>
  22. #endif
  23. #ifdef GC_AMIGA_SB
  24. /******************************************************************
  25. Find the base of the stack.
  26. ******************************************************************/
  27. ptr_t GC_get_main_stack_base(void)
  28. {
  29. struct Process *proc = (struct Process*)SysBase->ThisTask;
  30. /* Reference: Amiga Guru Book Pages: 42,567,574 */
  31. if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS
  32. && proc->pr_CLI != NULL) {
  33. /* first ULONG is StackSize */
  34. /*longPtr = proc->pr_ReturnAddr;
  35. size = longPtr[0];*/
  36. return (char *)proc->pr_ReturnAddr + sizeof(ULONG);
  37. } else {
  38. return (char *)proc->pr_Task.tc_SPUpper;
  39. }
  40. }
  41. #endif
  42. #ifdef GC_AMIGA_DS
  43. /******************************************************************
  44. Register data segments.
  45. ******************************************************************/
  46. void GC_register_data_segments(void)
  47. {
  48. struct Process *proc;
  49. struct CommandLineInterface *cli;
  50. BPTR myseglist;
  51. ULONG *data;
  52. # ifdef __GNUC__
  53. ULONG dataSegSize;
  54. GC_bool found_segment = FALSE;
  55. extern char __data_size[];
  56. dataSegSize=__data_size+8;
  57. /* Can`t find the Location of __data_size, because
  58. it`s possible that is it, inside the segment. */
  59. # endif
  60. proc= (struct Process*)SysBase->ThisTask;
  61. /* Reference: Amiga Guru Book Pages: 538ff,565,573
  62. and XOper.asm */
  63. myseglist = proc->pr_SegList;
  64. if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {
  65. if (proc->pr_CLI != NULL) {
  66. /* ProcLoaded 'Loaded as a command: '*/
  67. cli = BADDR(proc->pr_CLI);
  68. myseglist = cli->cli_Module;
  69. }
  70. } else {
  71. ABORT("Not a Process.");
  72. }
  73. if (myseglist == NULL) {
  74. ABORT("Arrrgh.. can't find segments, aborting");
  75. }
  76. /* xoper hunks Shell Process */
  77. for (data = (ULONG *)BADDR(myseglist); data != NULL;
  78. data = (ULONG *)BADDR(data[0])) {
  79. if ((ULONG)GC_register_data_segments < (ULONG)(&data[1])
  80. || (ULONG)GC_register_data_segments > (ULONG)(&data[1])
  81. + data[-1]) {
  82. # ifdef __GNUC__
  83. if (dataSegSize == data[-1]) {
  84. found_segment = TRUE;
  85. }
  86. # endif
  87. GC_add_roots_inner((char *)&data[1],
  88. ((char *)&data[1]) + data[-1], FALSE);
  89. }
  90. } /* for */
  91. # ifdef __GNUC__
  92. if (!found_segment) {
  93. ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library");
  94. }
  95. # endif
  96. }
  97. #endif
  98. #ifdef GC_AMIGA_AM
  99. #ifndef GC_AMIGA_FASTALLOC
  100. void *GC_amiga_allocwrapper(size_t size,void *(*AllocFunction)(size_t size2)){
  101. return (*AllocFunction)(size);
  102. }
  103. void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
  104. =GC_amiga_allocwrapper;
  105. #else
  106. void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2));
  107. void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
  108. =GC_amiga_allocwrapper_firsttime;
  109. /******************************************************************
  110. Amiga-specific routines to obtain memory, and force GC to give
  111. back fast-mem whenever possible.
  112. These hacks makes gc-programs go many times faster when
  113. the Amiga is low on memory, and are therefore strictly necessary.
  114. -Kjetil S. Matheussen, 2000.
  115. ******************************************************************/
  116. /* List-header for all allocated memory. */
  117. struct GC_Amiga_AllocedMemoryHeader{
  118. ULONG size;
  119. struct GC_Amiga_AllocedMemoryHeader *next;
  120. };
  121. struct GC_Amiga_AllocedMemoryHeader *GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(int)~(NULL);
  122. /* Type of memory. Once in the execution of a program, this might change to MEMF_ANY|MEMF_CLEAR */
  123. ULONG GC_AMIGA_MEMF = MEMF_FAST | MEMF_CLEAR;
  124. /* Prevents GC_amiga_get_mem from allocating memory if this one is TRUE. */
  125. #ifndef GC_AMIGA_ONLYFAST
  126. BOOL GC_amiga_dontalloc=FALSE;
  127. #endif
  128. #ifdef GC_AMIGA_PRINTSTATS
  129. int succ=0,succ2=0;
  130. int nsucc=0,nsucc2=0;
  131. int nullretries=0;
  132. int numcollects=0;
  133. int chipa=0;
  134. int allochip=0;
  135. int allocfast=0;
  136. int cur0=0;
  137. int cur1=0;
  138. int cur10=0;
  139. int cur50=0;
  140. int cur150=0;
  141. int cur151=0;
  142. int ncur0=0;
  143. int ncur1=0;
  144. int ncur10=0;
  145. int ncur50=0;
  146. int ncur150=0;
  147. int ncur151=0;
  148. #endif
  149. /* Free everything at program-end. */
  150. void GC_amiga_free_all_mem(void){
  151. struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM));
  152. #ifdef GC_AMIGA_PRINTSTATS
  153. printf("\n\n"
  154. "%d bytes of chip-mem, and %d bytes of fast-mem where allocated from the OS.\n",
  155. allochip,allocfast
  156. );
  157. printf(
  158. "%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n",
  159. chipa
  160. );
  161. printf("\n");
  162. printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects);
  163. printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries);
  164. printf("\n");
  165. printf("Succeeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
  166. printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2);
  167. printf("\n");
  168. printf(
  169. "Number of retries before succeeding a chip->fast force:\n"
  170. "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
  171. cur0,cur1,cur10,cur50,cur150,cur151
  172. );
  173. printf(
  174. "Number of retries before giving up a chip->fast force:\n"
  175. "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
  176. ncur0,ncur1,ncur10,ncur50,ncur150,ncur151
  177. );
  178. #endif
  179. while(gc_am!=NULL){
  180. struct GC_Amiga_AllocedMemoryHeader *temp = gc_am->next;
  181. FreeMem(gc_am,gc_am->size);
  182. gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp));
  183. }
  184. }
  185. #ifndef GC_AMIGA_ONLYFAST
  186. /* All memory with address lower than this one is chip-mem. */
  187. char *chipmax;
  188. /*
  189. * Always set to the last size of memory tried to be allocated.
  190. * Needed to ensure allocation when the size is bigger than 100000.
  191. *
  192. */
  193. size_t latestsize;
  194. #endif
  195. #ifdef GC_AMIGA_FASTALLOC
  196. /*
  197. * The actual function that is called with the GET_MEM macro.
  198. *
  199. */
  200. void *GC_amiga_get_mem(size_t size){
  201. struct GC_Amiga_AllocedMemoryHeader *gc_am;
  202. #ifndef GC_AMIGA_ONLYFAST
  203. if(GC_amiga_dontalloc==TRUE){
  204. return NULL;
  205. }
  206. /* We really don't want to use chip-mem, but if we must, then as little as possible. */
  207. if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL;
  208. #endif
  209. gc_am=AllocMem((ULONG)(size + sizeof(struct GC_Amiga_AllocedMemoryHeader)),GC_AMIGA_MEMF);
  210. if(gc_am==NULL) return NULL;
  211. gc_am->next=GC_AMIGAMEM;
  212. gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader);
  213. GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am));
  214. #ifdef GC_AMIGA_PRINTSTATS
  215. if((char *)gc_am<chipmax){
  216. allochip+=size;
  217. }else{
  218. allocfast+=size;
  219. }
  220. #endif
  221. return gc_am+1;
  222. }
  223. #endif
  224. #ifndef GC_AMIGA_ONLYFAST
  225. /* Tries very hard to force GC to find fast-mem to return. Done recursively
  226. * to hold the rejected memory-pointers reachable from the collector in an
  227. * easy way.
  228. *
  229. */
  230. #ifdef GC_AMIGA_RETRY
  231. void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const int rec){
  232. void *ret;
  233. ret=(*AllocFunction)(size);
  234. #ifdef GC_AMIGA_PRINTSTATS
  235. if((char *)ret>chipmax || ret==NULL){
  236. if(ret==NULL){
  237. nsucc++;
  238. nsucc2+=size;
  239. if(rec==0) ncur0++;
  240. if(rec==1) ncur1++;
  241. if(rec>1 && rec<10) ncur10++;
  242. if(rec>=10 && rec<50) ncur50++;
  243. if(rec>=50 && rec<150) ncur150++;
  244. if(rec>=150) ncur151++;
  245. }else{
  246. succ++;
  247. succ2+=size;
  248. if(rec==0) cur0++;
  249. if(rec==1) cur1++;
  250. if(rec>1 && rec<10) cur10++;
  251. if(rec>=10 && rec<50) cur50++;
  252. if(rec>=50 && rec<150) cur150++;
  253. if(rec>=150) cur151++;
  254. }
  255. }
  256. #endif
  257. if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))){
  258. ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1);
  259. }
  260. return ret;
  261. }
  262. #endif
  263. /* The allocating-functions defined inside the Amiga-blocks in gc.h is called
  264. * via these functions.
  265. */
  266. void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){
  267. void *ret;
  268. GC_amiga_dontalloc=TRUE; /* Pretty tough thing to do, but its indeed necessary. */
  269. latestsize=size;
  270. ret=(*AllocFunction)(size);
  271. if(((char *)ret) <= chipmax){
  272. if(ret==NULL){
  273. /* Give GC access to allocate memory. */
  274. #ifdef GC_AMIGA_GC
  275. if(!GC_dont_gc){
  276. GC_gcollect();
  277. #ifdef GC_AMIGA_PRINTSTATS
  278. numcollects++;
  279. #endif
  280. ret=(*AllocFunction)(size);
  281. }
  282. if(ret==NULL)
  283. #endif
  284. {
  285. GC_amiga_dontalloc=FALSE;
  286. ret=(*AllocFunction)(size);
  287. if(ret==NULL){
  288. WARN("Out of Memory! Returning NIL!\n", 0);
  289. }
  290. }
  291. #ifdef GC_AMIGA_PRINTSTATS
  292. else{
  293. nullretries++;
  294. }
  295. if(ret!=NULL && (char *)ret<=chipmax) chipa+=size;
  296. #endif
  297. }
  298. #ifdef GC_AMIGA_RETRY
  299. else{
  300. void *ret2;
  301. /* We got chip-mem. Better try again and again and again etc., we might get fast-mem sooner or later... */
  302. /* Using gctest to check the effectiveness of doing this, does seldom give a very good result. */
  303. /* However, real programs doesn't normally rapidly allocate and deallocate. */
  304. if(
  305. AllocFunction!=GC_malloc_uncollectable
  306. #ifdef GC_ATOMIC_UNCOLLECTABLE
  307. && AllocFunction!=GC_malloc_atomic_uncollectable
  308. #endif
  309. ){
  310. ret2=GC_amiga_rec_alloc(size,AllocFunction,0);
  311. }else{
  312. ret2=(*AllocFunction)(size);
  313. #ifdef GC_AMIGA_PRINTSTATS
  314. if((char *)ret2<chipmax || ret2==NULL){
  315. nsucc++;
  316. nsucc2+=size;
  317. ncur0++;
  318. }else{
  319. succ++;
  320. succ2+=size;
  321. cur0++;
  322. }
  323. #endif
  324. }
  325. if(((char *)ret2)>chipmax){
  326. GC_free(ret);
  327. ret=ret2;
  328. }else{
  329. GC_free(ret2);
  330. }
  331. }
  332. #endif
  333. }
  334. GC_amiga_dontalloc=FALSE;
  335. return ret;
  336. }
  337. void (*GC_amiga_toany)(void)=NULL;
  338. void GC_amiga_set_toany(void (*func)(void)){
  339. GC_amiga_toany=func;
  340. }
  341. #endif /* !GC_AMIGA_ONLYFAST */
  342. void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){
  343. void *ret;
  344. ret=(*AllocFunction)(size);
  345. if(ret==NULL){
  346. /* Enable chip-mem allocation. */
  347. #ifdef GC_AMIGA_GC
  348. if(!GC_dont_gc){
  349. GC_gcollect();
  350. #ifdef GC_AMIGA_PRINTSTATS
  351. numcollects++;
  352. #endif
  353. ret=(*AllocFunction)(size);
  354. }
  355. if(ret==NULL)
  356. #endif
  357. {
  358. #ifndef GC_AMIGA_ONLYFAST
  359. GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
  360. if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
  361. GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
  362. return GC_amiga_allocwrapper_any(size,AllocFunction);
  363. #endif
  364. }
  365. #ifdef GC_AMIGA_PRINTSTATS
  366. else{
  367. nullretries++;
  368. }
  369. #endif
  370. }
  371. return ret;
  372. }
  373. void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){
  374. atexit(&GC_amiga_free_all_mem);
  375. chipmax=(char *)SysBase->MaxLocMem; /* For people still having SysBase in chip-mem, this might speed up a bit. */
  376. GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast;
  377. return GC_amiga_allocwrapper_fast(size,AllocFunction);
  378. }
  379. #endif /* GC_AMIGA_FASTALLOC */
  380. /*
  381. * The wrapped realloc function.
  382. *
  383. */
  384. void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
  385. #ifndef GC_AMIGA_FASTALLOC
  386. return GC_realloc(old_object,new_size_in_bytes);
  387. #else
  388. void *ret;
  389. latestsize=new_size_in_bytes;
  390. ret=GC_realloc(old_object,new_size_in_bytes);
  391. if(ret==NULL && new_size_in_bytes != 0
  392. && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
  393. /* Out of fast-mem. */
  394. #ifdef GC_AMIGA_GC
  395. if(!GC_dont_gc){
  396. GC_gcollect();
  397. #ifdef GC_AMIGA_PRINTSTATS
  398. numcollects++;
  399. #endif
  400. ret=GC_realloc(old_object,new_size_in_bytes);
  401. }
  402. if(ret==NULL)
  403. #endif
  404. {
  405. #ifndef GC_AMIGA_ONLYFAST
  406. GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
  407. if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
  408. GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
  409. ret=GC_realloc(old_object,new_size_in_bytes);
  410. #endif
  411. }
  412. #ifdef GC_AMIGA_PRINTSTATS
  413. else{
  414. nullretries++;
  415. }
  416. #endif
  417. }
  418. if(ret==NULL && new_size_in_bytes != 0){
  419. WARN("Out of Memory! Returning NIL!\n", 0);
  420. }
  421. #ifdef GC_AMIGA_PRINTSTATS
  422. if(((char *)ret)<chipmax && ret!=NULL){
  423. chipa+=new_size_in_bytes;
  424. }
  425. #endif
  426. return ret;
  427. #endif
  428. }
  429. #endif /* GC_AMIGA_AM */