Merge branch 'charm' into isomalloc
[charm.git] / src / conv-core / isomalloc.c
1 /*****************************************************************************
2  * $Source$
3  * $Author$ 
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /**************************************************************************
9 Isomalloc:
10 A way to allocate memory at the same address on every processor.
11 This enables linked data structures, like thread stacks, to be migrated
12 to the same address range on other processors.  This is similar to an
13 explicitly managed shared memory system.
14
15 The memory is used and released via the mmap()/mumap() calls, so unused
16 memory does not take any (RAM, swap or disk) space.
17
18 The way it's implemented is that each processor claims some section 
19 of the available virtual address space, and satisfies all new allocations
20 from that space.  Migrating structures use whatever space they started with.
21
22 The b-tree implementation has two data structures that are maintained
23 simultaneously and in conjunction with each other: a b-tree of nodes
24 containing slotblocks used for quickly finding a particular slotblock;
25 and an array of doubly-linked lists containing the same slotblocks,
26 ordered according to the number of free slots in each slotblock, which
27 is used for quickly finding a block of free slots of a desired size.
28 The slotset contains pointers to both structures.
29 print_btree_top_down() and print_list_array() are very useful
30 functions for viewing the current structure of the tree and lists.
31
32 Each doubly-linked list has slotblocks containing between 2^(n-1)+1
33 and 2^n free slots, where n is the array index (i.e., bin number).
34 For example, list_array[0] points to a double-linked list of
35 slotblocks with 1 free slot, list_array[1] points to a double-linked
36 list of slotblocks with 2 free slots, list_array[2] to slotblocks with
37 3-4 free slots, list_array[3] to slotblocks with 5-8 free slots, etc.
38
39 Written for migratable threads by Milind Bhandarkar around August 2000;
40 generalized by Orion Lawlor November 2001.  B-tree implementation
41 added by Ryan Mokos in July 2008.
42  *************************************************************************/
43
44 #include "converse.h"
45 #include "memory-isomalloc.h"
46
47 #define CMK_THREADS_DEBUG 0
48
49 /* 0: use the old non-mempool implementation
50 1: use the new mempool implementation  */
51 #define USE_MEMPOOL_ISOMALLOC 1
52
53 /* 0: use the old isomalloc implementation (array)
54 1: use the new isomalloc implementation (b-tree)  */
55 #define USE_BTREE_ISOMALLOC 1
56
57 /* b-tree definitions */
58 #define TREE_NODE_SIZE 128 /* a power of 2 is probably best  */
59 #define TREE_NODE_MID  63  /* must be cieling(TREE_NODE_SIZE / 2) - 1  */
60
61 /* linked list definitions  */
62 #define LIST_ARRAY_SIZE 64
63
64 #include <fcntl.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <errno.h> /* just so I can find dynamically-linked symbols */
68 #include <unistd.h>
69
70 #if CMK_HAS_ADDR_NO_RANDOMIZE
71 #include <sys/personality.h>
72 #endif
73
74 #if USE_MEMPOOL_ISOMALLOC
75 #include "mempool.h"
76 #endif 
77
78 static int _sync_iso = 0;
79 static int _mmap_probe = 0;
80
81 static int read_randomflag(void)
82 {
83   FILE *fp;
84   int random_flag;
85   fp = fopen("/proc/sys/kernel/randomize_va_space", "r");
86   if (fp != NULL) {
87     fscanf(fp, "%d", &random_flag);
88     fclose(fp);
89 #if CMK_HAS_ADDR_NO_RANDOMIZE
90     if(random_flag)
91     {
92       int persona = personality(0xffffffff);
93       if(persona & ADDR_NO_RANDOMIZE)
94         random_flag = 0;
95     }
96 #endif
97   }
98   else {
99     random_flag = -1;
100   }
101   return random_flag;
102 }
103
104 struct CmiIsomallocBlock {
105   CmiInt8 slot;   /* First mapped slot */
106   CmiInt8 length; /* Length of (user portion of) mapping, in bytes*/
107 };
108 typedef struct CmiIsomallocBlock CmiIsomallocBlock;
109
110 /* Convert a heap block pointer to/from a CmiIsomallocBlock header */
111 static void *block2pointer(CmiIsomallocBlock *blockHeader) {
112   return (void *)(blockHeader+1);
113 }
114 static CmiIsomallocBlock *pointer2block(void *heapBlock) {
115   return ((CmiIsomallocBlock *)heapBlock)-1;
116 }
117
118 /* Integral type to be used for pointer arithmetic: */
119 typedef size_t memRange_t;
120
121 /* Size in bytes of a single slot */
122 static size_t slotsize;
123 static size_t regionSize;
124
125 /* Total number of slots per processor */
126 static CmiInt8 numslots=0;
127
128 /* Start and end of isomalloc-managed addresses.
129    If isomallocStart==NULL, isomalloc is disabled.
130    */
131 static char *isomallocStart=NULL;
132 static char *isomallocEnd=NULL;
133
134 /* Utility conversion functions */
135 static void *slot2addr(CmiInt8 slot) {
136   return isomallocStart+((memRange_t)slotsize)*((memRange_t)slot);
137 }
138 static int slot2pe(CmiInt8 slot) {
139   return (int)(slot/numslots);
140 }
141 static CmiInt8 pe2slot(int pe) {
142   return pe*numslots;
143 }
144 /* Return the number of slots in a block with n user data bytes */
145 static int length2slots(int nBytes) {
146   return (sizeof(CmiIsomallocBlock)+nBytes+slotsize-1)/slotsize;
147 }
148
149 /* ======================================================================
150  * New isomalloc (b-tree-based implementation)
151  * ====================================================================== */
152
153 #if USE_BTREE_ISOMALLOC
154
155 /* doubly-linked list node */
156 struct _dllnode {
157   struct _dllnode   *previous;
158   struct _slotblock *sb;
159   struct _dllnode   *next;
160 };
161
162 /* slotblock */
163 struct _slotblock {
164   CmiInt8 startslot;
165   CmiInt8 nslots;
166   struct _dllnode *listblock;
167 };
168
169 typedef struct _dllnode   dllnode;
170 typedef struct _slotblock slotblock;
171
172 /* b-tree node */
173 struct _btreenode {
174   int num_blocks;
175   slotblock blocks[TREE_NODE_SIZE];
176   struct _btreenode *child[TREE_NODE_SIZE + 1];
177 };
178 typedef struct _btreenode btreenode;
179
180 /* slotset */
181 typedef struct _slotset {
182   btreenode *btree_root;
183   dllnode *list_array[LIST_ARRAY_SIZE];
184 } slotset;
185
186 /* return value for a b-tree insert */
187 typedef struct _insert_ret_val {
188   slotblock sb;
189   btreenode *btn;
190 } insert_ret_val;
191
192 /*****************************************************************
193  * Find and return the number of the bin (list) to which the number
194  * nslots belongs.  The range of each bin is 2^(b-1)+1 to 2^b, where b
195  * is the bin number.
196  *****************************************************************/
197
198 static int find_list_bin(CmiInt8 nslots) {
199   int list_bin     = 32;
200   CmiInt8 comp_num = 0x100000000LL;
201   int inc          = 16;
202
203   while (1) {
204     if ((nslots > (comp_num >> 1)) && (nslots <= comp_num)) {
205       /* found it */
206       return list_bin;
207     } else if (nslots < comp_num) {
208       /* look left  */
209       list_bin -= inc;
210       comp_num  = comp_num >> inc;
211       if ((inc = inc >> 1) == 0) {
212         inc = 1;
213       }
214     } else {
215       /* look right */
216       list_bin += inc;
217       comp_num  = comp_num << inc;
218       if ((inc = inc >> 1) == 0) {
219         inc = 1;
220       }
221     }
222   }
223
224 }
225
226 /*****************************************************************
227  * Creates and inserts a new dllnode into list_array (part of the
228  * slotset ss) that both points to and is pointed to by the slotblock
229  * sb.  This function also returns a pointer to that new dllnode.
230  *****************************************************************/
231
232 static dllnode *list_insert(slotset *ss, slotblock *sb) {
233
234   /* find the list bin to put the new dllnode in  */
235   int list_bin = find_list_bin(sb->nslots);
236
237   /* allocate memory for the new node */
238   dllnode *new_dlln = (dllnode *)(malloc_reentrant(sizeof(dllnode)));
239
240   /* insert the dllnode */
241   new_dlln->previous = NULL;
242   new_dlln->next     = ss->list_array[list_bin];
243   new_dlln->sb       = sb;
244   if (ss->list_array[list_bin] != NULL) {
245     ss->list_array[list_bin]->previous = new_dlln;
246   }
247   ss->list_array[list_bin] = new_dlln;
248
249   return new_dlln;
250
251 }
252
253 /*****************************************************************
254  * Deletes the dllnode from list_array (part of the slotset ss) that
255  * is pointed to by the slotblock sb.
256  *****************************************************************/
257
258 static void list_delete(slotset *ss, slotblock *sb) {
259
260   /* remove the node from the list */
261   if (sb->listblock->next != NULL) {
262     sb->listblock->next->previous = sb->listblock->previous;
263   }
264   if (sb->listblock->previous != NULL) {
265     sb->listblock->previous->next = sb->listblock->next;
266   } else {  /* first element in the list */
267     ss->list_array[find_list_bin(sb->nslots)] = sb->listblock->next;
268   }
269
270   /* free the memory from the node */
271   free_reentrant(sb->listblock);
272
273 }
274
275 /*****************************************************************
276  * Moves the dllnode dlln to the correct bin (list) of slotset ss
277  * based on the number of slots in the slotblock to which dlln points.
278  * It is assumed that the slotblock pointed to by dlln has already been
279  * updated with the new number of slots.  The integer old_nslots
280  * contains the number of slots that used to be in the slotblock.
281  *****************************************************************/
282
283 static void list_move(slotset *ss, dllnode *dlln, CmiInt8 old_nslots) {
284
285   /* determine the bin the slotblock used to be in */
286   int old_bin = find_list_bin(old_nslots);
287
288   /* determine the bin the slotblock is in now */
289   int new_bin = find_list_bin(dlln->sb->nslots);
290
291   /* if the old bin and new bin are different, move the slotblock */
292   if (new_bin != old_bin) {
293
294     /* remove from old bin */
295     if (dlln->previous == NULL) {  /* dlln is the 1st element in the list */
296       if (dlln->next != NULL) {
297         dlln->next->previous = NULL;
298       }
299       ss->list_array[old_bin] = dlln->next;
300     } else {
301       if (dlln->next != NULL) {
302         dlln->next->previous = dlln->previous;
303       }
304       dlln->previous->next = dlln->next;
305     }
306
307     /* insert at the beginning of the new bin */
308     dlln->next     = ss->list_array[new_bin];
309     dlln->previous = NULL;
310     if (dlln->next != NULL) {
311       dlln->next->previous = dlln;
312     }
313     ss->list_array[new_bin] = dlln;
314   }
315
316 }
317
318 /*****************************************************************
319  * Creates a new b-tree node
320  *****************************************************************/
321
322 static btreenode *create_btree_node() {
323   int i;
324   btreenode *btn = (btreenode *)malloc_reentrant(sizeof(btreenode));
325   btn->num_blocks = 0;
326   for (i = 0; i < TREE_NODE_SIZE; i++) {
327     btn->blocks[i].listblock = NULL;
328   }
329   for (i = 0; i < TREE_NODE_SIZE + 1; i++) {
330     btn->child[i] = NULL;
331   }
332   return btn;
333 }
334
335 /*****************************************************************
336  * Find the slotblock in the b-tree that contains startslot.  Returns
337  * NULL if such a block cannot be found.
338  *****************************************************************/
339
340 static slotblock *find_btree_slotblock(btreenode *node, CmiInt8 startslot) {
341
342   /* check if this node exists */
343   if ((node == NULL) || (startslot < 0) || (node->num_blocks == 0)) {
344     return NULL;
345   } else {
346
347     /*** Binary search on this node ***/
348     /* initialize */
349     int index = node->num_blocks >> 1;
350     int inc   = (index >> 1) + (node->num_blocks & 0x1);
351     CmiInt8 endslot;
352
353     /* loop until a node is found */
354     while (1) {
355
356       /* if startslot is in current slotblock, this is the slotblock */
357       endslot = node->blocks[index].startslot + node->blocks[index].nslots - 1;
358       if ((startslot >= node->blocks[index].startslot) &&
359           (startslot <= endslot)) {
360         return &(node->blocks[index]);
361       }
362
363       /* else, if startslot is less */
364       else if (startslot < node->blocks[index].startslot) {
365
366         /* if this is slotblock 0, take the left child */
367         if (index == 0) {
368           return find_btree_slotblock(node->child[index], startslot);
369         }
370
371         /* else check endslot of the slotblock to the left */
372         else {
373
374           /* if startslot > endslot-of-slotblock-to-the-left, take the
375              left child */
376           endslot = node->blocks[index-1].startslot + 
377             node->blocks[index-1].nslots - 1;
378           if (startslot > endslot) {
379             return find_btree_slotblock(node->child[index], startslot);
380           }
381
382           /* else continue to search this node to the left */
383           else {
384             index -= inc;
385             if ((inc = inc >> 1) == 0) {
386               inc = 1;
387             }
388           }
389         }
390       }
391
392       /* else, startslot must be greater */
393       else {
394
395         /* if this is the last slotblock, take the right child */
396         if (index == node->num_blocks - 1) {
397           return find_btree_slotblock(node->child[index+1], startslot);
398         }
399
400         /* else check startslot of the slotblock to the right */
401         else {
402
403           /* if startslot < startslot-of-slotblock-to-the-right, then
404              take the right child */
405           if (startslot < node->blocks[index+1].startslot) {
406             return find_btree_slotblock(node->child[index+1], startslot);
407           }
408
409           /* else continue to search this node to the right */
410           else {
411             index += inc;
412             if ((inc = inc >> 1) == 0) {
413               inc = 1;
414             }
415           }
416         }
417       }
418
419     }
420
421   }
422
423 }
424
425 /*****************************************************************
426  * Insert a slotblock into the b-tree starting at startslot and going
427  * for nslots slots
428  *****************************************************************/
429
430 static insert_ret_val btree_insert_int(slotset *ss, btreenode *node, 
431     CmiInt8 startslot, CmiInt8 nslots) {
432
433   insert_ret_val irv;
434
435   /*** binary search for the place to insert ***/
436
437   /* initialize */
438   int index = node->num_blocks >> 1;
439   int inc   = (index >> 1) + (node->num_blocks & 0x1);
440
441   /* loop until an insertion happens */
442   while (1) {
443     if (startslot < node->blocks[index].startslot) {  /* look to the left */
444       if ((index == 0) || 
445           (startslot > node->blocks[index-1].startslot)) {
446         if (node->child[index] != NULL) {             /* take left child */
447           irv = btree_insert_int(ss, node->child[index], startslot, nslots);
448           if (irv.btn == NULL) {
449             return irv;
450           } else {                                    /* merge return value */
451             int i, j;                                 /*   insert on left   */
452             for (i = node->num_blocks; i > index; i--) {
453               node->blocks[i].startslot     = node->blocks[i-1].startslot;
454               node->blocks[i].nslots        = node->blocks[i-1].nslots;
455               node->blocks[i].listblock     = node->blocks[i-1].listblock;
456               node->blocks[i].listblock->sb = &(node->blocks[i]);
457               node->child[i+1]              = node->child[i];
458             }
459             node->blocks[index].startslot     = irv.sb.startslot;
460             node->blocks[index].nslots        = irv.sb.nslots;
461             node->blocks[index].listblock     = irv.sb.listblock;
462             node->blocks[index].listblock->sb = &(node->blocks[index]);
463             node->child[index+1]              = irv.btn;
464             node->num_blocks++;
465             if (node->num_blocks == TREE_NODE_SIZE) {   /* split node */
466               btreenode *new_node = create_btree_node();
467               for (i = TREE_NODE_MID + 1; i < TREE_NODE_SIZE; i++) {
468                 j = i - (TREE_NODE_MID + 1);
469                 new_node->blocks[j].startslot     = node->blocks[i].startslot;
470                 new_node->blocks[j].nslots        = node->blocks[i].nslots;
471                 new_node->blocks[j].listblock     = node->blocks[i].listblock;
472                 new_node->blocks[j].listblock->sb = &(new_node->blocks[j]);
473               }
474               for (i = TREE_NODE_MID + 1; i <= TREE_NODE_SIZE; i++) {
475                 new_node->child[i-(TREE_NODE_MID+1)] = node->child[i];
476               }
477               node->num_blocks     = TREE_NODE_MID;
478               new_node->num_blocks = TREE_NODE_SIZE - TREE_NODE_MID - 1;
479
480               irv.sb.startslot = node->blocks[TREE_NODE_MID].startslot;
481               irv.sb.nslots    = node->blocks[TREE_NODE_MID].nslots;
482               irv.sb.listblock = node->blocks[TREE_NODE_MID].listblock;
483               irv.btn          = new_node;
484               return irv;
485             } else {
486               irv.btn = NULL;
487               return irv;
488             }
489           }
490         } else {                                      /* insert to the left */
491           int i, j;
492           for (i = node->num_blocks; i > index; i--) {
493             node->blocks[i].startslot     = node->blocks[i-1].startslot;
494             node->blocks[i].nslots        = node->blocks[i-1].nslots;
495             node->blocks[i].listblock     = node->blocks[i-1].listblock;
496             node->blocks[i].listblock->sb = &(node->blocks[i]);
497           }
498           node->blocks[index].startslot = startslot;
499           node->blocks[index].nslots    = nslots;
500           node->blocks[index].listblock = list_insert(ss, &(node->blocks[index]));
501           node->num_blocks++;
502           if (node->num_blocks == TREE_NODE_SIZE) {   /* split node */
503             btreenode *new_node = create_btree_node();
504             for (i = TREE_NODE_MID + 1; i < TREE_NODE_SIZE; i++) {
505               j = i - (TREE_NODE_MID + 1);
506               new_node->blocks[j].startslot     = node->blocks[i].startslot;
507               new_node->blocks[j].nslots        = node->blocks[i].nslots;
508               new_node->blocks[j].listblock     = node->blocks[i].listblock;
509               new_node->blocks[j].listblock->sb = &(new_node->blocks[j]);
510             }
511             node->num_blocks     = TREE_NODE_MID;
512             new_node->num_blocks = TREE_NODE_SIZE - TREE_NODE_MID - 1;
513
514             irv.sb.startslot = node->blocks[TREE_NODE_MID].startslot;
515             irv.sb.nslots    = node->blocks[TREE_NODE_MID].nslots;
516             irv.sb.listblock = node->blocks[TREE_NODE_MID].listblock;
517             irv.btn          = new_node;
518             return irv;
519           } else {
520             irv.btn = NULL;
521             return irv;
522           }
523         }
524       } else {                                        /* search to the left */
525         index -= inc;
526         if ((inc = inc >> 1) == 0) {
527           inc = 1;
528         }
529       }
530
531     } else {                                          /* look to the right */
532
533       if ((index == node->num_blocks - 1) || 
534           (startslot < node->blocks[index+1].startslot)) {
535         if (node->child[index+1] != NULL) {           /* take right child */
536           irv = btree_insert_int(ss, node->child[index+1], startslot, nslots);
537           if (irv.btn == NULL) {
538             return irv;
539           } else {                                    /* merge return value */
540             int i, j;                                 /*   insert on right  */
541             for (i = node->num_blocks; i > index + 1; i--) {
542               node->blocks[i].startslot     = node->blocks[i-1].startslot;
543               node->blocks[i].nslots        = node->blocks[i-1].nslots;
544               node->blocks[i].listblock     = node->blocks[i-1].listblock;
545               node->blocks[i].listblock->sb = &(node->blocks[i]);
546               node->child[i+1]              = node->child[i];
547             }
548             node->blocks[index+1].startslot     = irv.sb.startslot;
549             node->blocks[index+1].nslots        = irv.sb.nslots;
550             node->blocks[index+1].listblock     = irv.sb.listblock;
551             node->blocks[index+1].listblock->sb = &(node->blocks[index+1]);
552             node->child[index+2]                = irv.btn;
553             node->num_blocks++;
554             if (node->num_blocks == TREE_NODE_SIZE) {   /* split node */
555               btreenode *new_node = create_btree_node();
556               for (i = TREE_NODE_MID + 1; i < TREE_NODE_SIZE; i++) {
557                 j = i - (TREE_NODE_MID + 1);
558                 new_node->blocks[j].startslot     = node->blocks[i].startslot;
559                 new_node->blocks[j].nslots        = node->blocks[i].nslots;
560                 new_node->blocks[j].listblock     = node->blocks[i].listblock;
561                 new_node->blocks[j].listblock->sb = &(new_node->blocks[j]);
562               }
563               for (i = TREE_NODE_MID + 1; i <= TREE_NODE_SIZE; i++) {
564                 new_node->child[i-(TREE_NODE_MID+1)] = node->child[i];
565               }
566               node->num_blocks     = TREE_NODE_MID;
567               new_node->num_blocks = TREE_NODE_SIZE - TREE_NODE_MID - 1;
568
569               irv.sb.startslot = node->blocks[TREE_NODE_MID].startslot;
570               irv.sb.nslots    = node->blocks[TREE_NODE_MID].nslots;
571               irv.sb.listblock = node->blocks[TREE_NODE_MID].listblock;
572               irv.btn          = new_node;
573               return irv;
574             } else {
575               irv.btn = NULL;
576               return irv;
577             }
578           }
579         } else {                                      /* insert to the right */
580           int i, j;
581           for (i = node->num_blocks; i > index + 1; i--) {
582             node->blocks[i].startslot     = node->blocks[i-1].startslot;
583             node->blocks[i].nslots        = node->blocks[i-1].nslots;
584             node->blocks[i].listblock     = node->blocks[i-1].listblock;
585             node->blocks[i].listblock->sb = &(node->blocks[i]);
586           }
587           node->blocks[index+1].startslot = startslot;
588           node->blocks[index+1].nslots    = nslots;
589           node->blocks[index+1].listblock = list_insert(ss, &(node->blocks[index+1]));
590           node->num_blocks++;
591           if (node->num_blocks == TREE_NODE_SIZE) {   /* split node */
592             btreenode *new_node = create_btree_node();
593             for (i = TREE_NODE_MID + 1; i < TREE_NODE_SIZE; i++) {
594               j = i - (TREE_NODE_MID + 1);
595               new_node->blocks[j].startslot     = node->blocks[i].startslot;
596               new_node->blocks[j].nslots        = node->blocks[i].nslots;
597               new_node->blocks[j].listblock     = node->blocks[i].listblock;
598               new_node->blocks[j].listblock->sb = &(new_node->blocks[j]);
599             }
600             node->num_blocks = TREE_NODE_MID;
601             new_node->num_blocks = TREE_NODE_SIZE - TREE_NODE_MID - 1;
602
603             irv.sb.startslot = node->blocks[TREE_NODE_MID].startslot;
604             irv.sb.nslots    = node->blocks[TREE_NODE_MID].nslots;
605             irv.sb.listblock = node->blocks[TREE_NODE_MID].listblock;
606             irv.btn          = new_node;
607             return irv;
608           } else {
609             irv.btn = NULL;
610             return irv;
611           }
612         }
613       } else {                                        /* search to the right */
614         index += inc;
615         if ((inc = inc >> 1) == 0) {
616           inc = 1;
617         }
618       }
619     }
620   }
621
622 }
623
624 static btreenode *btree_insert(slotset *ss, btreenode *node, 
625     CmiInt8 startslot, CmiInt8 nslots) {
626
627   /* check the b-tree root: if it's empty, insert the element in the
628      first position */
629   if (node->num_blocks == 0) {
630
631     node->num_blocks          = 1;
632     node->blocks[0].startslot = startslot;
633     node->blocks[0].nslots    = nslots;
634     node->blocks[0].listblock = list_insert(ss, &(node->blocks[0]));
635
636   } else {
637
638     /* insert into the b-tree */
639     insert_ret_val irv = btree_insert_int(ss, node, startslot, nslots);
640
641     /* if something was returned, we need a new root */
642     if (irv.btn != NULL) {
643       btreenode *new_root  = create_btree_node();
644       new_root->num_blocks = 1;
645       new_root->blocks[0].startslot     = irv.sb.startslot;
646       new_root->blocks[0].nslots        = irv.sb.nslots;
647       new_root->blocks[0].listblock     = irv.sb.listblock;
648       new_root->blocks[0].listblock->sb = &(new_root->blocks[0]);
649       new_root->child[0] = node;
650       new_root->child[1] = irv.btn;
651       node = new_root;
652     }
653
654   }
655
656   return node;
657
658 }
659
660 /*****************************************************************
661  * Delete the slotblock from the b-tree starting at startslot
662  *****************************************************************/
663
664 static void btree_delete_int(slotset *ss, btreenode *node, 
665     CmiInt8 startslot, slotblock *sb) {
666
667   int i, index, inc;
668   int def_child;
669   int num_left, num_right, left_pos, right_pos;
670
671   /* If sb is not NULL, we're sending sb down the tree to a leaf to be
672      swapped with the next larger startslot so it can be deleted from
673      a leaf node (deletions from non-leaf nodes are not allowed
674      here).  At this point, the next larger startslot will always be
675      found by taking the leftmost child.  */
676   if (sb != NULL) {
677
678     if (node->child[0] != NULL) {
679       btree_delete_int(ss, node->child[0], startslot, sb);
680       index = 0;
681
682     } else {
683
684       /* we're now at a leaf node, so the slotblock can be deleted
685
686          first, copy slotblock 0 to the block passed down (sb) and
687          delete the list array node  */
688       list_delete(ss, sb);
689       sb->startslot     = node->blocks[0].startslot;
690       sb->nslots        = node->blocks[0].nslots;
691       sb->listblock     = node->blocks[0].listblock;
692       sb->listblock->sb = sb;
693
694       /* delete the slotblock */
695       for (i = 0; i < (node->num_blocks - 1); i++) {
696         node->blocks[i].startslot     = node->blocks[i+1].startslot;
697         node->blocks[i].nslots        = node->blocks[i+1].nslots;
698         node->blocks[i].listblock     = node->blocks[i+1].listblock;
699         node->blocks[i].listblock->sb = &(node->blocks[i]);
700       }
701       node->num_blocks--;
702
703       return;
704
705     }
706
707   } else {
708
709     /*** Binary search for the slotblock to delete ***/
710
711     /* initialize */
712     index = node->num_blocks >> 1;
713     inc = (index >> 1) + (node->num_blocks & 0x1);
714
715     /* loop until the slotblock with startslot is found */
716     while (1) {
717
718       if (startslot == node->blocks[index].startslot) {   /* found it */
719         if (node->child[index+1] != NULL) {               /* not a leaf */
720           btree_delete_int(ss, node->child[index+1], 
721               startslot, &(node->blocks[index]));
722           break;
723         } else {                                          /* is a leaf */
724           /* delete the slotblock */
725           list_delete(ss, &(node->blocks[index]));
726           for (i = index; i < (node->num_blocks - 1); i++) {
727             node->blocks[i].startslot     = node->blocks[i+1].startslot;
728             node->blocks[i].nslots        = node->blocks[i+1].nslots;
729             node->blocks[i].listblock     = node->blocks[i+1].listblock;
730             node->blocks[i].listblock->sb = &(node->blocks[i]);
731           }
732           node->num_blocks--;
733           return;
734         }
735       } else {
736         if (startslot < node->blocks[index].startslot) {  /* look left */
737           if ((index == 0) ||                             /* take left child */
738               (startslot > node->blocks[index-1].startslot)) {
739             btree_delete_int(ss, node->child[index], startslot, sb);
740             break;
741           } else {                                        /* search left */
742             index -= inc;
743             if ((inc = inc >> 1) == 0) {
744               inc = 1;
745             }
746           }
747         } else {                                          /* look right */
748           if ((index == node->num_blocks - 1) ||          /* take right child */
749               (startslot < node->blocks[index+1].startslot)) {
750             btree_delete_int(ss, node->child[index+1], startslot, sb);
751             break;
752           } else {                                        /* search right */
753             index += inc;
754             if ((inc = inc >> 1) == 0) {
755               inc = 1;
756             }
757           }
758         }
759       }
760
761     }
762
763   }
764
765   /* At this point, the desired slotblock has been removed, and we're
766      going back up the tree.  We must check for deficient nodes that
767      require the rotating or combining of elements to maintain a
768      balanced b-tree. */
769   def_child = -1;
770
771   /* check if one of the child nodes is deficient  */
772   if (node->child[index]->num_blocks < TREE_NODE_MID) {
773     def_child = index;
774   } else if (node->child[index+1]->num_blocks < TREE_NODE_MID) {
775     def_child = index + 1;
776   }
777
778   if (def_child >= 0) {
779
780     /* if there is a left sibling and it has enough elements, rotate */
781     /* to the right */
782     if ((def_child != 0) && (node->child[def_child-1] != NULL) && 
783         (node->child[def_child-1]->num_blocks > TREE_NODE_MID)) {
784
785       /* move all elements in deficient child to the right */
786       for (i = node->child[def_child]->num_blocks; i > 0; i--) {
787         node->child[def_child]->blocks[i].startslot = 
788           node->child[def_child]->blocks[i-1].startslot;
789         node->child[def_child]->blocks[i].nslots = 
790           node->child[def_child]->blocks[i-1].nslots;
791         node->child[def_child]->blocks[i].listblock = 
792           node->child[def_child]->blocks[i-1].listblock;
793         node->child[def_child]->blocks[i].listblock->sb = 
794           &(node->child[def_child]->blocks[i]);
795       }
796       for (i = node->child[def_child]->num_blocks + 1; i > 0; i--) {
797         node->child[def_child]->child[i] = 
798           node->child[def_child]->child[i-1];
799       }
800
801       /* move parent element to the deficient child */
802       node->child[def_child]->blocks[0].startslot = 
803         node->blocks[def_child-1].startslot;
804       node->child[def_child]->blocks[0].nslots = 
805         node->blocks[def_child-1].nslots;
806       node->child[def_child]->blocks[0].listblock = 
807         node->blocks[def_child-1].listblock;
808       node->child[def_child]->blocks[0].listblock->sb = 
809         &(node->child[def_child]->blocks[0]);
810       node->child[def_child]->num_blocks++;
811
812       /* move the right-most child of the parent's left child to the
813          left-most child of the formerly deficient child  */
814       i = node->child[def_child-1]->num_blocks;
815       node->child[def_child]->child[0] = 
816         node->child[def_child-1]->child[i];
817
818       /* move largest element from left child up to the parent */
819       i--;
820       node->blocks[def_child-1].startslot = 
821         node->child[def_child-1]->blocks[i].startslot;
822       node->blocks[def_child-1].nslots = 
823         node->child[def_child-1]->blocks[i].nslots;
824       node->blocks[def_child-1].listblock = 
825         node->child[def_child-1]->blocks[i].listblock;
826       node->blocks[def_child-1].listblock->sb = 
827         &(node->blocks[def_child-1]);
828       node->child[def_child-1]->num_blocks--;
829
830     }
831
832     /* otherwise, if there is a right sibling and it has enough */
833     /* elements, rotate to the left */
834     else if (((def_child + 1) <= node->num_blocks) && 
835         (node->child[def_child+1] != NULL) && 
836         (node->child[def_child+1]->num_blocks > TREE_NODE_MID)) {
837
838       /* move parent element to the deficient child */
839       i = node->child[def_child]->num_blocks;
840       node->child[def_child]->blocks[i].startslot = 
841         node->blocks[def_child].startslot;
842       node->child[def_child]->blocks[i].nslots = 
843         node->blocks[def_child].nslots;
844       node->child[def_child]->blocks[i].listblock = 
845         node->blocks[def_child].listblock;
846       node->child[def_child]->blocks[i].listblock->sb = 
847         &(node->child[def_child]->blocks[i]);
848       node->child[def_child]->num_blocks++;
849
850       /* move the left-most child of the parent's right child to the
851          right-most child of the formerly deficient child  */
852       i++;
853       node->child[def_child]->child[i] = 
854         node->child[def_child+1]->child[0];
855
856       /* move smallest element from right child up to the parent */
857       node->blocks[def_child].startslot = 
858         node->child[def_child+1]->blocks[0].startslot;
859       node->blocks[def_child].nslots = 
860         node->child[def_child+1]->blocks[0].nslots;
861       node->blocks[def_child].listblock = 
862         node->child[def_child+1]->blocks[0].listblock;
863       node->blocks[def_child].listblock->sb = 
864         &(node->blocks[def_child]);
865       node->child[def_child+1]->num_blocks--;
866
867       /* move all elements in the parent's right child to the left  */
868       for (i = 0; i < node->child[def_child+1]->num_blocks; i++) {
869         node->child[def_child+1]->blocks[i].startslot = 
870           node->child[def_child+1]->blocks[i+1].startslot;
871         node->child[def_child+1]->blocks[i].nslots = 
872           node->child[def_child+1]->blocks[i+1].nslots;
873         node->child[def_child+1]->blocks[i].listblock = 
874           node->child[def_child+1]->blocks[i+1].listblock;
875         node->child[def_child+1]->blocks[i].listblock->sb = 
876           &(node->child[def_child+1]->blocks[i]);
877       }
878       for (i = 0; i < node->child[def_child+1]->num_blocks + 1; i++) {
879         node->child[def_child+1]->child[i] = 
880           node->child[def_child+1]->child[i+1];
881       }
882     }
883
884     /* otherwise, merge the deficient node, parent, and the parent's
885        other child (one of the deficient node's siblings) by dropping
886        the parent down to the level of the children */
887     else {
888
889       /* move the parent element into the left child node */
890       i = node->child[index]->num_blocks;
891       node->child[index]->blocks[i].startslot = 
892         node->blocks[index].startslot;
893       node->child[index]->blocks[i].nslots = 
894         node->blocks[index].nslots;
895       node->child[index]->blocks[i].listblock = 
896         node->blocks[index].listblock;
897       node->child[index]->blocks[i].listblock->sb = 
898         &(node->child[index]->blocks[i]);
899       node->child[index]->num_blocks++;
900
901       /* move the elements and children of the right child node to the */
902       /* left child node */
903       num_left  = node->child[index]->num_blocks;
904       num_right = node->child[index+1]->num_blocks;
905       left_pos;
906       right_pos = 0;
907       for (left_pos = num_left; left_pos < num_left + num_right; left_pos++) {
908         node->child[index]->blocks[left_pos].startslot = 
909           node->child[index+1]->blocks[right_pos].startslot;
910         node->child[index]->blocks[left_pos].nslots = 
911           node->child[index+1]->blocks[right_pos].nslots;
912         node->child[index]->blocks[left_pos].listblock = 
913           node->child[index+1]->blocks[right_pos].listblock;
914         node->child[index]->blocks[left_pos].listblock->sb = 
915           &(node->child[index]->blocks[left_pos]);
916         right_pos++;
917       }
918       right_pos = 0;
919       for (left_pos = num_left; left_pos < num_left + num_right + 1; left_pos++) {
920         node->child[index]->child[left_pos] = 
921           node->child[index+1]->child[right_pos];
922         right_pos++;
923       }
924       node->child[index]->num_blocks = num_left + num_right;
925
926       /* delete the right child node */
927       free_reentrant(node->child[index+1]);
928       node->child[index+1] = NULL;
929
930       /* update the parent node */
931       node->num_blocks--;
932       for (i = index; i < node->num_blocks; i++) {
933         node->blocks[i].startslot     = node->blocks[i+1].startslot;
934         node->blocks[i].nslots        = node->blocks[i+1].nslots;
935         node->blocks[i].listblock     = node->blocks[i+1].listblock;
936         node->blocks[i].listblock->sb = &(node->blocks[i]);
937         node->child[i+1]              = node->child[i+2];
938       }
939
940     }
941
942   }
943
944 }
945
946 static btreenode *btree_delete(slotset *ss, btreenode *node, CmiInt8 startslot) {
947
948   /* delete element from the b-tree */
949   btree_delete_int(ss, node, startslot, NULL);
950
951   /* if the root node is empty (from a combine operation on the tree),
952      the left-most child of the root becomes the new root, unless the
953      left-most child is NULL, in which case we leave the root node
954      empty but not NULL */
955   if (node->num_blocks == 0) {
956     if (node->child[0] != NULL) {
957       btreenode *new_root = node->child[0];
958       free_reentrant(node);
959       node = new_root;
960     }
961   }
962
963   return node;
964
965 }
966
967 /*****************************************************************
968  * Creates a new slotset with nslots entries, starting with all empty
969  * slots.  The slot numbers are [startslot, startslot + nslots - 1].
970  *****************************************************************/
971
972 static slotset *new_slotset(CmiInt8 startslot, CmiInt8 nslots) {
973   int i;
974   int list_bin;
975
976   /* CmiPrintf("*** New Isomalloc ***\n"); */
977
978   /* allocate memory for the slotset */
979   slotset *ss = (slotset *)(malloc_reentrant(sizeof(slotset)));
980
981   /* allocate memory for the b-tree */
982   ss->btree_root = create_btree_node();
983
984   /* initialize the b-tree */
985   ss->btree_root->num_blocks          = 1;
986   ss->btree_root->blocks[0].startslot = startslot;
987   ss->btree_root->blocks[0].nslots    = nslots;
988
989   /* initialize the list array */
990   for (i = 0; i < LIST_ARRAY_SIZE; i++) {
991     ss->list_array[i] = NULL;
992   }
993   list_bin = find_list_bin(nslots);
994   ss->list_array[list_bin] = (dllnode *)(malloc_reentrant(sizeof(dllnode)));
995   ss->list_array[list_bin]->previous = NULL;
996   ss->list_array[list_bin]->next = NULL;
997   ss->list_array[list_bin]->sb = &(ss->btree_root->blocks[0]);
998
999   ss->btree_root->blocks[0].listblock = ss->list_array[list_bin];
1000
1001   return ss;
1002
1003 }
1004
1005 /*****************************************************************
1006  * Finds a slotblock containing at least nslots memory slots and
1007  * returns the startslot of that slotblock; returns -1 if no such
1008  * slotblock exists.
1009  *****************************************************************/
1010
1011 static CmiInt8 get_slots(slotset *ss, CmiInt8 nslots) {
1012
1013   /* calculate the smallest bin (list) to look in first */
1014   int start_list = find_list_bin(nslots);
1015
1016   /* search for a slotblock with enough slots */
1017   int i;
1018   dllnode *dlln;
1019   for (i = start_list; i < LIST_ARRAY_SIZE; i++) {
1020     dlln = ss->list_array[i];
1021     while (dlln != NULL) {
1022       if (dlln->sb->nslots >= nslots) {
1023         return dlln->sb->startslot;
1024       }
1025       dlln = dlln->next;
1026     }
1027   }
1028
1029   /* return -1 if no such slotblock exists */
1030   return (-1);
1031
1032 }
1033
1034 /*****************************************************************
1035  * Grab a slotblock with the specified range of blocks (nslots blocks
1036  * starting at sslot).  This is different from get_slots because
1037  * grab_slots specifies the slots to be grabbed and actually grabs
1038  * them (removes them from the set of free slots).  get_slots only
1039  * finds a set of free slots.
1040  *****************************************************************/
1041
1042 static void grab_slots(slotset *ss, CmiInt8 sslot, CmiInt8 nslots) {
1043
1044   CmiInt8 endslot;
1045   slotblock *sb = find_btree_slotblock(ss->btree_root, sslot);
1046
1047   if (sb == NULL) {
1048     CmiAbort("requested a non-existent slotblock\n");
1049   } else {
1050
1051     if (sb->startslot == sslot) {
1052
1053       /* range is exact range of slotblock - delete block from tree */
1054       if (sb->nslots == nslots) {
1055         ss->btree_root = btree_delete(ss, ss->btree_root, sslot);
1056       }
1057
1058       /* range is at beginning of slotblock - update block range */
1059       else {
1060         CmiInt8 old_nslots = sb->nslots;
1061         sb->startslot     += nslots;
1062         sb->nslots        -= nslots;
1063         list_move(ss, sb->listblock, old_nslots);
1064       }
1065
1066     } else {
1067
1068       /* range is at end of slotblock - update block range */
1069       endslot = sb->startslot + sb->nslots - 1;
1070       if (endslot == (sslot + nslots - 1)) {
1071         CmiInt8 old_nslots = sb->nslots;
1072         sb->nslots        -= nslots;
1073         list_move(ss, sb->listblock, old_nslots);
1074       }
1075
1076       /* range is in middle of slotblock - update block range with the */
1077       /* new lower range and insert a block with the new upper range */
1078       else {
1079         CmiInt8 old_nslots = sb->nslots;
1080         sb->nslots         = sslot - sb->startslot;
1081         list_move(ss, sb->listblock, old_nslots);
1082         ss->btree_root = btree_insert(ss, ss->btree_root, sslot + nslots, 
1083             endslot - (sslot + nslots) + 1);
1084       }
1085
1086     }
1087
1088   }
1089
1090 }
1091
1092 /*****************************************************************
1093  * Frees nslots memory slots starting at sslot by either adding them
1094  * to one of the slotblocks that exists (if the slot ranges are
1095  * contiguous) or by creating a new slotblock
1096  *****************************************************************/
1097
1098 static void free_slots(slotset *ss, CmiInt8 sslot, CmiInt8 nslots) {
1099
1100   slotblock *sb_low  = find_btree_slotblock(ss->btree_root, sslot - 1);
1101   slotblock *sb_high = find_btree_slotblock(ss->btree_root, sslot + nslots);
1102
1103   if (sb_low == NULL) {
1104     if (sb_high == NULL) {
1105
1106       /* there is no adjacent slotblock, so create a new one and */
1107       /* insert it in the b-tree */
1108       ss->btree_root = btree_insert(ss, ss->btree_root, sslot, nslots);
1109
1110     } else {
1111
1112       /* there is an adjacent slotblock to the right, so update its range */
1113       CmiInt8 old_nslots = sb_high->nslots;
1114       sb_high->startslot = sslot;
1115       sb_high->nslots   += nslots;
1116       list_move(ss, sb_high->listblock, old_nslots);
1117
1118     }
1119   } else {
1120     if (sb_high == NULL) {
1121
1122       /* there is an adjacent slotblock to the left, so update its range */
1123       CmiInt8 old_nslots  = sb_low->nslots;
1124       sb_low->nslots     += nslots;
1125       list_move(ss, sb_low->listblock, old_nslots);
1126
1127     } else {
1128
1129       /* there are adjacent slotblocks on both sides (i.e., the
1130          slots to be freed exactly span the gap between 2 slotblocks),
1131          so update the range of the lower slotblock and delete the
1132          upper one */
1133       CmiInt8 old_nslots = sb_low->nslots;
1134       sb_low->nslots     = sb_low->nslots + nslots + sb_high->nslots;
1135       list_move(ss, sb_low->listblock, old_nslots);
1136       ss->btree_root = btree_delete(ss, ss->btree_root, sb_high->startslot);
1137
1138     }
1139   }
1140
1141 }
1142
1143 /*****************************************************************
1144  * Recursively free the allocated memory of the b-tree
1145  *****************************************************************/
1146
1147 static void delete_btree(btreenode *node) {
1148   int i;
1149   for (i = 0; i <= node->num_blocks; i++) {
1150     if (node->child[i] != NULL) {
1151       delete_btree(node->child[i]);
1152       free_reentrant(node->child[i]);
1153     } else {
1154       return;
1155     }
1156   }
1157 }
1158
1159 /*****************************************************************
1160  * Free the allocated memory of the list array
1161  *****************************************************************/
1162
1163 static void delete_list_array(slotset *ss) {
1164   int i;
1165   dllnode *dlln;
1166   for (i = 0; i < LIST_ARRAY_SIZE; i++) {
1167     dlln = ss->list_array[i];
1168     if (dlln != NULL) {
1169       while (dlln->next != NULL) {
1170         dlln = dlln->next;
1171       }
1172       while (dlln->previous != NULL) {
1173         dlln = dlln->previous;
1174         free_reentrant(dlln->next);
1175       }
1176       free_reentrant(dlln);
1177     }
1178   }
1179 }
1180
1181 /*****************************************************************
1182  * Free the allocated memory of the slotset
1183  *****************************************************************/
1184
1185 static void delete_slotset(slotset *ss) {
1186   delete_btree(ss->btree_root);
1187   delete_list_array(ss);
1188   free_reentrant(ss->btree_root);
1189   free_reentrant(ss);
1190 }
1191
1192 /*****************************************************************
1193  * Print the contents of the b-tree on the screen in a top-down
1194  * fashion, starting with the root and progressing to the sub-trees
1195  *****************************************************************/
1196
1197 /* prints the elements in a single b-tree node */
1198 static void print_btree_node(btreenode *node, int node_num) {
1199   int i;
1200   CmiPrintf("Node %2d: ", node_num);
1201   for (i = 0; i < node->num_blocks; i++) {
1202     CmiPrintf("%d:[%lld,%lld] ", i, node->blocks[i].startslot, node->blocks[i].nslots);
1203   }
1204   CmiPrintf("\n");
1205 }
1206
1207 /* returns 1 if there's another level to print; 0 if not */
1208 static int print_btree_level(btreenode *node, int level, int current_level, int node_num) {
1209   int i, another_level;
1210   for (i = 0; i <= node->num_blocks; i++) {
1211     if (current_level == level) {
1212       print_btree_node(node, node_num);
1213       if (node->child[0] == NULL) {
1214         return 0;
1215       } else {
1216         return 1;
1217       }
1218     } else {
1219       another_level = print_btree_level(node->child[i], level, 
1220           current_level + 1, i);
1221     }
1222   }
1223   return another_level;
1224 }
1225
1226 static void print_btree_top_down(btreenode *node) {
1227   int level = 0;
1228   int another_level;
1229   do {
1230     CmiPrintf("B-tree Level %d\n", level);
1231     CmiPrintf("---------------\n");
1232     another_level = print_btree_level(node, level, 0, 0);
1233     level++;
1234     CmiPrintf("\n\n");
1235   } while (another_level);
1236 }
1237
1238 /*****************************************************************
1239  * Print the contents of the list arry on the screen
1240  *****************************************************************/
1241
1242 static void print_list_array(slotset *ss) {
1243   int i;
1244   dllnode *dlln;
1245   CmiPrintf("List Array\n");
1246   CmiPrintf("----------\n");
1247   for (i = 0; i < LIST_ARRAY_SIZE; i++) {
1248     CmiPrintf("List %2d: ", i);
1249     dlln = ss->list_array[i];
1250     while (dlln != NULL) {
1251       if (dlln->previous != NULL) {
1252         CmiPrintf("<->");
1253       } else {
1254         CmiPrintf(" ->");
1255       }
1256       CmiPrintf("[%lld,%lld]", dlln->sb->startslot, dlln->sb->nslots);
1257       dlln = dlln->next;
1258     }
1259     CmiPrintf("\n");
1260   }
1261 }
1262
1263 #if CMK_THREADS_DEBUG
1264 static void print_slots(slotset *ss) {
1265   print_btree_top_down(ss->btree_root);
1266   print_list_array(ss);
1267 }
1268 #else
1269 #  define print_slots(ss) /*empty*/
1270 #endif
1271
1272
1273
1274 /* ======================================================================
1275  * Old isomalloc (array-based implementation)
1276  * ====================================================================== */
1277
1278 #else
1279
1280 typedef struct _slotblock
1281 {
1282   CmiInt8 startslot;
1283   CmiInt8 nslots;
1284 } slotblock;
1285
1286 typedef struct _slotset
1287 {
1288   int maxbuf;
1289   slotblock *buf;
1290   CmiInt8 emptyslots;
1291 } slotset;
1292
1293 /*
1294  * creates a new slotset of nslots entries, starting with all
1295  * empty slots. The slot numbers are [startslot,startslot+nslot-1]
1296  */
1297
1298   static slotset *
1299 new_slotset(CmiInt8 startslot, CmiInt8 nslots)
1300 {
1301   /* CmiPrintf("*** Old isomalloc ***\n"); */
1302   int i;
1303   slotset *ss = (slotset*) malloc_reentrant(sizeof(slotset));
1304   _MEMCHECK(ss);
1305   ss->maxbuf = 16;
1306   ss->buf = (slotblock *) malloc_reentrant(sizeof(slotblock)*ss->maxbuf);
1307   _MEMCHECK(ss->buf);
1308   ss->emptyslots = nslots;
1309   ss->buf[0].startslot = startslot;
1310   ss->buf[0].nslots = nslots;
1311   for (i=1; i<ss->maxbuf; i++)
1312     ss->buf[i].nslots = 0;
1313   return ss;
1314 }
1315
1316 /*
1317  * returns new block of empty slots. if it cannot find any, returns (-1).
1318  */
1319
1320   static CmiInt8
1321 get_slots(slotset *ss, CmiInt8 nslots)
1322 {
1323   /* CmiPrintf("old get: nslots=%lld\n", nslots); */
1324   int i;
1325   if(ss->emptyslots < nslots)
1326     return (-1);
1327   for(i=0;i<(ss->maxbuf);i++)
1328     if(ss->buf[i].nslots >= nslots)
1329       return ss->buf[i].startslot;
1330   return (-1);
1331 }
1332
1333 /* just adds a slotblock to an empty position in the given slotset. */
1334
1335   static void
1336 add_slots(slotset *ss, CmiInt8 sslot, CmiInt8 nslots)
1337 {
1338   int pos; 
1339   int emptypos = -1;
1340   if (nslots == 0)
1341     return;
1342   for (pos=0; pos < (ss->maxbuf); pos++) {
1343     if (ss->buf[pos].nslots == 0) {
1344       emptypos = pos;
1345       break; /* found empty slotblock */
1346     }
1347   }
1348   if (emptypos == (-1)) /*no empty slotblock found */
1349   {
1350     int i;
1351     int newsize = ss->maxbuf*2;
1352     slotblock *newbuf = (slotblock *) malloc_reentrant(sizeof(slotblock)*newsize);
1353     _MEMCHECK(newbuf);
1354     for (i=0; i<(ss->maxbuf); i++)
1355       newbuf[i] = ss->buf[i];
1356     for (i=ss->maxbuf; i<newsize; i++)
1357       newbuf[i].nslots  = 0;
1358     free_reentrant(ss->buf);
1359     ss->buf = newbuf;
1360     emptypos = ss->maxbuf;
1361     ss->maxbuf = newsize;
1362   }
1363   ss->buf[emptypos].startslot = sslot;
1364   ss->buf[emptypos].nslots = nslots;
1365   ss->emptyslots += nslots;
1366   return;
1367 }
1368
1369 /* grab a slotblock with specified range of blocks
1370  * this is different from get_slots, since it pre-specifies the
1371  * slots to be grabbed.
1372  */
1373   static void
1374 grab_slots(slotset *ss, CmiInt8 sslot, CmiInt8 nslots)
1375 {
1376   /* CmiPrintf("old grab: sslot=%lld nslots=%lld\n", sslot, nslots); */
1377   CmiInt8 pos, eslot, e;
1378   eslot = sslot + nslots;
1379   for (pos=0; pos < (ss->maxbuf); pos++)
1380   {
1381     if (ss->buf[pos].nslots == 0)
1382       continue;
1383     e = ss->buf[pos].startslot + ss->buf[pos].nslots;
1384     if(sslot >= ss->buf[pos].startslot && eslot <= e)
1385     {
1386       CmiInt8 old_nslots;
1387       old_nslots = ss->buf[pos].nslots;
1388       ss->buf[pos].nslots = sslot - ss->buf[pos].startslot;
1389       ss->emptyslots -= (old_nslots - ss->buf[pos].nslots);
1390       add_slots(ss, sslot + nslots, old_nslots - ss->buf[pos].nslots - nslots);
1391       /* CmiPrintf("grab: sslot=%lld nslots=%lld pos=%lld i=%d\n", sslot, nslots, pos, i); */
1392       return;
1393     }
1394   }
1395   CmiAbort("requested a non-existent slotblock\n");
1396 }
1397
1398 /*
1399  * Frees slot by adding it to one of the blocks of empty slots.
1400  * this slotblock is one which is contiguous with the slots to be freed.
1401  * if it cannot find such a slotblock, it creates a new slotblock.
1402  * If the buffer fills up, it adds up extra buffer space.
1403  */
1404   static void
1405 free_slots(slotset *ss, CmiInt8 sslot, CmiInt8 nslots)
1406 {
1407   /* CmiPrintf("old free: sslot=%lld nslots=%lld\n", sslot, nslots); */
1408   int pos;
1409   /* eslot is the ending slot of the block to be freed */
1410   CmiInt8 eslot = sslot + nslots;
1411   for (pos=0; pos < (ss->maxbuf); pos++)
1412   {
1413     CmiInt8 e = ss->buf[pos].startslot + ss->buf[pos].nslots;
1414     if (ss->buf[pos].nslots == 0)
1415       continue;
1416     /* e is the ending slot of pos'th slotblock */
1417     if (e == sslot) /* append to the current slotblock */
1418     {
1419       ss->buf[pos].nslots += nslots;
1420       ss->emptyslots += nslots;
1421       /* CmiPrintf("free:append pos=%d\n", pos); */
1422       return;
1423     }
1424     if(eslot == ss->buf[pos].startslot) /* prepend to the current slotblock */
1425     {
1426       ss->buf[pos].startslot = sslot;
1427       ss->buf[pos].nslots += nslots;
1428       ss->emptyslots += nslots;
1429       /* CmiPrintf("free:prepend pos=%d\n", pos); */
1430       return;
1431     }
1432   }
1433   /* if we are here, it means we could not find a slotblock that the */
1434   /* block to be freed was combined with. */
1435   /* CmiPrintf("free: pos=%d\n", pos); */
1436   add_slots(ss, sslot, nslots);
1437 }
1438
1439 /*
1440  * destroys slotset-- currently unused
1441  static void
1442  delete_slotset(slotset* ss)
1443  {
1444  free_reentrant(ss->buf);
1445  free_reentrant(ss);
1446  }
1447  */
1448
1449 #if CMK_THREADS_DEBUG
1450   static void
1451 print_slots(slotset *ss)
1452 {
1453   int i;
1454   CmiPrintf("[%d] maxbuf = %d\n", CmiMyPe(), ss->maxbuf);
1455   CmiPrintf("[%d] emptyslots = %d\n", CmiMyPe(), ss->emptyslots);
1456   for(i=0;i<ss->maxbuf;i++) {
1457     if(ss->buf[i].nslots)
1458       CmiPrintf("[%d] (start[%d], end[%d], num=%d) \n", CmiMyPe(), ss->buf[i].startslot, 
1459           ss->buf[i].startslot+ss->buf[i].nslots, ss->buf[i].nslots);
1460   }
1461 }
1462 #else
1463 /*#  define print_slots(ss) */ /*empty*/
1464   static void
1465 print_slots(slotset *ss)
1466 {
1467   int i;
1468   CmiPrintf("[%d] maxbuf = %d\n", CmiMyPe(), ss->maxbuf);
1469   CmiPrintf("[%d] emptyslots = %d\n", CmiMyPe(), ss->emptyslots);
1470   for(i=0;i<ss->maxbuf;i++) {
1471     if(ss->buf[i].nslots)
1472       CmiPrintf("[%d] (start[%d], end[%d], num=%d) \n", CmiMyPe(), ss->buf[i].startslot, 
1473           ss->buf[i].startslot+ss->buf[i].nslots, ss->buf[i].nslots);
1474   }
1475 }
1476
1477 #endif
1478
1479
1480 #endif
1481
1482 /* ======================= END OLD ISOMALLOC ============================ */
1483
1484
1485 /*This version of the allocate/deallocate calls are used if the 
1486   real mmap versions are disabled.*/
1487 static int disabled_map_warned=0;
1488 static void *disabled_map(int nBytes) 
1489 {
1490   if (!disabled_map_warned) {
1491     disabled_map_warned=1;
1492     if (CmiMyPe()==0)
1493       CmiError("charm isomalloc.c> Warning: since mmap() doesn't work,"
1494           " you won't be able to migrate threads\n");
1495   }
1496   return malloc(nBytes);
1497 }
1498 static void disabled_unmap(void *bk) {
1499   free(bk);
1500 }
1501
1502 /*Turn off isomalloc memory, for the given reason*/
1503 static void disable_isomalloc(const char *why)
1504 {
1505   isomallocStart=NULL;
1506   isomallocEnd=NULL;
1507   if (CmiMyPe() == 0)
1508     CmiPrintf("[%d] isomalloc.c> Disabling isomalloc because %s\n",CmiMyPe(),why);
1509 }
1510
1511 #if ! CMK_HAS_MMAP
1512 /****************** Manipulate memory map (Win32 non-version) *****************/
1513 static void *call_mmap_fixed(void *addr,size_t len) {
1514   CmiAbort("isomalloc.c: mmap_fixed should never be called here.");
1515   return NULL;
1516 }
1517 static void *call_mmap_anywhere(size_t len) {
1518   CmiAbort("isomalloc.c: mmap_anywhere should never be called here.");
1519   return NULL;
1520 }
1521 static void call_munmap(void *addr,size_t len) {
1522   CmiAbort("isomalloc.c: munmap should never be called here.");
1523 }
1524
1525   static int 
1526 init_map(char **argv)
1527 {
1528   return 0; /*Isomalloc never works without mmap*/
1529 }
1530 #else /* CMK_HAS_MMAP */
1531 /****************** Manipulate memory map (UNIX version) *****************/
1532 #include <sys/types.h>
1533 #include <sys/mman.h>
1534 #include <sys/stat.h>
1535 #include <fcntl.h>
1536
1537 #if !CMK_HAS_MMAP_ANON
1538 CpvStaticDeclare(int, zerofd); /*File descriptor for /dev/zero, for mmap*/
1539 #endif
1540
1541 /**
1542  * Maps this address with these flags.
1543  */
1544 static void *call_mmap(void *addr,size_t len, int flags) {
1545   void *ret=mmap(addr, len, PROT_READ|PROT_WRITE,
1546 #if CMK_HAS_MMAP_ANON
1547       flags|MAP_PRIVATE|MAP_ANON,-1,
1548 #else
1549       flags|MAP_PRIVATE,CpvAccess(zerofd),
1550 #endif
1551       0);
1552   if (ret==((void*)(-1))) return (void *)0; /* all-ones means failure */
1553   else return ret;
1554 }
1555 static void *call_mmap_fixed(void *addr,size_t len) {
1556   return call_mmap(addr,len,MAP_FIXED);
1557 }
1558 static void *call_mmap_anywhere(size_t len) {
1559   return call_mmap((void *)0,len,0);
1560 }
1561
1562 /* Unmaps this address range */
1563 static void call_munmap(void *addr,size_t len) {
1564   int retval;
1565   if (addr == 0) return; /* NULL address is never mapped */ 
1566   retval = munmap(addr, len);
1567   if (retval==(-1))
1568     CmiAbort("munmap call failed to deallocate requested memory.\n");
1569 }
1570
1571   static int 
1572 init_map(char **argv)
1573 {
1574 #if CMK_HAS_MMAP_ANON
1575   /*Don't need /dev/zero*/
1576 #else
1577   CpvInitialize(int, zerofd);  
1578   CpvAccess(zerofd) = open("/dev/zero", O_RDWR);
1579   if(CpvAccess(zerofd)<0)
1580     return 0; /* Cannot open /dev/zero or use MMAP_ANON, so can't mmap memory */
1581 #endif
1582   return 1;
1583 }
1584
1585 #endif /* UNIX memory map */
1586
1587 /**
1588  * maps the virtual memory associated with slot using mmap
1589  */
1590   static CmiIsomallocBlock *
1591 map_slots(CmiInt8 slot, CmiInt8 nslots)
1592 {
1593   void *pa;
1594   void *addr=slot2addr(slot);
1595   pa = call_mmap_fixed(addr, slotsize*nslots);
1596
1597   if (pa==NULL)
1598   { /*Map just failed completely*/
1599 #if CMK_THREADS_DEBUG
1600     perror("mmap failed");
1601     CmiPrintf("[%d] tried to mmap %p, but encountered error\n",CmiMyPe(),addr);
1602 #endif
1603     return NULL;
1604   }
1605   if (pa != addr)
1606   { /*Map worked, but gave us back the wrong place*/
1607 #if CMK_THREADS_DEBUG
1608     CmiPrintf("[%d] tried to mmap %p, but got %p back\n",CmiMyPe(),addr,pa);
1609 #endif
1610     call_munmap(addr,slotsize*nslots);
1611     return NULL;
1612   }
1613 #if CMK_THREADS_DEBUG
1614   CmiPrintf("[%d] mmap'd slots %ld-%ld to address %p\n",CmiMyPe(),
1615       slot,slot+nslots-1,addr);
1616 #endif
1617   return (CmiIsomallocBlock *)pa;
1618 }
1619
1620 /*
1621  * unmaps the virtual memory associated with slot using munmap
1622  */
1623   static void
1624 unmap_slots(CmiInt8 slot, CmiInt8 nslots)
1625 {
1626   void *addr=slot2addr(slot);
1627   call_munmap(addr, slotsize*nslots);
1628 #if CMK_THREADS_DEBUG
1629   CmiPrintf("[%d] munmap'd slots %ld-%ld from address %p\n",CmiMyPe(),
1630       slot,slot+nslots-1,addr);
1631 #endif
1632 }
1633
1634 static void map_failed(CmiInt8 s,CmiInt8 n)
1635 {
1636   void *addr=slot2addr(s);
1637   CmiError("charm isomalloc.c> map failed to allocate %d bytes at %p, errno:%d.\n",
1638       slotsize*n, addr, errno);
1639   CmiAbort("Exiting\n");
1640 }
1641
1642
1643
1644 /************ Address space voodoo: find free address range **********/
1645
1646 CpvStaticDeclare(slotset *, myss); /*My managed slots*/
1647
1648 #if USE_MEMPOOL_ISOMALLOC
1649 CtvStaticDeclare(mempool_type *, threadpool); /*Thread managed pools*/
1650 #endif
1651
1652 /*This struct describes a range of virtual addresses*/
1653 typedef struct {
1654   char *start; /*First byte of region*/
1655   memRange_t len; /*Number of bytes in region*/
1656   const char *type; /*String describing memory in region (debugging only)*/
1657 } memRegion_t;
1658
1659 /*Estimate the top of the current stack*/
1660 static void *__cur_stack_frame(void)
1661 {
1662   char __dummy;
1663   void *top_of_stack=(void *)&__dummy;
1664   return top_of_stack;
1665 }
1666 /*Estimate the location of the static data region*/
1667 static void *__static_data_loc(void)
1668 {
1669   static char __dummy;
1670   return (void *)&__dummy;
1671 }
1672
1673 /*Pointer comparison is in these subroutines, because
1674   comparing arbitrary pointers is nonportable and tricky.
1675   */
1676 static int pointer_lt(const char *a,const char *b) {
1677   return ((memRange_t)a)<((memRange_t)b);
1678 }
1679 static int pointer_ge(const char *a,const char *b) {
1680   return ((memRange_t)a)>=((memRange_t)b);
1681 }
1682
1683 static char *pmin(char *a,char *b) {return pointer_lt(a,b)?a:b;}
1684 static char *pmax(char *a,char *b) {return pointer_lt(a,b)?b:a;}
1685
1686 const static memRange_t meg=1024u*1024u; /*One megabyte*/
1687 const static memRange_t gig=1024u*1024u*1024u; /*One gigabyte*/
1688
1689 /*Check if this memory location is usable.  
1690   If not, return 1.
1691   */
1692 static int bad_location(char *loc) {
1693   void *addr;
1694   addr=call_mmap_fixed(loc,slotsize);
1695   if (addr==NULL || addr!=loc) {
1696 #if CMK_THREADS_DEBUG
1697     CmiPrintf("[%d] Skipping unmappable space at %p\n",CmiMyPe(),loc);
1698 #endif
1699     return 1; /*No good*/
1700   }
1701   call_munmap(addr,slotsize);
1702   return 0; /*This works*/
1703 }
1704
1705 /* Split this range up into n pieces, returning the size of each piece */
1706 static memRange_t divide_range(memRange_t len,int n) {
1707   return (len+1)/n;
1708 }
1709
1710 /* Return if this memory region has *any* good parts. */
1711 static int partially_good(char *start,memRange_t len,int n) {
1712   int i;
1713   memRange_t quant=divide_range(len,n);
1714   CmiAssert (quant > 0);
1715   for (i=0;i<n;i++)
1716     if (!bad_location(start+i*quant)) return 1; /* it's got some good parts */
1717   return 0; /* all locations are bad */
1718 }
1719
1720 /* Return if this memory region is usable at n samples.  
1721 */
1722 static int good_range(char *start,memRange_t len,int n) {
1723   int i;
1724   memRange_t quant=divide_range(len,n);
1725 #if CMK_THREADS_DEBUG
1726   CmiPrintf("good_range: %lld, %d\n", quant, n);
1727 #endif
1728   CmiAssert (quant > 0);
1729
1730   for (i=0;i<n;i++)
1731     if (bad_location(start+i*quant)) return 0; /* it's got some bad parts */
1732   /* It's all good: */
1733   return 1;
1734 }
1735
1736 /*Check if this entire memory range, or some subset 
1737   of the range, is usable.  If so, write it into max.
1738   */
1739 static void check_range(char *start,char *end,memRegion_t *max)
1740 {
1741   memRange_t len;
1742   CmiUInt8 tb = (CmiUInt8)gig*1024ul;   /* One terabyte */
1743   CmiUInt8 vm_limit = tb*256ul;   /* terabyte */
1744
1745   if (start>=end) return; /*Ran out of hole*/
1746   len=(memRange_t)end-(memRange_t)start;
1747
1748 #if 0
1749   /* too conservative */
1750   if (len/gig>64u) { /* This is an absurd amount of space-- cut it down, for safety */
1751     start+=16u*gig;
1752     end=start+32u*gig;
1753     len=(memRange_t)end-(memRange_t)start;  
1754   }
1755 #else
1756   /* Note: 256TB == 248 bytes.  So a 48-bit virtual-address CPU 
1757    *    can only actually address 256TB of space. */
1758   if (len/tb>10u) { /* This is an absurd amount of space-- cut it down, for safety */
1759     const memRange_t other_libs=16ul*gig; /* space for other libraries to use */
1760     start+=other_libs;
1761     end=pmin(start+vm_limit-2*other_libs, end-other_libs);
1762     len=(memRange_t)end-(memRange_t)start;
1763   }
1764 #endif
1765   if (len<=max->len) return; /*It's too short already!*/
1766 #if CMK_THREADS_DEBUG
1767   CmiPrintf("[%d] Checking at %p - %p\n",CmiMyPe(),start,end);
1768 #endif
1769
1770   /* Check the middle of the range */
1771   if (!good_range(start,len,256)) {
1772     /* Try to split into subranges: */
1773     int i,n=2;
1774 #if CMK_THREADS_DEBUG
1775     CmiPrintf("[%d] Trying to split bad address space at %p - %p...\n",CmiMyPe(),start,end);
1776 #endif
1777     len=divide_range(len,n);
1778     for (i=0;i<n;i++) {
1779       char *cur=start+i*len;
1780       if (partially_good(cur,len,16))
1781         check_range(cur,cur+len,max);
1782     }
1783     return; /* Hopefully one of the subranges will be any good */
1784   }
1785   else /* range is good */
1786   { 
1787 #if CMK_THREADS_DEBUG
1788     CmiPrintf("[%d] Address space at %p - %p is largest\n",CmiMyPe(),start,end);
1789 #endif
1790
1791     /*If we got here, we're the new largest usable range*/
1792     max->len=len;
1793     max->start=start;
1794     max->type="Unused";
1795   }
1796 }
1797
1798 /*Find the first available memory region of at least the
1799   given size not touching any data in the used list.
1800   */
1801 static memRegion_t find_free_region(memRegion_t *used,int nUsed,int atLeast) 
1802 {
1803   memRegion_t max;
1804   int i,j;  
1805
1806   max.start=0; 
1807   max.len=atLeast;
1808   /*Find the largest hole between regions*/
1809   for (i=0;i<nUsed;i++) {
1810     /*Consider a hole starting at the end of region i*/
1811     char *holeStart=used[i].start+used[i].len;
1812     char *holeEnd=(void *)(-1);
1813
1814     /*Shrink the hole by all others*/ 
1815     for (j=0;j<nUsed && pointer_lt(holeStart,holeEnd);j++) {
1816       if (pointer_lt(used[j].start,holeStart)) 
1817         holeStart=pmax(holeStart,used[j].start+used[j].len);
1818       else if (pointer_lt(used[j].start,holeEnd)) 
1819         holeEnd=pmin(holeEnd,used[j].start);
1820     } 
1821
1822     check_range(holeStart,holeEnd,&max);
1823   }
1824
1825   return max; 
1826 }
1827
1828 /*
1829    By looking at the address range carefully, try to find 
1830    the largest usable free region on the machine.
1831    */
1832 static int find_largest_free_region(memRegion_t *destRegion) {
1833   char *staticData =(char *) __static_data_loc();
1834   char *code = (char *)&find_free_region;
1835   char *threadData = (char *)&errno;
1836   char *codeDll = (char *)fprintf;
1837   char *heapLil = (char*) malloc(1);
1838   char *heapBig = (char*) malloc(6*meg);
1839   char *stack = (char *)__cur_stack_frame();
1840   size_t mmapAnyLen = 1*meg;
1841   char *mmapAny = (char*) call_mmap_anywhere(mmapAnyLen);
1842
1843   int i,nRegions=0;
1844   memRegion_t regions[10]; /*used portions of address space*/
1845   memRegion_t freeRegion; /*Largest unused block of address space*/
1846
1847   /*Mark off regions of virtual address space as ususable*/
1848   regions[nRegions].type="NULL";
1849   regions[nRegions].start=NULL; 
1850 #if CMK_POWER7 && CMK_64BIT
1851   regions[nRegions++].len=2u*gig;   /* on bluedrop, don't mess with the lower memory region */
1852 #else
1853   regions[nRegions++].len=16u*meg;
1854 #endif
1855
1856   regions[nRegions].type="Static program data";
1857   regions[nRegions].start=staticData; regions[nRegions++].len=256u*meg;
1858
1859   regions[nRegions].type="Program executable code";
1860   regions[nRegions].start=code; regions[nRegions++].len=256u*meg;
1861
1862   regions[nRegions].type="Heap (small blocks)";
1863   regions[nRegions].start=heapLil; regions[nRegions++].len=1u*gig;
1864
1865   regions[nRegions].type="Heap (large blocks)";
1866   regions[nRegions].start=heapBig; regions[nRegions++].len=1u*gig;
1867
1868   regions[nRegions].type="Stack space";
1869   regions[nRegions].start=stack; regions[nRegions++].len=256u*meg;
1870
1871   regions[nRegions].type="Program dynamically linked code";
1872   regions[nRegions].start=codeDll; regions[nRegions++].len=256u*meg; 
1873
1874   regions[nRegions].type="Result of a non-fixed call to mmap";
1875   regions[nRegions].start=mmapAny; regions[nRegions++].len=2u*gig; 
1876
1877   regions[nRegions].type="Thread private data";
1878   regions[nRegions].start=threadData; regions[nRegions++].len=256u*meg; 
1879
1880   _MEMCHECK(heapBig); free(heapBig);
1881   _MEMCHECK(heapLil); free(heapLil); 
1882   call_munmap(mmapAny,mmapAnyLen);
1883
1884   /*Align each memory region*/
1885   for (i=0;i<nRegions;i++) {
1886     memRegion_t old=regions[i];
1887     memRange_t p=(memRange_t)regions[i].start;
1888     p&=~(regions[i].len-1); /*Round start down to a len-boundary (mask off low bits)*/
1889     regions[i].start=(char *)p;
1890 #if CMK_MACOSX
1891     if (regions[i].start+regions[i].len*2>regions[i].start) regions[i].len *= 2;
1892 #endif
1893 #if CMK_THREADS_DEBUG
1894     CmiPrintf("[%d] Memory map: %p - %p (len: %lu => %lu) %s \n",CmiMyPe(),
1895         regions[i].start,regions[i].start+regions[i].len,
1896         old.len, regions[i].len, regions[i].type);
1897 #endif
1898   }
1899
1900   /*Find a large, unused region in this map: */
1901   freeRegion=find_free_region(regions,nRegions,(512u)*meg);
1902
1903   if (freeRegion.start==0) 
1904   { /*No free address space-- disable isomalloc:*/
1905     return 0;
1906   }
1907   else /* freeRegion is valid */
1908   {
1909     *destRegion=freeRegion;
1910
1911     return 1;
1912   }
1913 }
1914
1915 static int try_largest_mmap_region(memRegion_t *destRegion)
1916 {
1917   void *bad_alloc=(void*)(-1); /* mmap error return address */
1918   void *range, *good_range=NULL;
1919   double shrink = 1.5;
1920   static int count = 0;
1921   size_t size=((size_t)(-1l)), good_size=0;
1922   int retry = 0;
1923   if (sizeof(size_t) >= 8) size = size>>2;  /* 25% of machine address space! */
1924   while (1) { /* test out an allocation of this size */
1925 #if CMK_HAS_MMAP
1926     range=mmap(NULL,size,PROT_READ|PROT_WRITE,
1927         MAP_PRIVATE
1928 #if CMK_HAS_MMAP_ANON
1929         |MAP_ANON
1930 #endif
1931 #if CMK_HAS_MMAP_NORESERVE
1932         |MAP_NORESERVE
1933 #endif
1934         ,-1,0);
1935 #else
1936     range = bad_alloc;
1937 #endif
1938     if (range == bad_alloc) {  /* mmap failed */
1939 #if CMK_THREADS_DEBUG
1940       /* CmiPrintf("[%d] test failed at size: %llu error: %d\n", CmiMyPe(), size, errno);  */
1941 #endif
1942 #if CMK_HAS_USLEEP
1943       if (retry++ < 5) { usleep(rand()%10000); continue; }
1944       else retry = 0;
1945 #endif
1946       size=(double)size/shrink; /* shrink request */
1947       if (size<=0) return 0; /* mmap doesn't work */
1948     }
1949     else { /* this allocation size is available */
1950 #if CMK_THREADS_DEBUG
1951       CmiPrintf("[%d] available: %p, %lld\n", CmiMyPe(), range, size);
1952 #endif
1953       call_munmap(range,size); /* needed/wanted? */
1954       if (size > good_size) {
1955         good_range = range;
1956         good_size = size;
1957         size=((double)size)*1.1;
1958         continue;
1959       }
1960       break;
1961     }
1962   }
1963   CmiAssert(good_range!=NULL);
1964   destRegion->start=good_range; 
1965   destRegion->len=good_size;
1966 #if CMK_THREADS_DEBUG
1967   pid_t pid = getpid();
1968   {
1969     char s[128];
1970     sprintf(s, "cat /proc/%d/maps", pid);
1971     system(s);
1972   }
1973   CmiPrintf("[%d] try_largest_mmap_region: %p, %lld\n", CmiMyPe(), good_range, good_size);
1974 #endif
1975   return 1;
1976 }
1977
1978 #ifndef CMK_CPV_IS_SMP
1979 #define CMK_CPV_IS_SMP
1980 #endif
1981
1982 static void init_ranges(char **argv)
1983 {
1984   memRegion_t freeRegion;
1985   /*Largest value a signed int can hold*/
1986   memRange_t intMax=(((memRange_t)1)<<(sizeof(int)*8-1))-1;
1987   int pagesize = 0;
1988
1989   /*Round slot size up to nearest page size*/
1990   slotsize=16*1024;
1991 #if CMK_HAS_GETPAGESIZE
1992   pagesize = getpagesize();
1993 #endif
1994   if (pagesize < CMK_MEMORY_PAGESIZE)
1995     pagesize = CMK_MEMORY_PAGESIZE;
1996   slotsize=(slotsize+pagesize-1) & ~(pagesize-1);
1997
1998 #if CMK_THREADS_DEBUG
1999   if (CmiMyPe() == 0)
2000     CmiPrintf("[%d] Using slotsize of %d\n", CmiMyPe(), slotsize);
2001 #endif
2002   freeRegion.len=0u;
2003
2004   if (CmiMyRank()==0 && numslots==0)
2005   { /* Find the largest unused region of virtual address space */
2006 #ifdef CMK_MMAP_START_ADDRESS /* Hardcoded start address, for machines where automatic fails */
2007     freeRegion.start=CMK_MMAP_START_ADDRESS;
2008     freeRegion.len=CMK_MMAP_LENGTH_MEGS*meg;
2009 #endif
2010
2011     if (freeRegion.len==0u)  {
2012       if (_mmap_probe == 1) {
2013         if (try_largest_mmap_region(&freeRegion)) _sync_iso = 1;
2014       }
2015       else {
2016         if (freeRegion.len==0u) find_largest_free_region(&freeRegion);
2017       }
2018     }
2019
2020 #if 0
2021     /*Make sure our largest slot number doesn't overflow an int:*/
2022     if (freeRegion.len/slotsize>intMax)
2023       freeRegion.len=intMax*slotsize;
2024 #endif
2025
2026     if (freeRegion.len==0u) {
2027       disable_isomalloc("no free virtual address space");
2028     }
2029     else /* freeRegion.len>0, so can isomalloc */
2030     {
2031 #if CMK_THREADS_DEBUG
2032       CmiPrintf("[%d] Isomalloc memory region: %p - %p (%d megs)\n",CmiMyPe(),
2033           freeRegion.start,freeRegion.start+freeRegion.len,
2034           freeRegion.len/meg);
2035 #endif
2036     }
2037   }             /* end if myrank == 0 */
2038
2039   CmiNodeAllBarrier();
2040
2041   /*
2042      on some machines, isomalloc memory regions on different nodes 
2043      can be different. use +isomalloc_sync to calculate the
2044      intersect of all memory regions on all nodes.
2045      */
2046   if (_sync_iso == 1)
2047   {
2048     if (CmiMyRank() == 0 && freeRegion.len > 0u) {
2049       if (CmiBarrier() == -1 && CmiMyPe()==0) 
2050         CmiAbort("Charm++ Error> +isomalloc_sync requires CmiBarrier() implemented.\n");
2051       else {
2052         CmiUInt8 s = (CmiUInt8)freeRegion.start;
2053         CmiUInt8 e = (CmiUInt8)(freeRegion.start+freeRegion.len);
2054         int fd, i;
2055         char fname[128];
2056
2057         if (CmiMyNode()==0) printf("Charm++> synchronizing isomalloc memory region...\n");
2058
2059         sprintf(fname,".isomalloc.%d", CmiMyNode());
2060
2061         /* remove file before writing for safe */
2062         unlink(fname);
2063 #if CMK_HAS_SYNC && ! CMK_DISABLE_SYNC
2064         system("sync");
2065 #endif
2066
2067         CmiBarrier();
2068
2069         /* write region into file */
2070         while ((fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0644)) == -1) 
2071 #ifndef __MINGW_H
2072           CMK_CPV_IS_SMP
2073 #endif
2074             ;
2075         write(fd, &s, sizeof(CmiUInt8));
2076         write(fd, &e, sizeof(CmiUInt8));
2077         close(fd);
2078
2079 #if CMK_HAS_SYNC && ! CMK_DISABLE_SYNC
2080         system("sync");
2081 #endif
2082
2083         CmiBarrier();
2084
2085         for (i=0; i<CmiNumNodes(); i++) {
2086           CmiUInt8 ss, ee; 
2087           int try_count;
2088           char fname[128];
2089           if (i==CmiMyNode()) continue;
2090           sprintf(fname,".isomalloc.%d", i);
2091           try_count = 0;
2092           while ((fd = open(fname, O_RDONLY)) == -1 && try_count<10000)
2093           {
2094             try_count++;
2095 #ifndef __MINGW_H
2096             CMK_CPV_IS_SMP
2097 #endif
2098               ;
2099           }
2100           if (fd == -1) {
2101             CmiAbort("isomalloc_sync failed, make sure you have a shared file system.");
2102           }
2103           read(fd, &ss, sizeof(CmiUInt8));
2104           read(fd, &ee, sizeof(CmiUInt8));
2105 #if CMK_THREADS_DEBUG
2106           if (CmiMyPe() == 0) CmiPrintf("[%d] load node %d isomalloc region: %lx %lx. \n",
2107               CmiMyPe(), i, ss, ee);
2108 #endif
2109           close(fd);
2110           if (ss>s) s = ss;
2111           if (ee<e) e = ee;
2112         }
2113
2114         CmiBarrier();
2115
2116         unlink(fname);
2117 #if CMK_HAS_SYNC && ! CMK_DISABLE_SYNC
2118         system("sync");
2119 #endif
2120
2121         /* update */
2122         if (s > e)  {
2123           if (CmiMyPe()==0) CmiPrintf("[%d] Invalid isomalloc region: %lx - %lx.\n", CmiMyPe(), s, e);
2124           CmiAbort("isomalloc> failed to find consolidated isomalloc region!");
2125         }
2126         freeRegion.start = (void *)s;
2127         freeRegion.len = (char *)e -(char *)s;
2128
2129         if (CmiMyPe() == 0)
2130           CmiPrintf("[%d] consolidated Isomalloc memory region: %p - %p (%d megs)\n",CmiMyPe(),
2131               freeRegion.start,freeRegion.start+freeRegion.len,
2132               freeRegion.len/meg);
2133       }   /* end of barrier test */
2134     } /* end of rank 0 */
2135     else {
2136       CmiBarrier();
2137       CmiBarrier();
2138       CmiBarrier();
2139       CmiBarrier();
2140     }
2141   }
2142
2143   if (CmiMyRank() == 0 && freeRegion.len > 0u)
2144   {
2145     /*Isomalloc covers entire unused region*/
2146     isomallocStart=freeRegion.start;
2147     isomallocEnd=freeRegion.start+freeRegion.len;
2148     numslots=(freeRegion.len/slotsize)/CmiNumPes();
2149
2150 #if CMK_THREADS_DEBUG
2151     CmiPrintf("[%d] Can isomalloc up to %lu megs per pe\n",CmiMyPe(),
2152         ((memRange_t)numslots)*slotsize/meg);
2153 #endif
2154   }
2155
2156   /*SMP Mode: wait here for rank 0 to initialize numslots before calculating myss*/
2157   CmiNodeAllBarrier(); 
2158
2159   CpvInitialize(slotset *, myss);
2160   CpvAccess(myss) = NULL;
2161
2162 #if USE_MEMPOOL_ISOMALLOC
2163   CtvInitialize(mempool_type *, threadpool);
2164   CtvAccess(threadpool) = NULL;
2165 #endif
2166
2167   if (isomallocStart!=NULL) {
2168     CpvAccess(myss) = new_slotset(pe2slot(CmiMyPe()), numslots);
2169   }
2170 }
2171
2172
2173 /************* Communication: for grabbing/freeing remote slots *********/
2174 typedef struct _slotmsg
2175 {
2176   char cmicore[CmiMsgHeaderSizeBytes];
2177   int pe; /*Source processor*/
2178   CmiInt8 slot; /*First requested slot*/
2179   CmiInt8 nslots; /*Number of requested slots*/
2180 } slotmsg;
2181
2182 static slotmsg *prepare_slotmsg(CmiInt8 slot,CmiInt8 nslots)
2183 {
2184   slotmsg *m=(slotmsg *)CmiAlloc(sizeof(slotmsg));
2185   m->pe=CmiMyPe();
2186   m->slot=slot;
2187   m->nslots=nslots;
2188   return m;
2189 }
2190
2191 static void grab_remote(slotmsg *msg)
2192 {
2193   grab_slots(CpvAccess(myss),msg->slot,msg->nslots);
2194   CmiFree(msg);
2195 }
2196
2197 static void free_remote(slotmsg *msg)
2198 {
2199   free_slots(CpvAccess(myss),msg->slot,msg->nslots);
2200   CmiFree(msg);
2201 }
2202 static int grab_remote_idx, free_remote_idx;
2203
2204 struct slotOP {
2205   /*Function pointer to perform local operation*/
2206   void (*local)(slotset *ss,CmiInt8 s,CmiInt8 n);
2207   /*Index to perform remote operation*/
2208   int remote;
2209 };
2210 typedef struct slotOP slotOP;
2211 static slotOP grabOP,freeOP;
2212
2213 static void init_comm(char **argv)
2214 {
2215   grab_remote_idx=CmiRegisterHandler((CmiHandler)grab_remote);
2216   free_remote_idx=CmiRegisterHandler((CmiHandler)free_remote);  
2217   grabOP.local=grab_slots;
2218   grabOP.remote=grab_remote_idx;
2219   freeOP.local=free_slots;
2220   freeOP.remote=free_remote_idx;        
2221 }
2222
2223 /*Apply the given operation to the given slots which
2224   lie on the given processor.*/
2225 static void one_slotOP(const slotOP *op,int pe,CmiInt8 s,CmiInt8 n)
2226 {
2227   /*Shrink range to only those covered by this processor*/
2228   /*First and last slot for this processor*/
2229   CmiInt8 p_s=pe2slot(pe), p_e=pe2slot(pe+1);
2230   CmiInt8 e=s+n;
2231   if (s<p_s) s=p_s;
2232   if (e>p_e) e=p_e;
2233   n=e-s;
2234
2235   /*Send off range*/
2236   if (pe==CmiMyPe()) 
2237     op->local(CpvAccess(myss),s,n);
2238   else 
2239   {/*Remote request*/
2240     slotmsg *m=prepare_slotmsg(s,n);
2241     CmiSetHandler(m, freeOP.remote);
2242     CmiSyncSendAndFree(pe,sizeof(slotmsg),m);
2243   }
2244 }
2245
2246 /*Apply the given operation to all slots in the range [s, s+n) 
2247   After a restart from checkpoint, a slotset can cross an 
2248   arbitrary set of processors.
2249   */
2250 static void all_slotOP(const slotOP *op,CmiInt8 s,CmiInt8 n)
2251 {
2252   int spe=slot2pe(s), epe=slot2pe(s+n-1);
2253   int pe;
2254   for (pe=spe; pe<=epe; pe++)
2255     one_slotOP(op,pe,s,n);
2256 }
2257
2258 /************** External interface ***************/
2259 void *CmiIsomalloc(int size)
2260 {
2261   CmiInt8 s,n,i;
2262   CmiIsomallocBlock *blk;
2263   if (isomallocStart==NULL) return disabled_map(size);
2264   n=length2slots(size);
2265   /*Always satisfy mallocs with local slots:*/
2266   s=get_slots(CpvAccess(myss),n);
2267   if (s==-1) {
2268     CmiError("Not enough address space left on processor %d to isomalloc %d bytes!\n",
2269         CmiMyPe(),size);
2270     CmiAbort("Out of virtual address space for isomalloc");
2271   }
2272   grab_slots(CpvAccess(myss),s,n);
2273   for (i=0; i<5; i++) {
2274     blk=map_slots(s,n);
2275     if (blk!=NULL) break;
2276 #if CMK_HAS_USLEEP
2277     if (errno == ENOMEM) { usleep(rand()%1000); continue; }
2278     else break;
2279 #endif
2280   }
2281   if (!blk) map_failed(s,n);
2282   blk->slot=s;
2283   blk->length=size;
2284   return block2pointer(blk);
2285 }
2286
2287 #define MALLOC_ALIGNMENT           (2*sizeof(size_t))
2288 #define MINSIZE                    (sizeof(CmiIsomallocBlock))
2289
2290 /** return an aligned isomalloc memory, the alignment occurs after the
2291  *  first 'reserved' bytes.  Total requested size is (size+reserved)
2292  */
2293 static void *_isomallocAlign(size_t align, size_t size, size_t reserved)
2294 {
2295   void *ptr;
2296   CmiIntPtr ptr2align;
2297   CmiInt8 s;
2298
2299   if (align < MINSIZE) align = MINSIZE;
2300   /* make sure alignment is power of 2 */
2301   if ((align & (align - 1)) != 0) {
2302     size_t a = MALLOC_ALIGNMENT * 2;
2303     while ((unsigned long)a < (unsigned long)align) a <<= 1;
2304     align = a;
2305   }
2306   s = size + reserved + align;
2307   ptr = CmiIsomalloc(s);
2308   ptr2align = (CmiIntPtr)ptr;
2309   ptr2align += reserved;
2310   if (ptr2align % align != 0) { /* misaligned */
2311     CmiIsomallocBlock *blk = pointer2block(ptr);  /* save block */
2312     CmiIsomallocBlock savedblk = *blk;
2313     ptr2align = (ptr2align + align - 1) & -((CmiInt8) align);
2314     ptr2align -= reserved;
2315     ptr = (void*)ptr2align;
2316     blk = pointer2block(ptr);      /* restore block */
2317     *blk = savedblk;
2318   }
2319   return ptr;
2320 }
2321
2322 void *CmiIsomallocAlign(size_t align, size_t size)
2323 {
2324   return _isomallocAlign(align, size, 0);
2325 }
2326
2327 int CmiIsomallocEnabled()
2328 {
2329   return (isomallocStart!=NULL);
2330 }
2331
2332 void CmiIsomallocPup(pup_er p,void **blockPtrPtr)
2333 {
2334   CmiIsomallocBlock *blk;
2335   CmiInt8 s,length;
2336   CmiInt8 n;
2337   if (isomallocStart==NULL) CmiAbort("isomalloc is disabled-- cannot use IsomallocPup");
2338
2339   if (!pup_isUnpacking(p)) 
2340   { /*We have an existing block-- unpack start slot & length*/
2341     blk=pointer2block(*blockPtrPtr);
2342     s=blk->slot;
2343     length=blk->length;
2344   }
2345
2346   pup_int8(p,&s);
2347   pup_int8(p,&length);
2348   n=length2slots(length);
2349
2350   if (pup_isUnpacking(p)) 
2351   { /*Must allocate a new block in its old location*/
2352     if (pup_isUserlevel(p) || pup_isRestarting(p))
2353     {   /*Checkpoint: must grab old slots (even remote!)*/
2354       all_slotOP(&grabOP,s,n);
2355     }
2356     blk=map_slots(s,n);
2357     if (!blk) map_failed(s,n);
2358     blk->slot=s;
2359     blk->length=length;
2360     *blockPtrPtr=block2pointer(blk);
2361   }
2362
2363   /*Pup the allocated data*/
2364   pup_bytes(p,*blockPtrPtr,length);
2365
2366   if (pup_isDeleting(p)) 
2367   { /*Unmap old slots, but do not mark as free*/
2368     unmap_slots(s,n);
2369     *blockPtrPtr=NULL; /*Zero out user's pointer*/
2370   }
2371 }
2372
2373 void CmiIsomallocFree(void *blockPtr)
2374 {
2375   if (isomallocStart==NULL) {
2376     disabled_unmap(blockPtr);
2377   }
2378   else if (blockPtr!=NULL)
2379   {
2380     CmiIsomallocBlock *blk=pointer2block(blockPtr);
2381     CmiInt8 s=blk->slot; 
2382     CmiInt8 n=length2slots(blk->length);
2383     unmap_slots(s,n);
2384     /*Mark used slots as free*/
2385     all_slotOP(&freeOP,s,n);
2386   }
2387 }
2388
2389 CmiInt8   CmiIsomallocLength(void *block)
2390 {
2391   return pointer2block(block)->length;
2392 }
2393
2394 /*Return true if this address is in the region managed by isomalloc*/
2395 int CmiIsomallocInRange(void *addr)
2396 {
2397   if (isomallocStart==NULL) return 0; /* There is no range we manage! */
2398   return pointer_ge((char *)addr,isomallocStart) && 
2399     pointer_lt((char*)addr,isomallocEnd);
2400 }
2401
2402 void CmiIsomallocInit(char **argv)
2403 {
2404 #if CMK_NO_ISO_MALLOC
2405   disable_isomalloc("isomalloc disabled by conv-mach");
2406 #else
2407   if (CmiGetArgFlagDesc(argv,"+noisomalloc","disable isomalloc")) {
2408     disable_isomalloc("isomalloc disabled by user.");
2409     return;
2410   }
2411 #if CMK_MMAP_PROBE
2412   _mmap_probe = 1;
2413 #elif CMK_MMAP_TEST
2414   _mmap_probe = 0;
2415 #endif
2416   if (CmiGetArgFlagDesc(argv,"+isomalloc_probe","call mmap to probe the largest available isomalloc region"))
2417     _mmap_probe = 1;
2418   if (CmiGetArgFlagDesc(argv,"+isomalloc_test","mmap test common areas for the largest available isomalloc region"))
2419     _mmap_probe = 0;
2420   if (CmiGetArgFlagDesc(argv,"+isomalloc_sync","synchronize isomalloc region globaly"))
2421     _sync_iso = 1;
2422   init_comm(argv);
2423   if (!init_map(argv)) {
2424     disable_isomalloc("mmap() does not work");
2425   }
2426   else {
2427     if (CmiMyPe() == 0) {
2428       if (read_randomflag() == 1) {    /* randomization stack pointer */
2429         if (_sync_iso == 1)
2430           printf("Warning> Randomization of stack pointer is turned on in kernel.\n");
2431         else
2432           printf("Warning> Randomization of stack pointer is turned on in kernel, thread migration may not work! Run 'echo 0 > /proc/sys/kernel/randomize_va_space' as root to disable it, or try run with '+isomalloc_sync'.  \n");
2433       }
2434     }
2435     init_ranges(argv);
2436   }
2437 #endif
2438 }
2439
2440 /***************** BlockList interface *********
2441   This was moved here from memory-isomalloc.c when it 
2442   was realized that a list-of-isomalloc'd-blocks is useful for
2443   more than just isomalloc heaps.
2444   */
2445
2446 /*Convert a slot to a user address*/
2447 static char *Slot_toUser(CmiIsomallocBlockList *s) {return (char *)(s+1);}
2448 static CmiIsomallocBlockList *Slot_fmUser(void *s) {return ((CmiIsomallocBlockList *)s)-1;}
2449
2450
2451 /*Build a new blockList.*/
2452 CmiIsomallocBlockList *CmiIsomallocBlockListNew(void)
2453 {
2454   CmiIsomallocBlockList *ret;
2455   ret=(CmiIsomallocBlockList *)CmiIsomalloc(sizeof(*ret));
2456   ret->next=ret; /*1-entry circular linked list*/
2457   ret->prev=ret;
2458   return ret;
2459 }
2460
2461
2462 /* BIGSIM_OOC DEBUGGING */
2463 static void print_myslots();
2464
2465 /*Pup all the blocks in this list.  This amounts to two circular
2466   list traversals.  Because everything's isomalloc'd, we don't even
2467   have to restore the pointers-- they'll be restored automatically!
2468   */
2469 void CmiIsomallocBlockListPup(pup_er p,CmiIsomallocBlockList **lp)
2470 {
2471   /* BIGSIM_OOC DEBUGGING */
2472   /* if(!pup_isUnpacking(p)) print_myslots(); */
2473
2474   int i,nBlocks=0;
2475   CmiIsomallocBlockList *cur=NULL, *start=*lp;
2476 #if 0 /*#ifndef CMK_OPTIMIZE*/
2477   if (CpvAccess(isomalloc_blocklist)!=NULL)
2478     CmiAbort("Called CmiIsomallocBlockListPup while a blockList is active!\n"
2479         "You should swap out the active blocklist before pupping.\n");
2480 #endif
2481   /*Count the number of blocks in the list*/
2482   if (!pup_isUnpacking(p)) {
2483     nBlocks=1; /*<- Since we have to skip the start block*/
2484     for (cur=start->next; cur!=start; cur=cur->next) 
2485       nBlocks++;
2486     /*Prepare for next trip around list:*/
2487     cur=start;
2488   }
2489   pup_int(p,&nBlocks);
2490
2491   /*Pup each block in the list*/
2492   for (i=0;i<nBlocks;i++) {
2493     void *newBlock=cur;
2494     if (!pup_isUnpacking(p)) 
2495     { /*While packing, we traverse the list to find our blocks*/
2496       cur=cur->next;
2497     }
2498     CmiIsomallocPup(p,&newBlock);
2499     if (i==0 && pup_isUnpacking(p))
2500       *lp=(CmiIsomallocBlockList *)newBlock;
2501   }
2502   if (pup_isDeleting(p))
2503     *lp=NULL;
2504
2505   /* BIGSIM_OOC DEBUGGING */
2506   /* if(pup_isUnpacking(p)) print_myslots(); */
2507 }
2508
2509 /*Delete all the blocks in this list.*/
2510 void CmiIsomallocBlockListDelete(CmiIsomallocBlockList *l)
2511 {
2512   CmiIsomallocBlockList *start=l;
2513   CmiIsomallocBlockList *cur=start;
2514   if (cur==NULL) return; /*Already deleted*/
2515   do {
2516     CmiIsomallocBlockList *doomed=cur;
2517     cur=cur->next; /*Have to stash next before deleting cur*/
2518     CmiIsomallocFree(doomed);
2519   } while (cur!=start);
2520 }
2521
2522 /*Allocate a block from this blockList*/
2523 void *CmiIsomallocBlockListMalloc(CmiIsomallocBlockList *l,size_t nBytes)
2524 {
2525   CmiIsomallocBlockList *n; /*Newly created slot*/
2526   n=(CmiIsomallocBlockList *)CmiIsomalloc(sizeof(CmiIsomallocBlockList)+nBytes);
2527   /*Link the new block into the circular blocklist*/
2528   n->prev=l;
2529   n->next=l->next;
2530   l->next->prev=n;
2531   l->next=n;
2532   return Slot_toUser(n);
2533 }
2534
2535 /*Allocate a block from this blockList with alighment */
2536 void *CmiIsomallocBlockListMallocAlign(CmiIsomallocBlockList *l,size_t align,size_t nBytes)
2537 {
2538   CmiIsomallocBlockList *n; /*Newly created slot*/
2539   n=(CmiIsomallocBlockList *)_isomallocAlign(align,nBytes,sizeof(CmiIsomallocBlockList));
2540   /*Link the new block into the circular blocklist*/
2541   n->prev=l;
2542   n->next=l->next;
2543   l->next->prev=n;
2544   l->next=n;
2545   return Slot_toUser(n);
2546 }
2547
2548 /*Remove this block from its list and memory*/
2549 void CmiIsomallocBlockListFree(void *block)
2550 {
2551   CmiIsomallocBlockList *n=Slot_fmUser(block);
2552 #if DOHEAPCHECK
2553   if (n->prev->next!=n || n->next->prev!=n) 
2554     CmiAbort("Heap corruption detected in isomalloc block list header!\n"
2555         "  Run with ++debug and look for writes to negative array indices");
2556 #endif
2557   /*Link ourselves out of the blocklist*/
2558   n->prev->next=n->next;
2559   n->next->prev=n->prev;
2560   CmiIsomallocFree(n);
2561 }
2562
2563
2564
2565 /* BIGSIM_OOC DEBUGGING */
2566 static void print_myslots(){
2567   CmiPrintf("[%d] my slot set=%p\n", CmiMyPe(), CpvAccess(myss));
2568   print_slots(CpvAccess(myss));
2569 }
2570
2571
2572