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