1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
// Il y a deux buffers
// - Le premier buffer contient la configuration active de l'équipement : elle ne doit être accessible qu'en lecture seule pour le code application
// - Le second buffer est une zone de travail temporaire : lorsque l'équipement reçoit une nouvelle demande de configuration (appel de writerReadersProcess_openWriter()),
// la configuration active est copiée dans ce buffer puis le processus applicatif doit modifier la zone de travail en fonction des commandes de configuration reçues.
// => une fois toutes les commandes reçues sont traitées, la nouvelle configuration doit être appliquée au hardware de l'équipement puis les données de la zone de travail
// sont copiées dans la configuration active en appelant writerReadersProcess_closeWriter(TRUE).
//
// Un seul processus à la fois est autorisé à travailler sur la zone de travail temporaire (writerReadersProcess_openWriter() est blocant dans qu'il y a un writer d'actif).
// Plusieurs processus à la fois sont autorisés à lire la configuration active sauf au moment de la mise à jour de celle-ci.
// La mise à jour de la configuration active n'est autorisé que s'il n'y a plus aucun processus de lecture qui travaille sur la configuration active.
//
// La gestion des semaphore est inspirée de : https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem#Second_readers-writers_problem
//
// writerReadersProcess_ptrRead : pointeur sur la structure en lecture seul (configuration active)
// writerReadersProcess_ptrWrite : pointeur sur la seconde structure qui est en lecture et écriture (configuration temporaire)
// writerReadersProcess_readersCounter : nombre de reader en cours
// writerReadersProcess_writersCounter : nombre de writer en cours
SemaphoreHandle_t mutex_changePersistentInfos; // accès pour modification des variables persistantes (writerReadersProcess_ptrRead, writerReadersProcess_ptrWrite et writerReadersProcess_readersCounter, writerReadersProcess_writersCounter)
STRUCT_CONFIG config1;
STRUCT_CONFIG config2;
STRUCT_CONFIG * writerReadersProcess_ptrRead;
STRUCT_CONFIG * writerReadersProcess_ptrWrite;
int writerReadersProcess_readersCounter;
int writerReadersProcess_writersCounter;
void writerReadersProcess_init(void){
mutex_changePersistentInfos = xSemaphoreCreateMutex();
if(mutex_changePersistentInfos == NULL){
printf("[ERR] mutex_changePersistentInfos init\r\n");
while(1);
}
writerReadersProcess_ptrRead = &config1;
writerReadersProcess_ptrWrite = &config2;
writerReadersProcess_readersCounter = 0;
writerReadersProcess_writersCounter = 0;
}
// Réserve le mutex du processus de lecture
// => On peut ouvrir autant de readers que l'on veut sauf pendant que les
// données de writerReadersProcess_ptrWrite sont copiées dans writerReadersProcess_ptrRead.
const STRUCT_CONFIG * writerReadersProcess_openReader(void){
STRUCT_CONFIG * ret;
while(1){
xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
if(writerReadersProcess_writersCounter == 0){ // il n'y a plus/pas de writer actif
break; // pour pouvoir sortir de la boucle
}
xSemaphoreGive(mutex_changePersistentInfos); // redonne la main aux autres processus pour pouvoir libérer les readers actifs
}
writerReadersProcess_readersCounter++;
ret = writerReadersProcess_ptrRead;
xSemaphoreGive(mutex_changePersistentInfos); // autorise un nouveau reader a être réservé
return ret;
}
void writerReadersProcess_closeReader(void){
xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
writerReadersProcess_readersCounter--;
xSemaphoreGive(mutex_changePersistentInfos);
}
// Réserve le mutex du processus d'écriture
// Copie structure des données de writerReadersProcess_ptrRead dans writerReadersProcess_ptrWrite
// => On peut réserver un writer alors qu'il y a déja des readers d'actifs car le writer n'écrit pas dans la même zone mémoire que les readers
STRUCT_CONFIG * writerReadersProcess_openWriter(void){
while(1){
xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
if(writerReadersProcess_writersCounter == 0){ // il n'y a plus/pas de writer actif
break; // pour pouvoir sortir de la boucle
}
xSemaphoreGive(mutex_changePersistentInfos); // redonne la main aux autres processus pour pouvoir libérer les readers actifs
}
// Initialisation du buffer de travail
memcpy(writerReadersProcess_ptrWrite, writerReadersProcess_ptrRead, sizeof(*writerReadersProcess_ptrWrite)); // 65Ko à copier avec CPU 330DMIPS
writerReadersProcess_writersCounter++;
xSemaphoreGive(mutex_changePersistentInfos); // autorise un nouveau reader a être réservé
return writerReadersProcess_ptrWrite;
}
// Libère le mutex du processus d'écriture
// Si enableNewConfig vaut TRUE, mise à jour de writerReadersProcess_ptrRead avec valeurs de writerReadersProcess_ptrWrite
// => le changement ne se fait que s'il y a aucun reader d'ouvert
void writerReadersProcess_closeWriter(BOOL enableNewConfig){
if(enableNewConfig){
while(1){
xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
if(writerReadersProcess_readersCounter == 0){ // il n'y a plus/pas de reader actif
break; // pour pouvoir sortir de la boucle
}
xSemaphoreGive(mutex_changePersistentInfos); // redonne la main aux autres processus pour pouvoir libérer les readers actifs
}
// Mise à jour de la configuration active avec les nouvelles données du buffer de travail
memcpy(writerReadersProcess_ptrRead, writerReadersProcess_ptrWrite, sizeof(*writerReadersProcess_ptrRead)); // 65Ko à copier avec CPU 330DMIPS
xSemaphoreGive(mutex_changePersistentInfos); // autorise un nouveau reader a être réservé
}
xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
writerReadersProcess_writersCounter--; // Mise à jour du nombre de Writer
xSemaphoreGive(mutex_changePersistentInfos);
} |
Partager