PageRenderTime 61ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/libgc/AmigaOS.c

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