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 = _SHMMAX;
161
static unsigned long MaxShmem = MAX_REGIONS*_SHMMAX;
162
static context_t ctx_shmem; /* kr_malloc context */
163
static context_t *ctx_shmem_global; /* kr_malloc context stored in shmem */
164
static int create_call=0;
166
#ifdef SHMMAX_SEARCH_NO_FORK
167
static char *ptr_search_no_fork = (char*)0;
168
static int id_search_no_fork=0;
173
#define CLEANUP_CMD(command) sprintf(command,"/usr/bin/ipcrm shm %d",id);
174
#elif defined(SOLARIS)
175
#define CLEANUP_CMD(command) sprintf(command,"/bin/ipcrm -m %d",id);
177
#define CLEANUP_CMD(command) sprintf(command,"/usr/sbin/ipcrm -m %d",id);
179
#define CLEANUP_CMD(command) sprintf(command,"/usr/bin/ipcrm -m %d",id);
185
# include <elan/elan.h>
186
# include <elan3/elan3.h>
187
static char *armci_elan_starting_address = (char*)0;
190
# define ALLOC_MUNMAP_ALIGN 1024*1024
192
# define ALLOC_MUNMAP_ALIGN 64*1024
195
# define ALGN_MALLOC(s,a) elan_allocMain(elan_base->state, (a), (s))
197
# define ALGN_MALLOC(s,a) malloc((s))
200
static char* alloc_munmap(size_t size)
204
size_t bytes = size+pagesize-1;
206
if(armci_elan_starting_address){
207
tmp = armci_elan_starting_address;
208
armci_elan_starting_address += size;
209
# ifdef ALLOC_MUNMAP_ALIGN
210
armci_elan_starting_address += ALLOC_MUNMAP_ALIGN;
212
if(DEBUG_) {printf("%d: address for shm attachment is %p size=%ld\n",
213
armci_me,tmp,(long)size); fflush(stdout); }
215
tmp = ALGN_MALLOC(bytes, getpagesize());
217
iptr = (unsigned long)tmp + pagesize-1;
218
iptr >>= logpagesize; iptr <<= logpagesize;
219
if(DEBUG_) printf("%d:unmap ptr=%p->%p size=%d pagesize=%d\n",armci_me,
220
tmp,(char*)iptr,(int)size,pagesize);
222
if(munmap(tmp, size) == -1) armci_die("munmap failed",0);
223
if(DEBUG_){printf("%d: unmap OK\n",armci_me); fflush(stdout);}
224
}else armci_die("alloc_munmap: malloc failed",(int)size);
230
/*\ A wrapper to shmget. Just to be sure that ID is not 0.
232
static int armci_shmget(size_t size,char *from)
236
id = shmget(IPC_PRIVATE, size, (IPC_CREAT | 00600));
238
/*attaching with id 0 somehow fails (Seen on pentium4+linux24+gm163)
239
*so if id=0, shmget again. */
241
/* free id=0 and get a new one */
242
if(shmctl((int)id,IPC_RMID,(struct shmid_ds *)NULL)) {
243
fprintf(stderr,"id=%d \n",id);
244
armci_die("allocate: failed to _delete_ shared region ",id);
246
id = shmget(IPC_PRIVATE, size, (IPC_CREAT | 00600));
249
printf("\n%d:armci_shmget sz=%ld caller=%s id=%d\n",armci_me,(long)size,
257
/*\ test is a shared memory region of a specified size can be allocated
258
* return 0 (no) or 1 (yes)
260
int armci_test_allocate(long size)
263
int id = armci_shmget((size_t)size,"armci_test_allocate");
266
/* attach to segment */
267
ptr = shmat(id, (char *) NULL, 0);
269
/* delete segment id */
270
if(shmctl( id, IPC_RMID, (struct shmid_ds *)NULL))
271
fprintf(stderr,"failed to remove shm id=%d\n",id);
274
if (((long)ptr) == -1L) return 0;
279
#ifdef SHMMAX_SEARCH_NO_FORK
280
/*\ try to allocate a shared memory region of a specified size; return pointer
282
static int armci_shmalloc_try(long size)
285
int id = armci_shmget((size_t) size,"armci_shmalloc_try");
288
/* attach to segment */
289
ptr = shmat(id, (char *) NULL, 0);
292
if (((long)ptr) == -1L) return 0;
294
ptr_search_no_fork = ptr;
295
id_search_no_fork = id;
303
/* parameters that define range and granularity of search for shm segment size
304
* UBOUND is chosen to be < 2GB to avoid overflowing on 32-bit systems
305
* smaller PAGE gives more accurate results but with more search steps
306
* LBOUND is set to minimum amount for our purposes
307
* change UBOUND=512MB if you need larger arrays than 512 MB
309
#define PAGE (16*65536L)
310
#define LBOUND 1048576L
311
#if defined(MULTI_CTX) && defined(QUADRICS)
312
#define UBOUND 256*LBOUND
314
#define UBOUND 512*LBOUND
317
static long get_user_shmmax()
321
uval = getenv("ARMCI_DEFAULT_SHMMAX");
323
sscanf(uval,"%ld",&x);
324
if(x<1L || x> 8192L){
325
fprintf(stderr,"incorrect ARMCI_DEFAULT_SHMMAX should be <1,8192>mb and 2^N Found=%ld\n",x);
329
return x*1048576; /* return value in bytes */
332
/*\ determine the max shmem segment size using bisection
334
int armci_shmem_test()
338
long upper_bound=UBOUND;
341
x = get_user_shmmax();
342
if(!x) x = upper_bound;
345
if(DEBUG_){printf("%d: x = %ld upper_bound=%ld\n",armci_me, x, upper_bound); fflush(stdout);}
349
rc = armci_test_allocate(x);
351
printf("%d:test %d size=%ld bytes status=%d\n",armci_me,i,x,rc);
354
step = (upper_bound -x)>>1;
355
if(step < PAGE) break;
359
step = (x-lower_bound)>>1;
363
/* round it up to a full base-2 MB */
370
/* try if can get LBOUND - necessary if search starts from UBOUND */
372
rc = armci_test_allocate(lower_bound);
376
if(DEBUG_) printf("%ld bytes segment size, %d calls \n",lower_bound,i);
377
return (int)( lower_bound>>20); /* return shmmax in mb */
381
#ifdef SHMMAX_SEARCH_NO_FORK
382
/*\ determine the max shmem segment size by halving
384
static int armci_shmem_test_no_fork()
388
long lower_bound=_SHMMAX*SHM_UNIT;
389
#define UBOUND_SEARCH_NO_FORK (256*SHM_UNIT*SHM_UNIT)
391
x = get_user_shmmax();
392
if(!x) x = UBOUND_SEARCH_NO_FORK;
396
rc = armci_shmalloc_try(x);
398
printf("%d:test by halving size=%ld bytes rc=%d\n",armci_me,x,rc);
405
if(x<lower_bound) break;
409
if(DEBUG_) printf("%ld: shmax test no fork: bytes segment size, %d calls \n",lower_bound,i);
410
return (int)( lower_bound>>20); /* return shmmax in mb */
416
void armci_nattach_preallocate_info(int* segments, int *segsize)
420
uval = getenv("LIBELAN_NATTACH");
422
sscanf(uval,"%d",&x);
423
if(x<2 || x>8) armci_die("Error in LIBELAN_NATTACH <8, >1 ",(int)x);
425
armci_die("Inconsistent configuration: ARMCI needs LIBELAN_NATTACH",0);
427
*segsize = (int) (SHM_UNIT * MinShmem);
432
/* Create shared region to store kr_malloc context in shared memory */
433
void armci_krmalloc_init_ctxshmem() {
435
long idlist[SHMIDLEN];
437
int offset = sizeof(void*)/sizeof(int);
439
/* to store shared memory context and myptr */
440
size = SHMEM_CTX_MEM;
442
if(armci_me == armci_master ){
443
myptr = Create_Shared_Region(idlist+1,size,idlist);
444
if(!myptr && size>0 ) armci_die("armci_krmalloc_init_ctxshmem: could not create", (int)(size>>10));
445
if(size) *(volatile void**)myptr = myptr;
447
printf("%d:armci_krmalloc_init_ctxshmem addr mptr=%p ref=%p size=%ld\n", armci_me, myptr, *(void**)myptr, size);
451
/* Bootstrapping: allocate storage for ctx_shmem_global. NOTE:there is
452
offset,as master places its address at begining for others to see */
453
ctx_shmem_global = (context_t*) ( ((int*)myptr)+offset );
454
*ctx_shmem_global = ctx_shmem; /*master copies ctx into shared region */
457
/* broadcast shmem id to other processes on the same cluster node */
458
armci_msg_clus_brdcst(idlist, SHMIDLEN*sizeof(long));
460
if(armci_me != armci_master){
461
myptr=(double*)Attach_Shared_Region(idlist+1,size,idlist[0]);
462
if(!myptr)armci_die("armci_krmalloc_init_ctxshmem: could not attach", (int)(size>>10));
464
/* now every process in a SMP node needs to find out its offset
465
* w.r.t. master - this offset is necessary to use memlock table
467
if(size) armci_set_mem_offset(myptr);
469
printf("%d:armci_krmalloc_init_ctxshmem attached addr mptr=%p ref=%p size=%ld\n", armci_me,myptr, *(void**)myptr,size); fflush(stdout);
471
/* store context info */
472
ctx_shmem_global = (context_t*) ( ((int*)myptr)+offset );
474
printf("%d:armci_krmalloc_init_ctxshmem: shmid=%d off=%ld size=%ld\n", armci_me, ctx_shmem_global->shmid, ctx_shmem_global->shmoffset,
475
(long)ctx_shmem_global->shmsize);
481
void armci_shmem_init()
486
#if defined(QUADRICS)
487
# if (defined(__ia64__) || defined(__alpha)) && !defined(DECOSF)
489
/* this is to determine size of Elan Main memory allocator for munmap */
492
uval = getenv("LIBELAN_ALLOC_SIZE");
494
sscanf(uval,"%ld",&x);
495
if((x>80000000) && (x< 4*1024*1024*1024L)){
496
max_alloc_munmap = (x>>20) - 72;
498
printf("%d: max_alloc_munmap is %ld\n",armci_me,max_alloc_munmap);
504
/* an alternative approach is to use MMAP area where we get
505
the address from the Elan environment variable in qsnetlibs 1.4+ */
506
uval = getenv("LIBELAN3_MMAPBASE");
508
sscanf(uval,"%p",&armci_elan_starting_address);
512
# if defined(__ia64__)
513
/* need aligment on 1MB boundary rather than the actual pagesize */
514
pagesize = 1024*1024;
517
/* determine log2(pagesize) needed for address alignment */
520
pagesize = getpagesize();
521
if(tp>pagesize)armci_die("armci_shmem_init:pagesize",pagesize);
527
if(tp!=pagesize)armci_die("armci_shmem_init:pagesize pow 2",pagesize);
531
printf("page size =%d log=%d\n",pagesize,logpagesize); fflush(stdout); }
536
if(armci_me == armci_master){
537
#if !defined(NO_SHMMAX_SEARCH) || defined(SHMMAX_SEARCH_NO_FORK)
538
# ifdef SHMMAX_SEARCH_NO_FORK
539
int x = armci_shmem_test_no_fork();
541
int x = armci_child_shmem_init();
545
armci_die("no usable amount of shared memory available: only got \n",
548
# if defined(ALLOC_MUNMAP)
549
/* cap down for special memory allocator unless ARMCI_DEFAULT_SHMMAX
550
not set - the user knows what is doing*/
551
# if !defined(REGION_ALLOC)
552
if(!getenv("ARMCI_DEFAULT_SHMMAX"))
553
if(x>max_alloc_munmap && !armci_elan_starting_address) x=max_alloc_munmap;
560
printf("%d:shmem_init: %d mbytes max segment size\n",armci_me,x);fflush(stdout);}
562
MinShmem = (long)(x<<10); /* make sure it is in kb: mb <<10 */
563
MaxShmem = MAX_REGIONS*MinShmem;
564
# ifdef REPORT_SHMMAX
565
printf("%d using x=%d SHMMAX=%ldKB\n", armci_me,x, MinShmem);
570
/* nothing to do here - limits were given */
575
armci_krmalloc_init_ctxshmem();
576
if(DEBUG_)printf("%d: out of shmem_init\n",armci_me);
580
/*\ application can reset the upper limit (bytes) for memory allocation
582
void armci_set_shmem_limit(unsigned long shmemlimit)
584
unsigned long kbytes;
585
kbytes = (shmemlimit + SHM_UNIT -1)/SHM_UNIT;
586
if(MaxShmem > kbytes) MaxShmem = kbytes;
587
if(MinShmem > kbytes) MinShmem = kbytes;
591
static void shmem_errmsg(size_t size)
594
printf("******************* ARMCI INFO ************************\n");
595
printf("The application attempted to allocate a shared memory segment ");
596
printf("of %ld bytes in size. This might be in addition to segments ",sz);
597
printf("that were allocated succesfully previously. ");
598
printf("The current system configuration does not allow enough ");
599
printf("shared memory to be allocated to the application.\n");
600
printf("This is most often caused by:\n1) system parameter SHMMAX ");
601
printf("(largest shared memory segment) being too small or\n");
602
printf("2) insufficient swap space.\n");
603
printf("Please ask your system administrator to verify if SHMMAX ");
604
printf("matches the amount of memory needed by your application and ");
605
printf("the system has sufficient amount of swap space. ");
606
printf("Most UNIX systems can be easily reconfigured ");
607
printf("to allow larger shared memory segments,\n");
608
printf("see http://www.emsl.pnl.gov/docs/global/support.html\n");
609
printf("In some cases, the problem might be caused by insufficient swap space.\n");
610
printf("*******************************************************\n");
614
static struct shm_region_list{
619
}region_list[MAX_REGIONS];
620
static int alloc_regions=0;
621
static long occup_blocks=0;
624
* region - actual piece of shared memory allocated from OS
625
* block - a part of allocated shmem that is given to the requesting process
629
#if defined(MULTIPLE_REGIONS)
630
/********************************* MULTIPLE_REGIONS *******************/
631
/* allocate contiguous shmem -- glue pieces together -- works on SUN
632
* SUN max shmem segment is only 1MB so we might need several to satisfy request
636
/* SHM_OP is an operator to calculate shmem address to attach
637
* might be + or - depending on the system
639
#if defined(DECOSF) || defined(LINUX)
645
static int prev_alloc_regions=0;
648
unsigned long armci_max_region()
650
/* we assume that at least two regions can be glued */
655
* assembles the list of shmem id for the block
657
int find_regions(char *addrp, long* idlist, int *first)
659
int reg, nreg, freg=-1, min_reg, max_reg;
661
/* find the region where addrp belongs */
662
for(reg = 0; reg < alloc_regions-1; reg++){
663
if(region_list[reg].addr < region_list[reg+1].addr){
664
min_reg = reg; max_reg = reg+1;
666
min_reg = reg+1; max_reg = reg;
668
if(region_list[min_reg].addr <= addrp &&
669
region_list[max_reg].addr > addrp){
674
/* if not found yet, it must be the last region */
675
if(freg < 0) freg=alloc_regions-1;
677
if( alloc_regions == prev_alloc_regions){
678
/* no new regions were allocated this time - just get the id */
680
idlist[1] = region_list[freg].id;
682
/* get ids of the allocated regions */
683
idlist[0] = alloc_regions - prev_alloc_regions;
684
if(idlist[0] < 0)armci_die("armci find_regions error ",0);
685
for(reg =prev_alloc_regions,nreg=1; reg <alloc_regions;reg++,nreg++){
686
idlist[nreg] = region_list[reg].id;
688
prev_alloc_regions = alloc_regions;
694
int armci_get_shmem_info(char *addrp, int* shmid, long *shmoffset,
697
armci_die("armci_get_shmem_info: Fix Me",0L);
701
Header *armci_get_shmem_ptr(int shmid, long shmoffset, size_t shmsize)
703
armci_die("armci_get_shmem_ptr: Fix Me",0L);
707
char *Attach_Shared_Region(idlist, size, offset)
708
long *idlist, offset, size;
710
int ir, reg, found, first;
711
char *temp = (char*)0, *pref_addr=(char*)0;
714
printf("%d:AttachSharedRegion %d:size=%ld\n",armci_me,create_call++,size);
718
if(alloc_regions>=MAX_REGIONS)
719
armci_die("Attach_Shared_Region: too many regions ",0L);
721
/* first time needs to initialize region_list structure */
723
for(reg=0;reg<MAX_REGIONS;reg++){
724
region_list[reg].addr=(char*)0;
725
region_list[reg].attached=0;
726
region_list[reg].id=0;
728
MinShmem= idlist[SHMIDLEN-2];
732
* Now, process the idlist list:
733
* . for every shemem ID make sure that it is attached
734
* . calulate shmem address by adding offset to the address for 1st region
735
* . idlist[0] has the number of shmem regions to process
736
* . idlist is assumed to be ordered -- first region comes first etc.
738
pref_addr = (char*)0; /* first time let the OS choose address */
739
for (ir = 0; ir< idlist[0]; ir++){
740
/* search region_list for the current shmem id */
741
for(found =0, reg=0; reg < MAX_REGIONS;reg++)
742
if(found=(region_list[reg].id == idlist[1+ir])) break;
745
/* shmem id is not on the list */
747
region_list[reg].id =idlist[1+ir];
751
/* attach if not attached yet */
752
if(!region_list[reg].attached){
753
/* make sure the next shmem region will be adjacent to previous one */
755
if(temp) pref_addr= temp SHM_OP (MinShmem*SHM_UNIT);
758
pref_addr = alloc_munmap((size_t) (MinShmem*SHM_UNIT));
762
fprintf(stderr,"%d:trying id=%d pref=%ld tmp=%ld u=%d\n",armci_me,
763
idlist[1+ir],pref_addr,temp,MinShmem);
765
if ((long)(temp = (char*)shmat((int)idlist[1+ir], pref_addr, 0))==-1L){
766
fprintf(stderr,"%d:shmat err:id=%d pref=%ld off=%d\n",
767
armci_me, idlist[1+ir],pref_addr,offset);
769
armci_die("AttachSharedRegion:failed to attach",(long)idlist[1+ir]);
771
POST_ALLOC_CHECK(temp,MinShmem*SHM_UNIT);
773
region_list[reg].addr = temp;
774
region_list[reg].attached = 1;
778
printf("%d: Attach_Shared_Region: id=%d pref=%ld got addr=%ld\n",
779
armci_me, idlist[1+ir], pref_addr, temp);
784
/* now we have this region attached and ready to go */
786
if(!ir)first = reg; /* store the first region */
789
reg = first; /* first region on the list */
793
"AttachSharedRegion: reg=%d id= %d off=%d addr=%p addr+off=%p\n",
794
reg,region_list[reg].id, offset, region_list[reg].addr,
795
region_list[reg].addr+ offset);
797
/* check stamp to make sure that we are attached in the right place */
798
if(STAMP) if(*((int*)(region_list[reg].addr+ offset))!= alloc_regions-1){
799
fprintf(stderr, "attach: region=%d ",alloc_regions);
800
armci_die("Attach_Shared_Region: wrong stamp value !",
801
*((int*)(region_list[reg].addr+ offset)));
805
return (region_list[0].addr + offset);
809
/*\ allocates shmem, to be called by kr_malloc that is called by process that
810
* creates shmem region
812
void *armci_allocate(long size)
814
#define min(a,b) ((a)>(b)? (b): (a))
815
char *temp = (char*)0, *pref_addr=(char*)0, *ftemp;
820
printf("%d:Shmem allocate: size %ld bytes\n",armci_me,size);
824
newreg = (size+(SHM_UNIT*MinShmem)-1)/(SHM_UNIT*MinShmem);
826
if( (alloc_regions + newreg)> MAX_REGIONS)
827
armci_die("allocate: to many regions already allocated ",(long)newreg);
829
prev_alloc_regions = alloc_regions;
831
if(DEBUG_)fprintf(stderr, "in allocate size=%ld\n",size);
834
pref_addr = alloc_munmap((size_t) size);
836
pref_addr = (char*)0; /* first time let the OS choose address */
839
/* allocate shmem in as many segments as neccesary */
840
for(i =0; i< newreg; i++){
842
szl =(i==newreg-1)?size-i*MinShmem*SHM_UNIT: min(size,SHM_UNIT*MinShmem);
845
if ( (int)(id = armci_shmget(sz,"MULTIPLE_REGIONarmci_allocate")) < 0){
846
fprintf(stderr,"%d:id=%d size=%d MAX=%ld\n",armci_me,id,szl,MinShmem);
849
armci_die("allocate: failed to create shared region ",id);
852
/* make sure the next shmem region will be adjacent to previous one */
853
if(temp) pref_addr= temp SHM_OP (MinShmem*SHM_UNIT);
855
if(DEBUG_)printf("calling shmat:id=%d adr=%p sz=%ld\n",id,pref_addr,szl);
857
if ( (long)(temp = (char*)shmat(id, pref_addr, 0)) == -1L){
859
CLEANUP_CMD(command);
860
if(system(command) == -1)
861
printf("Please clean shared memory (id=%d): see man ipcrm\n",id);
863
printf("ARMCI shared memory allocator was unable to obtain from ");
864
printf("the operating system multiple segments adjacent to ");
865
printf("each other in order to combine them into a one large ");
866
printf("segment together\n");
868
armci_die("allocate: failed to attach to shared region", 0L);
871
POST_ALLOC_CHECK(temp,MinShmem*SHM_UNIT);
873
region_list[alloc_regions].addr = temp;
874
region_list[alloc_regions].id = id;
875
region_list[alloc_regions].attached=1;
877
if(DEBUG_) fprintf(stderr," allocate:attach: id=%d addr=%p \n",id, temp);
879
if(i==0)ftemp = temp;
881
return (void*)(min(ftemp,temp));
884
/************************** END of MULTIPLE_REGIONS *******************/
886
#else /* Now, the machines where shm segments are not glued together */
888
static int last_allocated=-1;
891
unsigned long armci_max_region()
897
int find_regions(char *addrp, long* id, int *region)
901
if(last_allocated!=-1){
906
for(reg=-1,nreg=0;nreg<alloc_regions; nreg++)
908
if(addrp >= region_list[nreg].addr &&
909
addrp < (region_list[nreg].addr + region_list[nreg].sz))
917
armci_die("find_regions: failed to locate shared region", 0L);
921
*id = region_list[reg].id;
926
/* returns the shmem info based on the addr */
927
int armci_get_shmem_info(char *addrp, int* shmid, long *shmoffset,
932
find_regions(addrp, &id, ®ion);
934
*shmoffset = (long)(addrp - region_list[region].addr);
935
*shmsize = region_list[region].sz;
940
long armci_shm_reg_size(int i, long id)
942
if(i<0 || i>= MAX_REGIONS)armci_die("armci_shmem_reg_size: bad i",i);
943
return region_list[i].sz;
946
void* armci_shm_reg_ptr(int i)
948
if(i<0 || i>= MAX_REGIONS)armci_die("armci_shmem_reg_ptr: bad i",i);
949
return (void *)region_list[i].addr;
952
Header *armci_get_shmem_ptr(int shmid, long shmoffset, size_t shmsize)
954
/* returns, address of the shared memory region based on shmid, offset.
955
* (i.e. return_addr = stating address of shmid + offset)*/
956
long idlist[SHMIDLEN];
959
idlist[1] = (long)shmid;
960
idlist[0] = shmoffset;
961
idlist[IDLOC+1] = shmsize; /* CHECK : idlist in CreateShmem????*/
963
if(!(p=(Header*)Attach_Shared_Region(idlist+1, shmsize, idlist[0])))
964
armci_die("kr_malloc:could not attach",(int)(p->s.shmsize>>10));
966
printf("%d: armci_get_shmem_ptr: %d %ld %ld %p\n",
967
armci_me, idlist[1], idlist[0], shmsize, p);
974
char *Attach_Shared_Region(id, size, offset)
975
long *id, offset, size;
977
int reg, found, shmflag=0;
980
#if defined(SGI_N32) && defined(SHM_SGI_ANYADDR)
981
shmflag= SHM_SGI_ANYADDR;
984
if(alloc_regions>=MAX_REGIONS)
985
armci_die("Attach_Shared_Region: to many regions ",0);
988
printf("%d:AttachSharedRegion %d:size=%ld id=%ld\n",
989
armci_me, create_call++, size,*id);
994
/* under Linux we can get valid id=0 */
996
if(!*id) armci_die("Attach_Shared_Region: shmem ID=0 ",(int)*id);
999
/* first time needs to initialize region_list structure */
1001
for(reg=0;reg<MAX_REGIONS;reg++){
1002
region_list[reg].addr=(char*)0;
1003
region_list[reg].attached=0;
1004
region_list[reg].id=0;
1006
MinShmem= id[SHMIDLEN-2];
1008
printf("%d:attach: allocation unit: %ldK\n",armci_me,MinShmem);
1013
/* search region_list for the current shmem id */
1014
for(found = 0, reg=0; reg < MAX_REGIONS;reg++)
1015
if((found=(region_list[reg].id == *id)))break;
1018
reg = alloc_regions;
1019
region_list[reg].id =*id;
1023
/* we need to use the actual shared memory segment not user req size */
1026
/* attach if not attached yet */
1027
if(!region_list[reg].attached){
1029
# ifdef ALLOC_MUNMAP
1030
char *pref_addr = alloc_munmap((size_t) (size));
1032
char *pref_addr = (char*)0;
1034
if ( (long) (temp = shmat((int) *id, pref_addr, shmflag)) == -1L){
1035
fprintf(stderr,"%d:attach error:id=%ld off=%ld seg=%ld\n",armci_me,*id,offset,MinShmem);
1036
shmem_errmsg((size_t)MinShmem*1024);
1037
armci_die("Attach_Shared_Region:failed to attach to segment id=",(int)*id);
1040
printf("%d:attached: id=%d address=%p\n",armci_me,(int)*id, temp);
1043
POST_ALLOC_CHECK(temp,size);
1044
region_list[reg].addr = temp;
1045
region_list[reg].attached = 1;
1046
region_list[reg].sz= size;
1048
/*SK: Tested only for OPENIB*/
1049
/* armci_region_register_loc(temp, size); */
1054
/* check stamp to make sure that we are attached in the right place */
1055
if(*((int*)(region_list[reg].addr+ offset))!= alloc_regions-1)
1056
armci_die("Attach_Shared_Region: wrong stamp value !",
1057
*((int*)(region_list[reg].addr+ offset)));
1059
return (region_list[reg].addr+ offset);
1063
extern void armci_region_register_shm(void *start, long size);
1066
/*\ allocates shmem, to be called by krmalloc that is called by process that
1067
* creates shmem region
1069
void *armci_allocate(long size)
1073
size_t sz = (size_t)size;
1075
char *pref_addr = alloc_munmap((size_t) (MinShmem*SHM_UNIT));
1077
char *pref_addr = (char*)0;
1079
#if defined(SGI_N32) && defined(SHM_SGI_ANYADDR)
1080
shmflag= SHM_SGI_ANYADDR;
1084
printf("%d:allocate: Shmem allocate size %ld bytes\n",armci_me,size);
1088
if( alloc_regions >= MAX_REGIONS)
1089
armci_die("Create_Shared_Region:allocate:too many regions allocated ",0);
1091
last_allocated = alloc_regions;
1093
#ifdef SHMMAX_SEARCH_NO_FORK
1094
if (ptr_search_no_fork){
1095
temp = ptr_search_no_fork;
1096
id = id_search_no_fork;
1097
ptr_search_no_fork = (char*)0; /* do not look at it again */
1101
if ( (id = armci_shmget(sz,"armci_allocate")) < 0 ) {
1102
fprintf(stderr,"id=%d size=%ld\n",id, size);
1104
armci_die("allocate: failed to create shared region ",id);
1107
if ( (long)( (temp = shmat(id, pref_addr, shmflag))) == -1L){
1109
CLEANUP_CMD(command);
1110
if(system(command) == -1)
1111
printf("Please clean shared memory (id=%d): see man ipcrm\n",id);
1112
armci_die("allocate: failed to attach to shared region id=",id);
1115
printf("%d:allocate:attach:id=%d paddr=%p size=%ld\n",armci_me,id,temp,size);
1118
#if !defined(AIX) && !defined(HPUX64)
1119
/* delete segment id so that OS cleans it when all attached processes are gone */
1120
if(shmctl( id, IPC_RMID, (struct shmid_ds *)NULL))
1121
fprintf(stderr,"failed to remove shm id=%d\n",id);
1125
POST_ALLOC_CHECK(temp,sz);
1127
region_list[alloc_regions].addr = temp;
1128
region_list[alloc_regions].id = id;
1129
region_list[alloc_regions].attached=1;
1130
region_list[alloc_regions].sz=sz;
1134
printf("%d:allocate:id=%d addr=%p size=%ld\n",armci_me,id,temp,size);
1139
armci_region_register_shm(temp, size);
1142
return (void*) (temp);
1147
/******************** common code for the two versions *********************/
1150
/*\ Allocate a block of shared memory - called by master process
1152
char *Create_Shared_Region(long *id, long size, long *offset)
1155
int reg, refreg=0,nreg;
1157
if(alloc_regions>=MAX_REGIONS)
1158
armci_die("Create_Shared_Region: to many regions ",0);
1161
printf("%d:CreateSharedRegion %d:size=%ld\n",armci_me,create_call++,size);
1165
/*initialization: 1st allocation request */
1167
for(reg=0;reg<MAX_REGIONS;reg++){
1168
region_list[reg].addr=(char*)0;
1169
region_list[reg].attached=0;
1170
region_list[reg].id=0;
1173
printf("%d:1st CreateSharedRegion: allocation unit:%ldK,shmax:%ldK\n",
1174
armci_me,MinShmem,MaxShmem);
1178
kr_malloc_init(SHM_UNIT, (size_t)MinShmem, (size_t)MaxShmem,
1179
armci_allocate, 0, &ctx_shmem);
1180
ctx_shmem.ctx_type = KR_CTX_SHMEM;
1181
id[SHMIDLEN-2]=MinShmem;
1184
if(!alloc_regions) temp = kr_malloc((size_t)size, &ctx_shmem);
1185
else temp = kr_malloc((size_t)size, ctx_shmem_global);
1187
if(temp == (char*)0 )
1188
armci_die("CreateSharedRegion:kr_malloc failed KB=",(int)size>>10);
1190
if(!(nreg=find_regions(temp,id,®)))
1191
armci_die("CreateSharedRegion: allocation inconsitent",0);
1193
#ifndef MULTIPLE_REGIONS
1197
if(STAMP) *((int*)temp) = alloc_regions-1;
1198
*offset = (long) (temp - region_list[refreg].addr);
1199
id[IDLOC]=region_list[reg].sz; /* elan post check */
1203
printf("%d:CreateShmReg:reg=%d id=%ld off=%ld ptr=%p adr=%p s=%d n=%d sz=%ld\n",
1204
armci_me,reg,region_list[reg].id,*offset,region_list[reg].addr,
1205
temp,(int)size,nreg,id[IDLOC]);
1214
/*\ only process that created shared region returns the pointer to kr_malloc
1216
void Free_Shmem_Ptr( id, size, addr)
1220
kr_free(addr, ctx_shmem_global);
1224
void Delete_All_Regions()
1229
for(reg = 0; reg < MAX_REGIONS; reg++){
1230
if(region_list[reg].addr != (char*)0){
1231
code += shmctl((int)region_list[reg].id,IPC_RMID,(struct shmid_ds *)NULL);
1232
region_list[reg].addr = (char*)0;
1233
region_list[reg].attached = 0;
1235
fprintf(stderr,"%d Delete_All_Regions id=%d code=%d\n",armci_me,
1236
(int)region_list[reg].id, code);
1244
what are doing here ?