Leave probing address ranges to rank 0. Without this fix,
[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 /*Size in bytes of a single slot*/
27 static int slotsize;
28
29 /*Total number of slots per processor*/
30 static int numslots=0;
31
32 /*Start and end of isomalloc-managed addresses*/
33 static char *isomallocStart=NULL;
34 static char *isomallocEnd=NULL;
35
36 /*Utility conversion functions*/
37 static int addr2slot(void *addr) {
38         return (((char *)addr)-isomallocStart)/slotsize;
39 }
40 static void *slot2addr(int slot) {
41         return isomallocStart+slotsize*slot;
42 }
43 static int slot2pe(int slot) {
44         return slot/numslots;
45 }
46 static int pe2slot(int pe) {
47         return pe*numslots;
48 }
49 static int length2slots(int nBytes) {
50         return (nBytes+slotsize-1)/slotsize;
51 }
52 static int slots2length(int nSlots) {
53         return nSlots*slotsize;
54 }
55
56 typedef struct _slotblock
57 {
58   int startslot;
59   int nslots;
60 } slotblock;
61
62 typedef struct _slotset
63 {
64   int maxbuf;
65   slotblock *buf;
66   int emptyslots;
67 } slotset;
68
69 /*
70  * creates a new slotset of nslots entries, starting with all
71  * empty slots. The slot numbers are [startslot,startslot+nslot-1]
72  */
73 static slotset *
74 new_slotset(int startslot, int nslots)
75 {
76   int i;
77   slotset *ss = (slotset*) malloc_reentrant(sizeof(slotset));
78   _MEMCHECK(ss);
79   ss->maxbuf = 16;
80   ss->buf = (slotblock *) malloc_reentrant(sizeof(slotblock)*ss->maxbuf);
81   _MEMCHECK(ss->buf);
82   ss->emptyslots = nslots;
83   ss->buf[0].startslot = startslot;
84   ss->buf[0].nslots = nslots;
85   for (i=1; i<ss->maxbuf; i++)
86     ss->buf[i].nslots = 0;
87   return ss;
88 }
89
90 /*
91  * returns new block of empty slots. if it cannot find any, returns (-1).
92  */
93 static int
94 get_slots(slotset *ss, int nslots)
95 {
96   int i;
97   if(ss->emptyslots < nslots)
98     return (-1);
99   for(i=0;i<(ss->maxbuf);i++)
100     if(ss->buf[i].nslots >= nslots)
101       return ss->buf[i].startslot;
102   return (-1);
103 }
104
105 /* just adds a slotblock to an empty position in the given slotset. */
106 static void
107 add_slots(slotset *ss, int sslot, int nslots)
108 {
109   int pos, emptypos = -1;
110   if (nslots == 0)
111     return;
112   for (pos=0; pos < (ss->maxbuf); pos++) {
113     if (ss->buf[pos].nslots == 0) {
114       emptypos = pos;
115       break; /* found empty slotblock */
116     }
117   }
118   if (emptypos == (-1)) /*no empty slotblock found */
119   {
120     int i;
121     int newsize = ss->maxbuf*2;
122     slotblock *newbuf = (slotblock *) malloc_reentrant(sizeof(slotblock)*newsize);
123     _MEMCHECK(newbuf);
124     for (i=0; i<(ss->maxbuf); i++)
125       newbuf[i] = ss->buf[i];
126     for (i=ss->maxbuf; i<newsize; i++)
127       newbuf[i].nslots  = 0;
128     free_reentrant(ss->buf);
129     ss->buf = newbuf;
130     emptypos = ss->maxbuf;
131     ss->maxbuf = newsize;
132   }
133   ss->buf[emptypos].startslot = sslot;
134   ss->buf[emptypos].nslots = nslots;
135   ss->emptyslots += nslots;
136   return;
137 }
138
139 /* grab a slotblock with specified range of blocks
140  * this is different from get_slots, since it pre-specifies the
141  * slots to be grabbed.
142  */
143 static void
144 grab_slots(slotset *ss, int sslot, int nslots)
145 {
146   int pos, eslot, e;
147   eslot = sslot + nslots;
148   for (pos=0; pos < (ss->maxbuf); pos++)
149   {
150     if (ss->buf[pos].nslots == 0)
151       continue;
152     e = ss->buf[pos].startslot + ss->buf[pos].nslots;
153     if(sslot >= ss->buf[pos].startslot && eslot <= e)
154     {
155       int old_nslots;
156       old_nslots = ss->buf[pos].nslots;
157       ss->buf[pos].nslots = sslot - ss->buf[pos].startslot;
158       ss->emptyslots -= (old_nslots - ss->buf[pos].nslots);
159       add_slots(ss, sslot + nslots, old_nslots - ss->buf[pos].nslots - nslots);
160       return;
161     }
162   }
163   CmiAbort("requested a non-existent slotblock\n");
164 }
165
166 /*
167  * Frees slot by adding it to one of the blocks of empty slots.
168  * this slotblock is one which is contiguous with the slots to be freed.
169  * if it cannot find such a slotblock, it creates a new slotblock.
170  * If the buffer fills up, it adds up extra buffer space.
171  */
172 static void
173 free_slots(slotset *ss, int sslot, int nslots)
174 {
175   int pos;
176   /* eslot is the ending slot of the block to be freed */
177   int eslot = sslot + nslots;
178   for (pos=0; pos < (ss->maxbuf); pos++)
179   {
180     int e = ss->buf[pos].startslot + ss->buf[pos].nslots;
181     if (ss->buf[pos].nslots == 0)
182       continue;
183     /* e is the ending slot of pos'th slotblock */
184     if (e == sslot) /* append to the current slotblock */
185     {
186             ss->buf[pos].nslots += nslots;
187       ss->emptyslots += nslots;
188             return;
189     }
190     if(eslot == ss->buf[pos].startslot) /* prepend to the current slotblock */
191     {
192             ss->buf[pos].startslot = sslot;
193             ss->buf[pos].nslots += nslots;
194       ss->emptyslots += nslots;
195             return;
196     }
197   }
198   /* if we are here, it means we could not find a slotblock that the */
199   /* block to be freed was combined with. */
200   add_slots(ss, sslot, nslots);
201 }
202
203 /*
204  * destroys slotset
205  */
206 static void
207 delete_slotset(slotset* ss)
208 {
209   free_reentrant(ss->buf);
210   free_reentrant(ss);
211 }
212
213 #if CMK_THREADS_DEBUG
214 static void
215 print_slots(slotset *ss)
216 {
217   int i;
218   CmiPrintf("[%d] maxbuf = %d\n", CmiMyPe(), ss->maxbuf);
219   CmiPrintf("[%d] emptyslots = %d\n", CmiMyPe(), ss->emptyslots);
220   for(i=0;i<ss->maxbuf;i++) {
221     if(ss->buf[i].nslots)
222       CmiPrintf("[%d] (%d, %d) \n", CmiMyPe(), ss->buf[i].startslot, 
223           ss->buf[i].nslots);
224   }
225 }
226 #endif
227
228 #if ! CMK_HAS_MMAP
229 /****************** Manipulate memory map (Win32 non-version) *****************/
230 static int map_warned=0;
231
232 static void *
233 map_slots(int slot, int nslots)
234 {
235         if (!map_warned) {
236                 map_warned=1;
237                 if (CmiMyPe()==0)
238                         CmiError("isomalloc.c> Warning: since mmap() doesn't work,"
239                         " you won't be able to migrate threads\n");
240         }
241
242         return malloc(slotsize*nslots);
243 }
244
245 static void
246 unmap_slots(int slot, int nslots)
247 {
248         /*emtpy-- there's no way to recover the actual address we 
249           were allocated at.*/
250 }
251
252 static void 
253 init_map(char **argv)
254 {
255 }
256 #else /* CMK_HAS_MMAP */
257 /****************** Manipulate memory map (UNIX version) *****************/
258 #include <sys/types.h>
259 #include <sys/mman.h>
260 #include <sys/stat.h>
261 #include <fcntl.h>
262
263 CpvStaticDeclare(int, zerofd); /*File descriptor for /dev/zero, for mmap*/
264
265 /*
266  * maps the virtual memory associated with slot using mmap
267  */
268 static void *
269 map_slots(int slot, int nslots)
270 {
271   void *pa;
272   void *addr=slot2addr(slot);
273   pa = mmap(addr, slotsize*nslots, 
274             PROT_READ|PROT_WRITE, 
275 #if CMK_HAS_MMAP_ANON
276             MAP_PRIVATE|MAP_ANON,-1,
277 #else
278             MAP_PRIVATE|MAP_FIXED,CpvAccess(zerofd),
279 #endif
280             0);
281   if (pa==((void*)(-1)) || pa==NULL) 
282   { /*Map just failed completely*/
283 #if CMK_THREADS_DEBUG
284     perror("mmap failed");
285     CmiPrintf("[%d] tried to mmap %p, but encountered error\n",CmiMyPe(),addr);
286 #endif
287     return NULL;
288   }
289   if (pa != addr)
290   { /*Map worked, but gave us back the wrong place*/
291 #if CMK_THREADS_DEBUG
292     CmiPrintf("[%d] tried to mmap %p, but got %p back\n",CmiMyPe(),addr,pa);
293 #endif
294     munmap(addr,slotsize*nslots);
295     return NULL;
296   }
297 #if CMK_THREADS_DEBUG
298   CmiPrintf("[%d] mmap'd slots %d-%d to address %p\n",CmiMyPe(),
299             slot,slot+nslots-1,addr);
300 #endif
301   return pa;
302 }
303
304 /*
305  * unmaps the virtual memory associated with slot using munmap
306  */
307 static void
308 unmap_slots(int slot, int nslots)
309 {
310   void *addr=slot2addr(slot);
311   int retval = munmap(addr, slotsize*nslots);
312   if (retval==(-1))
313     CmiAbort("munmap call failed to deallocate requested memory.\n");
314 #if CMK_THREADS_DEBUG
315   CmiPrintf("[%d] munmap'd slots %d-%d from address %p\n",CmiMyPe(),
316             slot,slot+nslots-1,addr);
317 #endif
318 }
319
320 static void 
321 init_map(char **argv)
322 {
323 #if CMK_HAS_MMAP_ANON
324   /*Don't need /dev/zero*/
325 #else
326   CpvInitialize(int, zerofd);  
327   CpvAccess(zerofd) = open("/dev/zero", O_RDWR);
328   if(CpvAccess(zerofd)<0)
329     CmiAbort("Cannot open /dev/zero. Aborting.\n");     
330 #endif
331 }
332
333 #endif /* UNIX memory map */
334
335
336 static void map_bad(int s,int n)
337 {
338   void *addr=slot2addr(s);
339   CmiError("map failed to allocate %d bytes at %p.\n", slotsize*n, addr);
340   CmiAbort("Exiting\n");
341 }
342
343
344
345 /************ Address space voodoo: find free address range **********/
346 CpvStaticDeclare(slotset *, myss); /*My managed slots*/
347
348 /*This struct describes a range of virtual addresses*/
349 typedef unsigned long memRange_t;
350 typedef struct {
351   char *start; /*First byte of region*/
352   memRange_t len; /*Number of bytes in region*/
353   const char *type; /*String describing memory in region (debugging only)*/
354 } memRegion_t;
355
356 /*Estimate the top of the current stack*/
357 static void *__cur_stack_frame(void)
358 {
359   char __dummy;
360   void *top_of_stack=(void *)&__dummy;
361   return top_of_stack;
362 }
363 /*Estimate the location of the static data region*/
364 static void *__static_data_loc(void)
365 {
366   static char __dummy;
367   return (void *)&__dummy;
368 }
369
370 static char *pmin(char *a,char *b) {return (a<b)?a:b;}
371 static char *pmax(char *a,char *b) {return (a>b)?a:b;}
372
373 /*Check if this memory location is usable.  
374   If not, return 1.
375 */
376 static int bad_range(char *loc) {
377   void *addr;
378   isomallocStart=loc;
379   addr=map_slots(0,1);
380   if (addr==NULL) {
381 #if CMK_THREADS_DEBUG
382     CmiPrintf("[%d] Skipping unmappable space at %p\n",CmiMyPe(),loc);
383 #endif
384     return 1; /*No good*/
385   }
386   unmap_slots(0,1);
387   return 0; /*This works*/
388 }
389
390 /*Check if this memory range is usable.  
391   If so, write it into max.
392 */
393 static void check_range(char *start,char *end,memRegion_t *max)
394 {
395   memRange_t len;
396   memRange_t searchQuantStart=128u*1024*1024; /*Shift search location by this far*/
397   memRange_t searchQuant;
398   void *addr;
399   char *initialStart=start, *initialEnd=end;
400
401   if (start>=end) return; /*Ran out of hole*/
402   len=(memRange_t)end-(memRange_t)start;
403   if (len<=max->len) return; /*It's too short already!*/
404 #if CMK_THREADS_DEBUG
405   CmiPrintf("[%d] Checking usable address space at %p - %p\n",CmiMyPe(),start,end);
406 #endif
407
408   /* Trim off start of range until we hit usable memory*/  
409   searchQuant=searchQuantStart;
410   while (bad_range(start)) {
411         start=initialStart+searchQuant;
412         if (start>=end) return; /*Ran out of hole*/
413         searchQuant*=2; /*Exponential search*/
414         if (searchQuant==0) return; /*SearchQuant overflowed-- no good memory anywhere*/
415   }
416
417   /* Trim off end of range until we hit usable memory*/
418   searchQuant=searchQuantStart;
419   while (bad_range(end-slotsize)) {
420         end=initialEnd-searchQuant;
421         if (start>=end) return; /*Ran out of hole*/
422         searchQuant*=2;
423         if (searchQuant==0) return; /*SearchQuant overflowed-- no good memory anywhere*/
424   }
425   
426   len=(memRange_t)end-(memRange_t)start;
427   if (len<max->len) return; /*It's now too short.*/
428   
429 #if CMK_THREADS_DEBUG
430   CmiPrintf("[%d] Address space at %p - %p is largest\n",CmiMyPe(),start,end);
431 #endif
432
433   /*If we got here, we're the new largest usable range*/
434   max->len=len;
435   max->start=start;
436   max->type="Unused";
437 }
438
439 /*Find the first available memory region of at least the
440   given size not touching any data in the used list.
441  */
442 static memRegion_t find_free_region(memRegion_t *used,int nUsed,int atLeast) 
443 {
444   memRegion_t max;
445   int i,j;  
446
447   max.len=0;
448   /*Find the largest hole between regions*/
449   for (i=0;i<nUsed;i++) {
450     /*Consider a hole starting at the end of region i*/
451     char *holeStart=used[i].start+used[i].len;
452     char *holeEnd=(void *)(-1);
453     
454     /*Shrink the hole by all others*/ 
455     for (j=0;j<nUsed && holeStart<holeEnd;j++) {
456       if ((memRange_t)used[j].start<(memRange_t)holeStart) 
457         holeStart=pmax(holeStart,used[j].start+used[j].len);
458       else if ((memRange_t)used[j].start<(memRange_t)holeEnd) 
459         holeEnd=pmin(holeEnd,used[j].start);
460     } 
461
462     check_range(holeStart,holeEnd,&max);
463   }
464
465   if (max.len==0)
466     CmiAbort("ISOMALLOC cannot locate any free virtual address space!");
467   return max; 
468 }
469
470 static void init_ranges(char **argv)
471 {
472   /*Largest value a signed int can hold*/
473   memRange_t intMax=((memRange_t)1)<<(sizeof(int)*8-1)-1;
474
475   /*Round slot size up to nearest page size*/
476   slotsize=16*1024;
477   slotsize=(slotsize+CMK_MEMORY_PAGESIZE-1) & ~(CMK_MEMORY_PAGESIZE-1);
478 #if CMK_THREADS_DEBUG
479   CmiPrintf("[%d] Using slotsize of %d\n", CmiMyPe(), slotsize);
480 #endif
481
482   if (CmiMyRank()==0 && numslots==0)
483   { /* Find the largest unused region of virtual address space */
484     char *staticData =(char *) __static_data_loc();
485     char *code = (char *)&init_ranges;
486     char *codeDll = (char *)&fclose;
487     char *heapLil = (char*) malloc(1);
488     char *heapBig = (char*) malloc(4*1024*1024);
489     char *stack = (char *)__cur_stack_frame();
490
491     memRange_t meg=1024*1024; /*One megabyte*/
492     memRange_t gig=1024*meg; /*One gigabyte*/
493     int i,nRegions=7;
494     memRegion_t regions[7]; /*used portions of address space*/
495     memRegion_t freeRegion; /*Largest unused block of address space*/
496
497 /*Mark off regions of virtual address space as ususable*/
498     regions[0].type="NULL (inaccessible)";
499     regions[0].start=NULL; regions[0].len=16u*meg;
500     
501     regions[1].type="Static program data";
502     regions[1].start=staticData; regions[1].len=256u*meg;
503     
504     regions[2].type="Program executable code";
505     regions[2].start=code; regions[2].len=256u*meg;
506     
507     regions[3].type="Heap (small blocks)";
508     regions[3].start=heapLil; regions[3].len=2u*gig;
509     
510     regions[4].type="Heap (large blocks)";
511     regions[4].start=heapBig; regions[4].len=1u*gig;
512     
513     regions[5].type="Stack space";
514     regions[5].start=stack; regions[5].len=256u*meg;
515
516     regions[6].type="Program dynamically linked code";
517     regions[6].start=codeDll; regions[6].len=256u*meg;    
518
519     _MEMCHECK(heapBig); free(heapBig);
520     _MEMCHECK(heapLil); free(heapLil); 
521     
522     /*Align each memory region*/
523     for (i=0;i<nRegions;i++) {
524       memRange_t p=(memRange_t)regions[i].start;
525       p&=~(regions[i].len-1); /*Round down to a len-boundary (mask off low bits)*/
526       regions[i].start=(char *)p;
527 #if CMK_THREADS_DEBUG
528     CmiPrintf("[%d] Memory map: %p - %p  %s\n",CmiMyPe(),
529               regions[i].start,regions[i].start+regions[i].len,regions[i].type);
530 #endif
531     }
532     
533     /*Find a large, unused region*/
534     freeRegion=find_free_region(regions,nRegions,(512u)*meg);
535
536     /*If the unused region is very large, pad it on both ends for safety*/
537     if (freeRegion.len/gig>64u) {
538       freeRegion.start+=16u*gig;
539       freeRegion.len-=20u*gig;
540     }
541
542 #if CMK_THREADS_DEBUG
543     CmiPrintf("[%d] Largest unused region: %p - %p (%d megs)\n",CmiMyPe(),
544               freeRegion.start,freeRegion.start+freeRegion.len,
545               freeRegion.len/meg);
546 #endif
547
548     /*Allocate stacks in unused region*/
549     isomallocStart=freeRegion.start;
550     isomallocEnd=freeRegion.start+freeRegion.len;
551
552     /*Make sure our largest slot number doesn't overflow an int:*/
553     if (freeRegion.len/slotsize>intMax)
554       freeRegion.len=intMax*slotsize;
555     
556     numslots=(freeRegion.len/slotsize)/CmiNumPes();
557     
558 #if CMK_THREADS_DEBUG
559     CmiPrintf("[%d] Can isomalloc up to %lu megs per pe\n",CmiMyPe(),
560               ((memRange_t)numslots)*slotsize/meg);
561 #endif
562   }
563   /*SMP Mode: wait here for rank 0 to initialize numslots so we can set up myss*/
564   CmiNodeBarrier(); 
565   
566   CpvInitialize(slotset *, myss);
567   CpvAccess(myss) = new_slotset(pe2slot(CmiMyPe()), numslots);
568 }
569
570
571 /************* Communication: for grabbing/freeing remote slots *********/
572 typedef struct _slotmsg
573 {
574   char cmicore[CmiMsgHeaderSizeBytes];
575   int pe; /*Source processor*/
576   int slot; /*First requested slot*/
577   int nslots; /*Number of requested slots*/
578 } slotmsg;
579
580 static slotmsg *prepare_slotmsg(int slot,int nslots)
581 {
582         slotmsg *m=(slotmsg *)CmiAlloc(sizeof(slotmsg));
583         m->pe=CmiMyPe();
584         m->slot=slot;
585         m->nslots=nslots;
586         return m;
587 }
588
589 static void grab_remote(slotmsg *msg)
590 {
591         grab_slots(CpvAccess(myss),msg->slot,msg->nslots);
592         CmiFree(msg);
593 }
594
595 static void free_remote(slotmsg *msg)
596 {
597         free_slots(CpvAccess(myss),msg->slot,msg->nslots);
598         CmiFree(msg);
599 }
600 static int grab_remote_idx, free_remote_idx;
601
602 struct slotOP {
603         /*Function pointer to perform local operation*/
604         void (*local)(slotset *ss,int s,int n);
605         /*Index to perform remote operation*/
606         int remote;
607 };
608 typedef struct slotOP slotOP;
609 static slotOP grabOP,freeOP;
610
611 static void init_comm(char **argv)
612 {
613         grab_remote_idx=CmiRegisterHandler((CmiHandler)grab_remote);
614         free_remote_idx=CmiRegisterHandler((CmiHandler)free_remote);    
615         grabOP.local=grab_slots;
616         grabOP.remote=grab_remote_idx;
617         freeOP.local=free_slots;
618         freeOP.remote=free_remote_idx;  
619 }
620
621 /*Apply the given operation to the given slots which
622   lie on the given processor.*/
623 static void one_slotOP(const slotOP *op,int pe,int s,int n)
624 {
625 /*Shrink range to only those covered by this processor*/
626         /*First and last slot for this processor*/
627         int p_s=pe2slot(pe), p_e=pe2slot(pe+1);
628         int e=s+n;
629         if (s<p_s) s=p_s;
630         if (e>p_e) e=p_e;
631         n=e-s;
632
633 /*Send off range*/
634         if (pe==CmiMyPe()) 
635                 op->local(CpvAccess(myss),s,n);
636         else 
637         {/*Remote request*/
638                 slotmsg *m=prepare_slotmsg(s,e);
639                 CmiSyncSendAndFree(pe,sizeof(slotmsg),m);
640         }
641 }
642
643 /*Apply the given operation to all slots in the range [s, s+n) 
644 After a restart from checkpoint, a slotset can cross an 
645 arbitrary set of processors.
646 */
647 static void all_slotOP(const slotOP *op,int s,int n)
648 {
649         int spe=slot2pe(s), epe=slot2pe(s+n-1);
650         int pe;
651         for (pe=spe; pe<=epe; pe++)
652                 one_slotOP(op,pe,s,n);
653 }
654
655 /************** External interface ***************/
656 void *CmiIsomalloc(int size,CmiIsomallocBlock *b)
657 {
658         int s,n;
659         void *ret;
660         n=length2slots(size);
661         /*Always satisfy mallocs with local slots:*/
662         s=get_slots(CpvAccess(myss),n);
663         if (s==-1) {
664                 CmiError("Not enough address space left on processor %d to isomalloc %d bytes!\n",
665                          CmiMyPe(),size);
666                 CmiAbort("Out of virtual address space for isomalloc");
667         }
668         grab_slots(CpvAccess(myss),s,n);
669         b->slot=s;
670         b->nslots=n;
671         ret=map_slots(s,n);
672         if (!ret) map_bad(s,n);
673         return ret;
674 }
675
676 void *CmiIsomallocPup(pup_er p,CmiIsomallocBlock *b)
677 {
678         int s,n;
679         pup_int(p,&b->slot);
680         pup_int(p,&b->nslots);
681         s=b->slot, n=b->nslots;
682         if (pup_isUnpacking(p)) 
683         { /*Allocate block in its old location*/
684                 if (pup_isUserlevel(p))
685                         /*Checkpoint: must grab old slots (even remote!)*/
686                         all_slotOP(&grabOP,s,n);
687                 if (!map_slots(s,n)) map_bad(s,n);
688         }
689         
690         /*Pup the allocated data*/
691         pup_bytes(p,slot2addr(s),slots2length(n));
692
693         if (pup_isDeleting(p)) 
694         { /*Unmap old slots, but do not mark as free*/
695                 unmap_slots(s,n);
696                 b->nslots=0;/*Mark as unmapped*/
697         }
698         return slot2addr(s);
699 }
700
701 void CmiIsomallocFree(CmiIsomallocBlock *b)
702 {
703         int s=b->slot, n=b->nslots;
704         if (n==0) return;
705         unmap_slots(s,n);
706         /*Mark used slots as free*/
707         all_slotOP(&freeOP,s,n);
708 }
709
710 /*Return true if this address is in the region managed by isomalloc*/
711 int CmiIsomallocInRange(void *addr)
712 {
713         return (isomallocStart<=((char *)addr)) && (((char *)addr)<isomallocEnd);
714 }
715
716 void CmiIsomallocInit(char **argv)
717 {
718   init_comm(argv);
719   init_map(argv);
720   init_ranges(argv);
721 }
722