Only skip *ranges* initialization if we've already been started.
[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=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\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   /* Find the largest unused region of virtual address space */
483   if (isomallocStart==NULL)
484   {
485     char *staticData =(char *) __static_data_loc();
486     char *code = (char *)&init_ranges;
487     char *codeDll = (char *)&fclose;
488     char *heapLil = (char*) malloc(1);
489     char *heapBig = (char*) malloc(4*1024*1024);
490     char *stack = (char *)__cur_stack_frame();
491
492     memRange_t meg=1024*1024; /*One megabyte*/
493     memRange_t gig=1024*meg; /*One gigabyte*/
494     int i,nRegions=7;
495     memRegion_t regions[7]; /*used portions of address space*/
496     memRegion_t freeRegion; /*Largest unused block of address space*/
497
498 /*Mark off regions of virtual address space as ususable*/
499     regions[0].type="NULL (inaccessible)";
500     regions[0].start=NULL; regions[0].len=16u*meg;
501     
502     regions[1].type="Static program data";
503     regions[1].start=staticData; regions[1].len=256u*meg;
504     
505     regions[2].type="Program executable code";
506     regions[2].start=code; regions[2].len=256u*meg;
507     
508     regions[3].type="Heap (small blocks)";
509     regions[3].start=heapLil; regions[3].len=2u*gig;
510     
511     regions[4].type="Heap (large blocks)";
512     regions[4].start=heapBig; regions[4].len=1u*gig;
513     
514     regions[5].type="Stack space";
515     regions[5].start=stack; regions[5].len=256u*meg;
516
517     regions[6].type="Program dynamically linked code";
518     regions[6].start=codeDll; regions[6].len=256u*meg;    
519
520     _MEMCHECK(heapBig); free(heapBig);
521     _MEMCHECK(heapLil); free(heapLil); 
522     
523     /*Align each memory region*/
524     for (i=0;i<nRegions;i++) {
525       memRange_t p=(memRange_t)regions[i].start;
526       p&=~(regions[i].len-1); /*Round down to a len-boundary (mask off low bits)*/
527       regions[i].start=(char *)p;
528 #if CMK_THREADS_DEBUG
529     CmiPrintf("[%d] Memory map: %p - %p  %s\n",CmiMyPe(),
530               regions[i].start,regions[i].start+regions[i].len,regions[i].type);
531 #endif
532     }
533     
534     /*Find a large, unused region*/
535     freeRegion=find_free_region(regions,nRegions,(512u)*meg);
536
537     /*If the unused region is very large, pad it on both ends for safety*/
538     if (freeRegion.len/gig>64u) {
539       freeRegion.start+=16u*gig;
540       freeRegion.len-=20u*gig;
541     }
542
543 #if CMK_THREADS_DEBUG
544     CmiPrintf("[%d] Largest unused region: %p - %p (%d megs)\n",CmiMyPe(),
545               freeRegion.start,freeRegion.start+freeRegion.len,
546               freeRegion.len/meg);
547 #endif
548
549     /*Allocate stacks in unused region*/
550     isomallocStart=freeRegion.start;
551     isomallocEnd=freeRegion.start+freeRegion.len;
552
553     /*Make sure our largest slot number doesn't overflow an int:*/
554     if (freeRegion.len/slotsize>intMax)
555       freeRegion.len=intMax*slotsize;
556     
557     numslots=(freeRegion.len/slotsize)/CmiNumPes();
558     
559 #if CMK_THREADS_DEBUG
560     CmiPrintf("[%d] Can isomalloc up to %lu megs per pe\n",CmiMyPe(),
561               ((memRange_t)numslots)*slotsize/meg);
562 #endif
563   }
564
565   CpvInitialize(slotset *, myss);
566   CpvAccess(myss) = new_slotset(pe2slot(CmiMyPe()), numslots);
567 }
568
569
570 /************* Communication: for grabbing/freeing remote slots *********/
571 typedef struct _slotmsg
572 {
573   char cmicore[CmiMsgHeaderSizeBytes];
574   int pe; /*Source processor*/
575   int slot; /*First requested slot*/
576   int nslots; /*Number of requested slots*/
577 } slotmsg;
578
579 static slotmsg *prepare_slotmsg(int slot,int nslots)
580 {
581         slotmsg *m=(slotmsg *)CmiAlloc(sizeof(slotmsg));
582         m->pe=CmiMyPe();
583         m->slot=slot;
584         m->nslots=nslots;
585         return m;
586 }
587
588 static void grab_remote(slotmsg *msg)
589 {
590         grab_slots(CpvAccess(myss),msg->slot,msg->nslots);
591         CmiFree(msg);
592 }
593
594 static void free_remote(slotmsg *msg)
595 {
596         free_slots(CpvAccess(myss),msg->slot,msg->nslots);
597         CmiFree(msg);
598 }
599 static int grab_remote_idx, free_remote_idx;
600
601 struct slotOP {
602         /*Function pointer to perform local operation*/
603         void (*local)(slotset *ss,int s,int n);
604         /*Index to perform remote operation*/
605         int remote;
606 };
607 typedef struct slotOP slotOP;
608 static slotOP grabOP,freeOP;
609
610 static void init_comm(char **argv)
611 {
612         grab_remote_idx=CmiRegisterHandler((CmiHandler)grab_remote);
613         free_remote_idx=CmiRegisterHandler((CmiHandler)free_remote);    
614         grabOP.local=grab_slots;
615         grabOP.remote=grab_remote_idx;
616         freeOP.local=free_slots;
617         freeOP.remote=free_remote_idx;  
618 }
619
620 /*Apply the given operation to the given slots which
621   lie on the given processor.*/
622 static void one_slotOP(const slotOP *op,int pe,int s,int n)
623 {
624 /*Shrink range to only those covered by this processor*/
625         /*First and last slot for this processor*/
626         int p_s=pe2slot(pe), p_e=pe2slot(pe+1);
627         int e=s+n;
628         if (s<p_s) s=p_s;
629         if (e>p_e) e=p_e;
630         n=e-s;
631
632 /*Send off range*/
633         if (pe==CmiMyPe()) 
634                 op->local(CpvAccess(myss),s,n);
635         else 
636         {/*Remote request*/
637                 slotmsg *m=prepare_slotmsg(s,e);
638                 CmiSyncSendAndFree(pe,sizeof(slotmsg),m);
639         }
640 }
641
642 /*Apply the given operation to all slots in the range [s, s+n) 
643 After a restart from checkpoint, a slotset can cross an 
644 arbitrary set of processors.
645 */
646 static void all_slotOP(const slotOP *op,int s,int n)
647 {
648         int spe=slot2pe(s), epe=slot2pe(s+n-1);
649         int pe;
650         for (pe=spe; pe<=epe; pe++)
651                 one_slotOP(op,pe,s,n);
652 }
653
654 /************** External interface ***************/
655 void *CmiIsomalloc(int size,CmiIsomallocBlock *b)
656 {
657         int s,n;
658         void *ret;
659         n=length2slots(size);
660         /*Always satisfy mallocs with local slots:*/
661         s=get_slots(CpvAccess(myss),n);
662         if (s==-1) {
663                 CmiError("Not enough address space left on processor %d to isomalloc %d bytes!\n",
664                          CmiMyPe(),size);
665                 CmiAbort("Out of virtual address space for isomalloc");
666         }
667         grab_slots(CpvAccess(myss),s,n);
668         b->slot=s;
669         b->nslots=n;
670         ret=map_slots(s,n);
671         if (!ret) map_bad(s,n);
672         return ret;
673 }
674
675 void *CmiIsomallocPup(pup_er p,CmiIsomallocBlock *b)
676 {
677         int s,n;
678         pup_int(p,&b->slot);
679         pup_int(p,&b->nslots);
680         s=b->slot, n=b->nslots;
681         if (pup_isUnpacking(p)) 
682         { /*Allocate block in its old location*/
683                 if (pup_isUserlevel(p))
684                         /*Checkpoint: must grab old slots (even remote!)*/
685                         all_slotOP(&grabOP,s,n);
686                 if (!map_slots(s,n)) map_bad(s,n);
687         }
688         
689         /*Pup the allocated data*/
690         pup_bytes(p,slot2addr(s),slots2length(n));
691
692         if (pup_isDeleting(p)) 
693         { /*Unmap old slots, but do not mark as free*/
694                 unmap_slots(s,n);
695                 b->nslots=0;/*Mark as unmapped*/
696         }
697         return slot2addr(s);
698 }
699
700 void CmiIsomallocFree(CmiIsomallocBlock *b)
701 {
702         int s=b->slot, n=b->nslots;
703         if (n==0) return;
704         unmap_slots(s,n);
705         /*Mark used slots as free*/
706         all_slotOP(&freeOP,s,n);
707 }
708
709 /*Return true if this address is in the region managed by isomalloc*/
710 int CmiIsomallocInRange(void *addr)
711 {
712         return (isomallocStart<=((char *)addr)) && (((char *)addr)<isomallocEnd);
713 }
714
715 void CmiIsomallocInit(char **argv)
716 {
717   init_comm(argv);
718   init_map(argv);
719   init_ranges(argv);
720 }
721