1.) Added MAP_ANON(YMOUS), for Compaq Tru64 machines.
[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;
31
32 /*Start and end of isomalloc-managed addresses*/
33 static char *isomallocStart;
34 static char *isomallocEnd;
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\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_ANONYMOUS,-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   CpvInitialize(int, zerofd);  
325   CpvAccess(zerofd) = open("/dev/zero", O_RDWR);
326   if(CpvAccess(zerofd)<0)
327     CmiAbort("Cannot open /dev/zero. Aborting.\n");     
328 #endif
329 }
330
331 #endif /* UNIX memory map */
332
333
334 static void map_bad(int s,int n)
335 {
336   void *addr=slot2addr(s);
337   CmiError("map failed to allocate %d bytes at %p.\n", slotsize*n, addr);
338   CmiAbort("Exiting\n");
339 }
340
341
342
343 /************ Address space voodoo: find free address range **********/
344 CpvStaticDeclare(slotset *, myss); /*My managed slots*/
345
346 /*This struct describes a range of virtual addresses*/
347 typedef unsigned long memRange_t;
348 typedef struct {
349   char *start; /*First byte of region*/
350   memRange_t len; /*Number of bytes in region*/
351   const char *type; /*String describing memory in region (debugging only)*/
352 } memRegion_t;
353
354 /*Estimate the top of the current stack*/
355 static void *__cur_stack_frame(void)
356 {
357   char __dummy;
358   void *top_of_stack=(void *)&__dummy;
359   return top_of_stack;
360 }
361 /*Estimate the location of the static data region*/
362 static void *__static_data_loc(void)
363 {
364   static char __dummy;
365   return (void *)&__dummy;
366 }
367
368 static char *pmin(char *a,char *b) {return (a<b)?a:b;}
369 static char *pmax(char *a,char *b) {return (a>b)?a:b;}
370
371 /*Check if this memory location is usable.  
372   If not, return 1.
373 */
374 static int bad_range(char *loc) {
375   void *addr;
376   isomallocStart=loc;
377   addr=map_slots(0,1);
378   if (addr==NULL) {
379 #if CMK_THREADS_DEBUG
380     CmiPrintf("[%d] Skipping unmappable space at %p\n",CmiMyPe(),loc);
381 #endif
382     return 1; /*No good*/
383   }
384   unmap_slots(0,1);
385   return 0; /*This works*/
386 }
387
388 /*Check if this memory range is usable.  
389   If so, write it into max.
390 */
391 static void check_range(char *start,char *end,memRegion_t *max)
392 {
393   memRange_t len;
394   memRange_t searchQuantStart=128u*1024*1024; /*Shift search location by this far*/
395   memRange_t searchQuant;
396   void *addr;
397
398   if (start>=end) return; /*Ran out of hole*/
399   len=(memRange_t)end-(memRange_t)start;
400   if (len<=max->len) return; /*It's too short already!*/
401 #if CMK_THREADS_DEBUG
402   CmiPrintf("[%d] Checking usable address space at %p - %p\n",CmiMyPe(),start,end);
403 #endif
404
405   /* Trim off start of range until we hit usable memory*/  
406   searchQuant=searchQuantStart;
407   while (bad_range(start)) {
408         start+=searchQuant;
409         if (start>=end) return; /*Ran out of hole*/
410         searchQuant*=2; /*Exponential search*/
411         if (searchQuant==0) return; /*SearchQuant overflowed-- no good memory anywhere*/
412   }
413
414   /* Trim off end of range until we hit usable memory*/
415   searchQuant=searchQuantStart;
416   while (bad_range(end-slotsize)) {
417         end-=searchQuant;
418         if (start>=end) return; /*Ran out of hole*/
419         searchQuant*=2;
420         if (searchQuant==0) return; /*SearchQuant overflowed-- no good memory anywhere*/
421   }
422   
423   len=(memRange_t)end-(memRange_t)start;
424   if (len<max->len) return; /*It's now too short.*/
425   
426 #if CMK_THREADS_DEBUG
427   CmiPrintf("[%d] Address space at %p - %p is largest\n",CmiMyPe(),start,end);
428 #endif
429
430   /*If we got here, we're the new largest usable range*/
431   max->len=len;
432   max->start=start;
433   max->type="Unused";
434 }
435
436 /*Find the first available memory region of at least the
437   given size not touching any data in the used list.
438  */
439 static memRegion_t find_free_region(memRegion_t *used,int nUsed,int atLeast) 
440 {
441   memRegion_t max;
442   int i,j;  
443
444   max.len=0;
445   /*Find the largest hole between regions*/
446   for (i=0;i<nUsed;i++) {
447     /*Consider a hole starting at the end of region i*/
448     char *holeStart=used[i].start+used[i].len;
449     char *holeEnd=(void *)(-1);
450     
451     /*Shrink the hole by all others*/ 
452     for (j=0;j<nUsed && holeStart<holeEnd;j++) {
453       if ((memRange_t)used[j].start<(memRange_t)holeStart) 
454         holeStart=pmax(holeStart,used[j].start+used[j].len);
455       else if ((memRange_t)used[j].start<(memRange_t)holeEnd) 
456         holeEnd=pmin(holeEnd,used[j].start);
457     } 
458
459     check_range(holeStart,holeEnd,&max);
460   }
461
462   if (max.len==0)
463     CmiAbort("ISOMALLOC cannot locate any free virtual address space!");
464   return max; 
465 }
466
467 static void init_ranges(char **argv)
468 {
469   /*Largest value a signed int can hold*/
470   memRange_t intMax=((memRange_t)1)<<(sizeof(int)*8-1)-1;
471
472   /*Round slot size up to nearest page size*/
473   slotsize=16*1024;
474   slotsize=(slotsize+CMK_MEMORY_PAGESIZE-1) & ~(CMK_MEMORY_PAGESIZE-1);
475 #if CMK_THREADS_DEBUG
476   CmiPrintf("[%d] Using slotsize of %d\n", CmiMyPe(), slotsize);
477 #endif
478
479   /* Find the largest unused region of virtual address space */
480   {
481     char *staticData =(char *) __static_data_loc();
482     char *code = (char *)&init_ranges;
483     char *codeDll = (char *)&fclose;
484     char *heapLil = (char*) malloc(1);
485     char *heapBig = (char*) malloc(4*1024*1024);
486     char *stack = (char *)__cur_stack_frame();
487
488     memRange_t meg=1024*1024; /*One megabyte*/
489     memRange_t gig=1024*meg; /*One gigabyte*/
490     int i,nRegions=7;
491     memRegion_t regions[7]; /*used portions of address space*/
492     memRegion_t freeRegion; /*Largest unused block of address space*/
493
494 /*Mark off regions of virtual address space as ususable*/
495     regions[0].type="NULL (inaccessible)";
496     regions[0].start=NULL; regions[0].len=16u*meg;
497     
498     regions[1].type="Static program data";
499     regions[1].start=staticData; regions[1].len=256u*meg;
500     
501     regions[2].type="Program executable code";
502     regions[2].start=code; regions[2].len=256u*meg;
503     
504     regions[3].type="Heap (small blocks)";
505     regions[3].start=heapLil; regions[3].len=2u*gig;
506     
507     regions[4].type="Heap (large blocks)";
508     regions[4].start=heapBig; regions[4].len=1u*gig;
509     
510     regions[5].type="Stack space";
511     regions[5].start=stack; regions[5].len=256u*meg;
512
513     regions[6].type="Program dynamically linked code";
514     regions[6].start=codeDll; regions[6].len=256u*meg;    
515
516     _MEMCHECK(heapBig); free(heapBig);
517     _MEMCHECK(heapLil); free(heapLil); 
518     
519     /*Align each memory region*/
520     for (i=0;i<nRegions;i++) {
521       memRange_t p=(memRange_t)regions[i].start;
522       p&=~(regions[i].len-1); /*Round down to a len-boundary (mask off low bits)*/
523       regions[i].start=(char *)p;
524 #if CMK_THREADS_DEBUG
525     CmiPrintf("[%d] Memory map: %p - %p  %s\n",CmiMyPe(),
526               regions[i].start,regions[i].start+regions[i].len,regions[i].type);
527 #endif
528     }
529     
530     /*Find a large, unused region*/
531     freeRegion=find_free_region(regions,nRegions,(512u)*meg);
532
533     /*If the unused region is very large, pad it on both ends for safety*/
534     if (freeRegion.len/gig>64u) {
535       freeRegion.start+=16u*gig;
536       freeRegion.len-=20u*gig;
537     }
538
539 #if CMK_THREADS_DEBUG
540     CmiPrintf("[%d] Largest unused region: %p - %p (%d megs)\n",CmiMyPe(),
541               freeRegion.start,freeRegion.start+freeRegion.len,
542               freeRegion.len/meg);
543 #endif
544
545     /*Allocate stacks in unused region*/
546     isomallocStart=freeRegion.start;
547     isomallocEnd=freeRegion.start+freeRegion.len;
548
549     /*Make sure our largest slot number doesn't overflow an int:*/
550     if (freeRegion.len/slotsize>intMax)
551       freeRegion.len=intMax*slotsize;
552     
553     numslots=(freeRegion.len/slotsize)/CmiNumPes();
554     
555 #if CMK_THREADS_DEBUG
556     CmiPrintf("[%d] Can isomalloc up to %lu megs per pe\n",CmiMyPe(),
557               ((memRange_t)numslots)*slotsize/meg);
558 #endif
559   }
560
561   CpvInitialize(slotset *, myss);
562   CpvAccess(myss) = new_slotset(pe2slot(CmiMyPe()), numslots);
563 }
564
565
566 /************* Communication: for grabbing/freeing remote slots *********/
567 typedef struct _slotmsg
568 {
569   char cmicore[CmiMsgHeaderSizeBytes];
570   int pe; /*Source processor*/
571   int slot; /*First requested slot*/
572   int nslots; /*Number of requested slots*/
573 } slotmsg;
574
575 static slotmsg *prepare_slotmsg(int slot,int nslots)
576 {
577         slotmsg *m=(slotmsg *)CmiAlloc(sizeof(slotmsg));
578         m->pe=CmiMyPe();
579         m->slot=slot;
580         m->nslots=nslots;
581         return m;
582 }
583
584 static void grab_remote(slotmsg *msg)
585 {
586         grab_slots(CpvAccess(myss),msg->slot,msg->nslots);
587         CmiFree(msg);
588 }
589
590 static void free_remote(slotmsg *msg)
591 {
592         free_slots(CpvAccess(myss),msg->slot,msg->nslots);
593         CmiFree(msg);
594 }
595 static int grab_remote_idx, free_remote_idx;
596
597 struct slotOP {
598         /*Function pointer to perform local operation*/
599         void (*local)(slotset *ss,int s,int n);
600         /*Index to perform remote operation*/
601         int remote;
602 };
603 typedef struct slotOP slotOP;
604 static slotOP grabOP,freeOP;
605
606 static void init_comm(char **argv)
607 {
608         grab_remote_idx=CmiRegisterHandler((CmiHandler)grab_remote);
609         free_remote_idx=CmiRegisterHandler((CmiHandler)free_remote);    
610         grabOP.local=grab_slots;
611         grabOP.remote=grab_remote_idx;
612         freeOP.local=free_slots;
613         freeOP.remote=free_remote_idx;  
614 }
615
616 /*Apply the given operation to the given slots which
617   lie on the given processor.*/
618 static void one_slotOP(const slotOP *op,int pe,int s,int n)
619 {
620 /*Shrink range to only those covered by this processor*/
621         /*First and last slot for this processor*/
622         int p_s=pe2slot(pe), p_e=pe2slot(pe+1);
623         int e=s+n;
624         if (s<p_s) s=p_s;
625         if (e>p_e) e=p_e;
626         n=e-s;
627
628 /*Send off range*/
629         if (pe==CmiMyPe()) 
630                 op->local(CpvAccess(myss),s,n);
631         else 
632         {/*Remote request*/
633                 slotmsg *m=prepare_slotmsg(s,e);
634                 CmiSyncSendAndFree(pe,sizeof(slotmsg),m);
635         }
636 }
637
638 /*Apply the given operation to all slots in the range [s, s+n) 
639 After a restart from checkpoint, a slotset can cross an 
640 arbitrary set of processors.
641 */
642 static void all_slotOP(const slotOP *op,int s,int n)
643 {
644         int spe=slot2pe(s), epe=slot2pe(s+n-1);
645         int pe;
646         for (pe=spe; pe<=epe; pe++)
647                 one_slotOP(op,pe,s,n);
648 }
649
650 /************** External interface ***************/
651 void *CmiIsomalloc(int size,CmiIsomallocBlock *b)
652 {
653         int s,n;
654         void *ret;
655         n=length2slots(size);
656         /*Always satisfy mallocs with local slots:*/
657         s=get_slots(CpvAccess(myss),n);
658         if (s==-1) {
659                 CmiError("Not enough address space left on processor %d to isomalloc %d bytes!\n",
660                          CmiMyPe(),size);
661                 CmiAbort("Out of virtual address space for isomalloc");
662         }
663         grab_slots(CpvAccess(myss),s,n);
664         b->slot=s;
665         b->nslots=n;
666         ret=map_slots(s,n);
667         if (!ret) map_bad(s,n);
668         return ret;
669 }
670
671 void *CmiIsomallocPup(pup_er p,CmiIsomallocBlock *b)
672 {
673         int s,n;
674         pup_int(p,&b->slot);
675         pup_int(p,&b->nslots);
676         s=b->slot, n=b->nslots;
677         if (pup_isUnpacking(p)) 
678         { /*Allocate block in its old location*/
679                 if (pup_isUserlevel(p))
680                         /*Checkpoint: must grab old slots (even remote!)*/
681                         all_slotOP(&grabOP,s,n);
682                 if (!map_slots(s,n)) map_bad(s,n);
683         }
684         
685         /*Pup the allocated data*/
686         pup_bytes(p,slot2addr(s),slots2length(n));
687
688         if (pup_isDeleting(p)) 
689         { /*Unmap old slots, but do not mark as free*/
690                 unmap_slots(s,n);
691                 b->nslots=0;/*Mark as unmapped*/
692         }
693         return slot2addr(s);
694 }
695
696 void CmiIsomallocFree(CmiIsomallocBlock *b)
697 {
698         int s=b->slot, n=b->nslots;
699         if (n==0) return;
700         unmap_slots(s,n);
701         /*Mark used slots as free*/
702         all_slotOP(&freeOP,s,n);
703 }
704
705 /*Return true if this address is in the region managed by isomalloc*/
706 int CmiIsomallocInRange(void *addr)
707 {
708         return (isomallocStart<=((char *)addr)) && (((char *)addr)<isomallocEnd);
709 }
710
711 void CmiIsomallocInit(char **argv)
712 {
713   init_comm(argv);
714   init_ranges(argv);
715   init_map(argv);
716 }
717