Commit 3f8cdcee authored by Arnaud Blanchard's avatar Arnaud Blanchard
Browse files

Initial files for managing blc_channels

parents
# Copyright ETIS — ENSEA, Université de Cergy-Pontoise, CNRS (2011 - 2016)
# Author: Arnaud Blanchard
# This software is governed by the CeCILL v2.1 license under French law and abiding by the rules of distribution of free software.
# You can use, modify and/ or redistribute the software under the terms of the CeCILL v2.1 license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info".
# As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license,
# users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors have only limited liability.
# In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or reproducing the software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge.
# Users are therefore encouraged to load and test the software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured  and, more generally, to use and operate it in the same conditions as regards security.
# The fact that you are presently reading this means that you have had knowledge of the CeCILL v2.1 license and that you accept its terms.
cmake_minimum_required(VERSION 2.6)
project(blc_channel)
add_definitions(-Wall -Wextra -Wno-multichar)
get_filename_component(BLAAR_DIR ${CMAKE_SOURCE_DIR} PATH)
if (NOT TARGET shared_blc_core)
add_subdirectory(${BLAAR_DIR}/blc/blc_core blc_core)
endif()
include_directories(include ${BLC_CORE_INCLUDE_DIR})
#source files
set(sources src/blc_channel.cpp)
add_library(shared_blc_channel SHARED ${sources})
add_library(static_blc_channel STATIC ${sources})
#Both librairies have the same name only the extension will change depending on the OS
set_target_properties(shared_blc_channel PROPERTIES OUTPUT_NAME blc_channel)
set_target_properties(static_blc_channel PROPERTIES OUTPUT_NAME blc_channel)
target_link_libraries(shared_blc_channel shared_blc_core)
#in case it is included for another project
set(BLC_CHANNEL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
#Describe what will be to install or in the package
install(DIRECTORY include/ DESTINATION include)
install(TARGETS shared_blc_channel shared_blc_channel DESTINATION lib)
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Arnaud Blanchard")
include(CPack)
#Building examples
#add_executable(blc_demo examples/blc_demo.c)
#target_link_libraries(blc_demo shared_blc)
#Add a target to generate documentation
#find_package(Doxygen)
#if(DOXYGEN_FOUND)
#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxyfile.in doxyfile.doxy) #Replace the CMAKE variables in the Doxyfile
#add_custom_target(doc_${PROJECT_NAME} ALL ${DOXYGEN_EXECUTABLE} doxyfile.doxy COMMENT "Generating API documentation with Doxygen" VERBATIM )
#else(DOXYGEN_FOUND)
#message("You need to install doxygen to generate the doc.")
#endif(DOXYGEN_FOUND)
blc_array
=========
Define a structure for n-dimentional array.
Depend on libblc_core
PROJECT_NAME = "BLC channelk"
OUTPUT_DIRECTORY = doc/blc_channel
OPTIMIZE_OUTPUT_FOR_C = YES
EXTRACT_LOCAL_CLASSES = NO
HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES
HIDE_FRIEND_COMPOUNDS = YES
HIDE_IN_BODY_DOCS = YES
CASE_SENSE_NAMES = NO
SORT_MEMBER_DOCS = NO
QUIET = YES
INPUT = ${CMAKE_CURRENT_SOURCE_DIR}
RECURSIVE = YES
# USE_MDFILE_AS_MAINPAGE = ${CMAKE_CURRENT_SOURCE_DIR}/README.md
ALPHABETICAL_INDEX = NO
HTML_OUTPUT = html
LATEX_OUTPUT = latex
MACRO_EXPANSION = YES
PREDEFINED = __cplusplus = 1
REPEAT_BRIEF = YES
SKIP_FUNCTION_MACROS = NO
CLASS_DIAGRAMS = NO
/* Basic Library for C/C++ (blclib)
Copyright ETIS — ENSEA, Université de Cergy-Pontoise, CNRS (2011 - 2015)
Author: Aranud Blanchard
This software is a computer program whose purpose is to simulate neural networks and control robots or simulations.
This software is governed by the CeCILL v2.1 license under French law and abiding by the rules of distribution of free software.
You can use, modify and/ or redistribute the software under the terms of the CeCILL v2.1 license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license,
 users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors have only limited liability.
 In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or reproducing the software by the user in light of its specific status of free software,
 that may mean that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge.
Users are therefore encouraged to load and test the software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured
 and, more generally, to use and operate it in the same conditions as regards security.
 The fact that you are presently reading this means that you have had knowledge of the CeCILL v2.1 license and that you accept its terms. */
/**
*
* @date Oct 10, 2014
* @author Arnaud Blanchard
@defgroup blc_channel channels
@{
*/
#ifndef BLC_CHANNEL_H
#define BLC_CHANNEL_H
#include "blc_tools.h"
#include "blc_array.h"
#include <limits.h> //NAME_MAX, ...
#include <fcntl.h> //< O_... constants O_RDONLY, 0_RDWR, O_WRONLY
#define SEM_NAME_LEN 31 // At least on OSX
#define BLC_CHANNELS_MAX UINT16_MAX
#define BLC_CHANNEL_READ O_RDONLY
#define BLC_CHANNEL_WRITE O_RDWR
#define BLC_CHANNEL_READ_BLOCK (O_RDONLY | (O_ACCMODE + 1 )) // (O_ACCMODE + 1 First flag after access mode (O_RDONLY, O_RDWR))
#define BLC_CHANNEL_WRITE_BLOCK (O_RDWR | (O_ACCMODE + 1 )) // (O_ACCMODE + 1 First flag after access mode (O_RDONLY, O_RDWR)
#define BLC_PARAMETER_MAX 31
#define EXIT_ON_CHANNEL_ERROR(channel, ...) blc_channel_fatal_error(channel, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
typedef struct shared_control{
pthread_mutex_t mutex;
pthread_cond_t writer_cond, reader_cond;
int writing;
uint64_t new_value_flags, readers_flags, reading_flags; //bitfield max 64 blocking_readers;
}blc_share_control;
typedef struct blc_channel
#ifdef __cplusplus
:blc_array {
blc_channel();
blc_channel(char const *name, int mode, uint32_t type, uint32_t format, int dims_nb, int length0, ...);
int fscan_info(FILE *file);
void fprint_info(FILE *file);
void map_memory(int mode);
void open_block_semaphore();
void open_ack_semaphore();
void create_semaphores();
void vcreate(char const *name, int mode, uint32_t type, uint32_t format, int dims_nb, int length0, va_list arguments);
int vcreate_or_open(char const *name, int mode, uint32_t type, uint32_t format, int dims_nb, int length0, va_list arguments);
void create(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, int length0, ...);
void create(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, blc_dim *dims);
void create();
void open(const char *name, int mode);
int create_or_open(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, int length0, ...);
int create_or_open(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, blc_dim *dims);
///Send the name of the channel on stdout
void publish();
void fprint_debug(FILE *file=stdout);
int create_or_open_control();
void close_control();
void begin_write();
void begin_read();
void end_write();
void end_read();
/* void protect(int value=1);*/
void set_namef(char const *name, ...);
void unlink(); //Remove the memory from the system unless another process retain it.
//Unmap the memory and close the file but the other informations are kept. The semaphores are not affected. @TODO See what to do with semaphores
void close();
#else
{
blc_array array;// Not beautiful but makes it easy to convert C++ heritage of "class" in C struct inclusion.
#endif
int id, mode;
char name[NAME_MAX+1];
char parameter[BLC_PARAMETER_MAX+1];
int fd, ctrl_fd ; ///< shared memory file descriptor
blc_share_control *control; //Part that we be share in purpose of control
uint64_t reader_flag;
}blc_channel;
extern int blc_channel_port;
void start_channel_server(int port);
START_EXTERN_C
void blc_channel_fatal_error(blc_channel *channel, const char *name_of_file, const char* name_of_function, int numero_of_line, const char *message, ...);
/*Create a channel with the name, the kind of semaphore "abp" a:ack, b:block, p:protect, the type of data UIN8, INT8, UI16, IN16, FL32, FL64. ( default 0:UIN8),
The format are four chars user defined but usually describe the image format 'RGB3', 'YUV2' ,..., parameter is an user defined text.
Dims_nb is the number of dimenssions of the data ( 1 for a vector).
The following value are the the length of each dims. You must have the same number of length than dim.
*/
void blc_channel_create(blc_channel* channel, const char *name, int mode, uint32_t type, uint32_t format, int dims_nb, int length0, ...);
/*Open an exisiting channel 'name' */
void blc_channel_open(blc_channel* channel, const char *name, int mode);
int blc_channel_create_or_open(blc_channel *channel, const char *name, int mode, uint32_t type, uint32_t format, int dims_nb, int length0, ...);
/** Close the channel and unlink the shared memory. No new process can use it.*/
int blc_channel_unlink(blc_channel *channel);
/** Allocate (need to be free) and give the array of existing shared memory files on the system.*/
int blc_channel_get_all_infos(blc_channel **channels_infos);
/** Allocate (need to be free) and give the array of existing shared memory files on the system.*/
int blc_channel_get_all_infos_with_filter(blc_channel **channels_infos, char const *start_name_filter);
///Retrieve the informations about a channel if it is known and return the id. Otherwise, return -1
int blc_channel_get_info_with_name(blc_channel *info, char const *name);
/** Remove the channels
* \param channels Address of a pointer to an array containing a list of channel. This array may have been created by blc_channel_get_availables.
* \param channels_nb number of channels in the array.*/
void blc_channel_close_all(blc_channel *channels, int channels_nb);
void blc_channel_begin_write(blc_channel *channel);
void blc_channel_end_write(blc_channel *channel);
void blc_channel_begin_read(blc_channel *channel);
void blc_channel_end_read(blc_channel *channel);
void blc_channel_check_changes(void(*callback)(void* user_data), void *user_data);
END_EXTERN_C
///@}
#endif
/*
Basic Library for C/C++ (blclib)
Copyright ETIS — ENSEA, Université de Cergy-Pontoise, CNRS (2011 - 2015)
Author: Arnaud Blanchard
This software is governed by the CeCILL v2.1 license under French law and abiding by the rules of distribution of free software.
You can use, modify and/ or redistribute the software under the terms of the CeCILL v2.1 license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license,
 users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors have only limited liability.
 In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or reproducing the software by the user in light of its specific status of free software,
 that may mean that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge.
Users are therefore encouraged to load and test the software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured
 and, more generally, to use and operate it in the same conditions as regards security.
 The fact that you are presently reading this means that you have had knowledge of the CeCILL v2.1 license and that you accept its terms. *
*
*
* Created on: Oct 9, 2014
* Author: Arnaud Blanchard
*/
#include "blc_channel.h"
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/mman.h> //mmap
#include <sys/stat.h> // mode S_ ... constants
#include "blc_core.h"
#define TMP_BUFFER_SIZE 4096
#define BLC_CHANNELS_LIST_PATH "/tmp/blc_channels.txt"
#define CHANNELS_CONTROL_FILENAME "/blc_channels-ctrl"
static int blc_channel_id_max = 0;
static blc_channel blc_semaphores_channel;
static struct channels_control{
pthread_mutex_t mutex;
pthread_cond_t cond;
int event;
} *channels_control=NULL;
static pthread_t channels_control_thread;
static void (*channel_event_callback)(void*)=NULL;
static void create_or_open_channels_control(){
int created;
int fd, error;
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
fd = shm_open(CHANNELS_CONTROL_FILENAME, O_CREAT | O_EXCL | O_RDWR, S_IRWXU);
if (fd==-1)
{
if (errno == EEXIST) { //The file already exist, we open it
SYSTEM_ERROR_CHECK(fd = shm_open(CHANNELS_CONTROL_FILENAME, O_RDWR, S_IRWXU), -1, NULL);
}else EXIT_ON_SYSTEM_ERROR("Creating channel event control");
created=0;
}
else{ //We have created a new controler we define its size
SYSTEM_ERROR_CHECK(ftruncate(fd, sizeof(struct channels_control)), -1, NULL);
created=1;
}
SYSTEM_ERROR_CHECK(channels_control = (struct channels_control*)mmap(0, sizeof(struct channels_control), PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0), MAP_FAILED, "Mapping "CHANNELS_CONTROL_FILENAME" (size %ld bytes), fd(%d).", sizeof(blc_share_control), fd);
if (channels_control==NULL) EXIT_ON_ERROR( "Mapping channels_control");
if (created){
PTHREAD_CHECK(pthread_mutexattr_init(&mutex_attr), error, NULL);
PTHREAD_CHECK(pthread_condattr_init(&cond_attr), error, NULL);
PTHREAD_CHECK(pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED), error, NULL);
PTHREAD_CHECK(pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK), error, NULL);
PTHREAD_CHECK(pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED), error, NULL);
PTHREAD_CHECK(pthread_mutex_init(&channels_control->mutex, &mutex_attr), error, NULL);
PTHREAD_CHECK(pthread_cond_init(&channels_control->cond, &cond_attr), error, NULL);
PTHREAD_CHECK(pthread_mutexattr_destroy(&mutex_attr), error, NULL);
PTHREAD_CHECK(pthread_condattr_destroy(&cond_attr), error, NULL);
}
}
static void channels_set_event(){
int error;
if (channels_control==NULL) create_or_open_channels_control();
channels_control->event=1;
PTHREAD_CHECK(pthread_cond_broadcast(&channels_control->cond), error, NULL);
}
blc_channel::blc_channel(): mode(0), fd(-1),control(NULL){}
blc_channel::blc_channel(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, int length, ...): mode(0), control(NULL)
{
va_list arguments;
va_start(arguments, length);
vcreate_or_open(new_name, mode, type,format, dims_nb, length, arguments);
va_end(arguments);
}
void blc_channel::fprint_info(FILE *file){
int width;
uint32_t net_type = htonl(type);
uint32_t net_format = htonl(format);
if (type==0) EXIT_ON_ERROR("The type should not be null for '%s'. Use NDEF by default.", name);
if (format==0) EXIT_ON_ERROR("The format should not be null for '%s'. Use NDEF by default.", name);
if (parameter[0]==0) EXIT_ON_ERROR("The parameter should not be null for '%s'. Use NDEF by default.", name);
fprintf(file, "%6d %.4s %.4s %-31s ", id, (char*)&net_type, (char*)&net_format, parameter);
width=fprint_dims(file);
fprintf(file, "%*c", 32-width, ' ');
if (strlen(name)==0) EXIT_ON_ERROR("name is empty");
fprintf(file, " %s\n", name);
}
int blc_channel::fscan_info(FILE *file){
int ret;
dims_nb=0;
data=NULL;
size=0;
ret = fscanf(file, "%d %4c %4c %31s", &id, (char*)&type, (char*)&format, parameter);
if (ret == EOF) return -1;
else if (ret!=4) EXIT_ON_ERROR("Only %d parameters have been read instead of 5 in " BLC_CHANNELS_LIST_PATH" id '%d'.", ret, id);
NTOHL(type);
NTOHL(format);
fscan_dims(file);
if (fscanf(file, " %"STRINGIFY_CONTENT(NAME_MAX)"[^\n]\n", name) != 1) EXIT_ON_ERROR("Impossible to read channel's name of channel id '%d'.", id);
if (id > blc_channel_id_max) blc_channel_id_max=id;
return id;
}
void blc_channel::set_namef(char const *format, ...)
{
va_list arguments;
va_start(arguments, format);
if (vsnprintf(this->name, sizeof(this->name), format, arguments) >= (int)sizeof(this->name)) EXIT_ON_ERROR("Channel name '%s' has been cropped, it is more than '%d' chars", name, sizeof(name));
else if (name[0]!='/') EXIT_ON_ERROR("Shared memory names have to start with '/' but it is not the case in '%s'.", name);
va_end(arguments);
}
int blc_channel::create_or_open_control(){
char control_filename[NAME_MAX+1];
int error, i;
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
int created=0;
SPRINTF(control_filename, "/blc_channel%d-ctrl", id);
ctrl_fd = shm_open(control_filename, O_CREAT | O_EXCL | O_RDWR, S_IRWXU);
if (ctrl_fd==-1)
{
if (errno == EEXIST) { //The file already exist, we open it
SYSTEM_ERROR_CHECK(ctrl_fd = shm_open(control_filename, O_RDWR, S_IRWXU), -1, "channel '%s'", name);
}else EXIT_ON_SYSTEM_ERROR("Creating channel control '%s'.", name);
}
else{ //We have created a new controler we define its size
SYSTEM_ERROR_CHECK(ftruncate(ctrl_fd, sizeof(blc_share_control)), -1, "channel '%s', fd:%d, size '%ld'.", name, fd, sizeof(blc_share_control));
created=1;
}
SYSTEM_ERROR_CHECK(control = (blc_share_control*)mmap(0, sizeof(blc_share_control), PROT_WRITE | PROT_READ, MAP_SHARED, ctrl_fd, 0), MAP_FAILED, "Mapping control of %s (size %ld bytes), ctrl_fd(%d).", control_filename, sizeof(blc_share_control), ctrl_fd);
if (control==NULL) EXIT_ON_CHANNEL_ERROR(this, "Mapping control");
if (created){
PTHREAD_CHECK(pthread_mutexattr_init(&mutex_attr), error, "channel '%s'", name);
PTHREAD_CHECK(pthread_condattr_init(&cond_attr), error ,"channel '%s'", name) ;
PTHREAD_CHECK(pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED), error, "channel '%s'", name);
PTHREAD_CHECK(pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK), error, "channel '%s'" , name);
PTHREAD_CHECK(pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED), error, "channel '%s'", name);
PTHREAD_CHECK(pthread_mutex_init(&control->mutex, &mutex_attr), error, "channel '%s'", name);
PTHREAD_CHECK(pthread_cond_init(&control->writer_cond, &cond_attr), error, "channel '%s'", name);
PTHREAD_CHECK(pthread_cond_init(&control->reader_cond, &cond_attr), error, "channel '%s'", name);
PTHREAD_CHECK(pthread_mutexattr_destroy(&mutex_attr), error, NULL);
PTHREAD_CHECK(pthread_condattr_destroy(&cond_attr), error, NULL);
control->readers_flags = 0;
}
if (mode==BLC_CHANNEL_READ_BLOCK){
PTHREAD_CHECK(pthread_mutex_lock(&control->mutex), error, NULL);
if (created) reader_flag=1;
else{
//Look for an empty flag;
FOR(i, 64) if ((control->readers_flags & (1<<i))==0) break;
if ( i==-1) EXIT_ON_CHANNEL_ERROR(this, "Too many readers");
reader_flag=1<<i;
}
//We say that is a new value
control->new_value_flags|=reader_flag;
//We add the reader to the 'list'
control->readers_flags|=reader_flag;
SYSTEM_SUCCESS_CHECK(pthread_mutex_unlock(&control->mutex), 0, "channel '%s'", name);
}
return created;
}
void blc_channel::map_memory(int mode){
int prot=0;
this->mode=mode;
switch (mode & O_ACCMODE){
case O_RDONLY:prot=PROT_READ;break;
case O_RDWR:prot=PROT_WRITE | PROT_READ; break;
default: EXIT_ON_CHANNEL_ERROR(this, "Unknown mode '%d'.", mode);
}
SYSTEM_ERROR_CHECK(data = mmap(0, size, prot, MAP_SHARED, fd, 0), MAP_FAILED, "Mapping memory of %s (size %ld bytes), fd(%d), prot(%d).", name, size, fd, prot);
if (data==NULL) EXIT_ON_CHANNEL_ERROR(this, "Fail mapping blc_channel");
create_or_open_control();
channels_set_event();
}
void blc_channel::close_control(){
if (mode==BLC_CHANNEL_READ_BLOCK) control->readers_flags&=~reader_flag;
SYSTEM_SUCCESS_CHECK(munmap(control, sizeof(blc_share_control)), 0, "closing channel '%s'", name);
SYSTEM_SUCCESS_CHECK(::close(ctrl_fd), 0, "closing channel '%s'", name);
control=NULL;
}
///Open an existing channel, the sem_flags should not be global but a opening parameter.
void blc_channel::open(const char *new_name, int mode){
STRCPY(this->name, new_name);
id = blc_channel_get_info_with_name(this, name);
if (id==-1) EXIT_ON_ERROR("The blc_channel '%s' does not exist. Run blc_channels", name);
SYSTEM_ERROR_CHECK(fd = shm_open(name, mode, S_IRWXU), -1, "Impossible to open shared memory '%s'with mode %d.", name, mode);
map_memory(mode);
}
///Create a blc channel
void blc_channel::vcreate(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, int length0, va_list arguments){
blc_channel channel;
FILE *file;
vdef_array(type, format, dims_nb, length0, arguments);
strcpy(parameter, "NDEF");
if (new_name) STRCPY(name, new_name);
else if (*name==0) EXIT_ON_ERROR("The name has not been defined");
id = blc_channel_get_info_with_name(&channel, name);
if (id !=-1 ) EXIT_ON_ERROR("The channel '%s' is already referenced in '" BLC_CHANNELS_LIST_PATH"'.\nUnlink it before.", name);
if (blc_channel_id_max == BLC_CHANNELS_MAX) EXIT_ON_CHANNEL_ERROR(this, "creation impossible, channel id (%d) too big", blc_channel_id_max);
else blc_channel_id_max++;
id = blc_channel_id_max;
SYSTEM_ERROR_CHECK(file=fopen(BLC_CHANNELS_LIST_PATH, "a+"), NULL, "Openning the file '" BLC_CHANNELS_LIST_PATH"' in order to reference the channel '%s'.", name);
fd = shm_open(name, O_CREAT | O_EXCL | mode, S_IRWXU); // (O_EXCL first) is important in order to avoid a race condition. We create it at the same time we check it does not exist. Otherwise someone else could create it in between.
if (fd==-1){
fclose(file);
if (errno == EEXIST) EXIT_ON_ERROR("The shared memory '%s' already exists, you should destroy it before.", name);
else EXIT_ON_SYSTEM_ERROR("Creating shared memory '%s'.", name);
}
else{
fprint_info(file);
fclose(file);
SYSTEM_ERROR_CHECK(ftruncate(fd, size), -1, "fd:%d, size '%ld'.", fd, size);
map_memory(mode);
}
}
///Create a blc channel
void blc_channel::create(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, blc_dim *dims){
blc_channel channel;
FILE *file;
def_array(type, format, dims_nb, dims);
strcpy(parameter, "NDEF");
STRCPY(name, new_name);
id = blc_channel_get_info_with_name(&channel, name);
if (id !=-1 ) EXIT_ON_ERROR("The channel '%s' is already referenced in '" BLC_CHANNELS_LIST_PATH"'.\nUnlink it before.", name);
if (blc_channel_id_max == BLC_CHANNELS_MAX) EXIT_ON_CHANNEL_ERROR(this, "creation impossible, channel id (%d) too big", blc_channel_id_max);
else blc_channel_id_max++;
id = blc_channel_id_max;
SYSTEM_ERROR_CHECK(file=fopen(BLC_CHANNELS_LIST_PATH, "a+"), NULL, "Openning the file '" BLC_CHANNELS_LIST_PATH"' in order to reference the channel '%s'.", name);
fd = shm_open(name, O_CREAT | O_EXCL | mode, S_IRWXU); // (O_EXCL first) is important in order to avoid a race condition. We create it at the same time we check it does not exist. Otherwise someone else could create it in between.
if (fd==-1){
fclose(file);
if (errno == EEXIST) EXIT_ON_ERROR("The shared memory '%s' already exists, you should destroy it before.", name);
else EXIT_ON_SYSTEM_ERROR("Creating shared memory '%s'.", name);
}
else{
fprint_info(file);
fclose(file);
SYSTEM_ERROR_CHECK(ftruncate(fd, size), -1, "fd:%d, size '%ld'.", fd, size);
map_memory(mode);
}
}
///Create a blc channel
int blc_channel::vcreate_or_open(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, int length, va_list arguments){
int dim, create=1;
uint32_t new_type_str, new_format_str;
id = blc_channel_get_info_with_name(this, new_name);
if (id==-1) vcreate(new_name, mode, type, format, dims_nb, length, arguments);
else{
if (this->dims_nb!=dims_nb) EXIT_ON_CHANNEL_ERROR(this, "Reopening a blc_channel with different dims_nb '%d'.", dims_nb);
if (this->type!=type) EXIT_ON_CHANNEL_ERROR(this, "Reopening blc_channel with another type '%.4s'", UINT32_TO_STRING(new_type_str, type));
if (this->format!=format) EXIT_ON_CHANNEL_ERROR(this, "Reopening blc_channel with another format '%.4s'", UINT32_TO_STRING(new_format_str, format));
if (this->dims_nb!=0){
if (length && (dims[0].length != length)) EXIT_ON_ERROR("The reopening first dimmension length '%d' of '%s' differ from the existing one '%d'.", length, name, dims[0].length);
for(dim=1; dim != this->dims_nb; dim++) {
if (length && (dims[dim].length!=va_arg(arguments, int))) EXIT_ON_ERROR("The reopening dimmension %d length '%d' of '%s' differ from the existing one '%d'.", dim, length, name, dims[dim].length);
}
}
open(new_name, mode);
create=0;
}
return create;
}
int blc_channel::create_or_open(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, blc_dim *dims){
int id, dim, created;
uint32_t new_type_str, new_format_str;
id = blc_channel_get_info_with_name(this, new_name);
if (id==-1) {
create(new_name, mode, type, format, dims_nb, dims);
created=1;
}
else{
if (this->dims_nb!=dims_nb) EXIT_ON_CHANNEL_ERROR(this, "Reopening a blc_channel with different dims_nb '%d'.", dims_nb);
if (