Commit 8820c002 authored by Arnaud Blanchard's avatar Arnaud Blanchard
Browse files

Simplification and documentation

parent 3903c693
......@@ -18,8 +18,6 @@ find_package(blc_core REQUIRED)
#source files
set(sources src/blc_channel.cpp
src/blc_channel_control.cpp
# src/blc_net_channel.cpp
)
add_definitions(${BL_DEFINITIONS})
......
BLC channel
===========
Copyright : [ETIS](http://www.etis.ensea.fr/neurocyber) - ENSEA, University of Cergy-Pontoise, CNRS (2011-2016)
Author : [Arnaud Blanchard](http://arnaudblanchard.thoughtsheet.com)
Licence : [CeCILL v2.1](http://www.cecill.info/licences/Licence_CeCILL_V2-en.html)
- Copyright : [ETIS](http://www.etis.ensea.fr/neurocyber) - ENSEA, University of Cergy-Pontoise, CNRS (2011-2016)
- Author : [Arnaud Blanchard](http://arnaudblanchard.thoughtsheet.com)
- Licence : [CeCILL v2.1](http://www.cecill.info/licences/Licence_CeCILL_V2-en.html)
See [online documentation](https://framagit.org/blaar/blc_channel/wikis/home)
\ No newline at end of file
......@@ -14,13 +14,7 @@
 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
......@@ -29,43 +23,34 @@
#include <limits.h> //< NAME_MAX, ...
#include <fcntl.h> //< O_... constants O_RDONLY, 0_RDWR, O_WRONLY
#include <semaphore.h>
/*
For now we use sem_open. Sem_init is not OSX compatible
#ifdef __APPLE__
#include <dispatch/dispatch.h>
#define BLC_SEM dispatch_semaphore_t
#define BLC_SEM_INIT(semaphore, count) semaphore=dispatch_semaphore_create(count)
#define BLC_SEM_WAIT(semaphore) dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
#define BLC_SEM_POST(semaphore) dispatch_semaphore_signal(semaphore)
#elif __linux__
#define SEM_T sem_t
// to be completed maybe using futex
#endif
/**\mainpage Summary
- \ref blc_channel
*/
/**\defgroup blc_channel blc_channel functions
\{
*/
#define SEM_NAME_LEN 31 // At least on OSX
///Max number of blc_channels
#define BLC_CHANNELS_MAX UINT16_MAX
///Define channel in reading mode only
#define BLC_CHANNEL_READ O_RDONLY
///Defines channel in writting mode ( if memory can be written, we cannot disable reading )
#define BLC_CHANNEL_WRITE O_RDWR
///Not yet in use
#define BLC_CHANNEL_SYNC 4 // O_ACCMODE + 1 First flag after access mode
///Not yet in use
#define BLC_CHANNEL_BLOCK (BLC_CHANNEL_SYNC | 8) //BLOCK has to be SYNC
#define BLC_CHANNEL_READ_BLOCK (O_RDONLY | BLC_CHANNEL_BLOCK)
#define BLC_CHANNEL_WRITE_BLOCK (O_RDWR | BLC_CHANNEL_BLOCK)
#define BLC_CHANNEL_READ_SYNC (O_RDONLY | BLC_CHANNEL_SYNC)
#define BLC_CHANNEL_WRITE_SYNC (O_RDWR | BLC_CHANNEL_SYNC)
///Size of parameters for a channel description. Parameter is not used at this moment
#define BLC_PARAMETER_MAX 31
///Like EXIT_ON_ERROR but also display all debug informatin about the blc_channel
#define EXIT_ON_CHANNEL_ERROR(channel, ...) blc_channel_fatal_error(channel, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
///Not yet in use. Structure that will be used for synchronisation.
typedef struct shared_control{
/* pthread_mutex_t mutex;
pthread_cond_t writer_cond, reader_cond;*/
......@@ -74,63 +59,70 @@ typedef struct shared_control{
struct timeval write_time;
}blc_share_control;
///Structure extending blc_array allowing it to be share among processes
typedef struct blc_channel
#ifdef __cplusplus
:blc_array {
///Constructor initiating an empty blc_channel
blc_channel();
///Constructor opening the blc_channel in reading mode by default (otherwise use BLC_CHANNEL_WRITE)
blc_channel(char const *new_name, int mode);
///Constructor creating or opening the channel if it exist. In this case it has to be compatible with its properties.
blc_channel(char const *name, int mode, uint32_t type, uint32_t format, int dims_nb, int length0, ...);
//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
~blc_channel();
/**Check if the current description of the blc_channel and the blc_channel **name** are compatible. Useful to know if you need to use another name for a new blc_channel or to remove the previous one.
The return value indicates the conflict:
- 0 if there is no conflict
- 1 the number of dimensions differs
- 2 the type differs
- 3 the format differs
- 4 one of the dimension does not have the same length*/
int conflict(const char *name);
/**Set the blc_channel properties with the string (i.e "UIN8 RGB3 3x800x600 /channel_name")*/
int sscan_info(char const *string);
/**Set the blc_channel properties with the content of the file (i.e "UIN8 RGB3 3x800x600 /channel_name").
**scan_id** is a flag precising if the channel id preceeds the properties*/
int fscan_info(FILE *file, int scan_id);
/**Write the properties of the blc_channel on the buffer*/
void sprint_info(char *buffer, size_t buffer_size);
/**Write the properties of the blc_channel in the file. **print_id** is a flag in order to require to print or not the blc_channel id*/
void fprint_info(FILE *file, int print_id);
void map_memory(int mode);
void open_block_semaphore();
void open_ack_semaphore();
void create_semaphores();
// void create();
/**Create a new blc_channel with the list of dims described as va_args*/
void vcreate(char const *name, int mode, uint32_t type, uint32_t format, int dims_nb, size_t length0, va_list arguments);
/**Create a new blc_channel with the list of dims described as va_args*/
int vcreate_or_open(char const *name, int mode, uint32_t type, uint32_t format, int dims_nb, size_t length0, va_list arguments);
/**Creates a new blc_channel with the properties already defined*/
void create(char const *new_name, int mode);
/**Creates a new blc_channel and with the dims as a variable list of arguments */
void create(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, size_t length0, ...);
/**Creates a new blc_channel and with the dims as an array of dims*/
void create(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, blc_dim *dims);
/**Creates a new blc_channel and with the dims as a string (i.e. "3x800x600") */
void create(char const *new_name, int mode, uint32_t type, uint32_t format, const char *size_string);
/**Open a blc_channel with **name** */
void open(const char *name, int mode);
/**Create the blc_channel if it does not exist otherwise, open it. In this later case the properties have to be compatible.
You can use conflict function to check before if there is incompatibility*/
int create_or_open(char const *new_name, int mode);
int create_or_open(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, size_t length0, ...);
int create_or_open(char const *new_name, int mode, uint32_t type, uint32_t format, int dims_nb, blc_dim *dims);
int create_or_open(char const *new_name, int mode, uint32_t type, uint32_t format, char const *size_string);
int create_or_open(char const *new_name, int mode);
///Send the name of the channel on stdout
///Send the name of the channel on stdout. Useful to send this blc_channel on a pipe. It is a simple printf but with a unavoided fflush (with a pipe \n does not have effect)
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();
///Lock the channel copy the buffer and free the channel. It is possible to write in the midle of the channel using offset.
void write_buffer(char *buffer, size_t size, size_t offset=0);
/* void protect(int value=1);*/
// void set_namef(char const *name, ...);
void remove(); //Remove the memory from the system unless another process retain it.
///Displays all the informations about the blc_channel
void fprint_debug(FILE *file=stderr);
///Remove the blc_channel on the system. However other already running processes using it will still work but no new process will be able to use it.
void remove();
///Map the shared memory with the blc_channel
void map_memory(int mode);
#else
{
blc_array array;// Not beautiful but makes it easy to convert C++ heritage of "class" in C struct inclusion.
......@@ -145,51 +137,27 @@ typedef struct blc_channel
}blc_channel;
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 mode is BLC_CHANNEL_READ or BLC_CHANNEL_WRITE, the type of data UIN8, INT8, UI16, IN16, FL32, FL64. ( default 0:UIN8),
/**Used by EXIT_ON_CHANNEL_ERROR*/
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 blc_channel with the name, the mode is BLC_CHANNEL_READ or BLC_CHANNEL_WRITE, 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 'Y800' (for grey), 'RGB3', 'YUV2' ,...,.
Dims_nb is the number of dimenssions of the data ( 1 for a vector).
The following values are the the length of each dims. You must have the same number of length than dims_nb.
*/
The following values are the the length of each dims. You must have the same number of length than dims_nb*/
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);
/**Open an exisiting channel 'name' or create it if it does not exist */
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_remove(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. You need to free .dims, which is allocated to contain the list of blc_dims.
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);
*/
///Remove the blc_channel **name**. The other processes using it will still work but no new ones can use it.
void blc_remove_channel_with_name(char const *name);
END_EXTERN_C
///@}
......
//
// blc_channel_control.cpp
// blc_channels
//
// Created by Arnaud Blanchard on 06/07/2016.
//
//
#include "blc_core.h"
#include "blc_channel.h"
#include "blc_channel_control.hpp"
#include <errno.h> // EEXIST
#include <pthread.h> //pthread_create, ...
#include <unistd.h> //ftruncate
#include <semaphore.h> //sem_t, ...
#include <sys/mman.h> //sem_open, ...
#define CHANNELS_CONTROL_FILENAME "/blc_channels-ctrl"
static sem_t *control_sems[2]={NULL,NULL};
int sem_id=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 int blc_channel_check_changes_state;
int blc_channel::create_or_open_control(){
char control_filename[NAME_MAX+1];
int i;
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(NULL, 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){
control->readers_flags = 0;
control->new_value_flags = 0;
control->reading_flags = 0;
control->writing=0;
control->waitings_nb=0;
SPRINTF(control_filename, "/blc_channel%d-var", id);
SYSTEM_ERROR_CHECK(sem_var = sem_open(control_filename, O_EXCL | O_CREAT | O_RDWR, S_IRWXU, 1), SEM_FAILED, "semname %s, channel %s", control_filename, name);
SPRINTF(control_filename, "/blc_channel%d-write", id);
SYSTEM_ERROR_CHECK(sem_write = sem_open(control_filename, O_EXCL | O_CREAT | O_RDWR, S_IRWXU, 1), SEM_FAILED, "semname %s, channel %s", control_filename, name);
control->event_id=0;
SPRINTF(control_filename, "/blc_channel%d-event0", id);
SYSTEM_ERROR_CHECK(sem_events[0] = sem_open(control_filename, O_EXCL | O_CREAT | O_RDWR, S_IRWXU, 0), SEM_FAILED, "semname %s, channel %s", control_filename, name);
SPRINTF(control_filename, "/blc_channel%d-event1", id);
SYSTEM_ERROR_CHECK(sem_events[1] = sem_open(control_filename, O_EXCL | O_CREAT | O_RDWR, S_IRWXU, 0), SEM_FAILED, "semname %s, channel %s", control_filename, name);
}
else {
SPRINTF(control_filename, "/blc_channel%d-var", id);
SYSTEM_ERROR_CHECK(sem_var = sem_open(control_filename, O_RDWR), SEM_FAILED, "semname %s, channel %s", control_filename, name);
SPRINTF(control_filename, "/blc_channel%d-write", id);
SYSTEM_ERROR_CHECK(sem_write = sem_open(control_filename, O_RDWR), SEM_FAILED, "semname %s, channel %s", control_filename, name);
SPRINTF(control_filename, "/blc_channel%d-event0", id);
SYSTEM_ERROR_CHECK(sem_events[0] = sem_open(control_filename, O_RDWR), SEM_FAILED, "semname %s, channel %s", control_filename, name);
SPRINTF(control_filename, "/blc_channel%d-event1", id);
SYSTEM_ERROR_CHECK(sem_events[1] = sem_open(control_filename, O_RDWR), SEM_FAILED, "semname %s, channel %s", control_filename, name);
}
if (mode==BLC_CHANNEL_READ_BLOCK){
sem_wait(sem_var);
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;
sem_post(sem_var);
}
return created;
}
static void create_or_open_channels_control(){
int i;
char tmp_name[NAME_MAX];
FOR (i, 2){
SPRINTF(tmp_name, "/blc_channels-ctrl%d", i);
control_sems[i]=sem_open(tmp_name, O_CREAT | O_EXCL | O_RDWR, S_IRWXU, 0);
if (control_sems[i]==SEM_FAILED){
if (errno==EEXIST) SYSTEM_ERROR_CHECK(control_sems[i]=sem_open(tmp_name, O_RDWR), SEM_FAILED, "Name '%s'", tmp_name);
else EXIT_ON_SYSTEM_ERROR("Name '%s'", tmp_name);
}
}
}
void blc_channel::close_control(){
if (mode & BLC_CHANNEL_READ_BLOCK){
// PTHREAD_CHECK(pthread_mutex_lock(&control->mutex), error, "channel '%s'", name);
sem_wait(sem_var);
control->readers_flags&=~reader_flag;
sem_post(sem_var);
// PTHREAD_CHECK(pthread_mutex_unlock(&control->mutex), error, "channel '%s'", name);
}
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;
}
void channels_set_event(){
if (control_sems[0]==NULL || control_sems[1]==NULL) create_or_open_channels_control();
SYSTEM_ERROR_CHECK(sem_post(control_sems[0]), -1, NULL);
SYSTEM_ERROR_CHECK(sem_post(control_sems[1]), -1, NULL);
}
void* blc_channel_check_changes_routine(void *user_data){
int i=0;
while(blc_channel_check_changes_state){
SYSTEM_ERROR_CHECK(sem_wait(control_sems[i]), -1, NULL);
SYSTEM_ERROR_CHECK(sem_post(control_sems[i]), -1, NULL);
channel_event_callback(user_data);
i=1-i;
}
return NULL;
}
void blc_channel_stop_check_changes(){
int error;
blc_channel_check_changes_state=0;
channels_set_event();
PTHREAD_CHECK(pthread_join(channels_control_thread, NULL), error, NULL);
}
void blc_channel_check_changes(void(*callback)(void* user_data), void *user_data){
int error;
if (channels_control==NULL) create_or_open_channels_control();
if (channel_event_callback) EXIT_ON_ERROR("%s has already be called", __FUNCTION__);
channel_event_callback=callback;
blc_channel_check_changes_state=1;
PTHREAD_CHECK(pthread_create(&channels_control_thread, NULL, blc_channel_check_changes_routine, user_data), error, NULL);
atexit(blc_channel_stop_check_changes);
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment