5
/* $Id: shmem.c,v 1.87.2.2 2007-09-10 23:31:32 manoj Exp $ */
6
/* System V shared memory allocation and managment
10
* char *Create_Shared_Region(long *idlist, long size, long *offset)
11
* . to be called by just one process.
12
* . calls kr_malloc, malloc-like memory allocator from the K&R book.
13
* kr_malloc inturn calls armci_allocate() that does shmget() and shmat().
14
* . idlist might be just a pointer to integer or a true array in the
15
* MULTIPLE_REGIONS versions (calling routine has to take care of it)
16
* char *Attach_Shared_Region(long *idlist, long size, long offset)
17
* . called by any other process to attach to existing shmem region or
18
* if attached just calculate the address based on the offset
19
* . has to be called after shmem region was created
20
* void Free_Shmem_Ptr(long id, long size, char* addr)
21
* . called ONLY by the process that created shmem region (id) to return
22
* pointer to kr_malloc (shmem is not destroyed)
23
* void Delete_All_Regions()
24
* . destroys all shared memory regions
25
* . can be called by any process assuming that all processes attached
26
* to alllocated shmem regions
27
* . needs to by called by cleanup procedure(s)
29
* Jarek Nieplocha, 06.13.94
40
/* For debugging purposes at the beginning of the shared memory region
41
* creator process can write a stamp which then is read by attaching processes
42
* NOTE: on clusters we cannot use it anymore since ARMCI node master
43
* uses it since Nov 99 to write the value of address it attached at
44
* This feature is used in the ARMCI memlock table.
50
# include <sys/types.h>
59
# include <sys/param.h>
71
#include "kr_malloc.h"
78
# include <sys/mman.h>
83
static size_t pagesize=0;
84
static int logpagesize=0;
85
/* allow only that big shared memory segment (in MB)- incresed from 128 11/02 */
86
#define MAX_ALLOC_MUNMAP 128
87
#define MAX_ALLOC_MUNMAP_ 368
88
static long max_alloc_munmap=MAX_ALLOC_MUNMAP;
95
#define SHM_UNIT (1024)
98
/* Need to determine the max shmem segment size. There are 2 alternatives:
99
* 1. use predefined SHMMAX if available or set some reasonable values, or
100
* 2. trial-and-error search for a max value (default)
101
* case a) fork a process to determine shmmax size (more accurate)
102
* case b) search w/o forking until success (less accurate)
105
/* under Myrinet GM, we cannot fork */
106
#if defined(GM) || defined(VAPI)
107
# define SHMMAX_SEARCH_NO_FORK
109
#if defined(LAPI) || defined(AIX) || defined(SHMMAX_SEARCH_NO_FORK)
110
# define NO_SHMMAX_SEARCH
113
/* on some platforms with tiny shmmax can try to glue multiple regions */
114
#if (defined(SUN) || defined(SOLARIS)) && !defined(SHMMAX_SEARCH_NO_FORK)
115
# define MULTIPLE_REGIONS
118
/* Limits for the largest shmem segment are in Kilobytes to avoid passing
119
* Gigavalues to kr_malloc
120
* the limit for the KSR is lower than SHMMAX in sys/param.h because
121
* shmat would fail -- SHMMAX cannot be trusted (a bug)
123
#define _SHMMAX 4*1024
125
#if defined(SUN)||defined(SOLARIS)
127
# define _SHMMAX (1024) /* memory in KB */
128
#elif defined(SGI64) || defined(AIX) || defined(CONVEX)
130
# define _SHMMAX ((unsigned long)512*1024)
131
#elif defined(SGI) && !defined(SGI64)
133
# define _SHMMAX ((unsigned long)128*1024)
136
# define _SHMMAX ((unsigned long)512*1024)
139
# define _SHMMAX ((unsigned long)64*1024)
140
#elif defined(__FreeBSD__)
142
# define _SHMMAX ((unsigned long)3*1024)
144
# if !defined(SHMMAX) /* Red Hat does not define SHMMAX */
146
# if defined(__sparc__) || defined(__powerpc__)
147
# define _SHMMAX ((unsigned long)16*1024)
148
# elif defined(__alpha__)
149
# define _SHMMAX ((unsigned long)4072)
152
# define _SHMMAX ((unsigned long)32*1024)
155
#elif defined(SHMMAX)
157
# define _SHMMAX (((unsigned long)SHMMAX)>>10)
160
static unsigned long MinShmem_per_core = 0;
161
static unsigned long MaxShmem_per_core = 0;
162
static unsigned long MinShmem = _SHMMAX;
163
static unsigned long MaxShmem = MAX_REGIONS*_SHMMAX;
164
static context_t ctx_shmem; /* kr_malloc context */
165
static context_t *ctx_shmem_global; /* kr_malloc context stored in shmem */
166
static int create_call=0;
168
#ifdef SHMMAX_SEARCH_NO_FORK
169
static char *ptr_search_no_fork = (char*)0;
170
static int id_search_no_fork=0;
175
#define CLEANUP_CMD(command) sprintf(command,"/usr/bin/ipcrm shm %d",id);
176
#elif defined(SOLARIS)
177
#define CLEANUP_CMD(command) sprintf(command,"/bin/ipcrm -m %d",id);
179
#define CLEANUP_CMD(command) sprintf(command,"/usr/sbin/ipcrm -m %d",id);
181
#define CLEANUP_CMD(command) sprintf(command,"/usr/bin/ipcrm -m %d",id);
187
# include <elan/elan.h>
188
# include <elan3/elan3.h>
189
static char *armci_elan_starting_address = (char*)0;
192
# define ALLOC_MUNMAP_ALIGN 1024*1024
194
# define ALLOC_MUNMAP_ALIGN 64*1024
197
# define ALGN_MALLOC(s,a) elan_allocMain(elan_base->state, (a), (s))
199
# define ALGN_MALLOC(s,a) malloc((s))
202
static char* alloc_munmap(size_t size)
206
size_t bytes = size+pagesize-1;
208
if(armci_elan_starting_address){
209
tmp = armci_elan_starting_address;
210
armci_elan_starting_address += size;
211
# ifdef ALLOC_MUNMAP_ALIGN
212
armci_elan_starting_address += ALLOC_MUNMAP_ALIGN;
214
if(DEBUG_) {printf("%d: address for shm attachment is %p size=%ld\n",
215
armci_me,tmp,(long)size); fflush(stdout); }
217
tmp = ALGN_MALLOC(bytes, getpagesize());
219
iptr = (unsigned long)tmp + pagesize-1;
220
iptr >>= logpagesize; iptr <<= logpagesize;
221
if(DEBUG_) printf("%d:unmap ptr=%p->%p size=%d pagesize=%d\n",armci_me,
222
tmp,(char*)iptr,(int)size,pagesize);
224
if(munmap(tmp, size) == -1) armci_die("munmap failed",0);
225
if(DEBUG_){printf("%d: unmap OK\n",armci_me); fflush(stdout);}
226
}else armci_die("alloc_munmap: malloc failed",(int)size);
232
/*\ A wrapper to shmget. Just to be sure that ID is not 0.
234
static int armci_shmget(size_t size,char *from)
238
id = shmget(IPC_PRIVATE, size, (IPC_CREAT | 00600));
240
/*attaching with id 0 somehow fails (Seen on pentium4+linux24+gm163)
241
*so if id=0, shmget again. */
243
/* free id=0 and get a new one */
244
if(shmctl((int)id,IPC_RMID,(struct shmid_ds *)NULL)) {
245
fprintf(stderr,"id=%d \n",id);
246
armci_die("allocate: failed to _delete_ shared region ",id);
248
id = shmget(IPC_PRIVATE, size, (IPC_CREAT | 00600));
251
printf("\n%d:armci_shmget sz=%ld caller=%s id=%d\n",armci_me,(long)size,
259
/*\ test is a shared memory region of a specified size can be allocated
260
* return 0 (no) or 1 (yes)
262
int armci_test_allocate(long size)
265
int id = armci_shmget((size_t)size,"armci_test_allocate");
268
/* attach to segment */
269
ptr = shmat(id, (char *) NULL, 0);
271
/* delete segment id */
272
if(shmctl( id, IPC_RMID, (struct shmid_ds *)NULL))
273
fprintf(stderr,"failed to remove shm id=%d\n",id);
276
if (((long)ptr) == -1L) return 0;
281
#ifdef SHMMAX_SEARCH_NO_FORK
282
/*\ try to allocate a shared memory region of a specified size; return pointer
284
static int armci_shmalloc_try(long size)
287
int id = armci_shmget((size_t) size,"armci_shmalloc_try");
290
/* attach to segment */
291
ptr = shmat(id, (char *) NULL, 0);
294
if (((long)ptr) == -1L) return 0;
296
ptr_search_no_fork = ptr;
297
id_search_no_fork = id;
305
/* parameters that define range and granularity of search for shm segment size
306
* UBOUND is chosen to be < 2GB to avoid overflowing on 32-bit systems
307
* smaller PAGE gives more accurate results but with more search steps
308
* LBOUND is set to minimum amount for our purposes
309
* change UBOUND=512MB if you need larger arrays than 512 MB
311
#define PAGE (16*65536L)
312
#define LBOUND 1048576L
313
#if defined(MULTI_CTX) && defined(QUADRICS)
314
#define UBOUND 256*LBOUND
316
#define UBOUND 512*LBOUND
319
#define ARMCI_STRINGIFY(str) #str
320
#define ARMCI_CONCAT(str) strL
321
#ifndef ARMCI_DEFAULT_SHMMAX_UBOUND
322
#define ARMCI_DEFAULT_SHMMAX_UBOUND 8192
324
static long get_user_shmmax()
328
uval = getenv("ARMCI_DEFAULT_SHMMAX");
330
sscanf(uval,"%d",&x);
331
if(x<1 || x> ARMCI_DEFAULT_SHMMAX_UBOUND){
333
"incorrect ARMCI_DEFAULT_SHMMAX should be <1,"
334
ARMCI_STRINGIFY(ARMCI_DEFAULT_SHMMAX)
335
">mb and 2^N Found=%ld\n",x);
339
return ((long)x)*1048576L; /* return value in bytes */
342
/*\ determine the max shmem segment size using bisection
344
int armci_shmem_test()
348
long upper_bound=UBOUND;
351
x = get_user_shmmax();
352
if(!x) x = upper_bound;
355
if(DEBUG_){printf("%d: x = %ld upper_bound=%ld\n",armci_me, x, upper_bound); fflush(stdout);}
359
rc = armci_test_allocate(x);
361
printf("%d:test %d size=%ld bytes status=%d\n",armci_me,i,x,rc);
364
step = (upper_bound -x)>>1;
365
if(step < PAGE) break;
369
step = (x-lower_bound)>>1;
373
/* round it up to a full base-2 MB */
380
/* try if can get LBOUND - necessary if search starts from UBOUND */
382
rc = armci_test_allocate(lower_bound);
386
if(DEBUG_) printf("%ld bytes segment size, %d calls \n",lower_bound,i);
387
return (int)( lower_bound>>20); /* return shmmax in mb */
391
#ifdef SHMMAX_SEARCH_NO_FORK
392
/*\ determine the max shmem segment size by halving
394
static int armci_shmem_test_no_fork()
398
long lower_bound=_SHMMAX*SHM_UNIT;
399
#define UBOUND_SEARCH_NO_FORK (256*SHM_UNIT*SHM_UNIT)
401
x = get_user_shmmax();
402
if(!x) x = UBOUND_SEARCH_NO_FORK;
406
rc = armci_shmalloc_try(x);
408
printf("%d:test by halving size=%ld bytes rc=%d\n",armci_me,x,rc);
415
if(x<lower_bound) break;
419
if(DEBUG_) printf("%ld: shmax test no fork: bytes segment size, %d calls \n",lower_bound,i);
420
return (int)( lower_bound>>20); /* return shmmax in mb */
426
void armci_nattach_preallocate_info(int* segments, int *segsize)
430
uval = getenv("LIBELAN_NATTACH");
432
sscanf(uval,"%d",&x);
433
if(x<2 || x>8) armci_die("Error in LIBELAN_NATTACH <8, >1 ",(int)x);
435
armci_die("Inconsistent configuration: ARMCI needs LIBELAN_NATTACH",0);
437
*segsize = (int) (SHM_UNIT * MinShmem);
442
/* Create shared region to store kr_malloc context in shared memory */
443
void armci_krmalloc_init_ctxshmem() {
445
long idlist[SHMIDLEN];
447
int offset = sizeof(void*)/sizeof(int);
449
/* to store shared memory context and myptr */
450
size = SHMEM_CTX_MEM;
452
if(armci_me == armci_master ){
453
myptr = Create_Shared_Region(idlist+1,size,idlist);
454
if(!myptr && size>0 ) armci_die("armci_krmalloc_init_ctxshmem: could not create", (int)(size>>10));
455
if(size) *(volatile void**)myptr = myptr;
457
printf("%d:armci_krmalloc_init_ctxshmem addr mptr=%p ref=%p size=%ld\n", armci_me, myptr, *(void**)myptr, size);
461
/* Bootstrapping: allocate storage for ctx_shmem_global. NOTE:there is
462
offset,as master places its address at begining for others to see */
463
ctx_shmem_global = (context_t*) ( ((int*)myptr)+offset );
464
*ctx_shmem_global = ctx_shmem; /*master copies ctx into shared region */
467
/* broadcast shmem id to other processes on the same cluster node */
468
armci_msg_clus_brdcst(idlist, SHMIDLEN*sizeof(long));
470
if(armci_me != armci_master){
471
myptr=(double*)Attach_Shared_Region(idlist+1,size,idlist[0]);
472
if(!myptr)armci_die("armci_krmalloc_init_ctxshmem: could not attach", (int)(size>>10));
474
/* now every process in a SMP node needs to find out its offset
475
* w.r.t. master - this offset is necessary to use memlock table
477
if(size) armci_set_mem_offset(myptr);
479
printf("%d:armci_krmalloc_init_ctxshmem attached addr mptr=%p ref=%p size=%ld\n", armci_me,myptr, *(void**)myptr,size); fflush(stdout);
481
/* store context info */
482
ctx_shmem_global = (context_t*) ( ((int*)myptr)+offset );
484
printf("%d:armci_krmalloc_init_ctxshmem: shmid=%d off=%ld size=%ld\n", armci_me, ctx_shmem_global->shmid, ctx_shmem_global->shmoffset,
485
(long)ctx_shmem_global->shmsize);
491
void armci_shmem_init()
496
#if defined(QUADRICS)
497
# if (defined(__ia64__) || defined(__alpha)) && !defined(DECOSF)
499
/* this is to determine size of Elan Main memory allocator for munmap */
502
uval = getenv("LIBELAN_ALLOC_SIZE");
504
sscanf(uval,"%ld",&x);
505
if((x>80000000) && (x< 4*1024*1024*1024L)){
506
max_alloc_munmap = (x>>20) - 72;
508
printf("%d: max_alloc_munmap is %ld\n",armci_me,max_alloc_munmap);
514
/* an alternative approach is to use MMAP area where we get
515
the address from the Elan environment variable in qsnetlibs 1.4+ */
516
uval = getenv("LIBELAN3_MMAPBASE");
518
sscanf(uval,"%p",&armci_elan_starting_address);
522
# if defined(__ia64__)
523
/* need aligment on 1MB boundary rather than the actual pagesize */
524
pagesize = 1024*1024;
527
/* determine log2(pagesize) needed for address alignment */
530
pagesize = getpagesize();
531
if(tp>pagesize)armci_die("armci_shmem_init:pagesize",pagesize);
537
if(tp!=pagesize)armci_die("armci_shmem_init:pagesize pow 2",pagesize);
541
printf("page size =%d log=%d\n",pagesize,logpagesize); fflush(stdout); }
546
if(armci_me == armci_master){
547
#if !defined(NO_SHMMAX_SEARCH) || defined(SHMMAX_SEARCH_NO_FORK)
548
# ifdef SHMMAX_SEARCH_NO_FORK
549
int x = armci_shmem_test_no_fork();
551
int x = armci_child_shmem_init();
555
armci_die("no usable amount of shared memory available: only got \n",
558
# if defined(ALLOC_MUNMAP)
559
/* cap down for special memory allocator unless ARMCI_DEFAULT_SHMMAX
560
not set - the user knows what is doing*/
561
# if !defined(REGION_ALLOC)
562
if(!getenv("ARMCI_DEFAULT_SHMMAX"))
563
if(x>max_alloc_munmap && !armci_elan_starting_address) x=max_alloc_munmap;
570
printf("%d:shmem_init: %d mbytes max segment size\n",armci_me,x);fflush(stdout);}
572
MinShmem = (long)(x<<10); /* make sure it is in kb: mb <<10 */
573
MaxShmem = MAX_REGIONS*MinShmem;
574
# ifdef REPORT_SHMMAX
575
printf("%d using x=%d SHMMAX=%ldKB\n", armci_me,x, MinShmem);
580
/* nothing to do here - limits were given */
585
armci_krmalloc_init_ctxshmem();
586
if(DEBUG_)printf("%d: out of shmem_init\n",armci_me);
589
void armci_set_shmem_limit_per_node(int nslaves)
591
if (MaxShmem_per_core > 0) MaxShmem = nslaves*MaxShmem_per_core;
592
if (MinShmem_per_core > 0) MinShmem = nslaves*MinShmem_per_core;
595
void armci_set_shmem_limit_per_core(unsigned long shmemlimit)
597
MaxShmem_per_core = (shmemlimit + SHM_UNIT - 1)/SHM_UNIT;
598
MinShmem_per_core = (shmemlimit + SHM_UNIT - 1)/SHM_UNIT;
601
/*\ application can reset the upper limit (bytes) for memory allocation
603
void armci_set_shmem_limit(unsigned long shmemlimit)
605
unsigned long kbytes;
606
kbytes = (shmemlimit + SHM_UNIT -1)/SHM_UNIT;
607
if(MaxShmem > kbytes) MaxShmem = kbytes;
608
if(MinShmem > kbytes) MinShmem = kbytes;
612
static void shmem_errmsg(size_t size)
615
printf("******************* ARMCI INFO ************************\n");
616
printf("The application attempted to allocate a shared memory segment ");
617
printf("of %ld bytes in size. This might be in addition to segments ",sz);
618
printf("that were allocated succesfully previously. ");
619
printf("The current system configuration does not allow enough ");
620
printf("shared memory to be allocated to the application.\n");
621
printf("This is most often caused by:\n1) system parameter SHMMAX ");
622
printf("(largest shared memory segment) being too small or\n");
623
printf("2) insufficient swap space.\n");
624
printf("Please ask your system administrator to verify if SHMMAX ");
625
printf("matches the amount of memory needed by your application and ");
626
printf("the system has sufficient amount of swap space. ");
627
printf("Most UNIX systems can be easily reconfigured ");
628
printf("to allow larger shared memory segments,\n");
629
printf("see http://www.emsl.pnl.gov/docs/global/support.shtml\n");
630
printf("In some cases, the problem might be caused by insufficient swap space.\n");
631
printf("*******************************************************\n");
635
static struct shm_region_list{
640
}region_list[MAX_REGIONS];
641
static int alloc_regions=0;
642
static long occup_blocks=0;
645
* region - actual piece of shared memory allocated from OS
646
* block - a part of allocated shmem that is given to the requesting process
650
#if defined(MULTIPLE_REGIONS)
651
/********************************* MULTIPLE_REGIONS *******************/
652
/* allocate contiguous shmem -- glue pieces together -- works on SUN
653
* SUN max shmem segment is only 1MB so we might need several to satisfy request
657
/* SHM_OP is an operator to calculate shmem address to attach
658
* might be + or - depending on the system
660
#if defined(DECOSF) || defined(LINUX)
666
static int prev_alloc_regions=0;
669
unsigned long armci_max_region()
671
/* we assume that at least two regions can be glued */
676
* assembles the list of shmem id for the block
678
int find_regions(char *addrp, long* idlist, int *first)
680
int reg, nreg, freg=-1, min_reg, max_reg;
682
/* find the region where addrp belongs */
683
for(reg = 0; reg < alloc_regions-1; reg++){
684
if(region_list[reg].addr < region_list[reg+1].addr){
685
min_reg = reg; max_reg = reg+1;
687
min_reg = reg+1; max_reg = reg;
689
if(region_list[min_reg].addr <= addrp &&
690
region_list[max_reg].addr > addrp){
695
/* if not found yet, it must be the last region */
696
if(freg < 0) freg=alloc_regions-1;
698
if( alloc_regions == prev_alloc_regions){
699
/* no new regions were allocated this time - just get the id */
701
idlist[1] = region_list[freg].id;
703
/* get ids of the allocated regions */
704
idlist[0] = alloc_regions - prev_alloc_regions;
705
if(idlist[0] < 0)armci_die("armci find_regions error ",0);
706
for(reg =prev_alloc_regions,nreg=1; reg <alloc_regions;reg++,nreg++){
707
idlist[nreg] = region_list[reg].id;
709
prev_alloc_regions = alloc_regions;
715
int armci_get_shmem_info(char *addrp, int* shmid, long *shmoffset,
718
armci_die("armci_get_shmem_info: Fix Me",0L);
722
Header *armci_get_shmem_ptr(int shmid, long shmoffset, size_t shmsize)
724
armci_die("armci_get_shmem_ptr: Fix Me",0L);
728
char *Attach_Shared_Region(idlist, size, offset)
729
long *idlist, offset, size;
731
int ir, reg, found, first;
732
char *temp = (char*)0, *pref_addr=(char*)0;
735
printf("%d:AttachSharedRegion %d:size=%ld\n",armci_me,create_call++,size);
739
if(alloc_regions>=MAX_REGIONS)
740
armci_die("Attach_Shared_Region: too many regions ",0L);
742
/* first time needs to initialize region_list structure */
744
for(reg=0;reg<MAX_REGIONS;reg++){
745
region_list[reg].addr=(char*)0;
746
region_list[reg].attached=0;
747
region_list[reg].id=0;
749
MinShmem= idlist[SHMIDLEN-2];
753
* Now, process the idlist list:
754
* . for every shemem ID make sure that it is attached
755
* . calulate shmem address by adding offset to the address for 1st region
756
* . idlist[0] has the number of shmem regions to process
757
* . idlist is assumed to be ordered -- first region comes first etc.
759
pref_addr = (char*)0; /* first time let the OS choose address */
760
for (ir = 0; ir< idlist[0]; ir++){
761
/* search region_list for the current shmem id */
762
for(found =0, reg=0; reg < MAX_REGIONS;reg++)
763
if(found=(region_list[reg].id == idlist[1+ir])) break;
766
/* shmem id is not on the list */
768
region_list[reg].id =idlist[1+ir];
772
/* attach if not attached yet */
773
if(!region_list[reg].attached){
774
/* make sure the next shmem region will be adjacent to previous one */
776
if(temp) pref_addr= temp SHM_OP (MinShmem*SHM_UNIT);
779
pref_addr = alloc_munmap((size_t) (MinShmem*SHM_UNIT));
783
fprintf(stderr,"%d:trying id=%d pref=%ld tmp=%ld u=%d\n",armci_me,
784
idlist[1+ir],pref_addr,temp,MinShmem);
786
if ((long)(temp = (char*)shmat((int)idlist[1+ir], pref_addr, 0))==-1L){
787
fprintf(stderr,"%d:shmat err:id=%d pref=%ld off=%d\n",
788
armci_me, idlist[1+ir],pref_addr,offset);
790
armci_die("AttachSharedRegion:failed to attach",(long)idlist[1+ir]);
792
POST_ALLOC_CHECK(temp,MinShmem*SHM_UNIT);
794
region_list[reg].addr = temp;
795
region_list[reg].attached = 1;
799
printf("%d: Attach_Shared_Region: id=%d pref=%ld got addr=%ld\n",
800
armci_me, idlist[1+ir], pref_addr, temp);
805
/* now we have this region attached and ready to go */
807
if(!ir)first = reg; /* store the first region */
810
reg = first; /* first region on the list */
814
"AttachSharedRegion: reg=%d id= %d off=%d addr=%p addr+off=%p\n",
815
reg,region_list[reg].id, offset, region_list[reg].addr,
816
region_list[reg].addr+ offset);
818
/* check stamp to make sure that we are attached in the right place */
819
if(STAMP) if(*((int*)(region_list[reg].addr+ offset))!= alloc_regions-1){
820
fprintf(stderr, "attach: region=%d ",alloc_regions);
821
armci_die("Attach_Shared_Region: wrong stamp value !",
822
*((int*)(region_list[reg].addr+ offset)));
826
return (region_list[0].addr + offset);
830
/*\ allocates shmem, to be called by kr_malloc that is called by process that
831
* creates shmem region
833
void *armci_allocate(long size)
835
#define min(a,b) ((a)>(b)? (b): (a))
836
char *temp = (char*)0, *pref_addr=(char*)0, *ftemp;
841
printf("%d:Shmem allocate: size %ld bytes\n",armci_me,size);
845
newreg = (size+(SHM_UNIT*MinShmem)-1)/(SHM_UNIT*MinShmem);
847
if( (alloc_regions + newreg)> MAX_REGIONS)
848
armci_die("allocate: to many regions already allocated ",(long)newreg);
850
prev_alloc_regions = alloc_regions;
852
if(DEBUG_)fprintf(stderr, "in allocate size=%ld\n",size);
855
pref_addr = alloc_munmap((size_t) size);
857
pref_addr = (char*)0; /* first time let the OS choose address */
860
/* allocate shmem in as many segments as neccesary */
861
for(i =0; i< newreg; i++){
863
szl =(i==newreg-1)?size-i*MinShmem*SHM_UNIT: min(size,SHM_UNIT*MinShmem);
866
if ( (int)(id = armci_shmget(sz,"MULTIPLE_REGIONarmci_allocate")) < 0){
867
fprintf(stderr,"%d:id=%d size=%d MAX=%ld\n",armci_me,id,szl,MinShmem);
870
armci_die("allocate: failed to create shared region ",id);
873
/* make sure the next shmem region will be adjacent to previous one */
874
if(temp) pref_addr= temp SHM_OP (MinShmem*SHM_UNIT);
876
if(DEBUG_)printf("calling shmat:id=%d adr=%p sz=%ld\n",id,pref_addr,szl);
878
if ( (long)(temp = (char*)shmat(id, pref_addr, 0)) == -1L){
880
CLEANUP_CMD(command);
881
if(system(command) == -1)
882
printf("Please clean shared memory (id=%d): see man ipcrm\n",id);
884
printf("ARMCI shared memory allocator was unable to obtain from ");
885
printf("the operating system multiple segments adjacent to ");
886
printf("each other in order to combine them into a one large ");
887
printf("segment together\n");
889
armci_die("allocate: failed to attach to shared region", 0L);
892
POST_ALLOC_CHECK(temp,MinShmem*SHM_UNIT);
894
region_list[alloc_regions].addr = temp;
895
region_list[alloc_regions].id = id;
896
region_list[alloc_regions].attached=1;
898
if(DEBUG_) fprintf(stderr," allocate:attach: id=%d addr=%p \n",id, temp);
900
if(i==0)ftemp = temp;
902
return (void*)(min(ftemp,temp));
905
/************************** END of MULTIPLE_REGIONS *******************/
907
#else /* Now, the machines where shm segments are not glued together */
909
static int last_allocated=-1;
912
unsigned long armci_max_region()
918
int find_regions(char *addrp, long* id, int *region)
922
if(last_allocated!=-1){
927
for(reg=-1,nreg=0;nreg<alloc_regions; nreg++)
929
if(addrp >= region_list[nreg].addr &&
930
addrp < (region_list[nreg].addr + region_list[nreg].sz))
938
armci_die("find_regions: failed to locate shared region", 0L);
942
*id = region_list[reg].id;
947
/* returns the shmem info based on the addr */
948
int armci_get_shmem_info(char *addrp, int* shmid, long *shmoffset,
953
find_regions(addrp, &id, ®ion);
955
*shmoffset = (long)(addrp - region_list[region].addr);
956
*shmsize = region_list[region].sz;
961
long armci_shm_reg_size(int i, long id)
963
if(i<0 || i>= MAX_REGIONS)armci_die("armci_shmem_reg_size: bad i",i);
964
return region_list[i].sz;
967
void* armci_shm_reg_ptr(int i)
969
if(i<0 || i>= MAX_REGIONS)armci_die("armci_shmem_reg_ptr: bad i",i);
970
return (void *)region_list[i].addr;
973
Header *armci_get_shmem_ptr(int shmid, long shmoffset, size_t shmsize)
975
/* returns, address of the shared memory region based on shmid, offset.
976
* (i.e. return_addr = stating address of shmid + offset)*/
977
long idlist[SHMIDLEN];
980
idlist[1] = (long)shmid;
981
idlist[0] = shmoffset;
982
idlist[IDLOC+1] = shmsize; /* CHECK : idlist in CreateShmem????*/
984
if(!(p=(Header*)Attach_Shared_Region(idlist+1, shmsize, idlist[0])))
985
armci_die("kr_malloc:could not attach",(int)(p->s.shmsize>>10));
987
printf("%d: armci_get_shmem_ptr: %d %ld %ld %p\n",
988
armci_me, idlist[1], idlist[0], shmsize, p);
995
char *Attach_Shared_Region(id, size, offset)
996
long *id, offset, size;
998
int reg, found, shmflag=0;
1001
#if defined(SGI_N32) && defined(SHM_SGI_ANYADDR)
1002
shmflag= SHM_SGI_ANYADDR;
1005
if(alloc_regions>=MAX_REGIONS)
1006
armci_die("Attach_Shared_Region: to many regions ",0);
1009
printf("%d:AttachSharedRegion %d:size=%ld id=%ld\n",
1010
armci_me, create_call++, size,*id);
1015
/* under Linux we can get valid id=0 */
1017
if(!*id) armci_die("Attach_Shared_Region: shmem ID=0 ",(int)*id);
1020
/* first time needs to initialize region_list structure */
1022
for(reg=0;reg<MAX_REGIONS;reg++){
1023
region_list[reg].addr=(char*)0;
1024
region_list[reg].attached=0;
1025
region_list[reg].id=0;
1027
MinShmem= id[SHMIDLEN-2];
1029
printf("%d:attach: allocation unit: %ldK\n",armci_me,MinShmem);
1034
/* search region_list for the current shmem id */
1035
for(found = 0, reg=0; reg < MAX_REGIONS;reg++)
1036
if((found=(region_list[reg].id == *id)))break;
1039
reg = alloc_regions;
1040
region_list[reg].id =*id;
1044
/* we need to use the actual shared memory segment not user req size */
1047
/* attach if not attached yet */
1048
if(!region_list[reg].attached){
1050
# ifdef ALLOC_MUNMAP
1051
char *pref_addr = alloc_munmap((size_t) (size));
1053
char *pref_addr = (char*)0;
1055
if ( (long) (temp = shmat((int) *id, pref_addr, shmflag)) == -1L){
1056
fprintf(stderr,"%d:attach error:id=%ld off=%ld seg=%ld\n",armci_me,*id,offset,MinShmem);
1057
shmem_errmsg((size_t)MinShmem*1024);
1058
armci_die("Attach_Shared_Region:failed to attach to segment id=",(int)*id);
1061
printf("%d:attached: id=%d address=%p\n",armci_me,(int)*id, temp);
1064
POST_ALLOC_CHECK(temp,size);
1065
region_list[reg].addr = temp;
1066
region_list[reg].attached = 1;
1067
region_list[reg].sz= size;
1069
/*SK: Tested only for OPENIB*/
1070
/* armci_region_register_loc(temp, size); */
1075
/* check stamp to make sure that we are attached in the right place */
1076
if(*((int*)(region_list[reg].addr+ offset))!= alloc_regions-1)
1077
armci_die("Attach_Shared_Region: wrong stamp value !",
1078
*((int*)(region_list[reg].addr+ offset)));
1080
return (region_list[reg].addr+ offset);
1084
extern void armci_region_register_shm(void *start, long size);
1087
/*\ allocates shmem, to be called by krmalloc that is called by process that
1088
* creates shmem region
1090
void *armci_allocate(long size)
1094
size_t sz = (size_t)size;
1096
char *pref_addr = alloc_munmap((size_t) (MinShmem*SHM_UNIT));
1098
char *pref_addr = (char*)0;
1100
#if defined(SGI_N32) && defined(SHM_SGI_ANYADDR)
1101
shmflag= SHM_SGI_ANYADDR;
1105
printf("%d:allocate: Shmem allocate size %ld bytes\n",armci_me,size);
1109
if( alloc_regions >= MAX_REGIONS)
1110
armci_die("Create_Shared_Region:allocate:too many regions allocated ",0);
1112
last_allocated = alloc_regions;
1114
#ifdef SHMMAX_SEARCH_NO_FORK
1115
if (ptr_search_no_fork){
1116
temp = ptr_search_no_fork;
1117
id = id_search_no_fork;
1118
ptr_search_no_fork = (char*)0; /* do not look at it again */
1122
if ( (id = armci_shmget(sz,"armci_allocate")) < 0 ) {
1123
fprintf(stderr,"id=%d size=%ld\n",id, size);
1125
armci_die("allocate: failed to create shared region ",id);
1128
if ( (long)( (temp = shmat(id, pref_addr, shmflag))) == -1L){
1130
CLEANUP_CMD(command);
1131
if(system(command) == -1)
1132
printf("Please clean shared memory (id=%d): see man ipcrm\n",id);
1133
armci_die("allocate: failed to attach to shared region id=",id);
1136
printf("%d:allocate:attach:id=%d paddr=%p size=%ld\n",armci_me,id,temp,size);
1139
#if !defined(AIX) && !defined(HPUX64)
1140
/* delete segment id so that OS cleans it when all attached processes are gone */
1141
if(shmctl( id, IPC_RMID, (struct shmid_ds *)NULL))
1142
fprintf(stderr,"failed to remove shm id=%d\n",id);
1146
POST_ALLOC_CHECK(temp,sz);
1148
region_list[alloc_regions].addr = temp;
1149
region_list[alloc_regions].id = id;
1150
region_list[alloc_regions].attached=1;
1151
region_list[alloc_regions].sz=sz;
1155
printf("%d:allocate:id=%d addr=%p size=%ld\n",armci_me,id,temp,size);
1160
armci_region_register_shm(temp, size);
1163
return (void*) (temp);
1168
/******************** common code for the two versions *********************/
1171
/*\ Allocate a block of shared memory - called by master process
1173
char *Create_Shared_Region(long *id, long size, long *offset)
1176
int reg, refreg=0,nreg;
1178
if(alloc_regions>=MAX_REGIONS)
1179
armci_die("Create_Shared_Region: to many regions ",0);
1182
printf("%d:CreateSharedRegion %d:size=%ld\n",armci_me,create_call++,size);
1186
/*initialization: 1st allocation request */
1188
for(reg=0;reg<MAX_REGIONS;reg++){
1189
region_list[reg].addr=(char*)0;
1190
region_list[reg].attached=0;
1191
region_list[reg].id=0;
1194
printf("%d:1st CreateSharedRegion: allocation unit:%ldK,shmax:%ldK\n",
1195
armci_me,MinShmem,MaxShmem);
1199
kr_malloc_init(SHM_UNIT, (size_t)MinShmem, (size_t)MaxShmem,
1200
armci_allocate, 0, &ctx_shmem);
1201
ctx_shmem.ctx_type = KR_CTX_SHMEM;
1202
id[SHMIDLEN-2]=MinShmem;
1205
if(!alloc_regions) temp = kr_malloc((size_t)size, &ctx_shmem);
1206
else temp = kr_malloc((size_t)size, ctx_shmem_global);
1208
if(temp == (char*)0 )
1209
armci_die("CreateSharedRegion:kr_malloc failed KB=",(int)size>>10);
1211
if(!(nreg=find_regions(temp,id,®)))
1212
armci_die("CreateSharedRegion: allocation inconsitent",0);
1214
#ifndef MULTIPLE_REGIONS
1218
if(STAMP) *((int*)temp) = alloc_regions-1;
1219
*offset = (long) (temp - region_list[refreg].addr);
1220
id[IDLOC]=region_list[reg].sz; /* elan post check */
1224
printf("%d:CreateShmReg:reg=%d id=%ld off=%ld ptr=%p adr=%p s=%d n=%d sz=%ld\n",
1225
armci_me,reg,region_list[reg].id,*offset,region_list[reg].addr,
1226
temp,(int)size,nreg,id[IDLOC]);
1235
/*\ only process that created shared region returns the pointer to kr_malloc
1237
void Free_Shmem_Ptr( id, size, addr)
1241
kr_free(addr, ctx_shmem_global);
1245
void Delete_All_Regions()
1250
for(reg = 0; reg < MAX_REGIONS; reg++){
1251
if(region_list[reg].addr != (char*)0){
1252
code += shmctl((int)region_list[reg].id,IPC_RMID,(struct shmid_ds *)NULL);
1253
region_list[reg].addr = (char*)0;
1254
region_list[reg].attached = 0;
1256
fprintf(stderr,"%d Delete_All_Regions id=%d code=%d\n",armci_me,
1257
(int)region_list[reg].id, code);
1265
what are doing here ?