Creating a generic data structure in c

I created a data structure in my C program like this:

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = (int *)malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  if (a->used == a->size) {
    a->size *= 2;
    a->array = (int *)realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

      

Then I add some data to this data structure from an external text file using the following method:

Array read_ints (const char* file_name)
{
  Array numbers;
  initArray(&numbers,5);

  FILE* file = fopen (file_name, "r");
  int i = 0;
  int count = 0;

  fscanf (file, "%d,", &i);  
  insertArray(&numbers,i);  
  while (!feof (file))
    {  
      //printf ("%d ", i);
      fscanf (file, "%d,", &i);
      insertArray(&numbers,i);      
    }
  fclose (file);
  return numbers;        
}

      

Now what I need to do is, I need to make the "Array" data structure part of shared memory so that both child and parent processes in my program can access this data structure. I have no idea how to make it shared memory. I know that system call shmget()

can be used to get shared memory in UNIX environment. But I can't see how to use this system call for this scenario. Please help me.

+3


source to share


1 answer


The main code is shm-master.c

#include "posixver.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include "so-stderr.h"

enum { DEFAULT_SHM_SIZE = 65536 };
enum { DEFAULT_FTOK_ID = 0 };
static const char default_filename[] = "/etc/passwd";

static const char usestr[] = "[-adx][-f file][-s size][-i id]";
static const char optstr[] = "adf:s:x";

int main(int argc, char **argv)
{
    int aflag = 0;
    int xflag = 0;
    int dflag = 0;
    int id = DEFAULT_FTOK_ID;
    size_t size = DEFAULT_SHM_SIZE;
    const char *file = default_filename;
    int opt;

    err_setarg0(argv[0]);
    while ((opt = getopt(argc, argv, optstr)) != -1)
    {
        switch (opt)
        {
        case 'a':
            aflag = 1;
            break;
        case 'd':
            dflag = 1;
            break;
        case 'f':
            file = optarg;
            break;
        case 'i':
            id = atoi(optarg);
            break;
        case 's':
            size = strtoull(optarg, 0, 0);
            if (size == 0)
                err_error("Invalid size (%s) evaluates to zero\n", optarg);
            break;
        case 'x':
            xflag = 1;
            break;
        default:
            err_usage(usestr);
        }
    }

    if (aflag + dflag + xflag > 1)
        err_error("%d of 3 mutually exclusive options -a, -d and -x specified\n", aflag + dflag + xflag);

    printf("ID: %d, File: %s\n", id, file);
    key_t key = ftok(file, id);
    printf("Key: 0x%.8" PRIX64 "\n", (uint64_t)key);
    int shmflg = S_IRUSR | S_IWUSR;
    if (!aflag && !dflag)
        shmflg |= IPC_CREAT;
    if (xflag)
        shmflg |= IPC_EXCL;

    int shmid = shmget(key, size, shmflg);
    if (shmid < 0)
        err_syserr("Failed to get shared memory ID: ");
    printf("ShmID: %d\n", shmid);

    if (dflag)
    {
        struct shmid_ds buf;
        int rc = shmctl(shmid, IPC_RMID, &buf);
        if (rc < 0)
            err_syserr("Failed to delete shared memory: ");
        printf("Shared memory removed\n");
    }
    else
    {
        void *space = shmat(shmid, 0, 0);
        if (space == (void *)-1)
            err_syserr("Failed to attach to shared memory: ");
        printf("Shared memory allocated at 0x%" PRIXPTR "\n", (uintptr_t)space);
        memset(space, '\0', size);
        int rc = shmdt(space);
        if (rc != 0)
            err_syserr("Failed to detach from shared memory: ");
        printf("Detached from shared memory\n");
    }

    return 0;
}

      

Library code - so-stderr.h

#ifndef SO_STDERR_H_INCLUDED
#define SO_STDERR_H_INCLUDED

extern void err_setarg0(const char *arg0);
extern void err_error(const char *fmt, ...);
extern void err_syserr(const char *fmt, ...);

#endif /* SO_STDERR_H_INCLUDED */

      

Library code - so-stderr.c

#include "so-stderr.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static const char *argv0 = "**undefined**";

void err_setarg0(const char *arg0)
{
  argv0 = arg0;
}

void err_error(const char *fmt, ...)
{
  fprintf(stderr, "%s: ", argv0);
  va_list args;
  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);
  exit(EXIT_FAILURE);
}

void err_syserr(const char *fmt, ...)
{
  int errnum = errno;
  fprintf(stderr, "%s: ", argv0);
  va_list args;
  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);
  if (errnum != 0)
    fprintf(stderr, "(%d: %s)", errnum, strerror(errnum));
  putc('\n', stderr);
  exit(EXIT_FAILURE);
}

      

Configuration header - posixver.h



You can set up a higher version number up to 700 (for POSIX 2008/2013) on many systems, but this is probably not a good idea on Mac OS X, even with 10.10.3 Yosemite.

#ifndef JLSS_ID_POSIXVER_H
#define JLSS_ID_POSIXVER_H

#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif

#endif

      

In all cases, the "real" code includes (several) comments and other explanations of what is going on. The production is stderr.h

and is stderr.c

more complex than the minimum version shown, but for many purposes shown is equivalent to the production version.

Execution example

$ ./shm-master -H
./shm-master: invalid option -- 'H'
Usage: ./shm-master [-adx][-f file][-s size][-i id]
$ ./shm-master -ax
./shm-master: 2 of 3 mutually exclusive options -a, -d and -x specified
$ ./shm-master -dx
./shm-master: 2 of 3 mutually exclusive options -a, -d and -x specified
$ ./shm-master -da
./shm-master: 2 of 3 mutually exclusive options -a, -d and -x specified
$ ./shm-master -dax
./shm-master: 3 of 3 mutually exclusive options -a, -d and -x specified
$ ipcs -m | grep -v '^0x00000000 '

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x620010f7 0          root       660        557920     4
0x63002725 32769      root       666        82164      3

$ ./shm-master -x
ID: 0, File: /etc/passwd
Key: 0x0000009F
ShmID: 44793901
Shared memory allocated at 0x7F29AC43A000
Detached from shared memory
$ ipcs -m | grep -v '^0x00000000 '

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x620010f7 0          root       660        557920     4
0x63002725 32769      root       666        82164      3
0x0000009f 44793901   jleffler   600        65536      0

$ ./shm-master -d
ID: 0, File: /etc/passwd
Key: 0x0000009F
ShmID: 44793901
Shared memory removed
$ ipcs -m
$ grep -v '^0x00000000 '

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x620010f7 0          root       660        557920     4
0x63002725 32769      root       666        82164      3

$ ./shm-master -f /home/jleffler/soq/shm-master -a
./shm-master: Failed to get shared memory ID: (2: No such file or directory)
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
$ ./shm-master -f /home/jleffler/soq/shm-master -d
./shm-master: Failed to get shared memory ID: (2: No such file or directory)
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
$ ./shm-master -f /home/jleffler/soq/shm-master -x
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
ShmID: 44826669
Shared memory allocated at 0x7FA1488CA000
Detached from shared memory
$ ./shm-master -f /home/jleffler/soq/shm-master -d
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
ShmID: 44826669
Shared memory removed
$ ./shm-master -f /home/jleffler/soq/shm-master -x
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
ShmID: 44859437
Shared memory allocated at 0x7F93005EC000
Detached from shared memory
$ shmid=$(./shm-master -f /home/jleffler/soq/shm-master -a sed -n '/ShmID: /s///p')
$ ipcs -m -i $shmid

Shared memory Segment shmid=44859437
uid=199484      gid=5000        cuid=199484     cgid=5000
mode=0600       access_perms=0600
bytes=65536     lpid=31202      cpid=31200      nattch=0
att_time=Fri Apr 17 11:37:06 2015
det_time=Fri Apr 17 11:37:06 2015
change_time=Fri Apr 17 11:37:06 2015

$ ./shm-master -f /home/jleffler/soq/shm-master -d
ID: 0, File: /home/jleffler/soq/shm-master
Key: 0x00010FB9
ShmID: 44859437
Shared memory removed
$

      

By the way, the option ipcs

-i id

is a POSIX-specific Linux extension for ipcs

, and the option is not available, for example, for Mac OS X (BSD). The closest equivalent would be something like ipcs -m -a | grep "$shmid"

, which is not perfect. The operations grep -v '^0x00000000 '

eliminate segments of private shared memory (there were a lot of them on the machine I tested on).

+2


source







All Articles