Reference to Primer on Interprocess Communication in Linux

​Dhanesh,

In Linux, we create a pipe using mknod(). I would like to create a buffered pipe( of length L, say), on which a remote process can write into using socket. How can we associate one end of pipe to a socket?

Here, http://beej.us/guide/bgipc/output/html/singlepage/bgipc.html is a useful IPC primer written in c. The devil is in the details as Wally alluded.

The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.
​ - Donald Knuth​

Regards,

Paul

Great guide, but I fear its at a low enough level it might scare people away. It leaves out mention of some of the higher level POSIX functions that can greatly simplify things. Love the Knuth quote!

Most of my named semaphore and shared memory code over the years has worked well with a few simple utility functions based on shm_open() and sem_open(), sem_wait(), and sem_post() by reusing these simple utilty functions I’ve used for years andmost recently on my Beaglebones:

`

#include <sys/time.h>
#include <time.h>
#include <fcntl.h> /* For O_* constants in open*/
#include <sys/stat.h> /* For mode constants in open*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <semaphore.h> /* requires linking with -lrt or -lpthread */
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

// Build object file for linking:
// gcc -c shm_ipc.c
//
// Build program that uses these functions:
// gcc program.c shm_ipc.o -o program_name -lrt -lpthread
// OR
// gcc program.c shm_ipc.c -o program_name -lrt -lpthread

// utility function to setup shared memory
void* setupSharedMemory(int* ipcFile, char* shrmem_filename, size_t size, FILE *logFile){

void *f_ptr=NULL;
int i,n=0;
char tmp, *str;

if (logFile) fprintf(logFile,“Creating POSIX shared memory: %s\n”, shrmem_filename);
if((*ipcFile=shm_open(shrmem_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)) <= 0){
if(logFile)
fprintf(logFile,"%s Shared memory file open failed!\n", shrmem_filename);
else
fprintf(stderr,"%s Shared memory file open failed!\n", shrmem_filename);
return(NULL);
}
// set the shared memory size – looks a lot like setting up a mmapped file, doesn’t it? By POSIX design!
if(ftruncate(*ipcFile, size)){
if(logFile)
fprintf(logFile,“ftruncate() can’t set %s ipcFile file length: %d Check for disk space or permissions.\n”, shrmem_filename, (int) size);
else
fprintf(stderr,“ftruncate() can’t set %s ipcFile file length: %d Check for disk space or permissions.\n”, shrmem_filename, (int) size);
close(*ipcFile);
*ipcFile=-1;
return(NULL);
}
if((f_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *ipcFile, 0)) == MAP_FAILED){
if(logFile)
fprintf(logFile,“can’t mmap %s ipcFile!\n”, shrmem_filename);
else
fprintf(stderr,“can’t mmap %s ipcFile!\n”, shrmem_filename);
close(*ipcFile);
*ipcFile=-1;
return(NULL);
}else{
// force memory access so page faults happen when it won’t matter
str=(char *)f_ptr;
for(i=0; (unsigned)i<size; i+=sysconf(_SC_PAGESIZE)){
n+=tmp=str[i];
str[i]=tmp;
}
return(f_ptr);
}
}

// what happens is the same for both mmapped files and shared memory
void cleanupMmappedFile(int ipcFile, void* f_ptr, size_t size){
munmap(f_ptr, size);
close(ipcFile);
}

sem_t* createNamedSemaphore(char* sem_name, FILE *logFile){

sem_t *Umutex=SEM_FAILED;

if(logFile) fprintf(logFile,“Creating Named Semaphore: %s\n”, sem_name);
Umutex = sem_open(sem_name, O_CREAT, 0660, 1); // always getting 640
if(Umutex == SEM_FAILED){
if(logFile)
fprintf(logFile,"%s *** Unable to create named semaphore!!!\n", sem_name);
else
fprintf(stderr,"%s *** Unable to create named semaphore!!!\n", sem_name);
sem_unlink(sem_name); // is this the correct boilerplate response for failure?
}
return(Umutex);
}

// cleanup semaphore
void cleanupSemaphore(char* sem_name, sem_t* Umutex){

sem_close(Umutex);
sem_unlink(sem_name);
}

`

Usage is pretty straight forward:

`

//I try to avoid uisng signals in multi-threaded situations, but the basics help things quit cleanly

// signal handler function, which just tries to provide a graceful exit via ctrl-C key press via a global variable.
int QUIT=0;

void handler(int signal){
QUIT=1;
}

int main( int argc, char** argv ){
{ //Setup signal handler for graceful exit

struct sigaction act;
act.sa_handler=handler; // try to catch all signals and set QUIT flag for a graceful exit
sigemptyset(&act.sa_mask);
act.sa_flags=0;
sigaction(SIGINT, &act, 0);
sigaction(SIGHUP, &act, 0);
sigaction(SIGQUIT, &act, 0);
sigaction(SIGTERM, &act, 0);
sigaction(SIGTSTP, &act, 0);
sigaction(SIGSEGV, &act, 0);
}
{ // setup mutex, open/create shared memory file pointer

alarm_mutex=createNamedSemaphore(SEM_NAME, NULL);
if(alarm_mutex == SEM_FAILED){
closeAlarm();
fprintf(stderr,“Failed to Create Alarm Mutex, exiting!\n”);
return(-1);
}
shmptr=setupSharedMemory(&ipcFile, SHM_NAME, sizeof(ALARMBONE_SHM), NULL);
if(shmptr == NULL){
cleanupSemaphore(SEM_NAME, alarm_mutex);
closeAlarm();
fprintf(stderr,“Failed to set up shared memory, exiting!\n”);
return(-1);
}
}

// cleanup on exit

cleanupSemaphore(SEM_NAME, alarm_mutex);
cleanupMmappedFile(int ipcFile, void* f_ptr, size_t size)

`

Sorry, I hate the Google Groups interface. This posted a bit prematurely when I hit a “shortcut” key by mistake :frowning:

The cleanupMmappedFile() cut and paste at the end should be:
cleanupMmappedFile(ipcFile, shmptr, sizeof(ALARMBONE_SHM));

You protect the shared memory access in various threads or processes with:

sem_wait(alarm_mutex);
// do your thing that needs to be atomic to others
sem_post(alarm_mutex);

I tend to use named semaphores instead of POSIX mutexes because I find the setup and syntax simpler, and they work with multiple processes as well as threads launched by the main process and pretty much hide all the complexity of fork() etc. from you.