I thought this issue had been cleared in the tutorials, but it seems there are
still problems.
The correct (portable) way to specify the access permission flags when
creating an IPC (with shmget(2), msgget(2), semget(2)) is to bitwise OR the
permission constants defined in the headers. I just checked, and they happen
to be equal to the permission bits for files, but you shouldn't rely on this -
and your source will be much more readable if you use them.
The constants are:
For semaphores (from sys/sem.h)
#define SEM_A 0200 /* alter permission */
#define SEM_R 0400 /* read permission */
For message queues (from sys/msg.h)
#define MSG_R 0400 /* read permission */
#define MSG_W 0200 /* write permission */
For shared memory (from sys/shm.h)
#define SHM_R 0400 /* read permission */
#define SHM_W 0200 /* write permission */ Moreover, you should generate IPC keys correctly: just putting a "#define KEY
0100" and hoping for the best is not enough. You should make sure that no
unrelated processes access your IPCs. So
- if your IPC are used by processes related by
a fork() (parent-children-grandchildren...)
use IPC_PRIVATE as the key
- if your IPC are used by proceses without a common
ancestor, or if you just want to be fancy,
create a file in a directory of your own,
% touch /my/private/idaho/myfile
make sure the directory is not searchable by
the rest of the world
% chmod a-x /my/private/idaho
In your source, generate a key using ftok(3),
passing to it the full path of that file.
key_t mykey=ftok("/my/private/idaho/myfile", 'a')
use the same file, but different values of the second
argument to ftok(3), the character, to get different
keys.
And don't forget that:
#define BEING_FANCY_WITHOUT_A_GOOD_REASON "Foolish"
Examples:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/msg.h>
/* A record in a shared memory area */
typedef struct foobar {
int a,b;
} Foobar;
/* semaphore wait */
void semwait(int id) {
struct sembuf buf;
buf.sem_num=0;
buf.sem_op=-1;
buf.sem_flg=0;
if (-1==semop(id, &buf, 1)) {
perror("semop");
exit(1);
}
}
/* semaphore signal */
void semsignal(int id) {
struct sembuf buf;
buf.sem_num=0;
buf.sem_op=+1;
buf.sem_flg=0;
if (-1==semop(id, &buf, 1)) {
perror("semop");
exit(1);
}
}
/* a message structure */
typedef char Msgtxt[20];
typedef struct _message {
long type;
Msgtxt s;
} Message;
int main(int argc, char *argv[]) {
int shid=0;
int semid;
int qid;
int i, j;
Foobar *blah;
union semun un;
Message msg = {1, "blahblah"};
Message rcv;
/* Get a private message queue */
if (-1==(qid=msgget(IPC_PRIVATE, MSG_R|MSG_W))) {
perror("msgget");
exit(1);
}
/* Send a message to yourself */
if (-1==msgsnd(qid, &msg, sizeof(Msgtxt), 0)) {
perror("msgsnd");
exit(1);
}
/* Receive it, print results */
if (-1==msgrcv(qid, &rcv, sizeof(Msgtxt), 1, 0)) {
perror("msgrcv");
exit(1);
}
printf("rcv: %d - %s\n\n",rcv.type, rcv.s);
sleep(3);
/* Get a semaphore to protect shared memory area */
if (-1==(semid=semget(IPC_PRIVATE, 1, SEM_R|SEM_A))) {
perror("semget");
exit(1);
}
/* Initialize it */
un.val=1;
if (-1==semctl(semid, 0, SETVAL, un)) {
perror("semctl-1");
exit(1);
}
/* Get shared memory area */
if (-1==(shid=shmget(IPC_PRIVATE, 10*sizeof(Foobar), SHM_R|SHM_W))) {
perror("shmget");
exit(1);
}
/* Attach it */
if (-1==(blah=(Foobar *)shmat(shid, 0, 0))) {
perror("shmat");
exit(1);
}
/* Fork off a child, write and read something
// in the shared aread both in parent and in child
*/
if (!fork()) {
fprintf(stderr, "Hiya this is my dear child person\n");
for (j=0; j<10; j++) {
semwait(semid);
for (i=0; i<10; i++) {
blah[i].a=blah[i].b=2;
}
semsignal(semid);
sleep(1); /* Otherwise it exits too soon */
semwait(semid);
for (i=0; i<10; i++) {
fprintf(stderr, "\ta %d b %d\n", blah[i].a, blah[i].b);
}
semsignal(semid);
}
exit(0);
}
/* Do the same in the parent */
for (j=0; j<10; j++) {
semwait(semid);
for (i=0; i<10; i++) {
blah[i].a=blah[i].b=1;
}
semsignal(semid);
sleep(1);
semwait(semid);
for (i=0; i<10; i++) {
fprintf(stderr, "a %d b %d\n", blah[i].a, blah[i].b);
}
semsignal(semid);
}
/* Be a good girl/boy: CLEAN AFTER YOURSELF */
wait(NULL);
/* Detach and clear shmem */
if (-1==shmdt((void*)blah)) {
perror("shmdt");
exit(1);
}
if (-1==shmctl(shid, IPC_RMID, NULL)) {
perror("shctl");
exit(1);
}
/* Clear sem */
if (-1==semctl(semid, 1, IPC_RMID, un)) {
perror("semctl-2");
exit(1);
}
/* Clear msgq */
if (-1==msgctl(qid, IPC_RMID, NULL)) {
perror("msgctl");
exit(1);
}
return 0;
}
|