calling CmiNodeAllBarrier instead if CmiNodeBarrier so that comm. thread also partici...
[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 1 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 struct CmiIsomallocBlock {
27       int slot; /*First mapped slot*/
28       int length; /*Length of (user portion of) mapping, in bytes*/
29 };
30 typedef struct CmiIsomallocBlock CmiIsomallocBlock;
31
32 /*Convert a heap block pointer to/from a CmiIsomallocBlock header*/
33 static void *block2pointer(CmiIsomallocBlock *blockHeader) {
34         return (void *)(blockHeader+1);
35 }
36 static CmiIsomallocBlock *pointer2block(void *heapBlock) {
37         return ((CmiIsomallocBlock *)heapBlock)-1;
38 }
39
40 /*Integral type to be used for pointer arithmetic:*/
41 typedef unsigned long memRange_t;
42
43 /*Size in bytes of a single slot*/
44 static int slotsize;
45
46 /*Total number of slots per processor*/
47 static int numslots=0;
48
49 /*Start and end of isomalloc-managed addresses.
50 If isomallocStart==NULL, isomalloc is disabled.
51 */
52 static char *isomallocStart=NULL;
53 static char *isomallocEnd=NULL;
54
55 /*Utility conversion functions*/
56 static void *slot2addr(int slot) {
57         return isomallocStart+((memRange_t)slotsize)*((memRange_t)slot);
58 }
59 static int slot2pe(int slot) {
60         return slot/numslots;
61 }
62 static int pe2slot(int pe) {
63         return pe*numslots;
64 }
65 /*Return the number of slots in a block with n user data bytes*/
66 static int length2slots(int nBytes) {
67         return (sizeof(CmiIsomallocBlock)+nBytes+slotsize-1)/slotsize;
68 }
69
70 typedef struct _slotblock
71 {
72   int startslot;
73   int nslots;
74 } slotblock;
75
76 typedef struct _slotset
77 {
78   int maxbuf;
79   slotblock *buf;
80   int emptyslots;
81 } slotset;
82
83 /*
84  * creates a new slotset of nslots entries, starting with all
85  * empty slots. The slot numbers are [startslot,startslot+nslot-1]
86  */
87 static slotset *
88 new_slotset(int startslot, int nslots)
89 {
90   int i;
91   slotset *ss = (slotset*) malloc_reentrant(sizeof(slotset));
92   _MEMCHECK(ss);
93   ss->maxbuf = 16;
94   ss->buf = (slotblock *) malloc_reentrant(sizeof(slotblock)*ss->maxbuf);
95   _MEMCHECK(ss->buf);
96   ss->emptyslots = nslots;
97   ss->buf[0].startslot = startslot;
98   ss->buf[0].nslots = nslots;
99   for (i=1; i<ss->maxbuf; i++)
100     ss->buf[i].nslots = 0;
101   return ss;
102 }
103
104 /*
105  * returns new block of empty slots. if it cannot find any, returns (-1).
106  */
107 static int
108 get_slots(slotset *ss, int nslots)
109 {
110   int i;
111   if(ss->emptyslots < nslots)
112     return (-1);
113   for(i=0;i<(ss->maxbuf);i++)
114     if(ss->buf[i].nslots >= nslots)
115       return ss->buf[i].startslot;
116   return (-1);
117 }
118
119 /* just adds a slotblock to an empty position in the given slotset. */
120 static void
121 add_slots(slotset *ss, int sslot, int nslots)
122 {
123   int pos, emptypos = -1;
124   if (nslots == 0)
125     return;
126   for (pos=0; pos < (ss->maxbuf); pos++) {
127     if (ss->buf[pos].nslots == 0) {
128       emptypos = pos;
129       break; /* found empty slotblock */
130     }
131   }
132   if (emptypos == (-1)) /*no empty slotblock found */
133   {
134     int i;
135     int newsize = ss->maxbuf*2;
136     slotblock *newbuf = (slotblock *) malloc_reentrant(sizeof(slotblock)*newsize);
137     _MEMCHECK(newbuf);
138     for (i=0; i<(ss->maxbuf); i++)
139       newbuf[i] = ss->buf[i];
140     for (i=ss->maxbuf; i<newsize; i++)
141       newbuf[i].nslots  = 0;
142     free_reentrant(ss->buf);
143     ss->buf = newbuf;
144     emptypos = ss->maxbuf;
145     ss->maxbuf = newsize;
146   }
147   ss->buf[emptypos].startslot = sslot;
148   ss->buf[emptypos].nslots = nslots;
149   ss->emptyslots += nslots;
150   return;
151 }
152
153 /* grab a slotblock with specified range of blocks
154  * this is different from get_slots, since it pre-specifies the
155  * slots to be grabbed.
156  */
157 static void
158 grab_slots(slotset *ss, int sslot, int nslots)
159 {
160   int pos, eslot, e;
161   eslot = sslot + nslots;
162   for (pos=0; pos < (ss->maxbuf); pos++)
163   {
164     if (ss->buf[pos].nslots == 0)
165       continue;
166     e = ss->buf[pos].startslot + ss->buf[pos].nslots;
167     if(sslot >= ss->buf[pos].startslot && eslot <= e)
168     {
169       int old_nslots;
170       old_nslots = ss->buf[pos].nslots;
171       ss->buf[pos].nslots = sslot - ss->buf[pos].startslot;
172       ss->emptyslots -= (old_nslots - ss->buf[pos].nslots);
173       add_slots(ss, sslot + nslots, old_nslots - ss->buf[pos].nslots - nslots);
174       return;
175     }
176   }
177   CmiAbort("requested a non-existent slotblock\n");
178 }
179
180 /*
181  * Frees slot by adding it to one of the blocks of empty slots.
182  * this slotblock is one which is contiguous with the slots to be freed.
183  * if it cannot find such a slotblock, it creates a new slotblock.
184  * If the buffer fills up, it adds up extra buffer space.
185  */
186 static void
187 free_slots(slotset *ss, int sslot, int nslots)
188 {
189   int pos;
190   /* eslot is the ending slot of the block to be freed */
191   int eslot = sslot + nslots;
192   for (pos=0; pos < (ss->maxbuf); pos++)
193   {
194     int e = ss->buf[pos].startslot + ss->buf[pos].nslots;
195     if (ss->buf[pos].nslots == 0)
196       continue;
197     /* e is the ending slot of pos'th slotblock */
198     if (e == sslot) /* append to the current slotblock */
199     {
200             ss->buf[pos].nslots += nslots;
201       ss->emptyslots += nslots;
202             return;
203     }
204     if(eslot == ss->buf[pos].startslot) /* prepend to the current slotblock */
205     {
206             ss->buf[pos].startslot = sslot;
207             ss->buf[pos].nslots += nslots;
208       ss->emptyslots += nslots;
209             return;
210     }
211   }
212   /* if we are here, it means we could not find a slotblock that the */
213   /* block to be freed was combined with. */
214   add_slots(ss, sslot, nslots);
215 }
216
217 /*
218  * destroys slotset-- currently unused
219 static void
220 delete_slotset(slotset* ss)
221 {
222   free_reentrant(ss->buf);
223   free_reentrant(ss);
224 }
225  */
226
227 #if CMK_THREADS_DEBUG
228 static void
229 print_slots(slotset *ss)
230 {
231   int i;
232   CmiPrintf("[%d] maxbuf = %d\n", CmiMyPe(), ss->maxbuf);
233   CmiPrintf("[%d] emptyslots = %d\n", CmiMyPe(), ss->emptyslots);
234   for(i=0;i<ss->maxbuf;i++) {
235     if(ss->buf[i].nslots)
236       CmiPrintf("[%d] (%d, %d) \n", CmiMyPe(), ss->buf[i].startslot, 
237           ss->buf[i].nslots);
238   }
239 }
240 #else
241 #  define print_slots(ss) /*empty*/
242 #endif
243
244 /*This version of the allocate/deallocate calls are used if the 
245 real mmap versions are disabled.*/
246 static int disabled_map_warned=0;
247 static void *disabled_map(int nBytes) 
248 {
249         if (!disabled_map_warned) {
250                 disabled_map_warned=1;
251                 if (CmiMyPe()==0)
252                         CmiError("isomalloc.c> Warning: since mmap() doesn't work,"
253                         " you won't be able to migrate threads\n");
254         }
255         return malloc(nBytes);
256 }
257 static void disabled_unmap(void *bk) {
258         free(bk);
259 }
260
261 /*Turn off isomalloc memory, for the given reason*/
262 static void disable_isomalloc(const char *why)
263 {
264     isomallocStart=NULL;
265     isomallocEnd=NULL;
266 #if CMK_THREADS_DEBUG
267     CmiPrintf("[%d] isomalloc.c> Disabling isomalloc because %s\n",CmiMyPe(),why);
268 #endif
269 }
270
271 #if ! CMK_HAS_MMAP
272 /****************** Manipulate memory map (Win32 non-version) *****************/
273 static CmiIsomallocBlock *
274 map_slots(int slot, int nslots)
275 {
276         CmiAbort("isomalloc.c: map_slots should never be called here.");
277 }
278
279 static void
280 unmap_slots(int slot, int nslots)
281 {
282         CmiAbort("isomalloc.c: unmap_slots should never be called here.");      
283 }
284
285 static int 
286 init_map(char **argv)
287 {
288   return 0; /*Isomalloc never works without mmap*/
289 }
290 #else /* CMK_HAS_MMAP */
291 /****************** Manipulate memory map (UNIX version) *****************/
292 #include <sys/types.h>
293 #include <sys/mman.h>
294 #include <sys/stat.h>
295 #include <fcntl.h>
296
297 #if !CMK_HAS_MMAP_ANON
298 CpvStaticDeclare(int, zerofd); /*File descriptor for /dev/zero, for mmap*/
299 #endif
300
301 /*
302  * maps the virtual memory associated with slot using mmap
303  */
304 static CmiIsomallocBlock *
305 map_slots(int slot, int nslots)
306 {
307   void *pa;
308   void *addr=slot2addr(slot);
309   pa = mmap(addr, slotsize*nslots, 
310             PROT_READ|PROT_WRITE, 
311 #if CMK_HAS_MMAP_ANON
312             MAP_PRIVATE|MAP_ANON,-1,
313 #else
314             MAP_PRIVATE|MAP_FIXED,CpvAccess(zerofd),
315 #endif
316             0);
317   if (pa==((void*)(-1)) || pa==NULL) 
318   { /*Map just failed completely*/
319 #if CMK_THREADS_DEBUG
320     perror("mmap failed");
321     CmiPrintf("[%d] tried to mmap %p, but encountered error\n",CmiMyPe(),addr);
322 #endif
323     return NULL;
324   }
325   if (pa != addr)
326   { /*Map worked, but gave us back the wrong place*/
327 #if CMK_THREADS_DEBUG
328     CmiPrintf("[%d] tried to mmap %p, but got %p back\n",CmiMyPe(),addr,pa);
329 #endif
330     munmap(addr,slotsize*nslots);
331     return NULL;
332   }
333 #if CMK_THREADS_DEBUG
334   CmiPrintf("[%d] mmap'd slots %d-%d to address %p\n",CmiMyPe(),
335             slot,slot+nslots-1,addr);
336 #endif
337   return (CmiIsomallocBlock *)pa;
338 }
339
340 /*
341  * unmaps the virtual memory associated with slot using munmap
342  */
343 static void
344 unmap_slots(int slot, int nslots)
345 {
346   void *addr=slot2addr(slot);
347   int retval = munmap(addr, slotsize*nslots);
348   if (retval==(-1))
349     CmiAbort("munmap call failed to deallocate requested memory.\n");
350 #if CMK_THREADS_DEBUG
351   CmiPrintf("[%d] munmap'd slots %d-%d from address %p\n",CmiMyPe(),
352             slot,slot+nslots-1,addr);
353 #endif
354 }
355
356 static int 
357 init_map(char **argv)
358 {
359 #if CMK_HAS_MMAP_ANON
360   /*Don't need /dev/zero*/
361 #else
362   CpvInitialize(int, zerofd);  
363   CpvAccess(zerofd) = open("/dev/zero", O_RDWR);
364   if(CpvAccess(zerofd)<0)
365     return 0; /* Cannot open /dev/zero or use MMAP_ANON, so can't mmap memory */
366 #endif
367   return 1;
368 }
369
370 #endif /* UNIX memory map */
371
372
373 static void map_failed(int s,int n)
374 {
375   void *addr=slot2addr(s);
376   CmiError("map failed to allocate %d bytes at %p.\n", slotsize*n, addr);
377   CmiAbort("Exiting\n");
378 }
379
380
381
382 /************ Address space voodoo: find free address range **********/
383
384 CpvStaticDeclare(slotset *, myss); /*My managed slots*/
385
386 /*This struct describes a range of virtual addresses*/
387 typedef struct {
388   char *start; /*First byte of region*/
389   memRange_t len; /*Number of bytes in region*/
390   const char *type; /*String describing memory in region (debugging only)*/
391 } memRegion_t;
392
393 /*Estimate the top of the current stack*/
394 static void *__cur_stack_frame(void)
395 {
396   char __dummy;
397   void *top_of_stack=(void *)&__dummy;
398   return top_of_stack;
399 }
400 /*Estimate the location of the static data region*/
401 static void *__static_data_loc(void)
402 {
403   static char __dummy;
404   return (void *)&__dummy;
405 }
406
407 /*Pointer comparison is in these subroutines, because
408   comparing arbitrary pointers is nonportable and tricky.
409 */
410 static int pointer_lt(const char *a,const char *b) {
411         return ((memRange_t)a)<((memRange_t)b);
412 }
413 static int pointer_ge(const char *a,const char *b) {
414         return ((memRange_t)a)>=((memRange_t)b);
415 }
416
417 static char *pmin(char *a,char *b) {return pointer_lt(a,b)?a:b;}
418 static char *pmax(char *a,char *b) {return pointer_lt(a,b)?b:a;}
419
420 /*Check if this memory location is usable.  
421   If not, return 1.
422 */
423 static int bad_range(char *loc) {
424   void *addr;
425   isomallocStart=loc;
426   addr=map_slots(0,1);
427   if (addr==NULL) {
428 #if CMK_THREADS_DEBUG
429     CmiPrintf("[%d] Skipping unmappable space at %p\n",CmiMyPe(),loc);
430 #endif
431     return 1; /*No good*/
432   }
433   unmap_slots(0,1);
434   return 0; /*This works*/
435 }
436
437 /*Check if this memory range is usable.  
438   If so, write it into max.
439 */
440 static void check_range(char *start,char *end,memRegion_t *max)
441 {
442   memRange_t len;
443   memRange_t searchQuantStart=128u*1024*1024; /*Shift search location by this far*/
444   memRange_t searchQuant;
445   char *initialStart=start, *initialEnd=end;
446
447   if (start>=end) return; /*Ran out of hole*/
448   len=(memRange_t)end-(memRange_t)start;
449   if (len<=max->len) return; /*It's too short already!*/
450 #if CMK_THREADS_DEBUG
451   CmiPrintf("[%d] Checking usable address space at %p - %p\n",CmiMyPe(),start,end);
452 #endif
453
454   /* Trim off start of range until we hit usable memory*/  
455   searchQuant=searchQuantStart;
456   while (bad_range(start)) {
457         start=initialStart+searchQuant;
458         if (pointer_ge(start,end)) return; /*Ran out of hole*/
459         searchQuant*=2; /*Exponential search*/
460         if (searchQuant==0) return; /*SearchQuant overflowed-- no good memory anywhere*/
461   }
462
463   /* Trim off end of range until we hit usable memory*/
464   searchQuant=searchQuantStart;
465   while (bad_range(end-slotsize)) {
466         end=initialEnd-searchQuant;
467         if (pointer_ge(start,end)) return; /*Ran out of hole*/
468         searchQuant*=2;
469         if (searchQuant==0) return; /*SearchQuant overflowed-- no good memory anywhere*/
470   }
471   
472   len=(memRange_t)end-(memRange_t)start;
473   if (len<max->len) return; /*It's now too short.*/
474   
475 #if CMK_THREADS_DEBUG
476   CmiPrintf("[%d] Address space at %p - %p is largest\n",CmiMyPe(),start,end);
477 #endif
478
479   /*If we got here, we're the new largest usable range*/
480   max->len=len;
481   max->start=start;
482   max->type="Unused";
483 }
484
485 /*Find the first available memory region of at least the
486   given size not touching any data in the used list.
487  */
488 static memRegion_t find_free_region(memRegion_t *used,int nUsed,int atLeast) 
489 {
490   memRegion_t max;
491   int i,j;  
492
493   max.len=0;
494   /*Find the largest hole between regions*/
495   for (i=0;i<nUsed;i++) {
496     /*Consider a hole starting at the end of region i*/
497     char *holeStart=used[i].start+used[i].len;
498     char *holeEnd=(void *)(-1);
499     
500     /*Shrink the hole by all others*/ 
501     for (j=0;j<nUsed && pointer_lt(holeStart,holeEnd);j++) {
502       if (pointer_lt(used[j].start,holeStart)) 
503         holeStart=pmax(holeStart,used[j].start+used[j].len);
504       else if (pointer_lt(used[j].start,holeEnd)) 
505         holeEnd=pmin(holeEnd,used[j].start);
506     } 
507
508     check_range(holeStart,holeEnd,&max);
509   }
510
511   return max; 
512 }
513
514 static void init_ranges(char **argv)
515 {
516   /*Largest value a signed int can hold*/
517   memRange_t intMax=(((memRange_t)1)<<(sizeof(int)*8-1))-1;
518
519   /*Round slot size up to nearest page size*/
520   slotsize=16*1024;
521   slotsize=(slotsize+CMK_MEMORY_PAGESIZE-1) & ~(CMK_MEMORY_PAGESIZE-1);
522 #if CMK_THREADS_DEBUG
523   CmiPrintf("[%d] Using slotsize of %d\n", CmiMyPe(), slotsize);
524 #endif
525
526   if (CmiMyRank()==0 && numslots==0)
527   { /* Find the largest unused region of virtual address space */
528     char *staticData =(char *) __static_data_loc();
529     char *code = (char *)&init_ranges;
530     char *codeDll = (char *)&fclose;
531     char *heapLil = (char*) malloc(1);
532     char *heapBig = (char*) malloc(4*1024*1024);
533     char *stack = (char *)__cur_stack_frame();
534
535     memRange_t meg=1024*1024; /*One megabyte*/
536     memRange_t gig=1024*meg; /*One gigabyte*/
537     int i,nRegions=7;
538     memRegion_t regions[7]; /*used portions of address space*/
539     memRegion_t freeRegion; /*Largest unused block of address space*/
540
541 /*Mark off regions of virtual address space as ususable*/
542     regions[0].type="NULL (inaccessible)";
543     regions[0].start=NULL; regions[0].len=16u*meg;
544     
545     regions[1].type="Static program data";
546     regions[1].start=staticData; regions[1].len=256u*meg;
547     
548     regions[2].type="Program executable code";
549     regions[2].start=code; regions[2].len=256u*meg;
550     
551     regions[3].type="Heap (small blocks)";
552     regions[3].start=heapLil; regions[3].len=2u*gig;
553     
554     regions[4].type="Heap (large blocks)";
555     regions[4].start=heapBig; regions[4].len=1u*gig;
556     
557     regions[5].type="Stack space";
558     regions[5].start=stack; regions[5].len=256u*meg;
559
560     regions[6].type="Program dynamically linked code";
561     regions[6].start=codeDll; regions[6].len=256u*meg;    
562
563     _MEMCHECK(heapBig); free(heapBig);
564     _MEMCHECK(heapLil); free(heapLil); 
565     
566     /*Align each memory region*/
567     for (i=0;i<nRegions;i++) {
568       memRange_t p=(memRange_t)regions[i].start;
569       p&=~(regions[i].len-1); /*Round down to a len-boundary (mask off low bits)*/
570       regions[i].start=(char *)p;
571 #if CMK_THREADS_DEBUG
572       CmiPrintf("[%d] Memory map: %p - %p  %s\n",CmiMyPe(),
573               regions[i].start,regions[i].start+regions[i].len,regions[i].type);
574 #endif
575     }
576     
577     /*Find a large, unused region*/
578     freeRegion=find_free_region(regions,nRegions,(512u)*meg);
579     
580     if (freeRegion.len==0) 
581     { /*No free address space-- disable isomalloc:*/
582       disable_isomalloc("no free virtual address space");
583     }
584     else 
585     {
586       /*If the unused region is very large, pad it on both ends for safety*/
587       if (freeRegion.len/gig>64u) {
588         freeRegion.start+=16u*gig;
589         freeRegion.len-=20u*gig;
590       }
591
592 #if CMK_THREADS_DEBUG
593       CmiPrintf("[%d] Largest unused region: %p - %p (%d megs)\n",CmiMyPe(),
594               freeRegion.start,freeRegion.start+freeRegion.len,
595               freeRegion.len/meg);
596 #endif
597
598       /*Allocate stacks in unused region*/
599       isomallocStart=freeRegion.start;
600       isomallocEnd=freeRegion.start+freeRegion.len;
601
602       /*Make sure our largest slot number doesn't overflow an int:*/
603       if (freeRegion.len/slotsize>intMax)
604         freeRegion.len=intMax*slotsize;
605     
606       numslots=(freeRegion.len/slotsize)/CmiNumPes();
607     
608 #if CMK_THREADS_DEBUG
609       CmiPrintf("[%d] Can isomalloc up to %lu megs per pe\n",CmiMyPe(),
610               ((memRange_t)numslots)*slotsize/meg);
611 #endif
612     }
613   }
614   /*SMP Mode: wait here for rank 0 to initialize numslots so we can set up myss*/
615   CmiNodeAllBarrier(); 
616   
617   if (isomallocStart!=NULL) {
618     CpvInitialize(slotset *, myss);
619     CpvAccess(myss) = new_slotset(pe2slot(CmiMyPe()), numslots);
620   }
621 }
622
623
624 /************* Communication: for grabbing/freeing remote slots *********/
625 typedef struct _slotmsg
626 {
627   char cmicore[CmiMsgHeaderSizeBytes];
628   int pe; /*Source processor*/
629   int slot; /*First requested slot*/
630   int nslots; /*Number of requested slots*/
631 } slotmsg;
632
633 static slotmsg *prepare_slotmsg(int slot,int nslots)
634 {
635         slotmsg *m=(slotmsg *)CmiAlloc(sizeof(slotmsg));
636         m->pe=CmiMyPe();
637         m->slot=slot;
638         m->nslots=nslots;
639         return m;
640 }
641
642 static void grab_remote(slotmsg *msg)
643 {
644         grab_slots(CpvAccess(myss),msg->slot,msg->nslots);
645         CmiFree(msg);
646 }
647
648 static void free_remote(slotmsg *msg)
649 {
650         free_slots(CpvAccess(myss),msg->slot,msg->nslots);
651         CmiFree(msg);
652 }
653 static int grab_remote_idx, free_remote_idx;
654
655 struct slotOP {
656         /*Function pointer to perform local operation*/
657         void (*local)(slotset *ss,int s,int n);
658         /*Index to perform remote operation*/
659         int remote;
660 };
661 typedef struct slotOP slotOP;
662 static slotOP grabOP,freeOP;
663
664 static void init_comm(char **argv)
665 {
666         grab_remote_idx=CmiRegisterHandler((CmiHandler)grab_remote);
667         free_remote_idx=CmiRegisterHandler((CmiHandler)free_remote);    
668         grabOP.local=grab_slots;
669         grabOP.remote=grab_remote_idx;
670         freeOP.local=free_slots;
671         freeOP.remote=free_remote_idx;  
672 }
673
674 /*Apply the given operation to the given slots which
675   lie on the given processor.*/
676 static void one_slotOP(const slotOP *op,int pe,int s,int n)
677 {
678 /*Shrink range to only those covered by this processor*/
679         /*First and last slot for this processor*/
680         int p_s=pe2slot(pe), p_e=pe2slot(pe+1);
681         int e=s+n;
682         if (s<p_s) s=p_s;
683         if (e>p_e) e=p_e;
684         n=e-s;
685
686 /*Send off range*/
687         if (pe==CmiMyPe()) 
688                 op->local(CpvAccess(myss),s,n);
689         else 
690         {/*Remote request*/
691                 slotmsg *m=prepare_slotmsg(s,e);
692                 CmiSyncSendAndFree(pe,sizeof(slotmsg),m);
693         }
694 }
695
696 /*Apply the given operation to all slots in the range [s, s+n) 
697 After a restart from checkpoint, a slotset can cross an 
698 arbitrary set of processors.
699 */
700 static void all_slotOP(const slotOP *op,int s,int n)
701 {
702         int spe=slot2pe(s), epe=slot2pe(s+n-1);
703         int pe;
704         for (pe=spe; pe<=epe; pe++)
705                 one_slotOP(op,pe,s,n);
706 }
707
708 /************** External interface ***************/
709 void *CmiIsomalloc(int size)
710 {
711         int s,n;
712         CmiIsomallocBlock *blk;
713         if (isomallocStart==NULL) return disabled_map(size);
714         n=length2slots(size);
715         /*Always satisfy mallocs with local slots:*/
716         s=get_slots(CpvAccess(myss),n);
717         if (s==-1) {
718                 CmiError("Not enough address space left on processor %d to isomalloc %d bytes!\n",
719                          CmiMyPe(),size);
720                 CmiAbort("Out of virtual address space for isomalloc");
721         }
722         grab_slots(CpvAccess(myss),s,n);
723         blk=map_slots(s,n);
724         if (!blk) map_failed(s,n);
725         blk->slot=s;
726         blk->length=size;
727         return block2pointer(blk);
728 }
729
730 void CmiIsomallocPup(pup_er p,void **blockPtrPtr)
731 {
732         CmiIsomallocBlock *blk;
733         int s,n,length;
734         if (isomallocStart==NULL) CmiAbort("isomalloc is disabled-- cannot use IsomallocPup");
735
736         if (!pup_isUnpacking(p)) 
737         { /*We have an existing block-- unpack start slot & length*/
738                 blk=pointer2block(*blockPtrPtr);
739                 s=blk->slot;
740                 length=blk->length;
741         }
742         
743         pup_int(p,&s);
744         pup_int(p,&length);
745         n=length2slots(length);
746         
747         if (pup_isUnpacking(p)) 
748         { /*Must allocate a new block in its old location*/
749                 if (pup_isUserlevel(p))
750                         /*Checkpoint: must grab old slots (even remote!)*/
751                         all_slotOP(&grabOP,s,n);
752                 blk=map_slots(s,n);
753                 if (!blk) map_failed(s,n);
754                 blk->slot=s;
755                 blk->length=length;
756                 *blockPtrPtr=block2pointer(blk);
757         }
758         
759         /*Pup the allocated data*/
760         pup_bytes(p,*blockPtrPtr,length);
761         
762         if (pup_isDeleting(p)) 
763         { /*Unmap old slots, but do not mark as free*/
764                 unmap_slots(s,n);
765                 *blockPtrPtr=NULL; /*Zero out user's pointer*/
766         }
767 }
768
769 void CmiIsomallocFree(void *blockPtr)
770 {
771         if (isomallocStart==NULL) {
772                 disabled_unmap(blockPtr);
773         }
774         else if (blockPtr!=NULL)
775         {
776                 CmiIsomallocBlock *blk=pointer2block(blockPtr);
777                 int s=blk->slot, n=length2slots(blk->length);
778                 unmap_slots(s,n);
779                 /*Mark used slots as free*/
780                 all_slotOP(&freeOP,s,n);
781         }
782 }
783 int   CmiIsomallocLength(void *block)
784 {
785         return pointer2block(block)->length;
786 }
787
788 /*Return true if this address is in the region managed by isomalloc*/
789 int CmiIsomallocInRange(void *addr)
790 {
791         if (isomallocStart==NULL) return 0; /* There is no range we manage! */
792         return pointer_ge((char *)addr,isomallocStart) && 
793                pointer_lt((char*)addr,isomallocEnd);
794 }
795
796 void CmiIsomallocInit(char **argv)
797 {
798   init_comm(argv);
799   if (!init_map(argv)) {
800     disable_isomalloc("mmap() does not work");
801   }
802   else {
803     init_ranges(argv);
804   }
805 }
806
807 /***************** BlockList interface *********
808 This was moved here from memory-isomalloc.c when it 
809 was realized that a list-of-isomalloc'd-blocks is useful for
810 more than just isomalloc heaps.
811 */
812
813 typedef CmiIsomallocBlockList Slot;
814
815 /*Convert a slot to a user address*/
816 static char *Slot_toUser(Slot *s) {return (char *)(s+1);}
817 static Slot *Slot_fmUser(void *s) {return ((Slot *)s)-1;}
818
819
820 /*Build a new blockList.*/
821 CmiIsomallocBlockList *CmiIsomallocBlockListNew(void)
822 {
823         CmiIsomallocBlockList *ret;
824         ret=(CmiIsomallocBlockList *)CmiIsomalloc(sizeof(*ret));
825         ret->next=ret; /*1-entry circular linked list*/
826         ret->prev=ret;
827         return ret;
828 }
829
830 /*Pup all the blocks in this list.  This amounts to two circular
831 list traversals.  Because everything's isomalloc'd, we don't even
832 have to restore the pointers-- they'll be restored automatically!
833 */
834 void CmiIsomallocBlockListPup(pup_er p,CmiIsomallocBlockList **lp)
835 {
836         int i,nBlocks=0;
837         Slot *cur=NULL, *start=*lp;
838 #if 0 /*#ifndef CMK_OPTIMIZE*/
839         if (CpvAccess(isomalloc_blocklist)!=NULL)
840                 CmiAbort("Called CmiIsomallocBlockListPup while a blockList is active!\n"
841                         "You should swap out the active blocklist before pupping.\n");
842 #endif
843         /*Count the number of blocks in the list*/
844         if (!pup_isUnpacking(p)) {
845                 nBlocks=1; /*<- Since we have to skip the start block*/
846                 for (cur=start->next; cur!=start; cur=cur->next) 
847                         nBlocks++;
848                 /*Prepare for next trip around list:*/
849                 cur=start;
850         }
851         pup_int(p,&nBlocks);
852         
853         /*Pup each block in the list*/
854         for (i=0;i<nBlocks;i++) {
855                 void *newBlock=cur;
856                 if (!pup_isUnpacking(p)) 
857                 { /*While packing, we traverse the list to find our blocks*/
858                         cur=cur->next;
859                 }
860                 CmiIsomallocPup(p,&newBlock);
861                 if (i==0 && pup_isUnpacking(p))
862                         *lp=(Slot *)newBlock;
863         }
864         if (pup_isDeleting(p))
865                 *lp=NULL;
866 }
867
868 /*Delete all the blocks in this list.*/
869 void CmiIsomallocBlockListDelete(CmiIsomallocBlockList *l)
870 {
871         Slot *start=l;
872         Slot *cur=start;
873         if (cur==NULL) return; /*Already deleted*/
874         do {
875                 Slot *doomed=cur;
876                 cur=cur->next; /*Have to stash next before deleting cur*/
877                 CmiIsomallocFree(doomed);
878         } while (cur!=start);
879 }
880
881 /*Allocate a block from this blockList*/
882 void *CmiIsomallocBlockListMalloc(CmiIsomallocBlockList *l,int nBytes)
883 {
884         Slot *n; /*Newly created slot*/
885         n=(Slot *)CmiIsomalloc(sizeof(Slot)+nBytes);
886         /*Link the new block into the circular blocklist*/
887         n->prev=l;
888         n->next=l->next;
889         l->next->prev=n;
890         l->next=n;
891         return Slot_toUser(n);
892 }
893
894 /*Remove this block from its list and memory*/
895 void CmiIsomallocBlockListFree(void *block)
896 {
897         Slot *n=Slot_fmUser(block);
898 #if DOHEAPCHECK
899         if (n->prev->next!=n || n->next->prev!=n) 
900                 CmiAbort("Heap corruption detected in isomalloc block list header!\n"
901                         "  Run with ++debug and look for writes to negative array indices");
902 #endif
903         /*Link ourselves out of the blocklist*/
904         n->prev->next=n->next;
905         n->next->prev=n->prev;
906         CmiIsomallocFree(n);
907 }
908
909
910
911
912