3

I am writing a C program where I am dealing out cards to n players, represented by n forked processes. I wish for them to all share the same deck of cards, so I am attempting to use mmap() to keep track of the deck size, however the machine I have to compile this program for does not allow MAP_ANONYMOUS or MAP_ANON. Is there another way that I can store a global variable in shared memory that would still be C89/pre Linux 2.4 compliant?

My program for context:

static int *deck_size;

int pop(int *arr, int *size, int loc)
{
    int i;
    int val = arr[loc];
    for(i = loc; i < (*size - 1); i++)
    {
        arr[i] = arr[(i+1)];
        arr[*size] = '\0';
    }
    *size = *size-1;
    return val;
}

int main(int argc, char* argv[])
{
    pid_t pid, wpid;
    int status, index, players, rdm_card;
    char outbuf[100];
    int deck[] = 
    {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13};

    deck_size = mmap(NULL, sizeof *deck_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    *deck_size = 52;
    /* reject an execution with no arguments */
    if(argv[1] == NULL)
    {
        write(STDERR_FILENO, "Usage: dealer <n>\n", 18);
        exit(EXIT_FAILURE);
    }
    else
    {
        if( (players = atoi(argv[1])) < 1)
        {
            write(STDERR_FILENO, "n cannot be less than 1\n", 24);
            exit(EXIT_FAILURE);
        }
    }

    srand ( time(NULL) );

    rdm_card = rand() % *deck_size;

    for(index = 0; index < players; index++)
    {
        pid = fork();
        if (pid == 0) {
            sprintf(outbuf, "random card: %d\n", pop(deck, deck_size, rdm_card));
            write(STDOUT_FILENO, outbuf, 17);
            printf("size of deck %d!\n", *deck_size);
            exit(EXIT_SUCCESS);
        } else if (pid < 0) {
            write(STDERR_FILENO, "fork error\n", 11);
            exit(EXIT_FAILURE);
        } else {
            do {
                wpid = waitpid(pid, &status, WUNTRACED);
            } while (!WIFEXITED(status) && !WIFSIGNALED(status));
        }
    }
    return 0;
}
jww
  • 97,681
  • 90
  • 411
  • 885
  • 2
    Have you looked at `man 2 shmget`? It describes the ancient System V shared memory interface that was used before POSIX shm – that other guy Jul 14 '17 at 22:34
  • 2
    did you remember to define `_BSD_SOURCE` or `_SVID_SOURCE` to get MAP_ANONYMOUS from – Seek Addo Jul 14 '17 at 22:51
  • Is there a specific reason you're trying to use forked processes here? Unless this is a project requirement (e.g, for a programming assignment), you're probably better off using threads… –  Jul 15 '17 at 04:07
  • *"C89/pre Linux 2.4"* - is kind of old, and its unusual to see it nowadays. Can you use C99 by way of [`gcc -std=c99 ...`](https://stackoverflow.com/q/2193634/608639)? C99 will allow other goodies, like initializing a variable at at place in the program. – jww Jul 15 '17 at 05:11
  • @jww Unfortunately, my university course requires our programs to compile for C89. Definitely wish I could do otherwise! – MSDOStoevsky Jul 16 '17 at 04:19

1 Answers1

2

When you clearly read the man page MMAP(2) it clearly state that MAP_ANONYMOUS is supported since Linux kernel 2.4.

The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is supported on Linux only since kernel 2.4.

Make sure you define _BSD_SOURCE or _SVID_SOURCE to get MAP_ANONYMOUS

#define _BSD_SOURCE
Seek Addo
  • 1,871
  • 2
  • 18
  • 30
  • Thanks! I didn't realize I needed to define those. Additionally, `#define _DEFAULT_SOURCE`, is the more current version of `_BSD_SOURCE` and `_SVID_SOURCE`. – MSDOStoevsky Jul 15 '17 at 01:56
  • @MSDOStoevsky - There's a completely new rabbit hole to go down for those macros :) I usually use `_X_OPEN_SOURCE` or `_POSIX_SOURCE`. I've found `_X_OPEN_SOURCE` or `_POSIX_SOURCE` work better with C++ compilers that use C libraries. Also see [1.3.4 Feature Test Macros](https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html) in the GNU manual. And Newlib is slightly different than Glibc. – jww Jul 15 '17 at 05:15
  • But the question says "pre Linux 2.4". Doesn't that mean Linux 2.2 and earlier? – that other guy Jul 15 '17 at 05:34
  • @thatotherguy you are right. MAP_ANONYMOUS in conjunction with MAP_SHARED is since 2.4, but before then with the _BSD_SOURCE defined it(MAP_ANONYMOUS) should work for his machine too. Thanks for pointing out. – Seek Addo Jul 15 '17 at 06:25