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