static char rcsid[] = "$Id: pvm_shmd.c,v 1.2 1999/03/12 20:22:39 pvmsrc Exp $"; #include #include #include #include #include #include #include #include #include #include #include #include /* GEF libs */ #include "shmd.h" /* Prototypes */ unsigned int get_max_seg_size(); unsigned int create_segments(); void clean_segs(); int make_mqueue(); int del_mqueue(); void bambismother(); void huphuphup(); /* Consts */ /* #define MAXSEGS 255 */ /* in the header files now */ /* well its a limit and we do need one */ /* can be controlled by ifdef or ENV vars */ /* at run-time */ #ifndef SHM_FAILED #define SHM_FAILED (void*)-1 #endif #define FAILEDCOUNT (10) /* Globals */ unsigned segsize; unsigned numsegs; key_t keys[MAXSEGS]; int shmids[MAXSEGS]; void* segptrs[MAXSEGS]; unsigned totalmem; main(argc, argv) int argc; char *argv[]; { int i,id; key_t key; int semid; struct shmid_ds shmsbuf; unsigned size; int pagesize; size_t bsize, bsizepb, o1, o2, o3; /* for working out mem offsets */ int pages[MAXSEGS]; char* addr; unsigned firstpagehdr; int tid; int bufid, from, bytes, msgtag; int died; int tidslots; /* not an array, but number of tids I can handle at once */ int slot, left, join; key_t mqkey; int mqid; int j, cc; int finished=0; /* first things first */ /* The PVM stuff */ tid = pvm_mytid(); if (tid<=0) { fprintf(stderr,"Cannot join the virtual machine.\n"); exit (-3); } if (register_shmd (tid)) { fprintf(stderr,"Cannot setup system mailbox entry.\n"); exit (-4); } o1 = (size_t) (16*1024); /* first offset is a 16K block */ /* calculate offsets into shmpages */ pagesize = getpagesize(); bsize = sizeof (blockinfo_t); /* calculate blockinfo size in whole pages (on page boundary) */ if (bsize%pagesize) bsizepb = ((bsize/pagesize)+1) * pagesize; else bsizepb = (bsize); key = (key_t) (0x2d000000+((int)getuid()*0x1000)); /* inital key */ /* segsize = get_max_seg_size(); */ segsize = get_max_seg_size(pagesize); /* printf("seg size %d %x\n", segsize, segsize); exit (-1); */ /* numsegs = create_segments(key, keys, shmids, segptrs, MAXSEGS); */ numsegs = create_segments(key, MAXSEGS); if (numsegs<2) { fprintf(stderr,"WARNING:\nCan not create 2 or more segments.\nExiting.\n"); fflush(stderr); clean_segs(); exit (-2); } for(i=0;isegoffset = firstpagehdr; /* first page starts after header */ /* First page offsets */ ((blockinfo_t*)addr)->nextoffset = bsizepb; /* and the previous is wrapped around... */ ((blockinfo_t*)addr)->previousoffset = (numsegs-1) * bsizepb; /* all other segments are just for message info */ for(i=1;isegoffset = 0; /* i.e. first page is at the head of the seg */ /* offsets to previous / next blockinfo structs */ if (i<(numsegs-1)) ((blockinfo_t*)addr)->nextoffset = bsizepb; else /* wrap around */ ((blockinfo_t*)addr)->nextoffset = -((numsegs-1) * bsizepb); ((blockinfo_t*)addr)->previousoffset = -bsizepb; } /* previous/next wrap around tests */ /* first forwards */ printf("Forwards loop\n"); addr = o1 + (char*)segptrs[0]; for(i=0;i<=numsegs;i++) { printf("segkey [0x%x]\t", ((blockinfo_t*)addr)->segkey ); addr += ((blockinfo_t*)addr)->nextoffset; } printf("\n\n"); /* backwards */ printf("Backwards loop\n"); addr = o1 + (char*)segptrs[0]; for(i=0;i<=numsegs;i++) { printf("segkey [0x%x]\t", ((blockinfo_t*)addr)->segkey ); addr += ((blockinfo_t*)addr)->previousoffset; } printf("\n\n"); for(i=0;inumsegs = numsegs; /* should check tidslots here TODO */ /* Safe to register myself now */ if (register_shmd (tid, shmids[0])) { fprintf(stderr,"Cannot setup system mailbox entry.\n"); exit (-4); } /* now the pvm daemon knows we are here */ /* when it exits it sends up a TERM so that we can exit neatly */ /* we also catch a HUP for completeness */ (void) signal (SIGTERM, bambismother); #ifndef LINUX (void) sigset (SIGTERM, bambismother); /* yes I mean it, ok ? */ #endif (void) signal (SIGHUP, huphuphup); while (!finished) { /* ok, we really would do some work in here... honest */ bufid = pvm_recv(-1,-1); pvm_bufinfo( bufid, &bytes, &msgtag, &from ); switch (msgtag) { case 1: /* join */ join = from; make_mqueue (join, &mqkey, &mqid); if (mqid<0) { pvm_initsend(PvmDataDefault); pvm_pkint (&mqid, 1, 1); /* failed */ pvm_send (join, join); fprintf(stderr,"TID [0x%x] failed on make_mqueue\n", join); break; } slot = add_tidinfo (join, mqkey, mqid); if (slot<0) { pvm_initsend(PvmDataDefault); pvm_pkint (&slot, 1, 1); /* failed */ pvm_send (join, join); fprintf(stderr,"TID [0x%x] failed on add_tidinfo\n", join); break; } /* else ok, so we setup notify and then signal task */ printf("TID [0x%x] added into tidinfo slot [%d]\n", join, slot); pvm_notify (PvmTaskExit, 9, 1, &join); fprintf(stderr,"Adding [0x%x] to notify list\n", join); fflush(stderr); j = 0; /* i.e. isitok is yes */ pvm_initsend(PvmDataDefault); pvm_pkint (&j, 1, 1); /* passed */ fprintf(stderr,"Sending message [%d] to [0x%x] tag [0x%x]\n", j, join, join); cc = pvm_send (join, join); fprintf(stderr,"Sent message [%d] to [0x%x] tag [0x%x] = [%d]\n", j, join, join, cc); fflush(stderr); break; case 2: /* exit (polite) */ left = from; /* just adds to readability, maybe */ del_mqueue (left); slot = remove_tidinfo (left); printf("TID [0x%x] removed from tidinfo slot [%d]\n", left, slot); /* freeing space by this task */ left = left & 0xFFFF; /* task part of address */ for(i=0;itidsexited++; break; case 3: /* blockmap */ for(i=0;itidsmurdered++; break; default: /* ? */ fprintf(stderr,"Unknown message from [0x%x] of tag [0x%x]\n", from, msgtag); pvm_freebuf (bufid); break; } /* end switch */ } clean_segs(); pvm_exit(); /* which takes the PVM reg with it! */ exit (0); /* Normally I hope */ } /* unsigned int get_max_seg_size() */ unsigned int get_max_seg_size(psize) unsigned psize; { key_t key; unsigned int size; int id; key = (key_t) 0x2d000000; /* size = 1024 * 1024 * 1024; */ /* size = 1024 * 1024 * 32; */ /* start looking from 32MBytes */ size = MAXPAGESALLOWED * psize; /* start from our limit */ for(;;) { id = shmget (key, size, IPC_CREAT | 0600); if (id>0) { /* printf("id\t%d\n",id); */ /* printf("key\t%x\n",key); */ /* printf("size\t[0x%x or %u bytes] [%u KBytes]\n", size, size, size/1024); */ break; } /* key += 0x10; */ if (id<0) { if (errno==EINVAL) perror("shmget:EINVAL"); if (errno==ENOSPC) perror("shmget:ENOSPC"); size /= 0x2; /* break; */ } } shmctl (id, IPC_RMID, 0); /* I know its a waste.. but.. */ return (size); } unsigned int create_segments(basekey, maxsegs) key_t basekey; unsigned int maxsegs; { int c=0; /* number of segments that we get a valid id for */ int v=0; /* number of segments that we get a valid ptr for */ void *ptr; key_t key; struct shmid_ds shmsbuf; int suc, attached; int i; int f; /* f is for failed */ int num; /* number of segments that we have a valid id and valid ptr for */ key = (key_t) basekey; /* make sure we are all reset fully */ for(i=0;i0) printf("%s storing syshdr as shmid [0x%x]\n", fullname, shmid); else { printf("%s marking shmem as disabled\n", fullname, shmid); shmid = -1; } ssbuf = pvm_setsbuf(0); sbuf = pvm_initsend(PvmDataDefault); pvm_pkint(&tid,1,1); pvm_pkint(&shmid,1,1); if ( (cc = pvm_putinfo(fullname, sbuf, PvmMboxDefault)) != 0 ) { pvm_perror("pvm_shmd already running?"); } pvm_setsbuf(ssbuf); pvm_freebuf(sbuf); return(cc); /* Will be PvmOK if register succeeded, < 0 otherwise */ } int make_mqueue (tid, mqkey, mqid) int tid; key_t* mqkey; int* mqid; { key_t key; int id; int i,j,k; key = (key_t) (0x2c000000+((int)getuid()*0x1000)+(0xFFFF&tid)); /* inital key */ for(i=0;i<1000;i++) { id = msgget(key, IPC_CREAT|0666); if (id>0) break; else key++; } if (id<0) return (-1); /* can't get one ! */ /* else we can and we did! */ printf("TID [0x%x] has a new message queue of key [0x%x] and id [%d]\n", tid, key, id); *mqkey = key; *mqid = id; return (0); } int del_mqueue (tid) int tid; { key_t key; int id; int i,j,k; /* first get the id from the tidinfo structure using the processes tid */ id = find_tidinfo_id (((char *)segptrs[0]), tid); if (id<0) { fprintf (stderr, "No TID [0x%x] found when removing mqueue ??\n", tid); fflush(stderr); return (-1); /* i.e. no tid record... ? */ } i = msgctl (id, IPC_RMID, (struct msqid_ds *) 0 ); if (!i) { printf("TID [0x%x] had a message queue of id [%d] deleted.\n", tid, id); return (0); } else { printf("Failed to remove TID [0x%x] message queue [%d]\n", tid, id); return (-1); } } void huphuphup () { fprintf(stderr,"pvm_shmd: Received a sig HUP.\nExiting.\n"); fflush(stderr); clean_segs(); pvmendtask(); exit (SIGHUP); } void bambismother () { fprintf(stderr,"pvm_shmd: Received a sig TERM.\nExiting.\n"); fflush(stderr); clean_segs(); pvmendtask(); /* pvm_exit(); */ /* this causes a PVM not implemented error to appear */ exit (SIGTERM); }