#include /* required by pthread functions */ #include /* required by fprintf() */ #include /* required by exit(), atoi() */ #include /* required by strncpy() */ #include /* required by getopt(), mmap() */ #include /* required by open(), shmat(), shmdt() */ #include /* required by open() */ #include /* required by shmat() shmdt(), shmctl() */ #include /* required by shmat() shmdt(), shmctl() */ #include /* required by mmap() */ #include /* required by open() */ #define dprt printf #define REPEAT 100 /******************************************************************************/ /* */ /* Function: usage */ /* */ /* Description: Print the usage message. */ /* */ /* Return: exits with -1 */ /* */ /******************************************************************************/ static void usage(char *progname) /* name of this program */{ fprintf(stderr, "Usage: %s -d NUMDIR -f NUMFILES -h -t NUMTHRD\n" "\t -h Help!\n" "\t -l Number of repatetions to execute: Default: 1000\n" "\t -t Number of threads to generate: Default: 30\n", progname); exit(-1); } /******************************************************************************/ /* */ /* Function: mapfile */ /* */ /* Description: This file creates a file of size equal to multiple of pagesize*/ /* and maps the file into memory. */ /* */ /* Input: map_address - pointer to the address */ /* map_size - pointer to size of the file mapped. */ /* */ /* Output: map_address - contains the address in memory of file mapped. */ /* map_size - contains the size of the file that is mapped. */ /* */ /* Return: exits with -1 on error, 0 on success */ /* */ /******************************************************************************/ static int mapfile(long **address, /* output parameter - addr of the mapped file*/ int size) /* size of this mapped file */ { int fd = 0; /* file descriptor of tmp file */ int write_index = 0; /* index to number of 4096 blocks written */ char *filename; /* name of the temporary file */ char buff[4096]; /* buffer that will e written to the file */ memset(buff, 'a', 4096); filename = (char *)tempnam(".", "tmpfile"); if ((fd = open(filename, O_CREAT | O_EXCL | O_RDWR, 0777)) == -1) { perror("mapfile(): open()"); return -1; } else { /* if the program dies prematurely, clean up tempfiles upfront. */ if (unlink(filename) == -1) { perror("mapfile(): unlink()"); return -1; } } dprt("pid{%d]: mapfile(): size = %d\n", getpid(), size); while (write_index < size) { write_index += 4096; if (write(fd, buff, 4096) == -1) { perror("mapfile(): write()"); return -1; } } if (fsync(fd) == -1) { perror("mkfile(): fsync()"); return -1; } if ((*address = (char *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (char *)-1) { perror("mapfile(): mmap()"); return -1; } dprt("pid{%d]: mapfile(): address = %#x size = %d\n", getpid(), *address, size); return 0; } /******************************************************************************/ /* */ /* Function: rm_shared_mem */ /* */ /* Description: This function removes the shared segments that were created */ /* This function is called when shmat fails or logical end of */ /* the while loop is reached in do_shmat_shmdt function. */ /* */ /* Input: shm_id - id of the shared memory segment to be removed */ /* shm_addr - address of the shared memory segment to be removed */ /* cmd - remove id only or remove id and detach?? */ /* 0 - remove id dont detach segment. */ /* 1 - remove id and detach segment. */ /* */ /* Output: NONE. */ /* */ /* Return: exits with -1 on error, 0 on success */ /* */ /******************************************************************************/ static int rm_shared_mem(key_t shm_id, /* id of shared memory segment to be removed */ char *shm_addr, /* address of shared mem seg to be removed */ int cmd) /* remove id only or remove id and detach seg */ { struct shmid *shmbuf; /* info about the segment pointed by shmkey */ dprt("pid[%d]: rm_shared_mem(): shm_id = %d shm_addr = %#x cmd = %d\n", getpid(), shm_id, shm_addr, cmd); if (shmctl(shm_id, IPC_RMID, shmbuf) == -1) { dprt("pid[%d]: rm_shared_mem(): shmctl unable to remove shm_id[%d]\n", getpid(), shm_id); perror("rm_shared_mem(): shmctl()"); return -1; } if (cmd) { if (shmdt((void *)shm_addr) == -1) { dprt("pid[%d]:rm_shared_mem(): shmdt unable to detach addr = %#x\n", getpid(), shm_addr); perror("rm_shared_mem(): shmdt()"); return -1; } } return 0; } /******************************************************************************/ /* */ /* Function: do_shmat_shmatd */ /* */ /* Description: This function attaches and detaches the memory */ /* that was mmaped. The size of the file is a multiple of page */ /* size. This function executes as a thread function. */ /* */ /* Input: The argument pointer contains the following. */ /* arg[1] - address of the memory that is to be attached. */ /* arg[2] - size of the memory that is to be attached. */ /* */ /* Return: exits with -1 on error, 0 on success */ /* */ /******************************************************************************/ static int do_shmat_shmdt(char *mapaddr, /* address of the mem attached. */ int size) /* size of the file mapped. */ { int shmndx = 0; /* index to the number of attach and detach */ int index = 0; /* index to the number of blocks touched */ key_t shmkey = 0; /* shared memory id */ char *shmat_addr; /* address of the attached memory */ dprt("pid[%d]:do_shmat_shmdt(): mapaddr = %#x, size = %d\n", getpid(), mapaddr, size); if ((shmkey = shmget(IPC_PRIVATE, (int)size, IPC_CREAT | 0666 )) == -1) { dprt("pid[%d]: do_shmat_shmdt(): shmget failed\n", getpid()); perror("do_shmat_shmadt(): shmget()"); return -1 ; } fprintf(stdout, "pid[%d]: do_shmat_shmdt(): shmget():" "success got segment id %d\n", getpid(), shmkey); dprt("pid[%d]: do_shmat_shmdt(): file mapped at = %#x\n", getpid(), mapaddr); if ((shmat_addr = shmat(shmkey, (void *)mapaddr, SHM_RND|SHMLBA)) == (void *)-1) { rm_shared_mem(shmkey, shmat_addr, 0); fprintf(stderr, "pid[%d]: do_shmat_shmadt(): shmat_addr = %#x\n", getpid(), shmat_addr); perror("do_shmat_shmadt(): shmat()"); return -1 ; } fprintf(stdout,"pid[%d]: do_shmat_shmadt(): shmat success, address = %#x\n", getpid(), shmat_addr); if (rm_shared_mem(shmkey, shmat_addr, 1) == -1) { fprintf(stderr, "pid[%d]: do_shmat_shmatd(): rm_shared_mem(): faild to rm id\n", getpid()); return -1 ; } return 0 ; } /******************************************************************************/ /* */ /* Function: main */ /* */ /* Description: This is the entry point to the program. This function will */ /* parse the input arguments and set the values accordingly. If */ /* no arguments (or desired) are provided default values are used*/ /* refer the usage function for the arguments that this program */ /* takes. It also creates the threads which do most of the dirty */ /* work. If the threads exits with a value '0' the program exits */ /* with success '0' else it exits with failure '-1'. */ /* */ /* Return: -1 on failure */ /* 0 on success */ /* */ /******************************************************************************/ main(int argc, /* number of input parameters */ char **argv) /* pointer to the command line arguments. */ { int index; /* number of times to repeat the mmap & shmat */ int map_size; /* size of the file mapped. */ char *map_address; /* address in memory of the mapped file */ for (index = 0; index < REPEAT; index++) { srand(time(NULL)%100); map_size = (1 + (int)(1000.0*rand()/(RAND_MAX+1.0))) * 4096; if (mapfile(&map_address, map_size) != 0) { fprintf(stdout, "main(): mapfile(): failed to map created file\n"); exit (-1); } dprt("main(): map_address = %#x map_size = %d\n",map_address, map_size); if (do_shmat_shmdt(map_address, map_size) == -1) { fprintf(stderr, "main(): do_shmat_shmdt(): failed.\n"); exit(-1); } } exit(0); }