Inter-process communication : Unix systems

Julien AGUILAR
5 min readApr 8, 2017

--

The following is my first article and shouldn’t be taken too seriously. I’m a french computer science student and the piece you’re about to read is part of an assessment. Enjoy !

Inter-process communication : a brief reminder

The first release of the System V UNIX operating system, developed by AT&T UNIX Support Group (USG), is published in 1983. This system brings along a few features, like the curse library, the vi editor, or, plot twist, the support for inter-process communication (let’s switch to IPC).

IPC simply allows processes to share data. When a process is running (see below), it has its own memory-space and its own resources (variables — functions…).

A conceptual model of a UNIX process — https://www.ibm.com/developerworks/aix/library/au-speakingunix8/

Sometimes, a user may want processes to communicate, to share data or to perform actions together. This is the very purpose of IPC.

Lemipc : let’s take a look

The lemipc is a two week Epitech project which tackle the concept of concurrent accesses. The goal is to fight players on a two dimensions game board. When a player is surrounded, it dies. 3 IPC methods are explored within this project :

Shared memory : shared memory is a memory block that can be accessed simultaneously by multiple processes. The project’s game board will be stored in a shared memory segment, so that the players have a common area to evolve.

Semaphores : A semaphore is used to control access to a shared resource. In our case, we need to protect the board. When a player wants to access a cell, we have to be sure that this cell is available.

A semaphore. Yes.

Message queue : The players need to have a certain strategy : each player can communicate with its team. To do that, we’ll use a message queue. A process can send or receive a message, which will make our players smarter (or less dumb)

Let’s talk code

Now that we have a better understanding of IPC, let’s see some code. The project contains only one binary. The first call will create the shared memory segment, and all the other calls will add a player to the game, with the specified team id. I use the return value to check if the resources are already created. Do not forget to check the errno variable

First of all, System V IPC relative functions need a key to work. We’ll use the ftok() function.

#include <sys/ipc.h>
...
key_t key;
char *path = "/valid/path";
int project_id = 42;
key = ftok(path, project_id);if (key == -1)
// error

We now have our key, it’s time to create the shared memory segment :

#include <sys/shm.h>
#include <sys/types.h>
...
int shm_id;
void *addr;
// we try to access the segment
shm_id = shmget(key, size, SHM_R | SHM_W);
if (shm_id == -1) // if it doesn't exist, we create it
{
if (errno)
// error
shm_id = shmget(key, size, IPC_CREAT | SHM_R | SHM_W);
}
// we now store the segment address !
addr = shmat(lemme->shm_id, NULL, SHM_R | SHM_W);

We have our board ! We now need to secure it with a semaphore. To create or to access a semaphore, we use the exact same code as before, with the semget() function :

#include <sys/sem.h>
...
int sem_id;
// we only need 1 semaphore
sem_id = semget(key, 1, SHM_R | SHM_W);
if (sem_id == -1)
{
if (errno)
// error
sem_id = semget(key, 1, IPC_CREAT | SHM_R | SHM_W);
semctl(sem_id, 0, SETVAL, 1);
}

Our semaphore can now be used. It acts like a counter. When its value is 0, the resource, our board, is locked. To change the counter’s value, we use a structure and a function, semop() :

struct sembuf         sops;                           

sops.sem_num = 0;
sops.sem_flg = 0;
sops.sem_op = op; // 1 or -1, to increase or decrease the counter
semop(sem_id, &sops, 1);

We need to perform this operation every time we want to access the board. The execution is simple : lock — check / modify the board — unlock.

Our players can now access to a protected game board. Since we didn’t have the time to create a powerful AI, they can only perform a few basic actions:

Their default comportment is to rush toward the center. If a player encounters an enemy, it will send a message to its team, ordering the other players to come and help. To create or use a message queue, we need to use the msgget() function, which has the same behavior as the others :

#include <sys/msg.h>
...
int msg_id;
msg_id = msgget(key, SHM_R | SHM_W);
if (msg_id == -1)
{
if (errno)
// error
msg_id = msgget(key, IPC_CREAT | SHM_R | SHM_W);
}

Let’s now see how to send or receive a message :

typedef struct  s_msg                              
{
long mtype; // the message type, our team number
char mtext[MSGSZ]; // the message text, our positions
} t_msg;
// We use a t_msg-like structure to send information.
// The IPC_NOWAIT flag allows the execution to continue
// if no message is received.
msgsnd(msg_id, &msg, sizeof(msg), IPC_NOWAIT);msgrcv(msg_id, msg, sizeof(*msg), team_number, IPC_NOWAIT);

So… Here we are… players can communicate, the game can start !

The final product

Here are some screens about the different steps of our game. Just a nice and awesome SFML graphical view of our board.

A game board, with some players in it

As expected, the players are heading toward the center :

Rush B P90 no stop
We have our winner

To sum up !

This was a cool project ! IPC is a very interesting notion, not so hard to understand. We had at first a few troubles to implement the message queue, because we didn’t know what to do with them. Anyway, it was fun !

I hope you have enjoyed reading this. It was my first article, and my English is not fluent, but I tried ! Don’t hesitate to correct my mistakes, the comment section is below :D Here’s a list of useful links, related of course to IPC :

http://www.tldp.org/pub/Linux/docs/ldp-archived/linuxfocus/English/Archives/lf-2003_01-0281.pdf

https://en.wikipedia.org/wiki/Inter-process_communication

https://linux.die.net/man/

Thanks !

--

--