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)
`