fixed various compilation erros for net-win64
[charm.git] / src / conv-core / isomalloc.c
1 /**************************************************************************
2 Isomalloc:
3   A way to allocate memory at the same address on every processor.
4 This enables linked data structures, like thread stacks, to be migrated
5 to the same address range on other processors.  This is similar to an
6 explicitly managed shared memory system.
7
8   The memory is used and released via the mmap()/mumap() calls, so unused
9 memory does not take any (RAM, swap or disk) space.
10
11   The way it's implemented is that each processor claims some section 
12 of the available virtual address space, and satisfies all new allocations
13 from that space.  Migrating structures use whatever space they started with.
14
15 Written for migratable threads by Milind Bhandarkar around August 2000;
16 generalized by Orion Lawlor November 2001.
17 */
18 #include "converse.h"
19 #include "memory-isomalloc.h"
20
21 #define CMK_THREADS_DEBUG 0
22
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h> /* just so I can find dynamically-linked symbols */
27
28 static int _sync_iso = 0;
29
30 static int read_randomflag(void)
31 {
32   FILE *fp;
33   int random_flag;
34   CmiLock(smp_mutex);
35   fp = fopen("/proc/sys/kernel/randomize_va_space", "r");
36   if (fp != NULL) {
37     fscanf(fp, "%d", &random_flag);
38   }
39   else {
40     random_flag = -1;
41   }
42   CmiUnlock(smp_mutex);
43   return random_flag;
44 }
45
46 struct CmiIsomallocBlock {
47       CmiInt8 slot; /*First mapped slot*/
48       CmiInt8 length; /*Length of (user portion of) mapping, in bytes*/
49 };
50 typedef struct CmiIsomallocBlock CmiIsomallocBlock;
51
52 /*Convert a heap block pointer to/from a CmiIsomallocBlock header*/
53 static void *block2pointer(CmiIsomallocBlock *blockHeader) {
54         return (void *)(blockHeader+1);
55 }
56 static CmiIsomallocBlock *pointer2block(void *heapBlock) {
57         return ((CmiIsomallocBlock *)heapBlock)-1;
58 }
59
60 /*Integral type to be used for pointer arithmetic:*/
61 typedef size_t memRange_t;
62
63 /*Size in bytes of a single slot*/
64 static size_t slotsize;
65
66 /*Total number of slots per processor*/
67 static CmiInt8 numslots=0;
68
69 /*Start and end of isomalloc-managed addresses.
70 If isomallocStart==NULL, isomalloc is disabled.
71 */
72 static char *isomallocStart=NULL;
73 static char *isomallocEnd=NULL;
74
75 /*Utility conversion functions*/
76 static void *slot2addr(CmiInt8 slot) {
77         return isomallocStart+((memRange_t)slotsize)*((memRange_t)slot);
78 }
79 static int slot2pe(CmiInt8 slot) {
80         return slot/numslots;
81 }
82 static CmiInt8 pe2slot(int pe) {
83         return pe*numslots;
84 }
85 /*Return the number of slots in a block with n user data bytes*/
86 static int length2slots(int nBytes) {
87         return (sizeof(CmiIsomallocBlock)+nBytes+slotsize-1)/slotsize;
88 }
89
90 typedef struct _slotblock
91 {
92   CmiInt8 startslot;
93   CmiInt8 nslots;
94 } slotblock;
95
96 typedef struct _slotset
97 {
98   int maxbuf;
99   slotblock *buf;
100   CmiInt8 emptyslots;
101 } slotset;
102
103 /*
104  * creates a new slotset of nslots entries, starting with all
105  * empty slots. The slot numbers are [startslot,startslot+nslot-1]
106  */
107 static slotset *
108 new_slotset(CmiInt8 startslot, CmiInt8 nslots)
109 {
110   int i;
111   slotset *ss = (slotset*) malloc_reentrant(sizeof(slotset));
112   _MEMCHECK(ss);
113   ss->maxbuf = 16;
114   ss->buf = (slotblock *) malloc_reentrant(sizeof(slotblock)*ss->maxbuf);
115   _MEMCHECK(ss->buf);
116   ss->emptyslots = nslots;
117   ss->buf[0].startslot = startslot;
118   ss->buf[0].nslots = nslots;
119   for (i=1; i<ss->maxbuf; i++)
120     ss->buf[i].nslots = 0;
121   return ss;
122 }
123
124 /*
125  * returns new block of empty slots. if it cannot find any, returns (-1).
126  */
127 static CmiInt8
128 get_slots(slotset *ss, CmiInt8 nslots)
129 {
130   int i;
131   if(ss->emptyslots < nslots)
132     return (-1);
133   for(i=0;i<(ss->maxbuf);i++)
134     if(ss->buf[i].nslots >= nslots)
135       return ss->buf[i].startslot;
136   return (-1);
137 }
138
139 /* just adds a slotblock to an empty position in the given slotset. */
140 static void
141 add_slots(slotset *ss, CmiInt8 sslot, CmiInt8 nslots)
142 {
143   int pos; 
144   int emptypos = -1;
145   if (nslots == 0)
146     return;
147   for (pos=0; pos < (ss->maxbuf); pos++) {
148     if (ss->buf[pos].nslots == 0) {
149       emptypos = pos;
150       break; /* found empty slotblock */
151     }
152   }
153   if (emptypos == (-1)) /*no empty slotblock found */
154   {
155     int i;
156     int newsize = ss->maxbuf*2;
157     slotblock *newbuf = (slotblock *) malloc_reentrant(sizeof(slotblock)*newsize);
158     _MEMCHECK(newbuf);
159     for (i=0; i<(ss->maxbuf); i++)
160       newbuf[i] = ss->buf[i];
161     for (i=ss->maxbuf; i<newsize; i++)
162       newbuf[i].nslots  = 0;
163     free_reentrant(ss->buf);
164     ss->buf = newbuf;
165     emptypos = ss->maxbuf;
166     ss->maxbuf = newsize;
167   }
168   ss->buf[emptypos].startslot = sslot;
169   ss->buf[emptypos].nslots = nslots;
170   ss->emptyslots += nslots;
171   return;
172 }
173
174 /* grab a slotblock with specified range of blocks
175  * this is different from get_slots, since it pre-specifies the
176  * slots to be grabbed.
177  */
178 static void
179 grab_slots(slotset *ss, CmiInt8 sslot, CmiInt8 nslots)
180 {
181   CmiInt8 pos, eslot, e;
182   eslot = sslot + nslots;
183   for (pos=0; pos < (ss->maxbuf); pos++)
184   {
185     if (ss->buf[pos].nslots == 0)
186       continue;
187     e = ss->buf[pos].startslot + ss->buf[pos].nslots;
188     if(sslot >= ss->buf[pos].startslot && eslot <= e)
189     {
190       CmiInt8 old_nslots;
191       old_nslots = ss->buf[pos].nslots;
192       ss->buf[pos].nslots = sslot - ss->buf[pos].startslot;
193       ss->emptyslots -= (old_nslots - ss->buf[pos].nslots);
194       add_slots(ss, sslot + nslots, old_nslots - ss->buf[pos].nslots - nslots);
195       return;
196     }
197   }
198   CmiAbort("requested a non-existent slotblock\n");
199 }
200
201 /*
202  * Frees slot by adding it to one of the blocks of empty slots.
203  * this slotblock is one which is contiguous with the slots to be freed.
204  * if it cannot find such a slotblock, it creates a new slotblock.
205  * If the buffer fills up, it adds up extra buffer space.
206  */
207 static void
208 free_slots(slotset *ss, CmiInt8 sslot, CmiInt8 nslots)
209 {
210   int pos;
211   /* eslot is the ending slot of the block to be freed */
212   CmiInt8 eslot = sslot + nslots;
213   for (pos=0; pos < (ss->maxbuf); pos++)
214   {
215     CmiInt8 e = ss->buf[pos].startslot + ss->buf[pos].nslots;
216     if (ss->buf[pos].nslots == 0)
217       continue;
218     /* e is the ending slot of pos'th slotblock */
219     if (e == sslot) /* append to the current slotblock */
220     {
221             ss->buf[pos].nslots += nslots;
222             ss->emptyslots += nslots;
223             return;
224     }
225     if(eslot == ss->buf[pos].startslot) /* prepend to the current slotblock */
226     {
227             ss->buf[pos].startslot = sslot;
228             ss->buf[pos].nslots += nslots;
229             ss->emptyslots += nslots;
230             return;
231     }
232   }
233   /* if we are here, it means we could not find a slotblock that the */
234   /* block to be freed was combined with. */
235   add_slots(ss, sslot, nslots);
236 }
237
238 /*
239  * destroys slotset-- currently unused
240 static void
241 delete_slotset(slotset* ss)
242 {
243   free_reentrant(ss->buf);
244   free_reentrant(ss);
245 }
246  */
247
248 #if CMK_THREADS_DEBUG
249 static void
250 print_slots(slotset *ss)
251 {
252   int i;
253   CmiPrintf("[%d] maxbuf = %d\n", CmiMyPe(), ss->maxbuf);
254   CmiPrintf("[%d] emptyslots = %d\n", CmiMyPe(), ss->emptyslots);
255   for(i=0;i<ss->maxbuf;i++) {
256     if(ss->buf[i].nslots)
257       CmiPrintf("[%d] (%d, %d) \n", CmiMyPe(), ss->buf[i].startslot, 
258           ss->buf[i].nslots);
259   }
260 }
261 #else
262 #  define print_slots(ss) /*empty*/
263 #endif
264
265 /*This version of the allocate/deallocate calls are used if the 
266 real mmap versions are disabled.*/
267 static int disabled_map_warned=0;
268 static void *disabled_map(int nBytes) 
269 {
270         if (!disabled_map_warned) {
271                 disabled_map_warned=1;
272                 if (CmiMyPe()==0)
273                         CmiError("charm isomalloc.c> Warning: since mmap() doesn't work,"
274                         " you won't be able to migrate threads\n");
275         }
276         return malloc(nBytes);
277 }
278 static void disabled_unmap(void *bk) {
279         free(bk);
280 }
281
282 /*Turn off isomalloc memory, for the given reason*/
283 static void disable_isomalloc(const char *why)
284 {
285     isomallocStart=NULL;
286     isomallocEnd=NULL;
287 #if CMK_THREADS_DEBUG
288     CmiPrintf("[%d] isomalloc.c> Disabling isomalloc because %s\n",CmiMyPe(),why);
289 #endif
290 }
291
292 #if ! CMK_HAS_MMAP
293 /****************** Manipulate memory map (Win32 non-version) *****************/
294 static void *call_mmap_fixed(void *addr,size_t len) {
295         CmiAbort("isomalloc.c: mmap_fixed should never be called here.");
296         return NULL;
297 }
298 static void *call_mmap_anywhere(size_t len) {
299         CmiAbort("isomalloc.c: mmap_anywhere should never be called here.");
300         return NULL;
301 }
302 static void call_munmap(void *addr,size_t len) {
303         CmiAbort("isomalloc.c: munmap should never be called here.");
304 }
305
306 static int 
307 init_map(char **argv)
308 {
309   return 0; /*Isomalloc never works without mmap*/
310 }
311 #else /* CMK_HAS_MMAP */
312 /****************** Manipulate memory map (UNIX version) *****************/
313 #include <sys/types.h>
314 #include <sys/mman.h>
315 #include <sys/stat.h>
316 #include <fcntl.h>
317
318 #if !CMK_HAS_MMAP_ANON
319 CpvStaticDeclare(int, zerofd); /*File descriptor for /dev/zero, for mmap*/
320 #endif
321
322 /**
323  * Maps this address with these flags.
324  */
325 static void *call_mmap(void *addr,size_t len, int flags) {
326   void *ret=mmap(addr, len, PROT_READ|PROT_WRITE,
327 #if CMK_HAS_MMAP_ANON
328             flags|MAP_PRIVATE|MAP_ANON,-1,
329 #else
330             flags|MAP_PRIVATE,CpvAccess(zerofd),
331 #endif
332             0);
333   if (ret==((void*)(-1))) return (void *)0; /* all-ones means failure */
334   else return ret;
335 }
336 static void *call_mmap_fixed(void *addr,size_t len) {
337         return call_mmap(addr,len,MAP_FIXED);
338 }
339 static void *call_mmap_anywhere(size_t len) {
340         return call_mmap((void *)0,len,0);
341 }
342
343 /* Unmaps this address range */
344 static void call_munmap(void *addr,size_t len) {
345   int retval;
346   if (addr == 0) return; /* NULL address is never mapped */ 
347   retval = munmap(addr, len);
348   if (retval==(-1))
349     CmiAbort("munmap call failed to deallocate requested memory.\n");
350 }
351
352 static int 
353 init_map(char **argv)
354 {
355 #if CMK_HAS_MMAP_ANON
356   /*Don't need /dev/zero*/
357 #else
358   CpvInitialize(int, zerofd);  
359   CpvAccess(zerofd) = open("/dev/zero", O_RDWR);
360   if(CpvAccess(zerofd)<0)
361     return 0; /* Cannot open /dev/zero or use MMAP_ANON, so can't mmap memory */
362 #endif
363   return 1;
364 }
365
366 #endif /* UNIX memory map */
367
368
369 /**
370  * maps the virtual memory associated with slot using mmap
371  */
372 static CmiIsomallocBlock *
373 map_slots(CmiInt8 slot, CmiInt8 nslots)
374 {
375   void *pa;
376   void *addr=slot2addr(slot);
377   pa = call_mmap_fixed(addr, slotsize*nslots);
378   
379   if (pa==NULL) 
380   { /*Map just failed completely*/
381 #if CMK_THREADS_DEBUG
382     perror("mmap failed");
383     CmiPrintf("[%d] tried to mmap %p, but encountered error\n",CmiMyPe(),addr);
384 #endif
385     return NULL;
386   }
387   if (pa != addr)
388   { /*Map worked, but gave us back the wrong place*/
389 #if CMK_THREADS_DEBUG
390     CmiPrintf("[%d] tried to mmap %p, but got %p back\n",CmiMyPe(),addr,pa);
391 #endif
392     call_munmap(addr,slotsize*nslots);
393     return NULL;
394   }
395 #if CMK_THREADS_DEBUG
396   CmiPrintf("[%d] mmap'd slots %ld-%ld to address %p\n",CmiMyPe(),
397             slot,slot+nslots-1,addr);
398 #endif
399   return (CmiIsomallocBlock *)pa;
400 }
401
402 /*
403  * unmaps the virtual memory associated with slot using munmap
404  */
405 static void
406 unmap_slots(CmiInt8 slot, CmiInt8 nslots)
407 {
408   void *addr=slot2addr(slot);
409   call_munmap(addr, slotsize*nslots);
410 #if CMK_THREADS_DEBUG
411   CmiPrintf("[%d] munmap'd slots %ld-%ld from address %p\n",CmiMyPe(),
412             slot,slot+nslots-1,addr);
413 #endif
414 }
415
416 static void map_failed(CmiInt8 s,CmiInt8 n)
417 {
418   void *addr=slot2addr(s);
419   CmiError("charm isomalloc.c> map failed to allocate %d bytes at %p.\n",
420       slotsize*n, addr);
421   CmiAbort("Exiting\n");
422 }
423
424
425
426 /************ Address space voodoo: find free address range **********/
427
428 CpvStaticDeclare(slotset *, myss); /*My managed slots*/
429
430 /*This struct describes a range of virtual addresses*/
431 typedef struct {
432   char *start; /*First byte of region*/
433   memRange_t len; /*Number of bytes in region*/
434   const char *type; /*String describing memory in region (debugging only)*/
435 } memRegion_t;
436
437 /*Estimate the top of the current stack*/
438 static void *__cur_stack_frame(void)
439 {
440   char __dummy;
441   void *top_of_stack=(void *)&__dummy;
442   return top_of_stack;
443 }
444 /*Estimate the location of the static data region*/
445 static void *__static_data_loc(void)
446 {
447   static char __dummy;
448   return (void *)&__dummy;
449 }
450
451 /*Pointer comparison is in these subroutines, because
452   comparing arbitrary pointers is nonportable and tricky.
453 */
454 static int pointer_lt(const char *a,const char *b) {
455         return ((memRange_t)a)<((memRange_t)b);
456 }
457 static int pointer_ge(const char *a,const char *b) {
458         return ((memRange_t)a)>=((memRange_t)b);
459 }
460
461 static char *pmin(char *a,char *b) {return pointer_lt(a,b)?a:b;}
462 static char *pmax(char *a,char *b) {return pointer_lt(a,b)?b:a;}
463
464 const static memRange_t meg=1024u*1024u; /*One megabyte*/
465 const static memRange_t gig=1024u*1024u*1024u; /*One gigabyte*/
466
467 /*Check if this memory location is usable.  
468   If not, return 1.
469 */
470 static int bad_location(char *loc) {
471   void *addr;
472   addr=call_mmap_fixed(loc,slotsize);
473   if (addr==NULL) {
474 #if CMK_THREADS_DEBUG
475     CmiPrintf("[%d] Skipping unmappable space at %p\n",CmiMyPe(),loc);
476 #endif
477     return 1; /*No good*/
478   }
479   call_munmap(addr,slotsize);
480   return 0; /*This works*/
481 }
482
483 /* Split this range up into n pieces, returning the size of each piece */
484 static memRange_t divide_range(memRange_t len,int n) {
485         return (len+1)/n;
486 }
487
488 /* Return if this memory region has *any* good parts. */
489 static int partially_good(char *start,memRange_t len,int n) {
490   int i;
491   memRange_t quant=divide_range(len,n);
492   for (i=0;i<n;i++)
493     if (!bad_location(start+i*quant)) return 1; /* it's got some good parts */
494   return 0; /* all locations are bad */
495 }
496
497 /* Return if this memory region is usable at n samples.  
498 */
499 static int good_range(char *start,memRange_t len,int n) {
500   int i;
501   memRange_t quant=divide_range(len,n);
502   for (i=0;i<n;i++)
503     if (bad_location(start+i*quant)) return 0; /* it's got some bad parts */
504   /* It's all good: */
505   return 1;
506 }
507
508 /*Check if this entire memory range, or some subset 
509   of the range, is usable.  If so, write it into max.
510 */
511 static void check_range(char *start,char *end,memRegion_t *max)
512 {
513   memRange_t len;
514   char *initialStart=start, *initialEnd=end;
515   CmiUInt8 tb = (CmiUInt8)gig*1024ul;   /* One terabyte */
516   CmiUInt8 vm_limit = tb*256ul;   /* terabyte */
517
518   if (start>=end) return; /*Ran out of hole*/
519   len=(memRange_t)end-(memRange_t)start;
520   
521 #if 0
522     /* too conservative */
523   if (len/gig>64u) { /* This is an absurd amount of space-- cut it down, for safety */
524      start+=16u*gig;
525      end=start+32u*gig;
526      len=(memRange_t)end-(memRange_t)start;  
527   }
528 #else
529   /* Note: 256TB == 248 bytes.  So a 48-bit virtual-address CPU 
530    *    can only actually address 256TB of space. */
531   if (len/tb>10u) { /* This is an absurd amount of space-- cut it down, for safety */
532     const memRange_t other_libs=16ul*gig; /* space for other libraries to use */
533     start+=other_libs;
534     end=pmin(start+vm_limit-2*other_libs, end-other_libs);
535     len=(memRange_t)end-(memRange_t)start;
536   }
537 #endif
538   if (len<=max->len) return; /*It's too short already!*/
539 #if CMK_THREADS_DEBUG
540   CmiPrintf("[%d] Checking at %p - %p\n",CmiMyPe(),start,end);
541 #endif
542   
543   /* Check the middle of the range */
544   if (!good_range(start,len,256)) {
545     /* Try to split into subranges: */
546     int i,n=2;
547 #if CMK_THREADS_DEBUG
548     CmiPrintf("[%d] Trying to split bad address space at %p - %p...\n",CmiMyPe(),start,end);
549 #endif
550     len=divide_range(len,n);
551     for (i=0;i<n;i++) {
552         char *cur=start+i*len;
553         if (partially_good(cur,len,16))
554            check_range(cur,cur+len,max);
555     }
556     return; /* Hopefully one of the subranges will be any good */
557   }
558   else /* range is good */
559   { 
560 #if CMK_THREADS_DEBUG
561     CmiPrintf("[%d] Address space at %p - %p is largest\n",CmiMyPe(),start,end);
562 #endif
563
564     /*If we got here, we're the new largest usable range*/
565     max->len=len;
566     max->start=start;
567     max->type="Unused";
568   }
569 }
570
571 /*Find the first available memory region of at least the
572   given size not touching any data in the used list.
573  */
574 static memRegion_t find_free_region(memRegion_t *used,int nUsed,int atLeast) 
575 {
576   memRegion_t max;
577   int i,j;  
578
579   max.start=0; 
580   max.len=atLeast;
581   /*Find the largest hole between regions*/
582   for (i=0;i<nUsed;i++) {
583     /*Consider a hole starting at the end of region i*/
584     char *holeStart=used[i].start+used[i].len;
585     char *holeEnd=(void *)(-1);
586     
587     /*Shrink the hole by all others*/ 
588     for (j=0;j<nUsed && pointer_lt(holeStart,holeEnd);j++) {
589       if (pointer_lt(used[j].start,holeStart)) 
590         holeStart=pmax(holeStart,used[j].start+used[j].len);
591       else if (pointer_lt(used[j].start,holeEnd)) 
592         holeEnd=pmin(holeEnd,used[j].start);
593     } 
594
595     check_range(holeStart,holeEnd,&max);
596   }
597
598   return max; 
599 }
600
601 /*
602 By looking at the address range carefully, try to find 
603 the largest usable free region on the machine.
604 */
605 static int find_largest_free_region(memRegion_t *destRegion) {
606     char *staticData =(char *) __static_data_loc();
607     char *code = (char *)&find_free_region;
608     char *threadData = (char *)&errno;
609     char *codeDll = (char *)fprintf;
610     char *heapLil = (char*) malloc(1);
611     char *heapBig = (char*) malloc(6*meg);
612     char *stack = (char *)__cur_stack_frame();
613     size_t mmapAnyLen = 1*meg;
614     char *mmapAny = (char*) call_mmap_anywhere(mmapAnyLen);
615
616     int i,nRegions=9;
617     memRegion_t regions[10]; /*used portions of address space*/
618     memRegion_t freeRegion; /*Largest unused block of address space*/
619
620 /*Mark off regions of virtual address space as ususable*/
621     regions[0].type="NULL";
622     regions[0].start=NULL; regions[0].len=16u*meg;
623     
624     regions[1].type="Static program data";
625     regions[1].start=staticData; regions[1].len=256u*meg;
626     
627     regions[2].type="Program executable code";
628     regions[2].start=code; regions[2].len=256u*meg;
629     
630     regions[3].type="Heap (small blocks)";
631     regions[3].start=heapLil; regions[3].len=1u*gig;
632     
633     regions[4].type="Heap (large blocks)";
634     regions[4].start=heapBig; regions[4].len=1u*gig;
635     
636     regions[5].type="Stack space";
637     regions[5].start=stack; regions[5].len=256u*meg;
638
639     regions[6].type="Program dynamically linked code";
640     regions[6].start=codeDll; regions[6].len=256u*meg; 
641
642     regions[7].type="Result of a non-fixed call to mmap";
643     regions[7].start=mmapAny; regions[7].len=1u*gig; 
644
645     regions[8].type="Thread private data";
646     regions[8].start=threadData; regions[8].len=256u*meg; 
647
648     _MEMCHECK(heapBig); free(heapBig);
649     _MEMCHECK(heapLil); free(heapLil); 
650     call_munmap(mmapAny,mmapAnyLen);
651     
652     /*Align each memory region*/
653     for (i=0;i<nRegions;i++) {
654       memRegion_t old=regions[i];
655       memRange_t p=(memRange_t)regions[i].start;
656       p&=~(regions[i].len-1); /*Round start down to a len-boundary (mask off low bits)*/
657       regions[i].start=(char *)p;
658 #if CMK_THREADS_DEBUG
659       CmiPrintf("[%d] Memory map: %p - %p %s (at %p)\n",CmiMyPe(),
660               regions[i].start,regions[i].start+regions[i].len,
661               regions[i].type, old.start);
662 #endif
663     }
664     
665     /*Find a large, unused region in this map: */
666     freeRegion=find_free_region(regions,nRegions,(512u)*meg);
667     
668     if (freeRegion.start==0) 
669     { /*No free address space-- disable isomalloc:*/
670       return 0;
671     }
672     else /* freeRegion is valid */
673     {
674       *destRegion=freeRegion;
675       
676       return 1;
677     }
678 }
679
680 static void init_ranges(char **argv)
681 {
682   /*Largest value a signed int can hold*/
683   memRange_t intMax=(((memRange_t)1)<<(sizeof(int)*8-1))-1;
684
685   /*Round slot size up to nearest page size*/
686   slotsize=16*1024;
687   slotsize=(slotsize+CMK_MEMORY_PAGESIZE-1) & ~(CMK_MEMORY_PAGESIZE-1);
688 #if CMK_THREADS_DEBUG
689   CmiPrintf("[%d] Using slotsize of %d\n", CmiMyPe(), slotsize);
690 #endif
691
692   if (CmiMyRank()==0 && numslots==0)
693   { /* Find the largest unused region of virtual address space */
694       memRegion_t freeRegion;
695       freeRegion.len=0u;
696 #ifdef CMK_MMAP_START_ADDRESS /* Hardcoded start address, for machines where automatic fails */
697       freeRegion.start=CMK_MMAP_START_ADDRESS;
698       freeRegion.len=CMK_MMAP_LENGTH_MEGS*meg;
699 #endif
700       if (freeRegion.len==0u) find_largest_free_region(&freeRegion);
701       
702 #if 0
703       /*Make sure our largest slot number doesn't overflow an int:*/
704       if (freeRegion.len/slotsize>intMax)
705         freeRegion.len=intMax*slotsize;
706 #endif
707       
708       if (freeRegion.len==0u) {
709         disable_isomalloc("no free virtual address space");
710       }
711       else /* freeRegion.len>0, so can isomalloc */
712       {
713 #if CMK_THREADS_DEBUG
714         CmiPrintf("[%d] Isomalloc memory region: %p - %p (%d megs)\n",CmiMyPe(),
715               freeRegion.start,freeRegion.start+freeRegion.len,
716               freeRegion.len/meg);
717 #endif
718         
719           /*
720              on some machines, isomalloc memory regions on different nodes 
721              can be different. use +isomalloc_sync to calculate the
722              intersect of all memory regions on all nodes.
723           */
724         if (_sync_iso == 1) {
725           if (CmiBarrier() == -1) 
726             CmiAbort("Charm++ Error> +isomalloc_sync requires CmiBarrier() implemented.\n");
727           else {
728             CmiUInt8 s = (CmiUInt8)freeRegion.start;
729             CmiUInt8 e = (CmiUInt8)(freeRegion.start+freeRegion.len);
730             int fd, i;
731             char fname[128];
732
733             if (CmiMyNode()==0) printf("Charm++> synchronizing isomalloc memory region...\n");
734
735               /* write region into file */
736             sprintf(fname,".isomalloc.%d", CmiMyNode());
737             while ((fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0644)) == -1) 
738 #ifndef __MINGW_H
739               CMK_CPV_IS_SMP
740 #endif
741             ;
742             write(fd, &s, sizeof(CmiUInt8));
743             write(fd, &e, sizeof(CmiUInt8));
744             close(fd);
745
746             CmiBarrier();
747
748             for (i=0; i<CmiNumNodes(); i++) {
749               CmiUInt8 ss, ee; 
750               char fname[128];
751               if (i==CmiMyNode()) continue;
752               sprintf(fname,".isomalloc.%d", i);
753               while ((fd = open(fname, O_RDONLY)) == -1)
754 #ifndef __MINGW_H
755               CMK_CPV_IS_SMP
756 #endif
757               ;
758               read(fd, &ss, sizeof(CmiUInt8));
759               read(fd, &ee, sizeof(CmiUInt8));
760               close(fd);
761               if (ss>s) s = ss;
762               if (ee<e) e = ee;
763             }
764
765             CmiBarrier();
766
767             unlink(fname);
768
769               /* update */
770             freeRegion.start = (void *)s;
771             freeRegion.len = (char *)e -(char *)s;
772 #if CMK_THREADS_DEBUG
773             CmiPrintf("[%d] consolidated Isomalloc memory region: %p - %p (%d megs)\n",CmiMyPe(),
774               freeRegion.start,freeRegion.start+freeRegion.len,
775               freeRegion.len/meg);
776 #endif
777           }   /* end of barrier test */
778         }
779
780         /*Isomalloc covers entire unused region*/
781         isomallocStart=freeRegion.start;
782         isomallocEnd=freeRegion.start+freeRegion.len;
783         numslots=(freeRegion.len/slotsize)/CmiNumPes();
784         
785 #if CMK_THREADS_DEBUG
786         CmiPrintf("[%d] Can isomalloc up to %lu megs per pe\n",CmiMyPe(),
787               ((memRange_t)numslots)*slotsize/meg);
788 #endif
789       }
790   }
791   /*SMP Mode: wait here for rank 0 to initialize numslots so we can set up myss*/
792   CmiNodeAllBarrier(); 
793   
794   if (isomallocStart!=NULL) {
795     CpvInitialize(slotset *, myss);
796     CpvAccess(myss) = new_slotset(pe2slot(CmiMyPe()), numslots);
797   }
798 }
799
800
801 /************* Communication: for grabbing/freeing remote slots *********/
802 typedef struct _slotmsg
803 {
804   char cmicore[CmiMsgHeaderSizeBytes];
805   int pe; /*Source processor*/
806   CmiInt8 slot; /*First requested slot*/
807   CmiInt8 nslots; /*Number of requested slots*/
808 } slotmsg;
809
810 static slotmsg *prepare_slotmsg(CmiInt8 slot,CmiInt8 nslots)
811 {
812         slotmsg *m=(slotmsg *)CmiAlloc(sizeof(slotmsg));
813         m->pe=CmiMyPe();
814         m->slot=slot;
815         m->nslots=nslots;
816         return m;
817 }
818
819 static void grab_remote(slotmsg *msg)
820 {
821         grab_slots(CpvAccess(myss),msg->slot,msg->nslots);
822         CmiFree(msg);
823 }
824
825 static void free_remote(slotmsg *msg)
826 {
827         free_slots(CpvAccess(myss),msg->slot,msg->nslots);
828         CmiFree(msg);
829 }
830 static int grab_remote_idx, free_remote_idx;
831
832 struct slotOP {
833         /*Function pointer to perform local operation*/
834         void (*local)(slotset *ss,CmiInt8 s,CmiInt8 n);
835         /*Index to perform remote operation*/
836         int remote;
837 };
838 typedef struct slotOP slotOP;
839 static slotOP grabOP,freeOP;
840
841 static void init_comm(char **argv)
842 {
843         grab_remote_idx=CmiRegisterHandler((CmiHandler)grab_remote);
844         free_remote_idx=CmiRegisterHandler((CmiHandler)free_remote);    
845         grabOP.local=grab_slots;
846         grabOP.remote=grab_remote_idx;
847         freeOP.local=free_slots;
848         freeOP.remote=free_remote_idx;  
849 }
850
851 /*Apply the given operation to the given slots which
852   lie on the given processor.*/
853 static void one_slotOP(const slotOP *op,int pe,CmiInt8 s,CmiInt8 n)
854 {
855 /*Shrink range to only those covered by this processor*/
856         /*First and last slot for this processor*/
857         CmiInt8 p_s=pe2slot(pe), p_e=pe2slot(pe+1);
858         CmiInt8 e=s+n;
859         if (s<p_s) s=p_s;
860         if (e>p_e) e=p_e;
861         n=e-s;
862
863 /*Send off range*/
864         if (pe==CmiMyPe()) 
865                 op->local(CpvAccess(myss),s,n);
866         else 
867         {/*Remote request*/
868                 slotmsg *m=prepare_slotmsg(s,n);
869                 CmiSetHandler(m, freeOP.remote);
870                 CmiSyncSendAndFree(pe,sizeof(slotmsg),m);
871         }
872 }
873
874 /*Apply the given operation to all slots in the range [s, s+n) 
875 After a restart from checkpoint, a slotset can cross an 
876 arbitrary set of processors.
877 */
878 static void all_slotOP(const slotOP *op,CmiInt8 s,CmiInt8 n)
879 {
880         int spe=slot2pe(s), epe=slot2pe(s+n-1);
881         int pe;
882         for (pe=spe; pe<=epe; pe++)
883                 one_slotOP(op,pe,s,n);
884 }
885
886 /************** External interface ***************/
887 void *CmiIsomalloc(int size)
888 {
889         CmiInt8 s,n;
890         CmiIsomallocBlock *blk;
891         if (isomallocStart==NULL) return disabled_map(size);
892         n=length2slots(size);
893         /*Always satisfy mallocs with local slots:*/
894         s=get_slots(CpvAccess(myss),n);
895         if (s==-1) {
896                 CmiError("Not enough address space left on processor %d to isomalloc %d bytes!\n",
897                          CmiMyPe(),size);
898                 CmiAbort("Out of virtual address space for isomalloc");
899         }
900         grab_slots(CpvAccess(myss),s,n);
901         blk=map_slots(s,n);
902         if (!blk) map_failed(s,n);
903         blk->slot=s;
904         blk->length=size;
905         return block2pointer(blk);
906 }
907
908 void CmiIsomallocPup(pup_er p,void **blockPtrPtr)
909 {
910         CmiIsomallocBlock *blk;
911         CmiInt8 s,length;
912         CmiInt8 n;
913         if (isomallocStart==NULL) CmiAbort("isomalloc is disabled-- cannot use IsomallocPup");
914
915         if (!pup_isUnpacking(p)) 
916         { /*We have an existing block-- unpack start slot & length*/
917                 blk=pointer2block(*blockPtrPtr);
918                 s=blk->slot;
919                 length=blk->length;
920         }
921         
922         pup_int8(p,&s);
923         pup_int8(p,&length);
924         n=length2slots(length);
925         
926         if (pup_isUnpacking(p)) 
927         { /*Must allocate a new block in its old location*/
928                 if (pup_isUserlevel(p) || pup_isRestarting(p))
929                         /*Checkpoint: must grab old slots (even remote!)*/
930                         all_slotOP(&grabOP,s,n);
931                 blk=map_slots(s,n);
932                 if (!blk) map_failed(s,n);
933                 blk->slot=s;
934                 blk->length=length;
935                 *blockPtrPtr=block2pointer(blk);
936         }
937         
938         /*Pup the allocated data*/
939         pup_bytes(p,*blockPtrPtr,length);
940         
941         if (pup_isDeleting(p)) 
942         { /*Unmap old slots, but do not mark as free*/
943                 unmap_slots(s,n);
944                 *blockPtrPtr=NULL; /*Zero out user's pointer*/
945         }
946 }
947
948 void CmiIsomallocFree(void *blockPtr)
949 {
950         if (isomallocStart==NULL) {
951                 disabled_unmap(blockPtr);
952         }
953         else if (blockPtr!=NULL)
954         {
955                 CmiIsomallocBlock *blk=pointer2block(blockPtr);
956                 CmiInt8 s=blk->slot; 
957                 CmiInt8 n=length2slots(blk->length);
958                 unmap_slots(s,n);
959                 /*Mark used slots as free*/
960                 all_slotOP(&freeOP,s,n);
961         }
962 }
963
964 CmiInt8   CmiIsomallocLength(void *block)
965 {
966         return pointer2block(block)->length;
967 }
968
969 /*Return true if this address is in the region managed by isomalloc*/
970 int CmiIsomallocInRange(void *addr)
971 {
972         if (isomallocStart==NULL) return 0; /* There is no range we manage! */
973         return pointer_ge((char *)addr,isomallocStart) && 
974                pointer_lt((char*)addr,isomallocEnd);
975 }
976
977 void CmiIsomallocInit(char **argv)
978 {
979 #if CMK_NO_ISO_MALLOC
980   disable_isomalloc("isomalloc disabled by conv-mach");
981 #else
982   if (CmiGetArgFlagDesc(argv,"+isomalloc_sync","synchronize isomalloc region globaly"))
983   _sync_iso = 1;
984   init_comm(argv);
985   if (!init_map(argv)) {
986     disable_isomalloc("mmap() does not work");
987   }
988   else {
989     if (read_randomflag() == 1) {    /* randomization stack pointer */
990       if (CmiMyPe() == 0)
991         printf("Charm warning> Randomization of stack pointer is turned on in Kernel, run 'echo 0 > /proc/sys/kernel/randomize_va_space' as root to disable it. Thread migration may not work! \n");
992     }
993     init_ranges(argv);
994   }
995 #endif
996 }
997
998 /***************** BlockList interface *********
999 This was moved here from memory-isomalloc.c when it 
1000 was realized that a list-of-isomalloc'd-blocks is useful for
1001 more than just isomalloc heaps.
1002 */
1003
1004 typedef CmiIsomallocBlockList Slot;
1005
1006 /*Convert a slot to a user address*/
1007 static char *Slot_toUser(Slot *s) {return (char *)(s+1);}
1008 static Slot *Slot_fmUser(void *s) {return ((Slot *)s)-1;}
1009
1010
1011 /*Build a new blockList.*/
1012 CmiIsomallocBlockList *CmiIsomallocBlockListNew(void)
1013 {
1014         CmiIsomallocBlockList *ret;
1015         ret=(CmiIsomallocBlockList *)CmiIsomalloc(sizeof(*ret));
1016         ret->next=ret; /*1-entry circular linked list*/
1017         ret->prev=ret;
1018         return ret;
1019 }
1020
1021 /*Pup all the blocks in this list.  This amounts to two circular
1022 list traversals.  Because everything's isomalloc'd, we don't even
1023 have to restore the pointers-- they'll be restored automatically!
1024 */
1025 void CmiIsomallocBlockListPup(pup_er p,CmiIsomallocBlockList **lp)
1026 {
1027         int i,nBlocks=0;
1028         Slot *cur=NULL, *start=*lp;
1029 #if 0 /*#ifndef CMK_OPTIMIZE*/
1030         if (CpvAccess(isomalloc_blocklist)!=NULL)
1031                 CmiAbort("Called CmiIsomallocBlockListPup while a blockList is active!\n"
1032                         "You should swap out the active blocklist before pupping.\n");
1033 #endif
1034         /*Count the number of blocks in the list*/
1035         if (!pup_isUnpacking(p)) {
1036                 nBlocks=1; /*<- Since we have to skip the start block*/
1037                 for (cur=start->next; cur!=start; cur=cur->next) 
1038                         nBlocks++;
1039                 /*Prepare for next trip around list:*/
1040                 cur=start;
1041         }
1042         pup_int(p,&nBlocks);
1043         
1044         /*Pup each block in the list*/
1045         for (i=0;i<nBlocks;i++) {
1046                 void *newBlock=cur;
1047                 if (!pup_isUnpacking(p)) 
1048                 { /*While packing, we traverse the list to find our blocks*/
1049                         cur=cur->next;
1050                 }
1051                 CmiIsomallocPup(p,&newBlock);
1052                 if (i==0 && pup_isUnpacking(p))
1053                         *lp=(Slot *)newBlock;
1054         }
1055         if (pup_isDeleting(p))
1056                 *lp=NULL;
1057 }
1058
1059 /*Delete all the blocks in this list.*/
1060 void CmiIsomallocBlockListDelete(CmiIsomallocBlockList *l)
1061 {
1062         Slot *start=l;
1063         Slot *cur=start;
1064         if (cur==NULL) return; /*Already deleted*/
1065         do {
1066                 Slot *doomed=cur;
1067                 cur=cur->next; /*Have to stash next before deleting cur*/
1068                 CmiIsomallocFree(doomed);
1069         } while (cur!=start);
1070 }
1071
1072 /*Allocate a block from this blockList*/
1073 void *CmiIsomallocBlockListMalloc(CmiIsomallocBlockList *l,int nBytes)
1074 {
1075         Slot *n; /*Newly created slot*/
1076         n=(Slot *)CmiIsomalloc(sizeof(Slot)+nBytes);
1077         /*Link the new block into the circular blocklist*/
1078         n->prev=l;
1079         n->next=l->next;
1080         l->next->prev=n;
1081         l->next=n;
1082         return Slot_toUser(n);
1083 }
1084
1085 /*Remove this block from its list and memory*/
1086 void CmiIsomallocBlockListFree(void *block)
1087 {
1088         Slot *n=Slot_fmUser(block);
1089 #if DOHEAPCHECK
1090         if (n->prev->next!=n || n->next->prev!=n) 
1091                 CmiAbort("Heap corruption detected in isomalloc block list header!\n"
1092                         "  Run with ++debug and look for writes to negative array indices");
1093 #endif
1094         /*Link ourselves out of the blocklist*/
1095         n->prev->next=n->next;
1096         n->next->prev=n->prev;
1097         CmiIsomallocFree(n);
1098 }
1099
1100
1101
1102
1103