0

I have the follow code, that i want to communicate between two processes via a shared memory segment. My problem is that i take an error at attaching memory segment and i don't know why.

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include "process.h"

int main(int argc, char** argv)
{
    /*- Check the command-line arguments -*/
    if(argc != 2)
    {
        printf("\n--- Wrong input at command-line arguments ---\n\n");
        printf("--- The program terminate --- \n");
        return 1;
    }

    int N = atoi(argv[1]);      // The amount of total threads to be created
    int status;         // for the wait() function
    char* data;         // a string to use for shared memory segment

    /*- Variables for the shared memory segment -*/
    key_t key = 1003;       // for the shmget() key argument
    int shmid;          // to store the returned value from shmget()
    int size = 1024;        // for the shmget() size argument


/* ************************************************************************************/

    pid_t pid = fork(); // create second process

    if(pid < 0)     // if something going wrong
    {
        printf("\n\n---- Error in function fork!----\n");
        exit(1);
    }
    else if(pid == 0)   // the child process (P) 
    {
        // create the shared memory segment for the P process
        shmid = CreateShmSegment(key, size, IPC_CREAT);

        if(shmid == -1)     // check if creating shared memory return an error
        {
            printf("\n---Error at creating the memory segment! ---\n");
            exit(1);
        }

        // attach the shared memory segment
        data = AttachShmSegment(shmid);

        if(data == (char*)-1)   // check if attached the shared memory return an error
        {
            printf("\n---Error at attaching the memory segment! ---\n");
            exit(1);
        }   

        char* str = data;
        sprintf(str, "testing");

//      ChildProcess();
        printf("\n** Child process! ** \n");
        printf("N = %d\n", N);
        printf("write: %s\n",str);

        // detach the shared memory segment
        if(shmdt(data) == -1)       //check for error
        {
            printf("\n---Error at detaching memory segment! ---\n");
            exit(1);
        }
    }
    else            // the parent process (C)
    {   
        // create the shared memory segment for the C process
        shmid = CreateShmSegment(key, size, IPC_CREAT);

        if(shmid == -1)     // check if creating shared memory return an error
        {
            printf("\n---Error at creating the memory segment! ---\n");
            exit(1);
        }

        // attach the shared memory segment
        data = AttachShmSegment(shmid);
        if(data == (char*)-1)   // check if attached the shared memory return an error
        {
            printf("\n---Error at attaching the memory segment! ---\n");
            exit(1);
        }   

//      ParentProcess();
        wait(&status);
        printf("\n** Parent process! **\n");
        printf("N = %d\n",N);   
        printf("read from segment: %s\n", data);

        // detach the shared memory segment
        if(shmdt(data) == -1)       //check for error
        {
            printf("\n---Error at detaching memory segment! ---\n");
            exit(1);
        }

        // deallocate the shared memory segment
        if(DeallocateShmSegment(shmid) == -1)   //check for error
        {
            printf("\n---Error at destroy memory segment! ---\n");
            exit(1);
        }
    }

    return 0;
}

I quote and the other two files for the compile.

process.h:

#ifndef __Processes_H_
#define __Processes_H_
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

void    ChildProcess();
void    ParentProcess();
int CreateShmSegment(key_t, size_t, int);
void*   AttachShmSegment(int);
int DetachShmSegment(const void*);
int     DeallocateShmSegment(int);

#endif

And process.c:

#include "process.h"

void ChildProcess()
{

}


/***************************************************************/

void ParentProcess()
{

}

/****************************************************************/

int CreateShmSegment(key_t key, size_t size, int flag)
{
    int id;
    id = shmget(key, size, flag);
    return id;
}

/*****************************************************************/

void* AttachShmSegment(int id)
{
    char* data = NULL;
    data = (char*) shmat(id, NULL, 0);
    return data;
}

/*****************************************************************/

int DetachShmSegment(const void* addr)
{
    return shmdt(addr);
}

/*****************************************************************/

int DeallocateShmSegment(int id)
{
    return shmctl(id, IPC_RMID, NULL);
}

I don't know what is going wrong about attaching the memory. I have search the web and make some changes at arguments of shmat(), but i couldn't solve it.

aragon
  • 114
  • 1
  • 8
  • 3
    You say you get an error, but *what* error do you get? Have you checked [`errno`](http://man7.org/linux/man-pages/man3/errno.3.html)? Have you tried to use e.g. [`strerror`](http://man7.org/linux/man-pages/man3/strerror.3.html) to get a printable string of the error? – Some programmer dude Nov 08 '16 at 13:52
  • 1
    It is mandatory to use System V functions? Otherwise `mmap` is the "modern" way to manage shared memory. Take a look at [this SO post](http://stackoverflow.com/questions/21311080/linux-shared-memory-shmget-vs-mmap) – LPs Nov 08 '16 at 13:58
  • in general, do not `#include` anything into a file that is not used within that file. I.E. in the Process.h file do not include header files those contents are not used within that file. Just include those header files where they are actually needed. – user3629249 Nov 09 '16 at 23:22
  • in general, error message should be output to `stderr`, not `stdout` so after the `if(argc !=2), The enclosed calls to `printf()` should be calls to `fprintf( stderr, ... )` – user3629249 Nov 09 '16 at 23:23
  • when a system function returns an error indication, the code should display that error message associated with that error. So this line: `printf("\n---Error at creating the memory segment! ---\n");` should be similar to: `perror( "shared memory create ( shmget() )failed" );` then a message similar to the following will be output to stderr: shared memory create ( shmget() )failed: Permission denied` – user3629249 Nov 09 '16 at 23:36

3 Answers3

1

You're not specifying any mode flags when you create the segment. I would therefore expect it to be created with neither read nor write access for anyone, including its creator. That's not erroneous in itself, but all attempts by unprivileged processes to attach that segment while it has that mode should fail with EACCES.

Presumably, you want to include at least S_IRWXU in the flags when you create the segment, or else use shmctl() after the fact to modify the the segment's mode to allow read and write access to the owner. (Note that execute permission is meaningless for this purpose, so it would be equivalent to use S_IRUSR | S_IWUSR.) For example,

    shmid = CreateShmSegment(key, size, IPC_CREAT | S_IRWXU);

Possibly you want to grant broader access.

Note also that it's strange that you fork first and then have both parent and child processes create and attach the shared-memory segment. Attached shared-memory segments are inherited across fork(), so it would be cleaner to create and attach the segment before forking.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • I have tried and before fork. The error i get is after attach function call, which return '-1'. – aragon Nov 08 '16 at 22:29
  • @aragon, did you read my whole answer? The position of the `shmget()` and `shmat()` after the fork is suboptimal, but not the actual problem. In any event, when one of those functions indicates an error by returning -1, the usual mechanism for getting more information is to consult `errno` directly or to immediately call `perror()` to get an appropriate error message printed to `stderr`. I'll bet you dollars to donuts that doing so reveals an access control issue such as I described. – John Bollinger Nov 08 '16 at 22:39
0

here problem is you are trying to get shmid in both process and when both process call CreateShmSegment() they got different shmid that's why they failed.

Call CreateShmSegment() and AttachShmSegment() before fork().

Sumit Gemini
  • 1,836
  • 1
  • 15
  • 19
  • Creating and attaching the segment before forking is a good idea, but failing to do so is unlikely to be responsible for the error. That parent and child might get different IDs for the shared-memory segment is inconsequential; those IDs are purely local to each process. It is the specified segment *key* that serves as a global segment identifier. – John Bollinger Nov 08 '16 at 14:46
  • @JohnBollinger i don't thing so, if your key isn't same, how can one get shared segment. Here i mean, key that you passed in shmget should be same for both process. – Sumit Gemini Nov 08 '16 at 15:56
  • The OP *does* pass the same key in both calls to `shmget()`. In any case, that has nothing to do with your answer, which asserts that it would be a problem for parent and child to receive different `shmid` values from `shmget()` / `CreateShmSegment()` (for the same key). That assertion is simply wrong. – John Bollinger Nov 08 '16 at 16:02
0

this kind of line:

shmid = CreateShmSegment(key, size, IPC_CREAT); 

is not correct, it should be similar to:

shmid = CreateShmSegment(key, size, IPC_CREAT|0666);

to give read/write permissions (in this case) to everyone

once the shared memory segment is ever created (with out the appropriate permissions) then you/the user will have to destroy the shared memory. To list the shared memory use:

ipcs -m 

in the resulting listing,

those with dest are no longer in use and should be destroyed.

Those with a 0 in the permissions column are also need to be destroyed.

you can destroy a shared memory via:

ipcrm shm 32768 

where the 32768 is the shared memory id, taken from the listing

output of your code after problems in code corrected and 'bad' shared memory destroyed:

** Child process! ** 
N = 2
write: testing

** Parent process! **
N = 2
read from segment: testing
user3629249
  • 16,402
  • 1
  • 16
  • 17