Shared Memory in C: Shmget Issues - c

int shmid;
int* locat;
//create shared memory segment
shmid = shmget(6666, size, 0666);
if (shmid < 0) {
perror("shmget");
exit(1);
}
locat = (int *) shmat(shmid, NULL, 0);
if (locat == (int *) -1) {
perror("shmat");
exit(1);
}
I am setting up shared memory as such, yet I keep getting this error: shmget: No such file or directory
This code was working fine, not sure why this occurs now.

As the man says
IPC_CREAT
Create a new segment. If this flag is not used, then shmget() will find the segment associated with key and check to see if the user has permission to access the segment.
You have to add IPC_CREAT to your shmget call
shmid = shmget(6666, size, IPC_CREAT | 0666);
You could also use the IPC_EXCL to ensure that the segment is newly created
IPC_EXCL
This flag is used with IPC_CREAT to ensure that this call
creates the segment. If the segment already exists, the
call fails.

There are two things :
When you want to initialize a shared memory ( corresponding to a particular key value ) , you have to BITWISE OR the permission number with IPC_CREAT.
Just like
shmget(6666 , size , 0666|IPC_CREAT);
When you want to attach the same segment ( identified by the key value ) to another process , IPC_CREAT is not mandatory as the shared memory has already been created the the logical address space.

Related

How to check if shared memory exists using shmget or ftok?

I am writting project in c using shared memory via shm functions. I want to try to "connect" to shared memory and check if it exists using shmget() function.
I tried a few flags with this function but failed to achieve expected result. I wonder if there is a way to see whether a shared memory already exists.
The manual page spells this out rather explicitly.
int shmget(key_t key, size_t size, int shmflg);
If shmflg specifies both IPC_CREAT and IPC_EXCL and a shared memory segment already exists for key, then shmget() fails with errno set to EEXIST.
And again, the flags:
IPC_CREAT
Create a new segment. If this flag is not used, then shmget() will find the segment associated with key and check to see if the user has permission to access the segment.
IPC_EXCL
This flag is used with IPC_CREAT to ensure that this call creates the segment. If the segment already exists, the call fails.
Alternatively, if the flag IPC_CREAT is not specified, and no memory segment exists for the given key, then shmget fails and sets errno to ENOENT.
ENOENT
No segment exists for the given key, and IPC_CREAT was not specified.
So you may want to try something along the lines of
errno = 0;
if (-1 == shmget(key, size, IPC_CREAT | IPC_EXCL)) {
if (EEXIST == errno) {
/* shared memory already exists */
}
}
or
errno = 0;
if (-1 == shmget(key, size, 0)) {
if (ENOENT == errno) {
/* shared memory does not exist */
}
}
On the other hand, ftok(3) fails for the same reasons as stat(2).

Shared memory on C struct not working correctly

I'm working on a small program that simulates a puzzle game, where I can print the state of the board, or move up, down, left, or right but am having an issue when I tried implementing it with shared memory. I have a struct in a header file that has a char *[4][4]
that is used in both the the other files
The setup is like this
// Instance of Board for the current state of the game.
Obj obj; // is initialized but not here for sake of space and post size
struct obj *pobj;
int main()
{
key_t key = ftok("/afs/x/y/z", 'b');
//Make shared memory
size_t BLOCK_SIZE = sizeof(struct Board);
int shmid = shmget(key, BLOCK_SIZE, 0666 | IPC_CREAT);
if (shmid == -1)
{
fail("Cannot create shared memory");
}
pobj = (Obj *) shmat(shmid, 0, 0);
if (pobj == (struct Board *) -1)
{
fail("Can't map shared memory segment into address space");
}obj
// setting pobj values to obj values
for(int i = 0; i < OBJ_ROWS; i++){
for(int j = 0; j < OBJ_COLS; j++){
pobj->field[i][j] = obj.field[i][j];
}
}
//Loop through and print the values just put in, I get the correct values I put in
shmdt( pobj );
return 0;
}
I get the correct values I put in
but when I access via this
key_t key = ftok("/afs/x/y/z", 'b');
//Make shared memory
int shmid = shmget( key, BLOCK_SIZE, 0666 | IPC_CREAT );//this IPC_CREAT not needed
if( shmid == -1){
fail( "Cannot create shared memory" );
}
pobj= (OBJ *) shmat(shmid, 0, 0);
if(pobj == (struct Obj *) -1){
fail( "Cannot map shared memory segment into address space" );
}
// loop through and print out values
I get nothing but garbage values like
# # ▒▒▒▒▒&▒E▒x▒▒U܋u܋E▒щ▒▒▒w▒▒▒▒
▒E▒▒}▒~▒▒E▒▒}▒~▒▒ ▒▒&▒E▒x▒▒U܋u܋E▒щ▒▒▒w▒▒▒▒
▒E▒▒}▒~▒▒E▒▒}▒~▒▒
▒E▒x▒▒U܋u܋E▒щ▒▒▒w▒▒▒▒
▒E▒▒}▒~▒▒E▒▒}▒~▒▒ ▒x▒▒U܋u܋E▒щ▒▒▒w▒▒▒▒
▒E▒▒}▒~▒▒E▒▒}▒~▒▒ ▒U܋u܋E▒щ▒▒▒w▒▒▒▒
▒E▒▒}▒~▒▒E▒▒}▒~▒▒ ▒u܋E▒щ▒▒▒w▒▒▒▒
▒E▒▒}▒~▒▒E▒▒}▒~▒▒
What is causing the difference in these values?
Edit: Fixed the issue by removing the IPC_CREAT from the second file that was causing issues and changed array to int[4][4];
You created a brand new shared memory block in both programs. You want to create memory in reset.c, and read it in fifteen.c. Remove the IPC_CREAT in fifteen.c. You can learn more here, where the syscall specifies:
IPC_CREAT
Create a new segment. If this flag is not used, then
shmget() will find the segment associated with key and
check to see if the user has permission to access the
segment.
There's also something that doesn't make much sense. String literals are arrays, i.e. pointers, and you made Board just a bunch of pointers. The only data you shared in your shared memory object were the pointers, which isn't helpful for fifteen.c, fifteen.c needs to see the actual character data. Instead, fifteen.c sees a bunch of pointers that point to string literals in reset.c. This isn't particularly useful, what should fifteen.c do with a bunch of random addresses? fifteen.c wants to see actual letters - likely null terminated arrays. You'll have to make your Board object contain a 2D array of character arrays (Of definite length, say, 16). Then, you can share the character data back and forth in your file.

C linux shmget Invalid argument

int shmCreate(int id, int size)
{
int shmid
key_t key;
if ((key = ftok(".", id)) == -1) {
perror("ftok");
exit(1);
}
if ((shmid = shmget(key, size, IPC_CREAT | 0666)) == -1) {
perror("shmget");
exit(1);
}
return shmid;
}
I'm trying to write function which use shmget, where function gets size as parameter. I'm getting Invalid argument error all the time, except for size = 1. When I pass size other than 1 i got error, but the memory segment is created when i check ipcs -m, and it has size of 1. How do I get rid of this error?
According to the man page for shmget(2):
EINVAL A segment for the given key exists, but size is greater than
the size of that segment.
You cannot attach a segment that already exists with a larger size. So you need to remove it first or use a different key.

shmctl throws "cannot allocate memory" in C

I have this code:
#define SHMSIZE 8388606
int main()
{
int shmid;
void *shmPtr;
char *shm;
if ((shmid = shmget(IPC_PRIVATE, sizeof(char) * SHMSIZE , IPC_CREAT | 0666)) < 0) {
perror("shmget");
exit(1);
}
if ((shmPtr = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
shm = (char *)shmPtr;
strncpy(shm, "0\n", 2);
struct shmid_ds shmid_ds;
int rtrn = shmctl(shmid, SHM_LOCK, &shmid_ds);
if(rtrn < 0) {
perror("shmctl");
exit(1);
}
else {
printf("Nailed it\n" );
}
return 0;
}
Running it, I get the error:
shmctl: Cannot allocate memory
Defining smaller value for SHMSIZE fixes the error, but what I found weird is that this error is thrown in the "shmctl" part. My reasoning tells me that this error is supposed to be thrown in the "shmget" part.
How does this code runs successfully through the shmget() call? Did I miss something important?
Read this, It may help you to solve your problem:
The caller can prevent or allow swapping of a shared memory segment
with the following cmd values:
SHM_LOCK (Linux-specific)
Prevent swapping of the shared memory segment. The caller
must fault in any pages that are required to be present
after locking is enabled. If a segment has been locked,
then the (nonstandard) SHM_LOCKED flag of the shm_perm.mode
field in the associated data structure retrieved by
IPC_STAT will be set.
SHM_UNLOCK (Linux-specific)
Unlock the segment, allowing it to be swapped out.
In kernels before 2.6.10, only a privileged process could employ
SHM_LOCK and SHM_UNLOCK. Since kernel 2.6.10, an unprivileged
process can employ these operations if its effective UID matches the
owner or creator UID of the segment, and (for SHM_LOCK) the amount of
memory to be locked falls within the RLIMIT_MEMLOCK resource limit
(see setrlimit(2)).
Try this:
int rtrn = shmctl(shmid, IPC_STAT, &shmid_ds);

how to make a process shared memory (c, linux)?

I have a process that dived itself with fork. I need to create a region of memory (a matrix) for the result of the computation of each process. How can I do this? Everything I tried or I can use but it's not shared between processes or I can't use (not sure if shared or not). Someone knows what I can use? It can be something simple and without any security. The simpler the better.
I tried shmget but it's not sharing and I couldn't get how to use mmap to allocate or use it correctly. I tried other estranges things, but nothing. Any tips?
Some tries:
segment_id = shmget(IPC_PRIVATE, (sizeof(int) * linhas_mat1 * colunas_mat2) , S_IRUSR|S_IWUSR);
matriz_result = (int **) shmat(segment_id, NULL, 0);
Forks after that. Each process can use the matriz_result normally as a matrix, but the memory is not shared. Each one has one like a local variable.
segment_id = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
matriz_result = mmap(NULL, (sizeof(int) * linhas_mat1 * colunas_mat2), PROT_READ | PROT_WRITE, MAP_SHARED, segment_id, 0);
Tried this with mmap, but I don't know if it's right. I'm not good with such low level programming and I couldn't find any good example on how to use it correctly.
declarations:
int segment_id is;
int **matriz_result;
int createMemShare(){
//File descriptor declaration:
int fd;
//We want to open the file with readwrite,create it, and empty it if it exists
//We want the user to have permission to read and write from it
fd = open(MEMSHARENAME, O_RDWR| O_CREAT | O_TRUNC, S_IRUSR| S_IWUSR );
if(fd <= 0){
puts("Failed in creating memory share .");
return -1;
}
//Move the file pointer and write an empty byte, this forces the file to
//be of the size we want it to be.
if (lseek(fd, MEMSHARESIZE - 1, SEEK_SET) == -1) {
puts("Failed to expand the memory share to the correct size.");
return -1;
}
//Write out 1 byte as said in previous comment
write(fd, "", 1);
//Memory share is now set to use, send it back.
return fd;
}
//Later on...
int memShareFD = mmap(NULL, MEMSHARESIZE, PROT_READ, MAP_SHARED, fd, 0);
//And to sync up data between the processes using it:
//The 0 will invalidate all memory so everything will be checked
msync(memshareFD,0,MS_SYNC|MS_INVALIDATE);
you can try the above function to create a shared memory space. Essentially all you need to do is treat it like any other file once you've made it. The code example on the man page is pretty complete and worth a look into: check it out here
Edit:
You'd probably be better off using shm_open as Jens Gustedt suggested in the comments. It's simple to use and simpler than making the file yourself with the function I've written above.

Resources