Functions to easily share data through shared memory (shm_... functions). The advantage is that it is the fastest and the more econom in memory ( no copy in each process ) way to share informtation between processes. At this moment it only works in asynchronous mode.
Functions to easily share data through shared memory (shm_... functions). It is the fastest, and the more econom in memory ( no copy in each process ), way to share informtation between processes. At this moment it only works in asynchronous mode.
The idea is that you have a structure blc_channel which is like a blc_array ( https://framagit.org/blaar/blc_core/blob/master/t_array/main.cpp ) but has a name starting with '/' to identificate it on your system.
...
...
@@ -50,6 +50,24 @@ You will see all the existing blc_channels, the process reading or writing and t
On Linux we can see and manipulate a virtual file containing this memory in /run/shm/<nameofyoursharedmemory>, on OSX you cannot but anyway it is only used for debug.
Synchronisation
===============
Two semaphores associated to the shared memory are created:
-`blc_channle<id>_new_data0` which indicates that new data is available on the shared memory
-`blc_channle<id>_ack_data0` which acknowledges that the data has been read
Proccesses which do not consider synchronisation use starting char '/'
`[writer]/->[reader]` means no synchronization
`[writer].->[reader]` means the reader waits for new data from the writer
`[writer]^->[reader]` means the writer waits for the reader to read and acknowledge the data
`[writer]:->[reader]` means both direction synchronization. The writer waits for acknowledgement and the reader wait for new data from the writer.
///Not yet in use. Structure that will be used for synchronisation.
typedefstructshared_control{
/* pthread_mutex_t mutex;
pthread_cond_t writer_cond, reader_cond;*/
intwriting,event_id,waitings_nb;
uint64_tnew_value_flags,readers_flags,reading_flags;//bitfield max 64 blocking_readers;
structtimevalwrite_time;
}blc_share_control;
///Extends **blc_array** allowing it to be share among processes through shared memory
typedefstructblc_channel
#ifdef __cplusplus
...
...
@@ -125,21 +112,38 @@ typedef struct blc_channel
voidremove();
///Map the shared memory with the blc_channel
voidmap_memory(intmode);
voidopen_semaphores(intcreate=0);
/**Post new data if the semaphore exist (otherwise return -1). Return 1, if the data has been used ( sem_new_data busy which is normal), 0 otherwise ( which means nobody is istening ).*/
intpost_new_data();
/**Post acknoledged data the semaphore exist (otherwise return -1). Return 1, if the data has been used ( sem_new_data busy which is normal ), 0 otherwise ( which means nobody is checking that).*/
intpost_ack_data();
#else
{
blc_arrayarray;// Not beautiful but makes it easy to convert C++ heritage of "class" in C struct inclusion.
/**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),
if(create)SYSTEM_ERROR_CHECK(sem_new_data=sem_open(tmp_name,O_CREAT|O_EXCL,S_IRWXU,0),SEM_FAILED,"Creating named semaphore '%s' for blc_channel '%s'",tmp_name,name);
elseSYSTEM_ERROR_CHECK(sem_new_data=sem_open(tmp_name,NO_FLAG),SEM_FAILED,"Opening named semaphore '%s' for blc_channel '%s'",tmp_name,name);
if(create)SYSTEM_ERROR_CHECK(sem_ack_data=sem_open(tmp_name,O_CREAT|O_EXCL,S_IRWXU,0),SEM_FAILED,"Creating named semaphore '%s' for blc_channel '%s'",tmp_name,name);
elseSYSTEM_ERROR_CHECK(sem_ack_data=sem_open(tmp_name,NO_FLAG),SEM_FAILED,"Opening named semaphore '%s' for blc_channel '%s'",tmp_name,name);
}
///Create a channel once the blc_array is already defined
name[0]='/';//We remove @ which was just to indicate synchronisation.
switch(name[0]){
case'/':
break;
case'.':
sync_new_data=1;
break;
case'^':
sync_ack_data=1;
break;
case':':
sync_new_data=1;
sync_ack_data=1;
break;
default:EXIT_ON_ERROR("Blc channel names must start with '/' for asynchrone mode or with '.',';',':' for synchrone mode. But it is '%s'",name);
break;
}
elseif(new_name[0]!='/')EXIT_ON_ERROR("Blc channel names must start with '/' for asynchrone mode or with '.' for synchrone mode");
name[0]='/';//In any case the name start with '/'
id=blc_channel_get_info_with_name(&info,name);
if(id!=-1)EXIT_ON_ERROR("The channel '%s' is already referenced in '"BLC_CHANNELS_LIST_PATH"'.\nYou may unlink it before:\n./run.sh i_channels --unlink %s",info.name);
if(id!=-1)EXIT_ON_ERROR("The channel '%s' is already referenced in '"BLC_CHANNELS_LIST_PATH"'.\nYou may unlink it before:\nblc_channels --unlink %s",info.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);
elseblc_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|access_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){
if(fd==-1){//Creation impossible
fclose(file);
if(errno==EEXIST)EXIT_ON_ERROR("The shared memory '%s' already exists, you should destroy it before. e.g.:\n./run.sh i_channels -u%s",name,name);
if(errno==EEXIST)EXIT_ON_ERROR("The shared memory '%s' already exists, you should destroy it before. e.g.:\nblc_channels --unlink%s",name,name);
SYSTEM_ERROR_CHECK(sem_new_data=sem_open(name_tmp,O_CREAT,S_IRWXU,0),NULL,"Creating or opening named semaphore '%s' for blc_channel '%s'",name_tmp,name);
SYSTEM_ERROR_CHECK(sem_new_data=sem_open(name_tmp,NO_FLAG),SEM_FAILED,"Opening named semaphore '%s' for blc_channel '%s'",name_tmp,name);
/* if (access_mode==BLC_CHANNEL_READ){ //As we have just started. Any data is new
while (sem_trywait(sem_new_data)==-1){ //If the semaphore is busy we post it until it is unlocked
if (errno==EAGAIN) SYSTEM_ERROR_CHECK(sem_post(sem_new_data), -1, "blc_channel '%s'", this->name);
@@ -291,12 +365,12 @@ int blc_channel::create_or_open(char const *new_name, int access_mode, uint32_t
created=1;
}
else{
if(info.dims_nb!=dims_nb)EXIT_ON_CHANNEL_ERROR(&info,"Reopening a blc_channel with different dims_nb '%d'. You may want to unlink it:\n./run.sh i_channels --unlink %s",dims_nb,name);
if(info.type!=type)EXIT_ON_CHANNEL_ERROR(&info,"Reopening blc_channel with another type '%.4s'. You may want to unlink it:\n./run.sh i_channels --unlink %s",UINT32_TO_STRING(new_type_str,type),name);
if(info.format!=format)EXIT_ON_CHANNEL_ERROR(&info,"Reopening blc_channel with another format '%.4s'. You may want to unlink it:\n./run.sh i_channels --unlink %s",UINT32_TO_STRING(new_format_str,format),name);
if(info.dims_nb!=dims_nb)EXIT_ON_CHANNEL_ERROR(&info,"Reopening a blc_channel with different dims_nb '%d'. You may want to unlink it:\nblc_channels --unlink %s",dims_nb,info.name);
if(info.type!=type)EXIT_ON_CHANNEL_ERROR(&info,"Reopening blc_channel with another type '%.4s'. You may want to unlink it:\nblc_channels --unlink %s",UINT32_TO_STRING(new_type_str,type),info.name);
if(info.format!=format)EXIT_ON_CHANNEL_ERROR(&info,"Reopening blc_channel with another format '%.4s'. You may want to unlink it:\nblc_channels --unlink %s",UINT32_TO_STRING(new_format_str,format),info.name);
if(info.dims_nb!=0){
for(dim=0;dim!=info.dims_nb;dim++){
if(dims[dim].length!=info.dims[dim].length)EXIT_ON_ERROR("The reopening dimension '%d' length '%d' of '%s' differ from the existing one '%d'. You may want to unlink it:\n ./run.sh i_channels --unlink %s",dim,info.dims[dim].length,info.name,dims[dim].length,info.name);
if(dims[dim].length!=info.dims[dim].length)EXIT_ON_ERROR("The reopening dimension '%d' length '%d' of '%s' differ from the existing one '%d'. You may want to unlink the blc_channel before:\n blc_channels --unlink %s",dim,dims[dim].length,info.name,info.dims[dim].length,info.name);
}
}
open(new_name,access_mode);
...
...
@@ -367,6 +441,7 @@ blc_channel::~blc_channel(){
if(fd!=-1){
close(fd);
blc_channel_post_event();
}
}
...
...
@@ -376,8 +451,16 @@ void blc_channel::remove(){
}
voidblc_channel::publish(){
if(sem_new_data)fprintf(stdout,".%s\n",name+1);//Replace first '/' by '.'
if (shm_unlink(control_filename)==-1) if (errno!=ENOENT) EXIT_ON_SYSTEM_ERROR("unlinking blc_channel '%s'", name); // It does not matter if the file does not exist
SYSTEM_ERROR_CHECK(sem_unlink(tmp_name),-1,"Unlinking sem_ack_data '%s' for blc_channel '%s'",tmp_name,name);
}
// Envoie un message d'erreur avec name_of_file, name_of_function, number_of_line et affiche le message formate avec les parametres variables. Puis exit le programme avec le parametre EXIT_FAILURE. To be used with EXIT_ON_ERROR.
...
...
@@ -216,5 +214,57 @@ int blc_channel_remove(blc_channel * channel)