From 961ddc46da8e00ce8757fce089dc9b624807e626 Mon Sep 17 00:00:00 2001 From: smas Date: Fri, 28 Jul 2000 15:34:22 +0000 Subject: [PATCH] =?UTF-8?q?Premi=C3=A8re=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/libmsg.3 | 618 ++++++++ lib/libmsg.c | 3181 ++++++++++++++++++++++++++++++++++++++ lib/libmsg.doc | Bin 0 -> 64512 bytes lib/libmsg.h | 118 ++ lib/msg.h | 516 +++++++ util/msgadmin.c | 235 +++ util/msgbench.xls | Bin 0 -> 18432 bytes util/pingpong.result.cc | 40 + util/pingpong.result.gcc | 40 + util/pingpong_ipc.c | 579 +++++++ util/pingpong_msg.c | 543 +++++++ util/result.linux | 20 + util/result.linux.old | 20 + util/skeleton.c | 155 ++ 14 files changed, 6065 insertions(+) create mode 100644 lib/libmsg.3 create mode 100644 lib/libmsg.c create mode 100644 lib/libmsg.doc create mode 100644 lib/libmsg.h create mode 100644 lib/msg.h create mode 100644 util/msgadmin.c create mode 100644 util/msgbench.xls create mode 100644 util/pingpong.result.cc create mode 100644 util/pingpong.result.gcc create mode 100644 util/pingpong_ipc.c create mode 100644 util/pingpong_msg.c create mode 100644 util/result.linux create mode 100644 util/result.linux.old create mode 100644 util/skeleton.c diff --git a/lib/libmsg.3 b/lib/libmsg.3 new file mode 100644 index 0000000..2f9fa5a --- /dev/null +++ b/lib/libmsg.3 @@ -0,0 +1,618 @@ +'\" t +.\" @(#)LIBMSG.3 1.0 00/07/04 SMA; +.TH LIBMSG 3 "07 Apr 2000" +.SH NOM +LIBMSG (librairie de communication inter-processus par messages) +.SH SYNOPSIS +.LP +.BI "cc [flag ...] file ... -lver -ldl -lnode -lshmem -ldatastr -lmsg [library ...]" +.LP +.BI "#include " +.LP +.BI "MSGT_Status MSG_Library_Open ( int " Instance ", const char * " Context ", MSGT_Flags " Open_Mode " );" +.LP +.BI "MSGT_Status MSG_Library_IsOpen ( void );" +.LP +.BI "MSGT_Status MSG_Library_Signal ( void );" +.LP +.BI "MSGT_Status MSG_Library_Close ( MSGT_Flags " Close_Mode " );" +.LP +.BI "MSGT_Status MSG_Library_Stderr_Set ( FILE * " Out " );" +.LP +.BI "MSGT_Status MSG_Library_Dump ( FILE * " Out " );" +.LP +.BI "MSGT_Status MSG_Port_Open ( int " Id ", MSGT_Port ** " Port ", MSGT_Flags " Open_Mode " );" +.LP +.BI "MSGT_Status MSG_Port_Lock ( MSGT_Port * " Port ", MSGT_Flags " Mode " );" +.LP +.BI "MSGT_Status MSG_Port_Unlock ( MSGT_Port * " Port ", MSGT_Flags " Mode " );" +.LP +.BI "MSGT_Status MSG_Port_Config ( MSGT_Port * " Port ", MSGT_Config " Tag ", " ... " );" +.LP +.BI "MSGT_Status MSG_Port_Close ( MSGT_Port * " Port ", MSGT_Flags " Close_Mode " );" +.LP +.BI "MSGT_Status MSG_PortList_Open ( MSGT_PortList ** " PortList " );" +.LP +.BI "MSGT_Status MSG_PortList_Port_Add ( MSGT_PortList * " PortList ", MSGT_Port * " Port " );" +.LP +.BI "MSGT_Status MSG_PortList_Port_Remove ( MSGT_PortList * " PortList ", MSGT_Port * " Port " );" +.LP +.BI "MSGT_Status MSG_PortList_Close ( MSGT_PortList * " PortList " );" +.LP +.BI "MSGT_Status MSG_PortList_Listen ( MSGT_PortList * " PortList ", unsigned int " Type ", MSGT_Message ** " Msg ", MSGT_Flags " Flags " );" +.LP +.BI "MSGT_Status MSG_Message_Alloc ( MSGT_Message ** " Msg ", size_t " Size " );" +.LP +.BI "MSGT_Status MSG_Message_Config ( MSGT_Message * " Msg ", MSGT_Config " Tag ", " ... " );" +.LP +.BI "MSGT_Status MSG_Message_Free ( MSGT_Message * " Msg " );" +.LP +.BI "MSGT_Status MSG_Message_Send ( MSGT_Port * " From ", , MSGT_Port * " To ", MSGT_Message * " Msg " );" +.LP +.BI "MSGT_Status MSG_Message_Receive ( MSGT_Port * " Port ", unsigned int " Type ", MSGT_Message ** " Msg ", MSGT_Flags " Flags " );" +.LP +.BI "MSGT_Status MSG_Message_Reply ( MSGT_Message * " Msg " );" +.LP +.BI "MSGT_Status MSG_Message_Return ( MSGT_Message * " Msg " );" +.LP +.SH "CODES RETOUR" +.LP +Toutes les fonctions constituant l'API de la librairie LIBMSG retournent un code de type +.B MSGT_Status +: +.LP +.RS 3 +- +.B MSGS_OK +: la fonction s'est correctement executee et a produit un resultat +.LP +- +.B MSGS_KO +: la fonction s'est correctement executee mais n'a pas produit de resultat +.LP +- +.B MSGS_ERRAPI +: la fonction a ete appelee avec des arguments de valeur incorrecte +.LP +- +.B MSGS_ERRMEM +: la fonction ne s'est pas correctement executee pour un probleme d'allocation memoire +.LP +- +.B MSGS_ERRSHM +: la fonction ne s'est pas correctement executee pour un probleme relatif a la memoire partagee +.LP +- +.B MSGS_ERRSEM +: la fonction ne s'est pas correctement executee pour un probleme relatif a l'utilisation des semaphores +.LP +- +.B MSGS_ERRSIG +: une operation sur semaphore a ete interrompue par un signal +.LP +- +.B MSGS_ERRNOWAIT +: une operation sur semaphore n'a pas pu etre realisee et le mode d'operation est sans attente +.LP +- +.B DSS_ERRDLL +: la fonction ne s'est pas correctement executee pour un probleme de chargement dynamique d'objet +.LP +.RS -3 +.I NB +: la macro +.B MSG_ERROR() +permet de tester si un code retour correspond a une erreur. +.LP +En cas d'erreur, la variable MSG_Error_Message contient un message du type : +.LP +.RS 3 +Error : +.RS -3 +.LP +Pour les fonctions de reception de messages, 3 codes retour supplementaires ont ete definis : +.LP +.RS 3 +- +.B MSGS_NO_MSG +si aucun message n'a ete trouve dans le(s) port(s) de messages ecoute(s) +.LP +- +.B MSGS_BAD_TYPE +si des messages sont presents mais qu'aucun ne correspond au type de message demande. +.LP +- +.B MSGS_SIGNAL +si l'ecoute du port a ete interrompue par un signal systeme. +.RS -3 +.LP +.SH "FONCTIONS" +.LP +.BI "MSGT_Status MSG_Library_Open ( int " Instance ", const char * " Context ", MSGT_Flags " Open_Mode " );" +.RS 3 +.LP +La librairie LIBMSG implemente une base qui reference tous les ports de messages et tous les messages crees. +.LP +Cette fonction permet donc d'acceder a toutes ces ressources pour un contexte et une instance donnes designes par leur nom +.I Context +et +.I Instance +: +.LP +.RS 3 +- en ouverture simple si +.I Open_Mode +vaut +.B MSGD_OPEN +.LP +- en creation si +.I Open_Mode +vaut +.B MSGD_CREATE +.RS -3 +.LP +.I NB +: l'indicateur d'ouverture +.I Open_Mode +pourra etre combinee avec un mode de debugging ( +.B MSGD_DEBUG_NONE +: aucun message d'erreur n'est affiche +.LP +.B MSGD_DEBUG +: les messages d'erreur generes par la librairie LIBMSG sont affiches sur la sortie standard d'erreur +.LP +.B MSGD_DEBUG_ALL +: les messages d'erreur generes par toutes les librairies sous-jacentes a la LIBMSG sont affiches sur la sortie standard d'erreur +.LP +.I NB +: l'ouverture de la librairie en creation est reservee aux administrateurs. +.LP +L'ouverture de la librairie est obligatoire avant d'utiliser toute autre fonction de la librairie LIBMSG. +.LP +.RS -3 +.LP +.BI "MSGT_Status MSG_Library_Signal ( void );" +.RS 3 +.LP +Cette fonction permet d'informer la librairie LIBMSG de la reception d'un signal systeme. +.LP +.I NB +: cette fonction sera utile a l'utilisateur pour eviter que le processus reste bloque sur une attente de message malgre la reception de signal. +.RS -3 +.LP +.BI "MSGT_Status MSG_Library_IsOpen ( void );" +.RS 3 +.LP +Cette fonction permet de tester si une instance de la librairie LIBMSG a deja ete ouverte. +.RS -3 +.LP +.BI "MSGT_Status MSG_Library_Close ( MSGT_Flags " Close_Mode " );" +.RS 3 +.LP +Cette fonction permet de fermer toutes les ressources de l'instance de la librairie ouverte : +.LP +.RS 3 +- fermeture simple si +.I Close_Mode +vaut +.B MSGD_CLOSE +.LP +- destruction si +.I Close_Mode +vaut +.B MSGD_DESTROY +.RS -3 +.LP +.I NB +: l'utilisation du parametre +.B MSGD_DESTROY +est reservee aux administrateurs. +.LP +.RS -3 +.BI "MSGT_Status MSG_Library_Dump ( FILE * " Out " );" +.RS 3 +.LP +Cette fonction permet d'afficher toutes les ressources de l'instance de la librairie ouverte. +.LP +L'argument +.I Out +designe le flux de sortie de l'affichage. +.LP +.RS -3 +.BI "MSGT_Status MSG_Port_Open ( int " Id ", MSGT_Port ** " Port ", MSGT_Flags " Open_Mode " );" +.LP +.RS 3 +Cette fonction permet d'ouvrir un port de messages. +.LP +Elle requiert les arguments suivants : +.RS 3 +.LP +* (In) +.I Id +: l'identifiant numerique du port de messages +.LP +* (Out) +.I Port +: l'adresse d'un pointeur sur le port de messages +.LP +* (In) +.I Open_Mode +: le mode d'ouverture du port de messages +.LP +.RS 3 +- en ouverture simple si +.I Open_Mode +vaut +.B MSGD_OPEN +.LP +- en creation si +.I Open_Mode +vaut +.B MSGD_CREATE +.RS -3 +.RS -3 +.LP +.RS -3 +.BI "MSGT_Status MSG_Port_Lock ( MSGT_Port * " Port ", MSGT_Flags " Mode " );" +.RS 3 +.LP +Cette fonction permet de verrouiller un port de messages. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Port +: un pointeur sur le port de messages a verrouiller +.LP +* (In) +.I Mode +: le mode de verrouillage ( +.B MSGD_READ +ou +.B MSGD_WRITE +) +.LP +.RS -3 +.LP +.RS -3 +.BI "MSGT_Status MSG_Port_Unlock ( MSGT_Port * " Port ", MSGT_Flags " Mode " );" +.RS 3 +.LP +Cette fonction permet d'oter le verrou pose sur un port de messages. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Port +: un pointeur sur le port de messages a deverrouiller +.LP +* (In) +.I Mode +: le mode dans lequel le port est verrouille ( +.B MSGD_READ +ou +.B MSGD_WRITE +) +.LP +.RS -3 +.LP +.RS -3 +.BI "MSGT_Status MSG_Port_Config ( MSGT_Port * " Port ", MSGT_Config " Tag ", " ... " );" +.RS 3 +.LP +Cette fonction permet de configurer un port de messages. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Port +: un pointeur sur le port de messages a configurer +.LP +* (In) +.I Tag +: le type de configuration ( +.B MSGD_CONFIG_SIZE +) +.LP +* (In) +.I ... +: la ou les valeurs utiles (fonction du type de configuration) +.LP +.RS -3 +.LP +.RS -3 +.BI "MSGT_Status MSG_Port_Close ( MSGT_Port * " Port ", MSGT_Flags " Close_Mode " );" +.RS 3 +.LP +Cette fonction permet de fermer un port de messages. +.LP +Elle requiert les arguments suivants : +.RS 3 +.LP +* (In) +.I Port +: un pointeur sur le port de messages a fermer +.LP +* (In) +.I Close_Mode +: le mode de fermeture du port de messages +.LP +.RS 3 +- fermeture simple si +.I Close_Mode +vaut +.B MSGD_CLOSE +.LP +- destruction si +.I Close_Mode +vaut +.B MSGD_DESTROY +.RS -3 +.RS -3 +.LP +.RS -3 +.BI "MSGT_Status MSG_PortList_Open ( MSGT_PortList ** " PortList " );" +.RS 3 +.LP +Cette fonction permet d'ouvrir une liste de ports de messages. +.LP +L'argument +.I PortList +est l'adresse d'un pointeur sur la liste de port a creer. +.LP +.I NB +: une liste de ports permet a un processus d'ecouter plusieurs ports de messages simultanement. +Une liste de ports n'est pas partageable entre les processus. +.LP +.RS -3 +.BI "MSGT_Status MSG_PortList_Port_Add ( MSGT_PortList * " PortList ", MSGT_Port * " Port " );" +.RS 3 +.LP +Cette fonction permet d'ajouter un port de messages a une liste de ports. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I PortList +: un pointeur sur une liste de ports +.LP +* (In) +.I Port +: un pointeur sur le port de messages a ajouter +.LP +.RS -3 +.LP +.RS -3 +.BI "MSGT_Status MSG_PortList_Port_Remove ( MSGT_PortList * " PortList ", MSGT_Port * " Port " );" +.RS 3 +.LP +Cette fonction permet de retirer un port de messages d'une liste de ports. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I PortList +: un pointeur sur une liste de ports +.LP +* (In) +.I Port +: un pointeur sur le port de messages a retirer +.LP +.RS -3 +.LP +.RS -3 +.BI "MSGT_Status MSG_PortList_Close ( MSGT_PortList * " PortList " );" +.RS 3 +.LP +Cette fonction permet de detruire une liste de ports de messages. +.LP +L'argument +.I PortList +est un pointeur sur la liste de port a supprimer. +.LP +.I NB +: lorsqu'un processus ajoute un port de messages a sa liste de ports, le port de messages memorise le fait que le processus doit etre averti si un message y est ajoute ou retire. +Il est donc important que chaque processus detruise explicitement toutes les listes de ports qu'il a creees lorsque celles-ci ne sont plus utilisees. +.LP +.RS -3 +.BI "MSGT_Status MSG_PortList_Listen ( MSGT_PortList * " PortList ", unsigned int " Type ", MSGT_Message ** " Msg ", MSGT_Flags " Flags " );" +.RS 3 +.LP +Cette fonction permet de receptionner un message a partir d'une liste de ports. +La notion d'ecoute correspond au fait qu'un processus pourra se mettre en attente jusqu'a ce qu'un message soit envoye sur l'un des ports. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Port +: un pointeur sur la liste de ports +.LP +* (In) +.I Type +: le type du message a receptionner (la valeur +.B MSGD_NO_TYPE +permet de ne specifier aucun type en particulier) +.LP +* (Out) +.I Msg +: l'adresse d'un pointeur sur le message a receptionner. +.LP +* (In) +.I Flags +: le type d'ecoute (avec attente : +.B MSGD_WAIT +, sans attente : +.B MSGD_NOWAIT +) +.LP +.RS -3 +.I NB +: pour une ecoute avec attente, un processus sera reveille a chaque fois qu'un message arrive dans l'un des ports de la liste. Il pourra toutefois se remettre en attente si le message a ete receptionne par un autre processus ou bien si son type n'est pas celui demande. +.LP +.I NB +: la recherche des messages dans les differents ports de la liste s'effectue dans l'ordre dans lequel ils ont ete ajoute a la liste. +.LP +.RS -3 +.BI "MSGT_Status MSG_Message_Alloc ( MSGT_Message ** " Msg ", size_t " Size " );" +.RS 3 +.LP +Cette fonction permet de creer un message et d'allouer de la memoire pour les donnees associees au message. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (Out) +.I Msg +: l'adresse d'un pointeur sur le message a creer +.LP +* (In) +.I Size +: la taille des donnees du message +.RS -3 +.LP +.I NB +: l'utilisateur pourra modifier a sa guise la zone de donnees du message pointee par le champ +.B Data +du message. +Il veillera toutefois a ne pas deborder en dehors de cette zone auquel cas le fonctionnement de la librairie pourrait etre corrompue. +.LP +.RS -3 +.BI "MSGT_Status MSG_Message_Config ( MSGT_Message * " Msg ", MSGT_Config " Tag ", " ... " );" +.RS 3 +.LP +Cette fonction permet de configurer un message. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Msg +: un pointeur sur le message a configurer +.LP +* (In) +.I Tag +: le type de configuration ( +.B MSGD_CONFIG_TYPE +, +.B MSGD_CONFIG_PRIORITY +) +.LP +* (In) +.I ... +: la ou les valeurs utiles (fonction du type de configuration) +.RS -3 +.LP +.RS -3 +.BI "MSGT_Status MSG_Message_Free ( MSGT_Message * " Msg " );" +.RS 3 +.LP +Cette fonction permet de supprimer un message de la base de la librairie LIBMSG. +.LP +L'argument +.I Msg +est un pointeur sur le message a supprimer. +.LP +.I NB +: l'utilisateur veillera a ne pas supprimer les messages de maniere inconsideree, ceux-ci pouvant etre en cours d'envoi dans un port de messages. +.LP +Les regles d'usage veulent que ce soit le processus initiateur d'un message qui le supprime. +Dans le cas ou les messages ne sont pas renvoyes au processus initiateur, c'est le processus qui receptionne le message qui le supprimera. +.LP +.RS -3 +.BI "MSGT_Status MSG_Message_Send ( MSGT_Port * " From ", , MSGT_Port * " To ", MSGT_Message * " Msg " );" +.RS 3 +.LP +Cette fonction permet d'envoyer un message dans un port de messages. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I From +: un pointeur sur le port de l'emetteur du message +.LP +* (In) +.I To +: un pointeur sur le port destinataire du message +.LP +* (In) +.I Msg +: un pointeur sur le message a envoyer +.LP +.RS -3 +.I NB +: un message ne pourra pas etre envoye simultanement dans plusieurs ports de messages. +.LP +.RS -3 +.BI "MSGT_Status MSG_Message_Receive ( MSGT_Port * " Port ", unsigned int " Type ", MSGT_Message ** " Msg ", MSGT_Flags " Flags " );" +.RS 3 +.LP +Cette fonction permet de receptionner un message dans un port de messages. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Port +: un pointeur sur le port de messages a ecouter +.LP +* (In) +.I Type +: le type du message a receptionner (la valeur +.B MSGD_NO_TYPE +permet de ne specifier aucun type en particulier) +.LP +* (Out) +.I Msg +: l'adresse d'un pointeur sur le message a receptionner. +.LP +* (In) +.I Flags +: le type d'ecoute (avec attente : +.B MSGD_WAIT +, sans attente : +.B MSGD_NOWAIT +) +.LP +.RS -3 +.I NB +: la reception d'un message ne fait que retirer celui-ci du port de messages. +Le message n'est donc pas supprime et pourra en consequence etre envoye a nouveau dans une autre port de messages. +.LP +Pour une reception avec attente, un processus sera reveille a chaque fois qu'un message arrive dans le port de la liste. +.LP +Independamment du type demande, les messages sont receptionnes selon leur priorite puis selon leur ordre d'envoi. +.LP +.RS -3 +.BI "MSGT_Status MSG_Message_Reply ( MSGT_Message * " Msg " );" +.RS 3 +.LP +Cette fonction permet de renvoyer un message a son envoyeur. +.LP +.I NB +: l'envoyeur devra alors avoir precise l'identifiant de son port d'ecoute dans le champ +.B From +du message +.I Msg +. +.LP +.RS -3 +.BI "MSGT_Status MSG_Message_Return ( MSGT_Message * " Msg " );" +.RS 3 +.LP +Cette fonction permet de renvoyer un message au processus initiateur du message (different de l'envoyeur si le message passe entre plusieurs mains. +.LP +.I NB +: l'initiateur du message devra alors avoir precise l'identifiant de son port d'ecoute dans le champ +.B Init +du message +.I Msg +. +.LP +.RS -3 diff --git a/lib/libmsg.c b/lib/libmsg.c new file mode 100644 index 0000000..d87914d --- /dev/null +++ b/lib/libmsg.c @@ -0,0 +1,3181 @@ +/* Utilisation des API sans vérification des arguments */ + +#define ND_MODE 1 +#define SM_MODE 1 +#define DS_MODE 1 + +#include + +VER_INFO_EXPORT(libmsg,"$Revision: 1.1 $", "$Name: $",__FILE__,"$Author: smas $") + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS PUBLIQUES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* FONCTIONS OPTIMISEES (MSG_MODE = 1) */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Teste si la librairie a été ouverte */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_IsOpen_I ( void ) +{ + if (!MSG_Base) return MSGS_NO; + + return MSGS_YES; +} + +/*------------------------------------------------------------------------------*/ +/* Permet d'indiquer à la librairie qu'un signal a été reçu. */ +/* */ +/* NB : cette fonction sera appelée par l'utilisateur pour éviter que le */ +/* processus se bloque sur une attente de message malgré la réception de signal */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Signal_I ( void ) +{ + MSG_Signal_Received = TRUE; + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Instance : numéro de l'instance de la librairie */ +/* (I) Context : contexte d'utilisation de la librairie */ +/* (I) Open_Mode : mode d'ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Open_I ( int Instance, const char * Context, MSGT_Flags Open_Mode ) +{ + MSGT_Status rc; + int Locked; + int DS_Debug_Mode = DSD_DEBUG_NONE; + + /* Définition du mode debug */ + + if (Open_Mode & MSGD_DEBUG) + { + MSG_stderr = stderr; + DS_Debug_Mode = DSD_DEBUG; + } + else if (Open_Mode & MSGD_DEBUG_ALL) + { + MSG_stderr = stderr; + DS_Debug_Mode = DSD_DEBUG_ALL; + } + + /* Ouverture de la librairie LIBDATASTR */ + + rc = DS_Library_Open (Instance, Context, DS_Debug_Mode); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : unable to open the LIBDATASTR library"); + MSG_Error_Print(); + return rc; + } + + /* Accès aux ressources partagées de la librairie */ + + if (Open_Mode & MSGD_CREATE) + { + /* On vérifie que le processus courant n'a pas déjà ouvert la librairie */ + + if (MSG_Open_Counter > 0) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : the current process has already opened the LIBMSG library"); + MSG_Error_Print (); + DS_Library_Close (); + return MSGS_ERRAPI; + } + + /* Création de la base LIBMSG */ + + rc = SM_Heap_Open (MSG_Name_Prefix (MSG_BASE_HEAP_NAME), &MSG_Base_Heap, MSG_BASE_HEAP_SEGMENT_SIZE, SMD_CREATE | SMD_WRITE, &Locked); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : unable to create the heap for the LIBMSG base"); + MSG_Error_Print (); + DS_Library_Close (); + return rc; + } + + rc = SM_Chunk_Alloc (MSG_Base_Heap, sizeof (MSGT_Base), (void **)&MSG_Base); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : unable to allocate memory for the LIBMSG base structure"); + MSG_Error_Print (); + DS_Library_Close (); + MSG_Base = NULL; + return rc; + } + + /* Création de la liste des ports de messages (en fait c'est un arbre) */ + + rc = DS_DataStruct_Open (MSG_Name_Prefix (MSG_PORT_LIST_NAME), &(MSG_Base->Port_List), NDD_DS_TREE | NDD_MN_AUTO_EQU, MSG_FILE_MANAGER, MSG_PORT_LIST_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : unable to create the base message port list"); + MSG_Error_Print (); + DS_Library_Close (); + MSG_Base = NULL; + return rc; + } + else strcpy (MSG_Base->Port_List->Manager, "MSG_Base_Port_List_Manager"); + + /* Création du heap dans lequel seront alloués les messages */ + + rc = SM_Heap_Open (MSG_Name_Prefix (MSG_MESSAGE_HEAP_NAME), &MSG_Message_Heap, MSG_MESSAGE_HEAP_SEGMENT_SIZE, SMD_CREATE, &Locked); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : unable to create the message heap"); + MSG_Error_Print (); + DS_Library_Close (); + MSG_Base = NULL; + return rc; + } + + /* Verrouillage de la base LIBMSG en lecture */ + + rc = SM_Heap_Lock (MSG_Base_Heap, SMD_READ, &Locked); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : unable to lock the LIBMSG base for reading"); + MSG_Error_Print (); + DS_Library_Close (); + MSG_Base = NULL; + return rc; + } + } + else + { + SMT_DSH * DSH; + NDT_Root * Root; + + /* On n'accède aux ressources que lors de la première ouverture */ + + if (MSG_Open_Counter == 0) + { + /* Ouverture de la base LIBMSG en lecture */ + + rc = SM_Heap_Open (MSG_Name_Prefix (MSG_BASE_HEAP_NAME), &MSG_Base_Heap, 0, SMD_OPEN | SMD_READ, &Locked); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : unable to open the heap for the LIBMSG base"); + MSG_Error_Print (); + DS_Library_Close (); + return rc; + } + + DSH = MSG_Base_Heap->MHH->DSR->Head->Value; + + /* La structure de la base se trouve dans le premier chunk du premier segment du heap */ + + MSG_Base = (MSGT_Base *)((size_t)(DSH->Start) + sizeof (NDT_Node) + sizeof (SMT_Chunk)); + + /* Ouverture de la liste des ports de messages */ + + rc = DS_DataStruct_Open (MSG_Name_Prefix (MSG_PORT_LIST_NAME), &Root, NULL, NULL, 0, SMD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : unable to open the base port list"); + MSG_Error_Print (); + return rc; + } + + /* Ouverture du heap dans lequel seront alloués les messages */ + + rc = SM_Heap_Open (MSG_Name_Prefix (MSG_MESSAGE_HEAP_NAME), &MSG_Message_Heap, 0, SMD_OPEN, &Locked); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Open : unable to open the message heap"); + MSG_Error_Print (); + DS_Library_Close (); + return rc; + } + } + } + + /* Mise à jour du compteur d'ouverture */ + + MSG_Open_Counter++; + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Close_Mode : mode de fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Close_I ( MSGT_Flags Close_Mode ) +{ + MSGT_Status rc; + + if (Close_Mode == MSGD_DESTROY) + { + /* Destruction de la liste des ports de messages */ + + rc = DS_DataStruct_Close (MSG_Base->Port_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Close : unable to destroy the base port list"); + MSG_Error_Print (); + return rc; + } + + /* Destruction du heap contenant les messages */ + + rc = SM_Heap_End (MSG_Name_Prefix (MSG_MESSAGE_HEAP_NAME)); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Close : unable to destroy the message heap"); + MSG_Error_Print (); + return rc; + } + + /* Destruction du heap contenant la structure de base */ + + rc = SM_Heap_End (MSG_Name_Prefix (MSG_BASE_HEAP_NAME)); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Close : unable to destroy the heap of the base structure"); + MSG_Error_Print (); + return rc; + } + + MSG_Base = NULL; + + /* Réinitialisation du compteur d'ouverture */ + + MSG_Open_Counter = 0; + } + else + { + /* On ne libère les ressources que lors de la dernière fermeture */ + + if (MSG_Open_Counter == 1) + { + /* Fermeture de la liste des ports de messages */ + + rc = DS_DataStruct_Close (MSG_Base->Port_List, DSD_CLOSE); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Close : unable to close the base port list"); + MSG_Error_Print (); + return rc; + } + + /* Fermeture du heap contenant les messages */ + + rc = SM_Heap_Close (MSG_Message_Heap); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Close : unable to close the message heap"); + MSG_Error_Print (); + return rc; + } + + /* Fermeture du heap contenant la structure de base */ + + rc = SM_Heap_Close (MSG_Base_Heap); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Close : unable to close the heap of the base structure"); + MSG_Error_Print (); + return rc; + } + + MSG_Base = NULL; + + /* Mise à jour du compteur d'ouverture */ + + MSG_Open_Counter--; + } + } + + /* Fermeture de la librairie LIBDATASTR */ + + rc = DS_Library_Close (); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Stderr_Set_I ( FILE * Out ) +{ + MSG_stderr = Out; + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Affichage des ressources de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : Flux de sortie de l'affichage */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Dump_I ( FILE * Out ) +{ + MSGT_Status rc; + size_t Total_Size = 0; + unsigned int Nb_Message; + int Locked; + + /* Verrouillage du heap des messages en lecture */ + + rc = SM_Heap_Lock (MSG_Message_Heap, SMD_READ, &Locked); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Dump : unable to lock the message heap for reading"); + MSG_Error_Print (); + return rc; + } + + /* Récupération de la taille totale des messages */ + + ND_DataStruct_Traverse (MSG_Message_Heap->MHH->ACR, NDD_CMD_SUM_VALUES, &Total_Size); + + Nb_Message = MSG_Message_Heap->MHH->ACR->Node_Number; + Total_Size -= Nb_Message * sizeof (NDT_Node); + + /* Déverrouillage du heap des messages */ + + rc = SM_Heap_Unlock (MSG_Message_Heap); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Dump : unable to unlock the message heap"); + MSG_Error_Print (); + return rc; + } + + /* Affichage des informations sur la base de la LIBMSG */ + + fprintf (Out, "LIBMSG :\n\t- %ld message port(s)\n\t- %d message(s) : %d byte(s)\n", MSG_Base->Port_List->Node_Number, Nb_Message, Total_Size); + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Test de l'existence d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Name : nom du port de messages */ +/* (O) Port : adresse d'un pointeur sur le port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Exist_I ( const char * Name, MSGT_Port ** Port ) +{ + MSGT_Status rc; + NDT_Node * Node; + MSGT_Port Tmp_Port; + + *Port = NULL; + + strcpy (Tmp_Port.Name, Name); + + rc = DS_Node_Find (MSG_Base->Port_List, &Node, (void *)&Tmp_Port, NULL); + if (DS_ERROR(rc)) return rc; + + if (rc == DSS_KO) return MSGS_NO; + + *Port = (MSGT_Port *)(Node->Value); + + return MSGS_YES; +} + +/*------------------------------------------------------------------------------*/ +/* Création/ouverture d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Name : nom du port de messages */ +/* (O) Port : adresse d'un pointeur sur le port de messages */ +/* (I) Open_Mode : mode d'ouverture du port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Open_I ( const char * Name, MSGT_Port ** Port, MSGT_Flags Open_Mode ) +{ + MSGT_Status rc; + union semun Sem_Ctl; + + *Port = NULL; + + /* Recherche du nom du port dans la liste des ports référencés par la base */ + + rc = MSG_Port_Exist_I (Name, Port); + if (MSG_ERROR(rc)) return rc; + if (rc == MSGS_YES) + { + NDT_Root * Root; + + if (!MSGD_MSK_OPEN (Open_Mode)) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : the message port \"%s\" already exists and (Open_Mode & MSGD_OPEN) is false", Name); + MSG_Error_Print (); + + *Port = NULL; + + return MSGS_ERRAPI; + } + + /* On ouvre le heap du port qui contient la queue de messages et la liste de sémaphores */ + + rc = DS_DataStruct_Open (MSG_Name_Prefix (Name), &Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : unable to open the main data structure of port \"%s\"", Name); + MSG_Error_Print (); + + *Port = NULL; + + return rc; + } + + return MSGS_OK; + } + + if (!MSGD_MSK_CREATE (Open_Mode)) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : the message port \"%s\" does not exist and (Open_Mode & MSGD_CREATE) is false", Name); + MSG_Error_Print (); + + return MSGS_ERRAPI; + } + + /* Création du port dans la liste des ports référencés par la base */ + + rc = DS_Value_Alloc (MSG_Base->Port_List, (void **)Port, Name); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : unable to create message port \"%s\"", Name); + MSG_Error_Print (); + + return rc; + } + + /* Création du sémaphore permettant le verrouillage du port */ + + (*Port)->LockSemID = semget (IPC_PRIVATE, 1, 0777|IPC_CREAT|IPC_EXCL); + if ((*Port)->LockSemID == -1) + { + switch (errno) + { + case ENOMEM: + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : the amount of memory is not sufficient to create a new semaphore"); + break; + + case ENOSPC: + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : the number of semaphores exceeds the system-imposed limit"); + break; + + default : + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : unknown error (%d) while creating a semaphore", errno); + break; + } + + MSG_Error_Print (); + + /* Suppression du port précédement créé */ + + DS_Value_Free (MSG_Base->Port_List, (void *)*Port); + + return rc; + } + + /* Initialisation du sémaphore à 1 (aucun verrou) */ + + Sem_Ctl.val = 1; + if (semctl ((*Port)->LockSemID, 0, SETVAL, Sem_Ctl)) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : unable to initialize the value of the listen semaphore %d", (*Port)->LockSemID); + MSG_Error_Print (); + + /* Suppression du port précédement créé */ + + DS_Value_Free (MSG_Base->Port_List, (void *)*Port); + + return rc; + } + + /* Création du sémaphore permettant l'écoute du port */ + + (*Port)->ListenSemID = semget (IPC_PRIVATE, 1, 0777|IPC_CREAT|IPC_EXCL); + if ((*Port)->ListenSemID == -1) + { + switch (errno) + { + case ENOMEM: + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : the amount of memory is not sufficient to create a new semaphore"); + break; + + case ENOSPC: + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : the number of semaphores exceeds the system-imposed limit"); + break; + + default : + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : unknown error (%d) while creating a semaphore", errno); + break; + } + + MSG_Error_Print (); + + /* Suppression du port précédement créé */ + + DS_Value_Free (MSG_Base->Port_List, (void *)*Port); + + return rc; + } + + /* Initialisation du sémaphore à 0 */ + + Sem_Ctl.val = 0; + if (semctl ((*Port)->ListenSemID, 0, SETVAL, Sem_Ctl)) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : unable to initialize the value of the listen semaphore %d", (*Port)->ListenSemID); + MSG_Error_Print (); + + /* Suppression du port précédement créé */ + + DS_Value_Free (MSG_Base->Port_List, (void *)*Port); + + return rc; + } + + /* Création de la queue de messages du port */ + + rc = DS_DataStruct_Open (MSG_Name_Prefix (Name), &((*Port)->MsgQueue), NDD_DS_LIST | NDD_MN_ORDERED, MSG_FILE_MANAGER, MSG_PORT_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : unable to create a message queue for port \"%s\"", Name); + MSG_Error_Print (); + + /* Suppression du port précédement créé */ + + DS_Value_Free (MSG_Base->Port_List, (void *)*Port); + + return rc; + } + else strcpy ((*Port)->MsgQueue->Manager, "MSG_MessageQueue_Manager"); + + /* Création de la liste des sémaphores des listes de ports qui sont à l'écoute du port (dans le même heap que pour la queue de messages) */ + + rc = DS_DataStruct_Open (MSG_Name_Prefix (Name), &((*Port)->SemList), NDD_DS_LIST | NDD_MN_FIFO, MSG_FILE_MANAGER, 0, DSD_NEW, TRUE); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : unable to create the list of semaphore for port \"%s\"", Name); + MSG_Error_Print (); + + /* Suppression du port précédement créé */ + + DS_Value_Free (MSG_Base->Port_List, (void *)*Port); + + return rc; + } + else strcpy ((*Port)->SemList->Manager, "MSG_Semaphore_List_Manager"); + + /* Ajout du port à la liste des ports référencés par la base */ + + rc = DS_Value_Add (MSG_Base->Port_List, (void *)(*Port)); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : unable to add message port \"%s\" to the base list", Name); + MSG_Error_Print (); + + /* Suppression du port précédement créé */ + + DS_Value_Free (MSG_Base->Port_List, (void *)*Port); + + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Configuration d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Tag : type de configuration */ +/* (I) ... : données de configuration */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Config_I ( MSGT_Port * Port, MSGT_Config Tag, ... ) +{ + MSGT_Status rc; + va_list Args; + + if (Tag == MSGD_CONFIG_SIZE) + { + size_t Size; + + va_start (Args, Tag); + Size = va_arg (Args, size_t); + + if (Size != MSGD_UNLIMITED) + { + /* On vérifie que la taille limite n'est pas déjà dépassée */ + + if ((size_t)(Port->MsgQueue->Node_Number) > Size) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Config : the limit has already been exceeded"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + } + + MSG_Port_Lock (Port, MSGD_WRITE); + + Port->Size = Size; + va_end (Args); + + MSG_Port_Unlock (Port, MSGD_WRITE); + + return MSGS_OK; + } + + if (Tag == MSGD_CONFIG_MSGQUEUE) + { + NDT_DataStruct_Type Type; + + va_start (Args, Tag); + Type = va_arg (Args, NDT_DataStruct_Type); + + MSG_Port_Lock (Port, MSGD_WRITE); + + rc = DS_DataStruct_Convert (Port->MsgQueue, Type); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Config : unable to configure the message queue of port \"%s\"", Port->Name); + MSG_Error_Print (); + } + + va_end (Args); + + MSG_Port_Unlock (Port, MSGD_WRITE); + + return MSGS_OK; + } + + sprintf (MSG_Error_Msg, "Error MSG_Port_Config : unknown config type %d", Tag); + MSG_Error_Print (); + + return MSGS_ERRAPI; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Close_Mode : mode de fermeture du port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Close_I ( MSGT_Port * Port, MSGT_Flags Close_Mode ) +{ + MSGT_Status rc; + + if (Close_Mode == MSGD_CLOSE) + { + rc = DS_DataStruct_Close (Port->MsgQueue, DSD_CLOSE); + if (rc != DSS_OK) + { + /* Pour la fermeture du port, on se contente de fermer sa data structure principale */ + + sprintf (MSG_Error_Msg, "Error MSG_Port_Close : unable to close the message queue of port \"%s\"", Port->Name); + MSG_Error_Print (); + return rc; + } + } + else if (Close_Mode == MSGD_DESTROY) + { + /* On ne prend pas la peine de vérifier si le port est référencé par une liste de ports (tant pis pour elle) */ + + /* Suppression du port de la liste des ports référencés par la base */ + + rc = DS_Value_Remove (MSG_Base->Port_List, Port, (void **)&Port); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Close : unable to remove port \"%s\" from the base list", Port->Name); + MSG_Error_Print (); + return rc; + } + + rc = DS_Value_Free (MSG_Base->Port_List, Port); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Close : unable to free port \"%s\"", Port->Name); + MSG_Error_Print (); + return rc; + } + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Verrouillage d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Mode : type de verrouillage */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Lock_I ( MSGT_Port * Port, MSGT_Flags Mode ) +{ + if (MSGD_MSK_READ(Mode)) return MSG_ShareLock_Set (Port->LockSemID); + + if (MSGD_MSK_WRITE(Mode)) return MSG_ExclusiveLock_Set (Port->LockSemID); + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Déverrouillage d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Mode : type de verrou à enlever */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Unlock_I ( MSGT_Port * Port, MSGT_Flags Mode ) +{ + if (MSGD_MSK_READ(Mode)) return MSG_ShareLock_Release (Port->LockSemID); + + if (MSGD_MSK_WRITE(Mode)) return MSG_ExclusiveLock_Release (Port->LockSemID); + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Création/ouverture d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +/* (O) PortList : adresse d'un pointeur sur la liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Open_I ( MSGT_PortList ** PortList ) +{ + MSGT_Status rc; + union semun Sem_Ctl; + + /* Allocation de la structure */ + + *PortList = (MSGT_PortList *) malloc (sizeof(MSGT_PortList)); + if (!*PortList) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Open : unable to allocate memory for the message port list"); + MSG_Error_Print (); + return MSGS_ERRMEM; + } + + /* Création en local d'une liste de ports */ + + rc = ND_DataStruct_Open (&((*PortList)->Root), NDD_DS_LIST | NDD_MN_FIFO, NULL, NULL, NULL, TRUE); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Open : unable to open the node structure"); + MSG_Error_Print (); + free (*PortList); + + return rc; + } + else strcpy((*PortList)->Root->Manager, "MSG_PortList_Manager"); + + /* Création du sémaphore pour l'écoute sur la liste de ports */ + + (*PortList)->ListenSemID = semget (IPC_PRIVATE, 1, 0777|IPC_CREAT|IPC_EXCL); + if ((*PortList)->ListenSemID == -1) + { + switch (errno) + { + case ENOMEM: + sprintf (MSG_Error_Msg, "Error MSG_PortList_Open : the amount of memory is not sufficient to create a new semaphore"); + break; + + case ENOSPC: + sprintf (MSG_Error_Msg, "Error MSG_PortList_Open : the number of semaphores exceeds the system-imposed limit"); + break; + + default : + sprintf (MSG_Error_Msg, "Error MSG_PortList_Open : unknown error (%d) while creating a semaphore", errno); + break; + } + + MSG_Error_Print (); + + ND_DataStruct_Close((*PortList)->Root); + free (*PortList); + + return MSGS_ERRSEM; + } + + /* Initialisation du sémaphore à 0 */ + + Sem_Ctl.val = 0; + if (semctl ((*PortList)->ListenSemID, 0, SETVAL, Sem_Ctl)) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Open : unable to initialize the value of the listen semaphore %d", (*PortList)->ListenSemID); + MSG_Error_Print (); + + semctl ((*PortList)->ListenSemID, 0, IPC_RMID, Sem_Ctl); + ND_DataStruct_Close((*PortList)->Root); + free (*PortList); + + return MSGS_ERRSEM; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un port de messages à une liste de ports */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur la liste de ports de messages */ +/* (I) Port : pointeur sur un port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Port_Add_I ( MSGT_PortList * PortList, MSGT_Port * Port ) +{ + MSGT_Status rc; + union semun Sem_Ctl, Tmp_Ctl; + + /* Ajout du port à la liste */ + + rc = ND_Value_Add (PortList->Root, (void *)Port); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Add : unable to add a value to the port list node structure"); + MSG_Error_Print (); + return rc; + } + + /* Mise à jour du sémaphore de la liste : pour cela, on verrouille temporairement le port écouté */ + + MSG_Port_Lock (Port, MSGD_READ); + + Sem_Ctl.val = semctl (PortList->ListenSemID, 0, GETVAL, Tmp_Ctl) + Port->MsgQueue->Node_Number; + if (semctl (PortList->ListenSemID, 0, SETVAL, Sem_Ctl)) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Open : unable to update the value of semaphore %d", PortList->ListenSemID); + MSG_Error_Print (); + + ND_Value_Remove (PortList->Root, Port, (void **)&Port); + ND_Value_Free (PortList->Root, Port); + MSG_Port_Unlock (Port, MSGD_READ); + + return MSGS_ERRSEM; + } + + /* On référence la présente liste au niveau du port que l'on écoute */ + + rc = ND_Value_Add (Port->SemList, (void *)PortList->ListenSemID); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Add : unable to reference the current list to the port"); + MSG_Error_Print (); + MSG_Port_Unlock (Port, MSGD_READ); + return rc; + } + + MSG_Port_Unlock (Port, MSGD_READ); + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Retrait d'un port de messages d'une liste de ports */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur la liste de ports de messages */ +/* (I) Port : pointeur sur un port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Port_Remove_I ( MSGT_PortList * PortList, MSGT_Port * Port ) +{ + MSGT_Status rc; + union semun Sem_Ctl, Tmp_Ctl; + + /* Retrait du port de la liste : pour cela, on verrouille temporairement le port */ + + MSG_Port_Lock (Port, MSGD_READ); + + rc = ND_Value_Remove (PortList->Root, Port, (void **)&Port); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Remove : unable to remove a port from the port list"); + MSG_Error_Print (); + MSG_Port_Unlock (Port, MSGD_READ); + return rc; + } + + rc = ND_Value_Free (PortList->Root, Port); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Remove : unable to free a port of the port list"); + MSG_Error_Print (); + MSG_Port_Unlock (Port, MSGD_READ); + return rc; + } + + /* On met à jour le sémaphore de la liste de ports */ + + Sem_Ctl.val = semctl (PortList->ListenSemID, 0, GETVAL, Tmp_Ctl) - Port->MsgQueue->Node_Number; + if (Sem_Ctl.val < 0) Sem_Ctl.val = 0; + if (semctl (PortList->ListenSemID, 0, SETVAL, Sem_Ctl)) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Remove : unable to update the value of the semaphore %d", PortList->ListenSemID); + MSG_Error_Print (); + rc = MSGS_ERRSEM; + } + + /* On retire la référence que le port avait sur la présente liste de ports */ + + rc = ND_Value_Remove (Port->SemList, (void *)PortList->ListenSemID, (void **)&(PortList->ListenSemID)); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Remove : unable to remove the current port list from the port"); + MSG_Error_Print (); + } + + rc = ND_Value_Free (Port->SemList, (void *)PortList->ListenSemID); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Remove : unable to free the current port list"); + MSG_Error_Print (); + } + + MSG_Port_Unlock (Port, MSGD_READ); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Suppression d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur la liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Close_I ( MSGT_PortList * PortList ) +{ + MSGT_Status rc; + union semun Sem_Ctl; + NDT_Node * Node; + + /* On détache tous les ports de la liste */ + + ND_Node_First_Get (PortList->Root, &Node); + while (Node) + { + NDT_Node * Next_Node; + MSGT_Port * Port = (MSGT_Port *)(Node->Value); + + ND_Node_Next_Get (Node, &Next_Node); + + rc = MSG_PortList_Port_Remove (PortList, Port); + if (MSG_ERROR(rc)) return rc; + + Node = Next_Node; + } + + /* Destruction de la liste de ports */ + + ND_DataStruct_Close (PortList->Root); + + /* Suppression du sémaphore de la liste de ports */ + + semctl (PortList->ListenSemID, 0, IPC_RMID, Sem_Ctl); + + /* Désallocation de la structure */ + + free (PortList); + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ecoute d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur une liste de ports de messages */ +/* (I) Type : type du message à récupérer */ +/* (O) Msg : adresse d'un pointeur sur le message à recevoir */ +/* (I) Flags : paramètres de réception */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Listen_I ( MSGT_PortList * PortList, unsigned int Type, MSGT_Message ** Msg, MSGT_Flags Flags) +{ + MSGT_Status rc; + NDT_Node * Node; + int End = FALSE; + int Found = FALSE; + int Empty = TRUE; + + /* + L'écoute d'une liste de ports est basée sur le + même algorithme que pour l'écoute d'un seul port. + + Pour cela, la liste de ports possède un sémaphore qui est + incrémentée lorsqu'un nouveau message arrive sur l'un des ports. + */ + + MSG_Signal_Received = FALSE; /* pour indiquer qu'aucun signal n'a encore interrompu l'attente */ + + do /* Boucle principale */ + { + /* On opère sur le sémaphore pour indiquer qu'on essaye de retirer un message */ + + rc = MSG_Semaphore_Operate (PortList->ListenSemID, MSG_SemOp_Receive, 1); + + switch ((int)rc) + { + case MSGS_OK: + case MSGS_ERRNOWAIT: + + break; + + case MSGS_ERRSIG: + return MSGS_ERRSIG; + + default : + sprintf (MSG_Error_Msg, "Error MSG_PortList_Listen : unable to operate on the listen port list semaphore (ID=%d)", PortList->ListenSemID); + MSG_Error_Print (); + return rc; + } + + /* Recherche d'un message du type demandé dans l'un des ports de la liste */ + + ND_Node_First_Get (PortList->Root, &Node); + while (Node && Found == FALSE) + { + MSGT_Port * Port = (MSGT_Port *)(Node->Value); + + /* On écoute chaque port de la liste sans attente */ + + rc = MSG_Message_Receive_I (Port, Type, Msg, MSGD_NO_WAIT); + + switch ((int)rc) + { + case MSGS_OK: + Found = TRUE; + break; + + case MSGS_NO_MSG: + ND_Node_Next_Get (Node, &Node); + break; + + case MSGS_BAD_TYPE: + Empty = FALSE; + ND_Node_Next_Get (Node, &Node); + break; + + case MSGS_ERRSIG: + return MSGS_ERRSIG; + + default : + sprintf (MSG_Error_Msg, "Error MSG_PortList_Listen : unable to remove a message from one of the list's port"); + MSG_Error_Print (); + return rc; + } + } + + /* Un message a-t'il été trouvé ? */ + + if (Found == TRUE) + { + /* Fin de la boucle de recherche */ + + End = TRUE; + } + else + { + /* En mode sans attente, on sort directement avec un code retour spécifique */ + + if (Flags == MSGD_NO_WAIT) return (Empty == TRUE ? MSGS_NO_MSG : MSGS_BAD_TYPE); + + /* Sinon, on se met en attente sur le sémaphore */ + + if (MSG_Signal_Received == TRUE) return MSGS_ERRSIG; + + rc = MSG_Semaphore_Operate (PortList->ListenSemID, MSG_SemOp_Listen, 2); + + /* Réveil du process : un message nouveau est-il arrivé sur l'un des ports de la liste ? */ + + switch ((int)rc) + { + case MSGS_OK: + + /* On boucle à nouveau sur la recherche de message */ + + break; + + case MSGS_ERRSIG: + return MSGS_ERRSIG; + + default : + sprintf (MSG_Error_Msg, "Error MSG_PortList_Listen: unable to operate on the listen port list semaphore (ID=%d)", PortList->ListenSemID); + MSG_Error_Print (); + return rc; + } + + } + } while (End ==FALSE); + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Création d'un message */ +/*------------------------------------------------------------------------------*/ +/* (O) Msg : adresse d'un pointeur sur le message */ +/* (I) Size : taille en octets des données du message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Alloc_I ( MSGT_Message ** Msg, size_t Size ) +{ + MSGT_Status rc; + NDT_Node * Node; + int Locked; + + *Msg = NULL; + + /* On verrouille le heap des messages en écriture */ + + rc = SM_Heap_Lock (MSG_Message_Heap, SMD_WRITE, &Locked); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Alloc : unable to lock the message heap for writing"); + MSG_Error_Print (); + return rc; + } + + /* Le noeud du message est alloué en même temps que le message */ + + rc = SM_Chunk_Alloc (MSG_Message_Heap, sizeof (NDT_Node) + sizeof (MSGT_Message) + Size, (void **)&Node); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Alloc : unable to allocate memory for a new message"); + MSG_Error_Print (); + return rc; + } + + Node->Value = (void *)((size_t)(Node) + sizeof (NDT_Node)); + + *Msg = (MSGT_Message *)(Node->Value); + + (*Msg)->From [0] = (char)0; + (*Msg)->Via [0] = (char)0; + (*Msg)->To [0] = (char)0; + (*Msg)->Type = MSGD_DEFAULT_TYPE; + (*Msg)->Priority = MSGD_DEFAULT_PRIORITY; + (*Msg)->Data = (void *)((size_t)(*Msg) + sizeof (MSGT_Message)); + (*Msg)->Size = Size; + (*Msg)->Swap = NULL; + + /* On déverrouille le heap des messages */ + + rc = SM_Heap_Unlock (MSG_Message_Heap); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Alloc : unable to unlock the message heap for writing"); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Configuration d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur un message */ +/* (I) Tag : type de configuration */ +/* (I) ... : données de configuration */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Config_I ( MSGT_Message * Msg, MSGT_Config Tag, ... ) +{ + va_list Args; + + if (Tag == MSGD_CONFIG_PRIORITY) + { + int Priority; + + va_start (Args, Tag); + Priority = va_arg (Args, int); + + if (Priority < MSGD_SYSTEM_HIGH_PRIORITY || Priority > MSGD_SYSTEM_LOW_PRIORITY) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Config : incorrect value (%d) for a priority", Priority); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + Msg->Priority = Priority; + + va_end (Args); + + return MSGS_OK; + } + + if (Tag == MSGD_CONFIG_TYPE) + { + unsigned int Type; + + va_start (Args, Tag); + Type = va_arg (Args, int); + + if (Type == MSGD_NO_TYPE) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Config : incorrect value (%d) for a message type", Type); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + /* + Petite sécurité pour le messages système PING : + + La taille du message doit être suffisante pour contenir + 4 dates (mises à jour automatiquement par la librairie) : + + - date d'envoi du PING REQUEST + - date de réception du PING REQUEST + - date d'envoi du PING REPLY + - date de réception du PING REPLY + */ + + if (Type == MSGD_SYSTEM_PING_REQUEST) + { + if (Msg->Size < sizeof (MSGT_PingData)) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Config : the message size (%d byte(s)) must be greater than %d bytes for a PING message", Msg->Size, sizeof (MSGT_PingData)); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + } + + Msg->Type = Type; + + va_end (Args); + + return MSGS_OK; + } + + sprintf (MSG_Error_Msg, "Error MSG_Message_Config : unknown config type %d", Tag); + MSG_Error_Print (); + + return MSGS_ERRAPI; +} + +/*------------------------------------------------------------------------------*/ +/* Destruction d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Free_I ( MSGT_Message * Msg ) +{ + MSGT_Status rc; + NDT_Node * Node; + int Locked; + + /* On verrouille le heap des messages en écriture */ + + rc = SM_Heap_Lock (MSG_Message_Heap, SMD_WRITE, &Locked); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Free : unable to lock the message heap for writing"); + MSG_Error_Print (); + return rc; + } + + /* Le noeud du message est désalloué en même temps que le message */ + + Node = (NDT_Node *)((size_t)Msg - sizeof (NDT_Node)); + + rc = SM_Chunk_Free (MSG_Message_Heap, Node); + if (rc != NDS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Free : unable to free memory which had been allocated for the message"); + MSG_Error_Print (); + return rc; + } + + /* On déverrouille le heap des messages */ + + rc = SM_Heap_Unlock (MSG_Message_Heap); + if (rc != SMS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Free : unable to unlock the message heap for writing"); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un message dans un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) From : nom du port de messages de l'envoyeur */ +/* (I) To : pointeur sur le port de messages destinataire */ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Send_I ( const char * From, MSGT_Port * To, MSGT_Message * Msg ) +{ + MSGT_Status rc; + NDT_Node * Node; + char To_Name [25]; + struct timeval * Current_Time; + + /* + Pour l'envoi d'un PING (message système), on modifie le contenu + du message en y mettant la date courante d'envoi. + */ + + if (Msg->Type == MSGD_SYSTEM_PING_REQUEST) + { + /* Petite sécurité : on vérifie que le port de l'envoyeur est renseigné ! */ + + if (From && !strlen (From)) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : unable to send a ping request message when the sender port is undefined"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + Current_Time = &(((MSGT_PingData *)(Msg->Data))->Snd1); + gettimeofday (Current_Time, NULL); + } + else if (Msg->Type == MSGD_SYSTEM_PING_REPLY) + { + Current_Time = &(((MSGT_PingData *)(Msg->Data))->Snd2); + gettimeofday (Current_Time, NULL); + } + + /* Verrouillage du port de messages en écriture */ + + rc = MSG_Port_Lock (To, MSGD_WRITE); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : unable to lock port \"%s\" for writing", To->Name); + MSG_Error_Print (); + return rc; + } + + /* On vérifie qu'il reste de la place dans le port de messages */ + + if (To->Size != MSGD_UNLIMITED && (unsigned int)(To->MsgQueue->Node_Number) == To->Size) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : port \"%s\" is full", To->Name); + MSG_Error_Print (); + + MSG_Port_Unlock (To, MSGD_WRITE); + + return rc; + } + + /* Mise à jour des champs du message */ + + strcpy (To_Name, To->Name); + + if (From && strlen (From)) + { + if (!strlen (Msg->From)) strcpy (Msg->From, From); + + strcpy (Msg->Via, From); + } + + strcpy (Msg->To, To_Name); + + /* Ajout du message = ajout du noeud (le noeud est déjà créé dans la liste de messages gérée par la base) */ + + Node = (NDT_Node *)((size_t)(Msg) - sizeof (NDT_Node)); + + rc = DS_Node_Add (To->MsgQueue, Node); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : unable to add the message node to the node structure"); + MSG_Error_Print (); + + MSG_Port_Unlock (To, MSGD_WRITE); + + return rc; + } + + /* On met à jour le sémaphore d'écoute du port de messages */ + + rc = MSG_Semaphore_Operate (To->ListenSemID, MSG_SemOp_Add, 1); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : unable to operate on semaphore %d", To->ListenSemID); + MSG_Error_Print (); + + DS_Node_Remove (Node); + MSG_Port_Unlock (To, MSGD_WRITE); + + return rc; + } + + /* On met à jour les sémaphores de toutes les liste de ports qui sont à l'écoute du port de messages */ + + ND_Node_First_Get (To->SemList, &Node); + + while (Node) + { + int SemID = (int)(Node->Value); + + rc = MSG_Semaphore_Operate (SemID, MSG_SemOp_Add, 1); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : unable to operate on semaphore %d", SemID); + MSG_Error_Print (); + + /* On continue quand même : peut-être un processus a-t'il oublié de nous avertir qu'il fermait sa liste de ports (quel idiot !) */ + } + + ND_Node_Next_Get (Node, &Node); + } + + /* Déverrouillage du port de messages en écriture */ + + rc = MSG_Port_Unlock (To, MSGD_WRITE); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : unable to unlock port \"%s\" which had been locked for writing", To->Name); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Réception d'un message dans un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Type : type du message à récupérer */ +/* (O) Msg : adresse d'un pointeur sur le message à recevoir */ +/* (I) Flags : paramètres de réception */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Receive_I ( MSGT_Port * Port, unsigned int Type, MSGT_Message ** Msg, MSGT_Flags Flags) +{ + NDT_Node * Node; + MSGT_Status rc; + struct timeval * Current_Time; + int End = FALSE; + int Found = FALSE; + int Empty = TRUE; + + /* L'écoute d'un port de messagee est basée sur l'algorithme suivant : + + - le processus commence par consulter la queue de messages (après verrouillage exclusif) + - s'il ne trouve rien qui lui convienne, il se met en attente sur le sémaphore attaché au port. + + NB : le sémaphore du port est incrémenté à chaque fois qu'un nouveau message est présent sur le port. + */ + + MSG_Signal_Received = FALSE; /* pour indiquer qu'aucun signal n'a encore interrompu l'attente */ + + do /* Boucle principale */ + { + /* Verrouillage du port de messages en écriture */ + + rc = MSG_Port_Lock (Port, MSGD_WRITE); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : unable to lock port \"%s\" for writing", Port->Name); + MSG_Error_Print (); + + return rc; + } + + /* On opère sur le sémaphore pour indiquer qu'on essaye de retirer un message */ + + rc = MSG_Semaphore_Operate (Port->ListenSemID, MSG_SemOp_Receive, 1); + + switch ((int)rc) + { + case MSGS_OK: + break; + + case MSGS_ERRNOWAIT: + break; + + case MSGS_ERRSIG: + MSG_Port_Unlock (Port, MSGD_WRITE); + return MSGS_ERRSIG; + break; + + default : + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : unable to operate on the listen port semaphore (ID=%d)", Port->ListenSemID); + MSG_Error_Print (); + MSG_Port_Unlock (Port, MSGD_WRITE); + return rc; + } + + /* Recherche d'un message du type demandé */ + + if (Type == MSGD_NO_TYPE) + { + /* Si aucun type n'est demandé en particulier, on prend le premier de la liste */ + + rc = DS_Node_First_Get (Port->MsgQueue, &Node); + if (DS_ERROR(rc)) return rc; + if (rc == DSS_OK) Found = TRUE; + } + else + { + DS_Node_First_Get (Port->MsgQueue, &Node); + while (Node && Found != TRUE) + { + unsigned int Msg_Type = ((MSGT_Message *)(Node->Value))->Type; + + Empty = FALSE; + + if (Type == MSGD_SYSTEM_GENERIC && MSGD_IS_SYSTEM (Msg_Type)) + { + /* Recherche d'un message système quelconque */ + + Found = TRUE; + } + else if (Msg_Type == Type) + { + /* Recherche d'un message d'un type particulier */ + + Found = TRUE; + } + else DS_Node_Next_Get (Node, &Node); + } + } + + /* Un message a-t'il été trouvé ? */ + + if (Found == TRUE) + { + *Msg = (MSGT_Message *)(Node->Value); + + /* Retrait du message = retrait du noeud (le noeud est géré dans la liste de messages référencés par la base) */ + + rc = DS_Node_Remove (Node); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : unable to remove the message node from the node structure"); + MSG_Error_Print (); + MSG_Port_Unlock (Port, MSGD_WRITE); + return rc; + } + + /* Fin de la boucle de recherche */ + + End = TRUE; + } + else + { + /* Déverrouillage du port de messages en écriture */ + + rc = MSG_Port_Unlock (Port, MSGD_WRITE); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : unable to unlock port \"%s\" which had been locked for writing", Port->Name); + MSG_Error_Print (); + return rc; + } + + /* En mode sans attente, on sort directement avec un code retour spécifique */ + + if (Flags == MSGD_NO_WAIT) return (Empty == TRUE ? MSGS_NO_MSG : MSGS_BAD_TYPE); + + /* Sinon, on se met en attente sur le sémaphore */ + + if (MSG_Signal_Received == TRUE) return MSGS_ERRSIG; + + rc = MSG_Semaphore_Operate (Port->ListenSemID, MSG_SemOp_Listen, 2); + + /* Réveil du process : un message nouveau est-il arrivé ? */ + + switch ((int)rc) + { + case MSGS_OK: + + /* On boucle sur la recherche de message */ + + break; + + case MSGS_ERRSIG: + return MSGS_ERRSIG; + break; + + default : + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : unable to operate on the listen port semaphore (ID=%d)", Port->ListenSemID); + MSG_Error_Print (); + return rc; + } + } + } while (End == FALSE); + + /* + Puisqu'un message a effectivement été retiré, on met à jour les sémaphores + de toutes les listes de ports qui seraient à l'écoute de ce port de messages. + */ + + ND_Node_First_Get (Port->SemList, &Node); + while (Node) + { + int SemID = (int)(Node->Value); + int semrc = MSG_Semaphore_Operate (SemID, MSG_SemOp_Receive, 1); + + switch (semrc) + { + case MSGS_OK: + break; + + case MSGS_ERRNOWAIT: + + /* Cas de la liste de ports sur laquelle le processus s'est précisément réveillé */ + + break; + + case MSGS_ERRSIG: + return MSGS_ERRSIG; + + break; + + default : + + /* Peut-être un processus a-t'il oublié de nous avertir qu'il fermait sa liste de ports (quelle négligence !) */ + + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : unable to operate on one of the semaphore list (Id=%d)", SemID); + MSG_Error_Print (); + + /* On continue quand même */ + } + + ND_Node_Next_Get (Node, &Node); + } + + /* Déverrouillage du port de messages en écriture */ + + rc = MSG_Port_Unlock (Port, MSGD_WRITE); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : unable to unlock port \"%s\" which had been locked for writing", Port->Name); + MSG_Error_Print (); + return rc; + } + + /* + Pour la réception d'un PING (REQUEST ou REPLY), on modifie le contenu + du message en y mettant la date courante de réception. + */ + + if ((*Msg)->Type == MSGD_SYSTEM_PING_REQUEST) + { + Current_Time = &(((MSGT_PingData *)((*Msg)->Data))->Rcv1); + gettimeofday (Current_Time, NULL); + + /* + Pour un ping request, on va jusqu'à renvoyer automatiquement + le message à son envoyeur, puis relancer l'écoute sur le port. + Ainsi, le ping devient parfaitement transparent pour l'utilisateur. + */ + + rc = MSG_Message_Reply (*Msg); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : unable to reply the PING REQUEST message"); + MSG_Error_Print (); + return rc; + } + + return MSG_Message_Receive (Port, Type, Msg, Flags); + } + else if ((*Msg)->Type == MSGD_SYSTEM_PING_REPLY) + { + Current_Time = &(((MSGT_PingData *)((*Msg)->Data))->Rcv2); + gettimeofday (Current_Time, NULL); + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Retour à l'envoyeur d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Reply_I ( MSGT_Message * Msg ) +{ + MSGT_Status rc; + MSGT_Port * To; + + /* On vérifie que le port de l'envoyeur est bien défini */ + + if (strlen (Msg->Via)) + { + /* Ouverture du port de messages de l'envoyeur */ + + rc = MSG_Port_Open_I (Msg->Via, &To, MSGD_OPEN); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Reply : unable to open port \"%s\"", Msg->Via); + MSG_Error_Print (); + return rc; + } + } + else + { + /* Sinon, on répond dans le port de messages par défaut */ + + rc = MSG_Port_Exist (MSGD_DEFAULT_PORT_NAME, &To); + if (rc == MSGS_YES) strcpy (Msg->Via, MSGD_DEFAULT_PORT_NAME); + else + { + if (MSG_ERROR(rc)) return rc; + + /* S'il n'est pas défini, on supprime le message */ + + rc = MSG_Message_Free_I (Msg); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Reply : unable to free the message"); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; + } + } + + /* + Pour les messages système de type REQUEST, on change le type en REPLY. + Pour les messages utilisateur, c'est à l'utilisateur de changer le type si nécessaire. + */ + + switch (Msg->Type) + { + case MSGD_SYSTEM_PING_REQUEST: + Msg->Type = MSGD_SYSTEM_PING_REPLY; + break; + + case MSGD_SYSTEM_STOP_REQUEST: + Msg->Type = MSGD_SYSTEM_STOP_REPLY; + break; + + case MSGD_SYSTEM_CONTINUE_REQUEST: + Msg->Type = MSGD_SYSTEM_CONT_REPLY; + break; + + case MSGD_SYSTEM_RESTART_REQUEST: + Msg->Type = MSGD_SYSTEM_RESTART_REPLY; + break; + + case MSGD_SYSTEM_SHUTDOWN_REQUEST: + Msg->Type = MSGD_SYSTEM_SHUTDOWN_REPLY; + break; + + case MSGD_SYSTEM_STATUS_REQUEST: + Msg->Type = MSGD_SYSTEM_STATUS_REPLY; + break; + + case MSGD_SYSTEM_INFO_REQUEST: + Msg->Type = MSGD_SYSTEM_INFO_REPLY; + break; + + case MSGD_SYSTEM_TRACEON_REQUEST: + Msg->Type = MSGD_SYSTEM_TRACEON_REPLY ; + break; + + case MSGD_SYSTEM_TRACEOFF_REQUEST: + Msg->Type = MSGD_SYSTEM_TRACEOFF_REPLY; + break; + + default : + break; + } + + /* Envoi du message dans le port de l'envoyeur */ + + rc = MSG_Message_Send_I (Msg->To, To, Msg); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Reply : unable to send the message to port \"%s\"", To->Name); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Retour à l'initiateur d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Return_I ( MSGT_Message * Msg ) +{ + MSGT_Status rc; + MSGT_Port * To; + + /* On vérifie que le port de l'initiateur est bien défini */ + + if (strlen (Msg->From)) + { + /* Ouverture du port de messages de l'initiateur */ + + rc = MSG_Port_Open_I (Msg->From, &To, MSGD_OPEN); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Return : unable to open port \"%s\"", Msg->Via); + MSG_Error_Print (); + return rc; + } + } + else + { + /* Sinon, on répond dans le port de messages par défaut */ + + rc = MSG_Port_Exist_I (MSGD_DEFAULT_PORT_NAME, &To); + if (rc == MSGS_YES) strcpy (Msg->From, MSGD_DEFAULT_PORT_NAME); + else + { + if (MSG_ERROR(rc)) return rc; + + /* S'il n'est pas défini, on supprime le message */ + + rc = MSG_Message_Free_I (Msg); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Return : unable to free the message"); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; + } + } + + /* Ouverture du port de messages de l'initiateur */ + + rc = MSG_Port_Open_I (Msg->From, &To, MSGD_OPEN); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Reply : unable to open port \"%s\"", Msg->From); + MSG_Error_Print (); + return rc; + } + + /* Envoi du message dans le port de l'initiateur */ + + rc = MSG_Message_Send_I (Msg->To, To, Msg); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Return : unable to send the message to port \"%s\"", To->Name); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* FONCTIONS SECURISEES (MSG_MODE = 0) */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Permet d'indiquer à la librairie qu'un signal a été reçu. */ +/* */ +/* NB : cette fonction sera appelée par l'utilisateur pour éviter que le */ +/* processus se bloque sur une attente de message malgré la réception de signal */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Signal_C ( void ) +{ + return MSG_Library_Signal_I (); +} + +/*------------------------------------------------------------------------------*/ +/* Teste si la librairie a été ouverte */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_IsOpen_C ( void ) +{ + return MSG_Library_IsOpen_I (); +} + +/*------------------------------------------------------------------------------*/ +/* Ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Instance : numéro de l'instance de la librairie */ +/* (I) Context : contexte d'utilisation de la librairie */ +/* (I) Open_Mode : mode d'ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Open_C ( int Instance, const char * Context, MSGT_Flags Open_Mode ) +{ + return MSG_Library_Open_I (Instance, Context, Open_Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Close_Mode : mode de fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Close_C ( MSGT_Flags Close_Mode ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Close : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Library_Close_I (Close_Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Stderr_Set_C ( FILE * Out ) +{ + return MSG_Library_Stderr_Set_I (Out); +} + +/*------------------------------------------------------------------------------*/ +/* Affichage des ressources de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : Flux de sortie de l'affichage */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Dump_C ( FILE * Out ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Dump : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Out) + { + sprintf (MSG_Error_Msg, "Error MSG_Library_Dump : the out stream is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Library_Dump_I (Out); +} + +/*------------------------------------------------------------------------------*/ +/* Test de l'existence d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Name : nom du port de messages */ +/* (O) Port : adresse d'un pointeur sur le port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Exist_C ( const char * Name, MSGT_Port ** Port ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Exist : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Name) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Exist : the port name is undefined"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Port) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Exist : the port address is undefined"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Port_Exist_I (Name, Port); +} + +/*------------------------------------------------------------------------------*/ +/* Création/ouverture d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Name : nom du port de messages */ +/* (O) Port : adresse d'un pointeur sur le port de messages */ +/* (I) Open_Mode : mode d'ouverture du port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Open_C ( const char * Name, MSGT_Port ** Port, MSGT_Flags Open_Mode ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Name) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : the port name is undefined"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Port) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Open : the port address is undefined"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Port_Open_I (Name, Port, Open_Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Configuration d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Tag : type de configuration */ +/* (I) ... : données de configuration */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Config_C ( MSGT_Port * Port, MSGT_Config Tag, ... ) +{ + MSGT_Status rc; + va_list Args; + + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Config : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Port) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Config : the message port is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (Tag == MSGD_CONFIG_SIZE) + { + size_t Size; + + va_start (Args, Tag); + Size = va_arg (Args, size_t); + + if (Size != MSGD_UNLIMITED) + { + /* On vérifie que la taille limite n'est pas déjà dépassée */ + + if ((size_t)(Port->MsgQueue->Node_Number) > Size) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Config : the limit has already been exceeded"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + } + + MSG_Port_Lock (Port, MSGD_WRITE); + + Port->Size = Size; + va_end (Args); + + MSG_Port_Unlock (Port, MSGD_WRITE); + + return MSGS_OK; + } + + if (Tag == MSGD_CONFIG_MSGQUEUE) + { + NDT_DataStruct_Type Type; + + va_start (Args, Tag); + Type = va_arg (Args, NDT_DataStruct_Type); + + MSG_Port_Lock (Port, MSGD_WRITE); + + rc = DS_DataStruct_Convert (Port->MsgQueue, Type); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Config : unable to configure the message queue of port \"%s\"", Port->Name); + MSG_Error_Print (); + } + + va_end (Args); + + MSG_Port_Unlock (Port, MSGD_WRITE); + + return MSGS_OK; + } + + sprintf (MSG_Error_Msg, "Error MSG_Port_Config : unknown config type %d", Tag); + MSG_Error_Print (); + + return MSGS_ERRAPI; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Close_Mode : mode de fermeture du port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Close_C ( MSGT_Port * Port, MSGT_Flags Close_Mode ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Close : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Port) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Close : the message port is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Port_Close_I (Port, Close_Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Verrouillage d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Mode : type de verrouillage */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Lock_C ( MSGT_Port * Port, MSGT_Flags Mode ) +{ + if (!Port) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Lock : the message port is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Port_Lock_I (Port, Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Déverrouillage d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Mode : type de verrou à enlever */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Unlock_C ( MSGT_Port * Port, MSGT_Flags Mode ) +{ + if (!Port) + { + sprintf (MSG_Error_Msg, "Error MSG_Port_Unlock : the message port is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Port_Unlock_I (Port, Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Création/ouverture d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +/* (O) PortList : adresse d'un pointeur sur la liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Open_C ( MSGT_PortList ** PortList ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Open : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!PortList) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Open : the port list address is undefined"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_PortList_Open_I (PortList); +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un port de messages à une liste de ports */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur la liste de ports de messages */ +/* (I) Port : pointeur sur un port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Port_Add_C ( MSGT_PortList * PortList, MSGT_Port * Port ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Add : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!PortList) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Add : the message port list is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Port) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Add : the message port is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_PortList_Port_Add_I (PortList, Port); +} + +/*------------------------------------------------------------------------------*/ +/* Retrait d'un port de messages d'une liste de ports */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur la liste de ports de messages */ +/* (I) Port : pointeur sur un port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Port_Remove_C ( MSGT_PortList * PortList, MSGT_Port * Port ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Remove : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!PortList) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Remove : the message port list is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Port) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Port_Remove : the message port is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_PortList_Port_Remove_I (PortList, Port); +} + +/*------------------------------------------------------------------------------*/ +/* Suppression d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur la liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Close_C ( MSGT_PortList * PortList ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Close : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!PortList) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Close : the message port list is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_PortList_Close_I (PortList); +} + +/*------------------------------------------------------------------------------*/ +/* Ecoute d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur une liste de ports de messages */ +/* (I) Type : type du message à récupérer */ +/* (O) Msg : adresse d'un pointeur sur le message à recevoir */ +/* (I) Flags : paramètres de réception */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Listen_C ( MSGT_PortList * PortList, unsigned int Type, MSGT_Message ** Msg, MSGT_Flags Flags ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Listen : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!PortList) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Listen : the message port list is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Msg) + { + sprintf (MSG_Error_Msg, "Error MSG_PortList_Listen : the message address is undefined"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_PortList_Listen_I (PortList, Type, Msg, Flags); +} + +/*------------------------------------------------------------------------------*/ +/* Création d'un message */ +/*------------------------------------------------------------------------------*/ +/* (O) Msg : adresse d'un pointeur sur le message */ +/* (I) Size : taille en octets des données du message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Alloc_C ( MSGT_Message ** Msg, size_t Size ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Alloc : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Msg) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Alloc : the message address is undefined"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Size) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Alloc : the allocation size must be > 0"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Message_Alloc_I (Msg, Size); +} + +/*------------------------------------------------------------------------------*/ +/* Configuration d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur un message */ +/* (I) Tag : type de configuration */ +/* (I) ... : données de configuration */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Config_C ( MSGT_Message * Msg, MSGT_Config Tag, ... ) +{ + va_list Args; + + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Config : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (Tag == MSGD_CONFIG_PRIORITY) + { + int Priority; + + va_start (Args, Tag); + Priority = va_arg (Args, int); + + if (Priority < MSGD_SYSTEM_HIGH_PRIORITY || Priority > MSGD_SYSTEM_LOW_PRIORITY) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Config : incorrect value (%d) for a priority", Priority); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + Msg->Priority = Priority; + + va_end (Args); + + return MSGS_OK; + } + + if (Tag == MSGD_CONFIG_TYPE) + { + unsigned int Type; + + va_start (Args, Tag); + Type = va_arg (Args, int); + + if (Type == MSGD_NO_TYPE) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Config : incorrect value (%d) for a message type", Type); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + /* + Petite sécurité pour le messages système PING : + + La taille du message doit être suffisante pour contenir + 4 dates (mises à jour automatiquement par la librairie) : + + - date d'envoi du PING REQUEST + - date de réception du PING REQUEST + - date d'envoi du PING REPLY + - date de réception du PING REPLY + */ + + if (Type == MSGD_SYSTEM_PING_REQUEST) + { + if (Msg->Size < sizeof (MSGT_PingData)) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Config : the message size (%d byte(s)) must be greater than %d bytes for a PING message", Msg->Size, sizeof (MSGT_PingData)); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + } + + Msg->Type = Type; + + va_end (Args); + + return MSGS_OK; + } + + sprintf (MSG_Error_Msg, "Error MSG_Message_Config : unknown config type %d", Tag); + MSG_Error_Print (); + + return MSGS_ERRAPI; +} + +/*------------------------------------------------------------------------------*/ +/* Destruction d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Free_C ( MSGT_Message * Msg ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Free : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Msg) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Free : the message is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Message_Free_I (Msg); +} + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un message dans un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) From : nom du port de messages de l'envoyeur */ +/* (I) To : pointeur sur le port de messages destinataire */ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Send_C ( const char * From, MSGT_Port * To, MSGT_Message * Msg ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!To) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : the target port is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Msg) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Send : the message is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Message_Send_I (From, To, Msg); +} + +/*------------------------------------------------------------------------------*/ +/* Réception d'un message dans un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Type : type du message à récupérer */ +/* (O) Msg : adresse d'un pointeur sur le message à recevoir */ +/* (I) Flags : paramètres de réception */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Receive_C ( MSGT_Port * Port, unsigned int Type, MSGT_Message ** Msg, MSGT_Flags Flags) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Port) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : the port is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Msg) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Receive : the message address is undefined"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Message_Receive_I (Port, Type, Msg, Flags); +} + +/*------------------------------------------------------------------------------*/ +/* Retour à l'envoyeur d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Reply_C ( MSGT_Message * Msg ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Reply : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Msg) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Reply : the message is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Message_Reply_I (Msg); +} + +/*------------------------------------------------------------------------------*/ +/* Retour à l'initiateur d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Return_C ( MSGT_Message * Msg ) +{ + if (!MSG_Base) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Return : the library is not open"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + if (!Msg) + { + sprintf (MSG_Error_Msg, "Error MSG_Message_Return : the message is null"); + MSG_Error_Print (); + return MSGS_ERRAPI; + } + + return MSG_Message_Return_I (Msg); +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS PRIVEES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Manager de la liste des ports de messages référencés par la base */ +/*------------------------------------------------------------------------------*/ +NDT_Status MSG_Base_Port_List_Manager (va_list Args) +{ + MSGT_Status rc; + NDT_Command Command = (NDT_Command) va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + MSGT_Port ** Port = va_arg (Args, MSGT_Port **); + va_list Args_Value = va_arg (Args, va_list); + char * Name = va_arg (Args_Value, char *); + + *Port = NULL; + + rc = DS_Alloc (Root, sizeof (MSGT_Port), (void **)Port); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Base_Port_List_Manager : unable to allocate a new port"); + MSG_Error_Print (); + return NDS_KO; + } + + strcpy ((*Port)->Name, Name); + (*Port)->ListenSemID = 0; + (*Port)->LockSemID = 0; + (*Port)->MsgQueue = NULL; + (*Port)->SemList = NULL; + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + MSGT_Port * Port = (MSGT_Port *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + MSGT_Port * Tmp_Port ; + + /* Pour afficher le port de messages, il faut préalablement l'ouvrir */ + + rc = MSG_Port_Open_I (Port->Name, &Tmp_Port, MSGD_OPEN); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Base_Port_List_Manager : unable to open port \"%s\" for printing", Port->Name); + MSG_Error_Print (); + return NDS_KO; + } + + fprintf (Out, "Port \"%s\" :\n\t- status = %s\n\t- queue = %ld message%c\n\t- listen semaphore = %d", Port->Name, MSG_LockStatus_Get (Port->LockSemID), Port->MsgQueue->Node_Number, Port->MsgQueue->Node_Number > 1 ? 's' : ' ', Port->ListenSemID); + if (Port->Size == MSGD_UNLIMITED) + fprintf (Out, "\n\t- max size = unlimited"); + else + fprintf (Out, "\n\t- max size = %d", Port->Size); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de ports = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + MSGT_Port * Port = (MSGT_Port *) va_arg (Args, void *); + union semun Sem_Ctl; + + /* Suppression de la queue de messages du port */ + + if (Port->MsgQueue) + { + NDT_Root * MSQ_Root; + NDT_Node * Node; + + /* Avant de supprimer la queue de messages, on l'ouvre au cas où cela n'aurait pas été fait */ + + rc = DS_DataStruct_Open (MSG_Name_Prefix (Port->Name), &MSQ_Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Base_Port_List_Manager : unable to open the message queue of port \"%s\"", Port->Name); + MSG_Error_Print (); + return rc; + } + + /* Les messages étant alloués indépendament de la queue de messages, on les détruit à part */ + + ND_Node_First_Get (Port->MsgQueue, &Node); + + while (Node) + { + NDT_Node * Next_Node; + MSGT_Message * Msg = (MSGT_Message *)(Node->Value); + + ND_Node_Next_Get (Node, &Next_Node); + + /* Détachement du noeud de la data structure */ + + ND_Node_Remove (Node); + + /* Désallocation du message (et de son noeud) */ + + MSG_Message_Free (Msg); + + Node = Next_Node; + } + + /* On peut maintenant détruire la data structure proprement dite */ + + rc = DS_DataStruct_Close (Port->MsgQueue, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_Base_Port_List_Manager : unable to destroy the message queue of port \"%s\"", Port->Name); + MSG_Error_Print (); + return rc; + } + } + + /* Suppression des sémaphores */ + + if (Port->ListenSemID) semctl (Port->ListenSemID, 0, IPC_RMID, Sem_Ctl); + + if (Port->LockSemID) semctl (Port->LockSemID, 0, IPC_RMID, Sem_Ctl); + + /* Désallocation de la structure du port */ + + DS_Free (Root, Port); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + MSGT_Port * Port1, * Port2; + long comp; + + Port1 = (MSGT_Port *) va_arg (Args, void *); + Port2 = (MSGT_Port *) va_arg (Args, void *); + + va_end (Args); + comp = strcmp (Port1->Name, Port2->Name); + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Manager d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +NDT_Status MSG_PortList_Manager (va_list Args) +{ + NDT_Command Command = (NDT_Command)va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_PRINT_VALUE) + { + MSGT_Port * Port = (MSGT_Port *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + /* Le port de messages est censé être déjà ouvert par le procsesus courant */ + + fprintf (Out, "Port \"%s\" :\n\t- status = %s\n\t- queue = %ld message%c\n\t- listen semaphore = %d", Port->Name, MSG_LockStatus_Get (Port->LockSemID), Port->MsgQueue->Node_Number, Port->MsgQueue->Node_Number > 1 ? 's' : ' ', Port->ListenSemID); + if (Port->Size == MSGD_UNLIMITED) fprintf (Out, "\n\t- max size = unlimited\n"); + else fprintf (Out, "\n\t- max size = %d\n", Port->Size); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de ports = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + MSGT_Port * Port1, * Port2; + long comp; + + Port1 = (MSGT_Port *) va_arg (Args, void *); + Port2 = (MSGT_Port *) va_arg (Args, void *); + + va_end (Args); + comp = strcmp (Port1->Name, Port2->Name); + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Manager d'une liste de sémaphores */ +/*------------------------------------------------------------------------------*/ +NDT_Status MSG_Semaphore_List_Manager (va_list Args) +{ + NDT_Command Command = (NDT_Command)va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_PRINT_VALUE) + { + int SemID = (int) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Semaphore %d", SemID); + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de sémaphores = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + int Sem1, Sem2; + long comp; + + Sem1 = (int) va_arg (Args, void *); + Sem2 = (int) va_arg (Args, void *); + + va_end (Args); + comp = Sem1 - Sem2; + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Manager d'une queue de messages associée à un port de messages */ +/*------------------------------------------------------------------------------*/ +NDT_Status MSG_MessageQueue_Manager (va_list Args) +{ + NDT_Command Command = (NDT_Command)va_arg(Args, NDT_Command); + + if (Command == NDD_CMD_PRINT_VALUE) + { + MSGT_Message * Msg = (MSGT_Message *) va_arg(Args, void *); + FILE * Out = va_arg (Args, FILE *); + unsigned int i, j; + + fprintf (Out, "Message :\n\t- Type = %d\n\t- Priority = %d\n\t- From = %s\n\t- Via = %s\n\t- To = %s\n\t- Size = %d\n\t- Data = \"", Msg->Type, Msg->Priority, Msg->From, Msg->Via, Msg->To, Msg->Size); + j = (Msg->Size > 50 ? 50 : Msg->Size); + for (i = 0; i < j; i++) + { + char c; + + c = *(char *)((size_t)(Msg->Data) + i); + switch ((int)c) + { + case '\0': fprintf (Out, "\\0"); break; + case '\n': fprintf (Out, "\\r"); break; + case '\t': fprintf (Out, "\\t"); break; + default : fprintf (Out, "%c", c); + } + } + if (i < Msg->Size) fprintf (Out, "..."); + fprintf (Out, "\""); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de messages = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + MSGT_Message * Msg1, * Msg2; + long comp; + + Msg1 = (MSGT_Message *) va_arg(Args, void *); + Msg2 = (MSGT_Message *) va_arg(Args, void *); + + va_end (Args); + + /* On trie les messages : + - par ordre inverse de priorité + - par ordre d'arrivée + */ + + comp = Msg1->Priority - Msg2->Priority; + + if (comp > 0) return NDS_LOWER; + if (comp < 0) return NDS_GREATER; + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Routine d'affichage d'un message d'erreur */ +/*------------------------------------------------------------------------------*/ +void MSG_Error_Print ( void ) +{ + if (MSG_stderr) fprintf (MSG_stderr, "%s\n", MSG_Error_Msg); +} + +/*------------------------------------------------------------------------------*/ +/* Pose d'un verrou en lecture */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_ShareLock_Set (int SemID) +{ + MSGT_Status rc; + rc = MSG_Semaphore_Operate (SemID, MSG_SemOp_SSL, 2); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_ShareLock_Set : unable to operate on semaphore %d", SemID); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Libération d'un verrou en lecture */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_ShareLock_Release (int SemID) +{ + MSGT_Status rc; + rc = MSG_Semaphore_Operate (SemID, MSG_SemOp_RSL, 2); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_ShareLock_Release : unable to operate on semaphore %d", SemID); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Pose d'un verrou en écriture */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_ExclusiveLock_Set (int SemID) +{ + MSGT_Status rc; + rc = MSG_Semaphore_Operate (SemID, MSG_SemOp_SEL, 2); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_ExclusiveLock_Set : unable to operate on semaphore %d", SemID); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Libération d'un verrou en écriture */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_ExclusiveLock_Release (int SemID) +{ + MSGT_Status rc; + rc = MSG_Semaphore_Operate (SemID, MSG_SemOp_REL, 2); + if (rc != MSGS_OK) + { + sprintf (MSG_Error_Msg, "Error MSG_ExclusiveLock_Release : unable to operate on semaphore %d", SemID); + MSG_Error_Print (); + return rc; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Opération sur un sémaphore */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Semaphore_Operate (int SemID, struct sembuf * Operations, unsigned int Nb_Oper) +{ + if (semop (SemID, Operations, Nb_Oper) == -1) + { + switch (errno) + { + case EAGAIN: + sprintf (MSG_Error_Msg, "Error MSG_Semaphore_Operate : the operation would result in suspension of the calling process but the operations have been defined in no wait mode"); + return MSGS_ERRNOWAIT; + + case EINTR: + sprintf (MSG_Error_Msg, "Error MSG_Semaphore_Operate : a signal was received while operating on semaphore %d", SemID); + return MSGS_ERRSIG; + break; + + case EACCES: + sprintf (MSG_Error_Msg, "Error MSG_Semaphore_Operate : current process is not allowed to operate on semaphore %d", SemID); + break; + + case EIDRM: + sprintf (MSG_Error_Msg, "Error MSG_Semaphore_Operate : semaphore %d does not exist", SemID); + break; + + case EINVAL: + sprintf (MSG_Error_Msg, "Error MSG_Semaphore_Operate : the semaphore %d is incorrect or the number of operations which can be done in UNDO mode exceeds the system-imposed limit", SemID); + break; + + case ENOSPC: + sprintf (MSG_Error_Msg, "Error MSG_Semaphore_Operate : the maximum number of process which can operate on semaphore in UNDO mode has been reached"); + break; + + case ERANGE: + sprintf (MSG_Error_Msg, "Error MSG_Semaphore_Operate: the value of semaphore %d has reached the system-imposed limit", SemID); + break; + + default : + sprintf (MSG_Error_Msg, "Error MSG_Semaphore_Operate : unknown error %d while operating on semaphore %d", errno, SemID); + break; + } + + MSG_Error_Print (); + + return MSGS_ERRSEM; + } + + return MSGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Pour préfixer les noms de heap avec le contexte de la librairie LIBMSG */ +/*------------------------------------------------------------------------------*/ +static char * MSG_Name_Prefix (const char * Name) +{ + static char Prefixed [256]; + + sprintf (Prefixed, "%s/%s", MSG_PREFIX, Name); + + return Prefixed; +} + +/*------------------------------------------------------------------------------*/ +/* Pour récupérer l'état de verrouillage d'un port de messages */ +/*------------------------------------------------------------------------------*/ +char * MSG_LockStatus_Get (int SemID) +{ + static char Status [50]; + union semun Sem_Ctl; + int i; + + i = semctl (SemID, 0, GETVAL, Sem_Ctl); + switch (i) + { + case 0: + sprintf (Status, "exclusive lock"); + break; + + case 1: + sprintf (Status, "unlocked"); + break; + + default : + if (i < 0) sprintf (Status, "anormal status (%d)", i); + else sprintf (Status, "share lock (%d process)", i - 1); + break; + } + + return Status; +} + diff --git a/lib/libmsg.doc b/lib/libmsg.doc new file mode 100644 index 0000000000000000000000000000000000000000..d8344d976a7819907e36ce70e207bdc6a0a088f7 GIT binary patch literal 64512 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 Ix0b;F2b#qhTmS$7 literal 0 HcmV?d00001 diff --git a/lib/libmsg.h b/lib/libmsg.h new file mode 100644 index 0000000..4d87c37 --- /dev/null +++ b/lib/libmsg.h @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char * strdup (const char *); + +int MSG_Signal_Received; + +/* Tous les heaps créés via la librairie LIBMSG seront préfixés par le nom suivant */ + +#define MSG_PREFIX "MSG" + +/* Nom du fichier à charger pour accéder aux fonctions manager d'une data structure créée par la LIBMSG */ + +#define MSG_FILE_MANAGER "libmsg.so" + +/* + Heap dans lequel sera stockée la base de la librairie LIBMSG : + Ce heap ne contient que la structure MSGT_Base qui permet de référencer + la liste des ports de messages. + + Ce heap ne sera constitué que d'une unique segment très petit. +*/ + +#define MSG_BASE_HEAP_NAME "BASE" +#define MSG_BASE_HEAP_SEGMENT_SIZE 100 + +/* + Heap dans lequel sera stockée la liste des ports de messages : + Ce heap ne contient que la structure MSGT_Base qui permet de référencer + la liste des ports de messages. + Ce heap n'a pas besoin besoin d'être très grand. +*/ + +#define MSG_PORT_LIST_NAME "PORT_REF" +#define MSG_PORT_LIST_SEGMENT_SIZE 10240 + +/* + Heap sous-jacent à un port de messages : + + Un port de messages est une data structure qui ne contient que sa racine, les + noeuds étant stockés par ailleurs. On peut donc se contenter d'un petit segment. +*/ + +#define MSG_PORT_SEGMENT_SIZE 1024 + +/* + Heap dans lequel seront alloués les messages : + + Ce heap étant amené à grandir rapidemment, il vaut mieux choisir + une taille importante par segment afin de limiter le nombre de segments. +*/ + +#define MSG_MESSAGE_HEAP_NAME "MSG_REF" +#define MSG_MESSAGE_HEAP_SEGMENT_SIZE 1024000 + +/* Utilisation des sémaphores pour l'écoute des ports de messages ou des liste de ports */ + +struct sembuf MSG_SemOp_Listen [2] = { {0, -1, 0}, {0, 1, 0} }; /* Opération d'écoute */ + +struct sembuf MSG_SemOp_Receive [1] = { {0, -1, IPC_NOWAIT} }; /* Opération de retrait de message */ + +struct sembuf MSG_SemOp_Add [1] = { {0, 1, IPC_NOWAIT} }; /* Opération d'ajout de message */ + +/* Utilisation des sémaphores pour verrouiller les ports de messages */ + +struct sembuf MSG_SemOp_SSL [2] = { {0, -1, SEM_UNDO}, {0, 2, SEM_UNDO} }; +struct sembuf MSG_SemOp_RSL [2] = { {0, -2, SEM_UNDO|IPC_NOWAIT}, {0, 1, SEM_UNDO|IPC_NOWAIT} }; +struct sembuf MSG_SemOp_SEL [2] = { {0, -1, SEM_UNDO}, {0, 0, SEM_UNDO} }; +struct sembuf MSG_SemOp_REL [2] = { {0, 0, SEM_UNDO|IPC_NOWAIT}, {0, 1, SEM_UNDO|IPC_NOWAIT} }; + +/* Compteur d'ouverture de la librairie */ + +unsigned int MSG_Open_Counter = 0; + +/* Flux de sortie des messages d'erreur générés par la librairie */ + +FILE * MSG_stderr; + +typedef union semun { + int val; + struct semid_ds * buf; + unsigned short int * array; +} semun; + +NDT_Status MSG_Base_Port_List_Manager (va_list); + +NDT_Status MSG_Semaphore_List_Manager (va_list args_ptr); + +NDT_Status MSG_PortList_Manager (va_list args_ptr); + +NDT_Status MSG_MessageQueue_Manager (va_list); + +MSGT_Status MSG_ShareLock_Set (int); + +MSGT_Status MSG_ShareLock_Release (int); + +MSGT_Status MSG_ExclusiveLock_Set (int); + +MSGT_Status MSG_ExclusiveLock_Release (int); + +MSGT_Status MSG_Semaphore_Operate (int, struct sembuf *, unsigned int); + +void MSG_Error_Print ( void ); + +static char * MSG_Name_Prefix (const char * Name); + +char * MSG_LockStatus_Get (int SemID); diff --git a/lib/msg.h b/lib/msg.h new file mode 100644 index 0000000..322de65 --- /dev/null +++ b/lib/msg.h @@ -0,0 +1,516 @@ +#ifndef _LIBMSG +#define _LIBMSG + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include + +/* Code retour des fonctions constituant l'API */ + +typedef long MSGT_Status; + +#define MSGS_OK DSS_OK /* La fonction s'est correctement exécutée et a produit un résultat */ +#define MSGS_KO DSS_KO /* La fonction s'est correctement exécutée mais n'a pas produit de résultat */ +#define MSGS_YES MSGS_OK /* Résultat booléen positif */ +#define MSGS_NO MSGS_KO /* Résultat booléen négatif */ + +#define MSGS_ERRMEM DSS_ERRMEM /* Problème d'allocation mémoire */ +#define MSGS_ERRAPI DSS_ERRAPI /* Utilisation incorrecte des API */ +#define MSGS_ERRSHM DSS_ERRSHM /* Problème relatif aux segments de mémoire partagée */ +#define MSGS_ERRSEM DSS_ERRSEM /* Problème relatif à l'utilisation des sémaphores */ +#define MSGS_ERRSIG DSS_ERRSIG /* Opération sur sémaphore interrompue par un signal */ +#define MSGS_ERRDLL DSS_ERRDLL /* Problème de chargement dynamique de librairie */ +#define MSGS_ERRNOWAIT -7 /* Opération sur sémaphore impossible et le mode d'opération est sans attente */ + +#define MSG_ERROR(s) ((s) < 0) /* Tous les codes retour négatifs correspondent à des erreurs */ + +/* Codes retour spécifiques pour la réception de messages */ + +#define MSGS_NO_MSG 5 +#define MSGS_BAD_TYPE 6 + +/* Indicateurs */ + +typedef int MSGT_Flags; + +/* Flags de debug sur l'ouverture de la librairie */ + +#define MSGD_DEBUG_NONE SMD_DEBUG_NONE /* pour n'afficher aucun message généré par les diverses librairies */ +#define MSGD_DEBUG SMD_DEBUG /* pour afficher les messages générés par la librairie */ +#define MSGD_DEBUG_ALL SMD_DEBUG_ALL /* pour afficher les messages générés par toutes les librairies sous-jacentes */ + +#define MSGD_DEBUG_MSK (MSGD_DEBUG & MSGD_DEBUG_ALL) + +/* Flags d'ouverture et de fermeture des différentes ressources de la librairie */ + +#define MSGD_OPEN SMD_OPEN +#define MSGD_CREATE SMD_CREATE + +#define MSGD_MSK_OPEN(a) (MSGD_OPEN & (a)) +#define MSGD_MSK_CREATE(a) (MSGD_CREATE & (a)) + +#define MSGD_CLOSE SMD_CLOSE +#define MSGD_DESTROY SMD_DESTROY + +/* Flags de réception de message */ + +#define MSGD_NO_WAIT 1 /* Réception sans attente si aucun message */ +#define MSGD_WAIT 2 /* Réception avec attente */ + +/* Flags de verrouillage d'un port de messages */ + +#define MSGD_READ 1 /* verrou partagé */ +#define MSGD_WRITE 2 /* verrou exclusif */ + +#define MSGD_MSK_READ(a) (MSGD_READ & (a)) +#define MSGD_MSK_WRITE(a) (MSGD_WRITE & (a)) + +#define MSGD_UNLIMITED 0 + +/* Notion de port de messages */ + +typedef struct { + char Name [50]; /* Nom du port de messages */ + size_t Size; /* Taille limite du port en nombre de messages */ + int ListenSemID; /* sémaphore permettant l'écoute du port */ + int LockSemID; /* sémaphore permettant le verrouillage du port */ + NDT_Root * SemList; /* Liste des sémaphores des listes de ports qui sont à l'écoute du port */ + NDT_Root * MsgQueue; /* File d'attente des messages */ +} MSGT_Port; + +/* Quelques ports de message prédéfinis */ + +#define MSGD_DEFAULT_PORT_NAME "DEFAULT_PORT" +#define MSGD_SYSTEM_PORT_NAME "SYSTEM_PORT" +#define MSGD_SUPERVISOR_PORT_NAME "SUPERVISOR_PORT" + +/* Notion de liste de ports de messages */ + +typedef struct { + NDT_Root * Root; /* Liste de ports de messages */ + int ListenSemID; /* Identifiant du sémaphore pour l'écoute de la liste de ports */ +} MSGT_PortList; + +/* Notion de messages */ + +typedef struct { + char From [50]; /* Nom du port d'écoute de l'initiateur du message */ + char Via [50]; /* Nom du port d'écoute du dernier envoyeur du message */ + char To [50]; /* Nom du port du dernier envoi du message */ + unsigned int Type; /* Type du message */ + int Priority; /* Priorité du message */ + size_t Size; /* Taille des données du message */ + void * Data; /* Données du message */ + char * Swap; /* Nom du fichier de swap dans lequel est stocké le message */ +} MSGT_Message; + +#define MSGD_NO_TYPE 0 + +/* + Types de message : + + Les types de message vont de 1 à 255 et sont partagés en 2 plages : + + - messages systèmes prédéfinis de 1 à 32 + - messages utilisateur de 33 à 255 +*/ + +#define MSGD_NO_TYPE 0 + +#define MSGD_NB_SYSTEM_MESSAGE 32 + +#define MSGD_IS_SYSTEM(t) ((t) != MSGD_NO_TYPE && (t) < MSGD_NB_SYSTEM_MESSAGE) +#define MSGD_IS_SYSTEM_REQUEST(t) ((t) != MSGD_NO_TYPE && (t) < MSGD_NB_SYSTEM_MESSAGE && (t) % 2 == 1) +#define MSGD_IS_SYSTEM_REPLY(t) ((t) != MSGD_NO_TYPE && (t) < MSGD_NB_SYSTEM_MESSAGE && (t) % 2 == 0) + +#define MSGD_SYSTEM_PING_REQUEST 1 +#define MSGD_SYSTEM_PING_REPLY 2 +#define MSGD_SYSTEM_STOP_REQUEST 3 +#define MSGD_SYSTEM_STOP_REPLY 4 +#define MSGD_SYSTEM_CONTINUE_REQUEST 5 +#define MSGD_SYSTEM_CONT_REPLY 6 +#define MSGD_SYSTEM_RESTART_REQUEST 7 +#define MSGD_SYSTEM_RESTART_REPLY 8 +#define MSGD_SYSTEM_SHUTDOWN_REQUEST 9 +#define MSGD_SYSTEM_SHUTDOWN_REPLY 10 +#define MSGD_SYSTEM_STATUS_REQUEST 11 +#define MSGD_SYSTEM_STATUS_REPLY 12 +#define MSGD_SYSTEM_INFO_REQUEST 13 +#define MSGD_SYSTEM_INFO_REPLY 14 +#define MSGD_SYSTEM_TRACEON_REQUEST 15 +#define MSGD_SYSTEM_TRACEON_REPLY 16 +#define MSGD_SYSTEM_TRACEOFF_REQUEST 17 +#define MSGD_SYSTEM_TRACEOFF_REPLY 18 + +/* Type de message système générique (utile pour ne réceptionner que les messages système) */ + +#define MSGD_SYSTEM_GENERIC MSGD_NB_SYSTEM_MESSAGE + +/* Quelques types de messages utilisateur prédéfinis */ + +#define MSGD_USER_TYPE1 MSGD_NB_SYSTEM_MESSAGE + 1 +#define MSGD_USER_TYPE2 MSGD_NB_SYSTEM_MESSAGE + 2 + +#define MSGD_DEFAULT_TYPE MSGD_USER_TYPE1 + +/* + Priorités des messages : + + Les priorités vont de -128 (la plus elevée) à 127 (plus basse) divisées en 2 plages : + + - Priorités des messages système : [-128, -65] U [+65, +127] + - Priorités des messages utilisateur : [-64, +64] +*/ + +#define MSGD_SYSTEM_HIGH_PRIORITY -128 +#define MSGD_SYSTEM_LOW_PRIORITY 127 + +#define MSGD_USER_HIGH_PRIORITY -64 +#define MSGD_USER_NORMAL_PRIORITY 0 +#define MSGD_USER_LOW_PRIORITY 64 + +#define MSGD_DEFAULT_PRIORITY MSGD_USER_NORMAL_PRIORITY + +/* Types de configuration */ + +typedef int MSGT_Config; + +#define MSGD_CONFIG_SIZE 1 /* Configuration de la taille d'un port de messages */ +#define MSGD_CONFIG_MSGQUEUE 2 /* Choix du type de structure pour la queue de message d'un port de messages */ + +#define MSGD_CONFIG_TYPE 3 /* Configuration du type d'un message */ +#define MSGD_CONFIG_PRIORITY 4 /* Configuration de la priorité d'un message */ + +char MSG_Error_Msg [512]; + +/* Base de la librairie LIBMSG */ + +SMT_Heap * MSG_Base_Heap; +SMT_Heap * MSG_Message_Heap; + +typedef struct { + NDT_Root * Port_List; /* Liste de tous les ports de messages */ +} MSGT_Base; + +MSGT_Base * MSG_Base; + +/* Contenu d'un message de type PING_REPLY */ + +typedef struct { + struct timeval Snd1; + struct timeval Rcv1; + struct timeval Snd2; + struct timeval Rcv2; +} MSGT_PingData; + +/* Définition des alias de l'API */ + +#ifndef MSG_MODE +#define MSG_MODE 0 +#endif + +#if MSG_MODE == 1 + +/* Utilisation des API sans vérification des arguments */ + +# define MSG_Library_Open MSG_Library_Open_I +# define MSG_Library_Signal MSG_Library_Signal_I +# define MSG_Library_IsOpen MSG_Library_IsOpen_I +# define MSG_Library_Context_Set MSG_Library_Context_Set_I +# define MSG_Library_Context_Get MSG_Library_Context_Get_I +# define MSG_Library_Close MSG_Library_Close_I +# define MSG_Library_Stderr_Set MSG_Library_Stderr_Set_I +# define MSG_Library_Dump MSG_Library_Dump_I +# define MSG_Port_Exist MSG_Port_Exist_I +# define MSG_Port_Open MSG_Port_Open_I +# define MSG_Port_Config MSG_Port_Config_I +# define MSG_Port_Lock MSG_Port_Lock_I +# define MSG_Port_Unlock MSG_Port_Unlock_I +# define MSG_Port_Close MSG_Port_Close_I +# define MSG_PortList_Open MSG_PortList_Open_I +# define MSG_PortList_Port_Add MSG_PortList_Port_Add_I +# define MSG_PortList_Port_Remove MSG_PortList_Port_Remove_I +# define MSG_PortList_Close MSG_PortList_Close_I +# define MSG_PortList_Listen MSG_PortList_Listen_I +# define MSG_Message_Alloc MSG_Message_Alloc_I +# define MSG_Message_Config MSG_Message_Config_I +# define MSG_Message_Free MSG_Message_Free_I +# define MSG_Message_Send MSG_Message_Send_I +# define MSG_Message_Receive MSG_Message_Receive_I +# define MSG_Message_Reply MSG_Message_Reply_I +# define MSG_Message_Return MSG_Message_Return_I + +#else + +/* Utilisation avec vérification des arguments */ + +# define MSG_Library_Open MSG_Library_Open_C +# define MSG_Library_IsOpen MSG_Library_IsOpen_C +# define MSG_Library_Signal MSG_Library_Signal_C +# define MSG_Library_Context_Set MSG_Library_Context_Set_C +# define MSG_Library_Context_Get MSG_Library_Context_Get_C +# define MSG_Library_Close MSG_Library_Close_C +# define MSG_Library_Stderr_Set MSG_Library_Stderr_Set_C +# define MSG_Library_Dump MSG_Library_Dump_C +# define MSG_Port_Exist MSG_Port_Exist_C +# define MSG_Port_Open MSG_Port_Open_C +# define MSG_Port_Config MSG_Port_Config_C +# define MSG_Port_Lock MSG_Port_Lock_C +# define MSG_Port_Unlock MSG_Port_Unlock_C +# define MSG_Port_Close MSG_Port_Close_C +# define MSG_PortList_Open MSG_PortList_Open_C +# define MSG_PortList_Port_Add MSG_PortList_Port_Add_C +# define MSG_PortList_Port_Remove MSG_PortList_Port_Remove_C +# define MSG_PortList_Close MSG_PortList_Close_C +# define MSG_PortList_Listen MSG_PortList_Listen_C +# define MSG_Message_Alloc MSG_Message_Alloc_C +# define MSG_Message_Config MSG_Message_Config_C +# define MSG_Message_Free MSG_Message_Free_C +# define MSG_Message_Send MSG_Message_Send_C +# define MSG_Message_Receive MSG_Message_Receive_C +# define MSG_Message_Reply MSG_Message_Reply_C +# define MSG_Message_Return MSG_Message_Return_C + +#endif + +/*------------------------------------------------------------------------------*/ +/* Permet d'indiquer à la librairie qu'un signal a été reçu. */ +/* */ +/* NB : cette fonction sera appelée par l'utilisateur pour éviter que le */ +/* processus se bloque sur une attente de message malgré la réception de signal */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Signal_I ( void ); +MSGT_Status MSG_Library_Signal_C ( void ); + +/*------------------------------------------------------------------------------*/ +/* Ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Instance : numéro de l'instance de la librairie */ +/* (I) Context : contexte d'utilisation de la librairie */ +/* (I) Open_Mode : mode d'ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Open_I ( int Instance, const char * Context, MSGT_Flags Open_Mode ); +MSGT_Status MSG_Library_Open_C ( int Instance, const char * Context, MSGT_Flags Open_Mode ); + +/*------------------------------------------------------------------------------*/ +/* Teste si la librairie a été ouverte */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_IsOpen_I ( void ); +MSGT_Status MSG_Library_IsOpen_C ( void ); + +/*------------------------------------------------------------------------------*/ +/* Changement de contexte d'utilisation de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Context : nom du nouveau contexte */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Context_Set_I (const char * Context); +MSGT_Status MSG_Library_Context_Set_C (const char * Context); + +/*------------------------------------------------------------------------------*/ +/* Récupération du nom du contexte utilisée */ +/*------------------------------------------------------------------------------*/ +/* (O) Context : adresse du nom du contexte utilisé */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Context_Get_I (char ** Context); +MSGT_Status MSG_Library_Context_Get_C (char ** Context); + +/*------------------------------------------------------------------------------*/ +/* Fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Close_Mode : mode de fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Close_I ( MSGT_Flags Close_Mode ); +MSGT_Status MSG_Library_Close_C ( MSGT_Flags Close_Mode ); + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Stderr_Set_I ( FILE * Out ); +MSGT_Status MSG_Library_Stderr_Set_C ( FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Affichage des ressources de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : Flux de sortie de l'affichage */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Library_Dump_I ( FILE * Out ); +MSGT_Status MSG_Library_Dump_C ( FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Teste l'existence d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Name : nom du port de messages */ +/* (O) Port : adresse d'un pointeur sur le port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Exist_I ( const char *, MSGT_Port ** ); +MSGT_Status MSG_Port_Exist_C ( const char *, MSGT_Port ** ); + +/*------------------------------------------------------------------------------*/ +/* Création/ouverture d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Name : nom du port de messages */ +/* (O) Port : adresse d'un pointeur sur le port de messages */ +/* (I) Open_Mode : mode d'ouverture du port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Open_I ( const char * Name, MSGT_Port ** Port, MSGT_Flags Open_Mode ); +MSGT_Status MSG_Port_Open_C ( const char * Name, MSGT_Port ** Port, MSGT_Flags Open_Mode ); + +/*------------------------------------------------------------------------------*/ +/* Configuration d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Tag : type de configuration */ +/* (I) ... : données de configuration */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Config_I ( MSGT_Port * Port, MSGT_Config Tag, ... ); +MSGT_Status MSG_Port_Config_C ( MSGT_Port * Port, MSGT_Config Tag, ... ); + +/*------------------------------------------------------------------------------*/ +/* Verrouillage d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Mode : type de verrouillage */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Lock_I ( MSGT_Port * Port, MSGT_Flags Mode ); +MSGT_Status MSG_Port_Lock_C ( MSGT_Port * Port, MSGT_Flags Mode ); + +/*------------------------------------------------------------------------------*/ +/* Déverrouillage d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Mode : type de verrou à enlever */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Unlock_I ( MSGT_Port * Port, MSGT_Flags Mode ); +MSGT_Status MSG_Port_Unlock_C ( MSGT_Port * Port, MSGT_Flags Mode ); + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Close_Mode : mode de fermeture du port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Port_Close_I ( MSGT_Port * Port, MSGT_Flags Close_Mode ); +MSGT_Status MSG_Port_Close_C ( MSGT_Port * Port, MSGT_Flags Close_Mode ); + +/*------------------------------------------------------------------------------*/ +/* Création/ouverture d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +/* (O) PortList : adresse d'un pointeur sur la liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Open_I ( MSGT_PortList ** PortList ); +MSGT_Status MSG_PortList_Open_C ( MSGT_PortList ** PortList ); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un port de messages à une liste de ports */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur la liste de ports de messages */ +/* (I) Port : pointeur sur un port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Port_Add_I ( MSGT_PortList * PortList, MSGT_Port * Port ); +MSGT_Status MSG_PortList_Port_Add_C ( MSGT_PortList * PortList, MSGT_Port * Port ); + +/*------------------------------------------------------------------------------*/ +/* Retrait d'un port de messages d'une liste de ports */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur la liste de ports de messages */ +/* (I) Port : pointeur sur un port de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Port_Remove_I ( MSGT_PortList * PortList, MSGT_Port * Port ); +MSGT_Status MSG_PortList_Port_Remove_C ( MSGT_PortList * PortList, MSGT_Port * Port ); + +/*------------------------------------------------------------------------------*/ +/* Suppressin d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur la liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Close_I ( MSGT_PortList * PortList ); +MSGT_Status MSG_PortList_Close_C ( MSGT_PortList * PortList ); + +/*------------------------------------------------------------------------------*/ +/* Ecoute d'une liste de ports de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) PortList : pointeur sur une liste de ports de messages */ +/* (I) Type : type du message à récupérer */ +/* (O) Msg : adresse d'un pointeur sur le message à recevoir */ +/* (I) Flags : paramètres de réception */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_PortList_Listen_I ( MSGT_PortList * PortList, unsigned int Type, MSGT_Message ** Msg, MSGT_Flags Flags); +MSGT_Status MSG_PortList_Listen_C ( MSGT_PortList * PortList, unsigned int Type, MSGT_Message ** Msg, MSGT_Flags Flags); + +/*------------------------------------------------------------------------------*/ +/* Création d'un message */ +/*------------------------------------------------------------------------------*/ +/* (O) Msg : adresse d'un pointeur sur le message */ +/* (I) Size : taille en octets des données du message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Alloc_I ( MSGT_Message ** Msg, size_t Size ); +MSGT_Status MSG_Message_Alloc_C ( MSGT_Message ** Msg, size_t Size ); + +/*------------------------------------------------------------------------------*/ +/* Configuration d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur un message */ +/* (I) Tag : type de configuration */ +/* (I) ... : données de configuration */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Config_I ( MSGT_Message * Msg, MSGT_Config Tag, ... ); +MSGT_Status MSG_Message_Config_C ( MSGT_Message * Msg, MSGT_Config Tag, ... ); + +/*------------------------------------------------------------------------------*/ +/* Destruction d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Free_I ( MSGT_Message * Msg ); +MSGT_Status MSG_Message_Free_C ( MSGT_Message * Msg ); + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un message dans un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) From : nom du port de messages de l'envoyeur */ +/* (I) To : pointeur sur le port de messages destinataire */ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Send_I ( const char * From, MSGT_Port * To, MSGT_Message * Msg ); +MSGT_Status MSG_Message_Send_C ( const char * From, MSGT_Port * To, MSGT_Message * Msg ); + +/*------------------------------------------------------------------------------*/ +/* Réception d'un message dans un port de messages */ +/*------------------------------------------------------------------------------*/ +/* (I) Port : pointeur sur le port de messages */ +/* (I) Type : type du message à récupérer */ +/* (O) Msg : adresse d'un pointeur sur le message à recevoir */ +/* (I) Flags : paramètres de réception */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Receive_I ( MSGT_Port * Port, unsigned int Type, MSGT_Message ** Msg, MSGT_Flags Flags ); +MSGT_Status MSG_Message_Receive_C ( MSGT_Port * Port, unsigned int Type, MSGT_Message ** Msg, MSGT_Flags Flags ); + +/*------------------------------------------------------------------------------*/ +/* Retour à l'envoyeur d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Reply_I ( MSGT_Message * Msg ); +MSGT_Status MSG_Message_Reply_C ( MSGT_Message * Msg ); + +/*------------------------------------------------------------------------------*/ +/* Retour à l'initiateur d'un message */ +/*------------------------------------------------------------------------------*/ +/* (I) Msg : pointeur sur le message */ +/*------------------------------------------------------------------------------*/ +MSGT_Status MSG_Message_Return_I ( MSGT_Message * Msg ); +MSGT_Status MSG_Message_Return_C ( MSGT_Message * Msg ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/util/msgadmin.c b/util/msgadmin.c new file mode 100644 index 0000000..17216cf --- /dev/null +++ b/util/msgadmin.c @@ -0,0 +1,235 @@ +#define DATASTR_MODE 1 /* Pas de vérif des arguments + verrou sytématique */ +#define MSG_MODE 1 /* Pas de vérif des arguments */ + +#include +#include +#include +#include +#include +#include +#include +#include + +VER_INFO_EXPORT (msgadmin, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $") + +#define USAGE "Usage : %s [ --help | --version [-v] | --create | --destroy ]\n" + +#define QUIT 0 +#define BASE_INIT 1 +#define BASE_OPEN 2 +#define BASE_INFO 3 +#define BASE_CLOSE 4 +#define BASE_END 5 +#define SHOW_PORT_LIST 6 +#define PORT_CREATE 7 +#define PORT_DUMP 8 +#define PORT_FLUSH 9 +#define PORT_DELETE 10 + +char menu [1000]; +char tmp [100]; + +void init_menu (void); +int print_menu (void); + +int main (int argc, char ** argv) +{ + int choice; + MSGT_Port * Port; + MSGT_Message * Msg; + char Answer[10]; + + /* Lancement de commande d'administration */ + + if (argc >= 2) + { + if (!strcmp (argv[1], "--help")) + { + fprintf (stderr, USAGE, argv[0]); + return -1; + } + else if (!strcmp (argv[1], "--version")) + { + if (argc >= 3 && !strcmp (argv[2], "-v")) return VER_Object_Print (stdout, VERD_VERBOSE); + else return VER_Object_Print (stdout, VERD_MINIMAL); + } + else if (!strcmp (argv[1], "--create")) + { + if (MSG_Library_Open (0, NULL, MSGD_CREATE | MSGD_DEBUG_ALL) != MSGS_OK) + { + fprintf (stderr, "=> Impossible de créer l'instance de la librairie LIBMSG\n"); + return -1; + } + + return 1; + } + else if (!strcmp (argv[1], "--destroy")) + { + if (MSG_Library_Open (0, NULL, MSGD_OPEN | MSGD_DEBUG_ALL) != MSGS_OK || MSG_Library_Close (MSGD_DESTROY) != MSGS_OK) + { + fprintf (stderr, "=> Impossible de détruire l'instance de la librairie LIBMSG\n"); + return -1; + } + return 0; + } + else + { + fprintf (stderr, USAGE, argv[0]); + return -1; + } + } + + /* Lancement du menu intercatif */ + + init_menu (); + + choice = print_menu (); + + while (choice != QUIT) + { + strcpy (Answer, "yes"); + + switch (choice) + { + case BASE_INIT: + fprintf (stdout, "\nReturn code = %s\n", \ + MSG_Library_Open (0, NULL, MSGD_CREATE | MSGD_DEBUG_ALL) == MSGS_OK ? "OK" : "NOK" ); + break; + + case BASE_OPEN: + fprintf (stdout, "\nReturn code = %s\n", \ + MSG_Library_Open (0, NULL, MSGD_OPEN | MSGD_DEBUG_ALL) == MSGS_OK ? "OK" : "NOK" ); + break; + + case BASE_END: + fprintf (stdout, "\nReturn code = %s\n", \ + MSG_Library_Close (MSGD_DESTROY) == MSGS_OK ? "OK" : "NOK" ); + break; + + case BASE_CLOSE: + fprintf (stdout, "\nReturn code = %s\n", \ + MSG_Library_Close (MSGD_CLOSE) == MSGS_OK ? "OK" : "NOK" ); + break; + + case BASE_INFO: + if (!MSG_Base) + fprintf (stdout, "\nLIBMSG base must be opened first\n"); + else + DS_DataStruct_Info_Print (MSG_Base->Port_List, stdout); + break; + + case SHOW_PORT_LIST: + if (!MSG_Base) fprintf (stdout, "\nLIBMSG base must be opened first\n"); + else DS_DataStruct_Print (MSG_Base->Port_List, stdout); + break; + + case PORT_CREATE: + if (!MSG_Base) fprintf (stdout, "\nLIBMSG base must be opened first\n"); + else + { + fprintf (stdout, "\nPort name ? "); + gets (tmp); + + if (MSG_Port_Open (tmp, &Port, MSGD_CREATE) != MSGS_OK) + fprintf (stdout, "Unable to create port \"%s\"\n", tmp); + } + break; + + case PORT_DUMP: + if (!MSG_Base) fprintf (stdout, "\nLIBMSG base must be opened first\n"); + else + { + fprintf (stdout, "\nPort name ? "); + gets (tmp); + + if (MSG_Port_Open (tmp, &Port, MSGD_OPEN) != MSGS_OK) + fprintf (stdout, "Unable to open port \"%s\"\n", tmp); + else + { + ND_Manager_Exec (MSG_Base->Port_List->Manager, NDD_CMD_PRINT_VALUE, Port, stdout); + + if (fprintf (stdout, "\n\nShow message queue ? (y/n) ") && gets (tmp) && *tmp == 'y') + DS_DataStruct_Print (Port->MsgQueue, stdout); + + if (fprintf (stdout, "\nShow semaphore list ? (y/n) ") && gets (tmp) && *tmp == 'y') + DS_DataStruct_Print (Port->SemList, stdout); + } + } + break; + + case PORT_FLUSH: + if (!MSG_Base) fprintf (stdout, "\nLIBMSG base must be opened first\n"); + else + { + fprintf (stdout, "\nPort name ? "); + gets (tmp); + + if (MSG_Port_Open (tmp, &Port, MSGD_OPEN) != MSGS_OK) + fprintf (stdout, "Unable to open port \"%s\"\n", tmp); + + /* Retrait de tous les messages du port */ + + while (MSG_Message_Receive (Port, MSGD_NO_TYPE, &Msg, MSGD_NO_WAIT) == MSGS_OK) + MSG_Message_Free (Msg); + + } + break; + + case PORT_DELETE: + if (!MSG_Base) fprintf (stdout, "\nLIBMSG base must be opened first\n"); + else + { + fprintf (stdout, "\nPort name ? "); + gets (tmp); + + if (MSG_Port_Exist (tmp, &Port) != MSGS_OK) + { + fprintf (stdout, "Port \"%s\" does not exist\n", tmp); + break; + } + + if (MSG_Port_Close (Port, MSGD_DESTROY) != MSGS_OK) + fprintf (stdout, "Unable to delete port \"%s\"\n", tmp); + } + break; + + case QUIT: + fprintf (stdout, "\nExiting program ...\n"); + break; + + default: + fprintf (stdout, "\nUndefined choice %d\n", choice); + } + choice = print_menu (); + } + return 0; +} + +void init_menu (void) +{ + sprintf (menu, "Menu :\n"); + sprintf (tmp, " - %2d) %-25s", QUIT, "Quit"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", BASE_INIT, "Init library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s", BASE_OPEN, "Open library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", BASE_INFO, "Info library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s", BASE_CLOSE, "Close library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", BASE_END, "End library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s", SHOW_PORT_LIST, "Show message ports"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", PORT_CREATE, "Create a message port"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s", PORT_DUMP, "Dump a message port"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", PORT_FLUSH, "Flush all message from a port"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", PORT_DELETE, "Delete a message port"); strcat (menu, tmp); +} + +int print_menu (void) +{ + fprintf (stdout, "---------------------------------------------------------------------------\n%s", menu); + + tmp[0] = '\0'; + while (tmp[0] == '\0') + { + printf ("\nChoice ? "); + gets (tmp); + } + return atoi (tmp); +} diff --git a/util/msgbench.xls b/util/msgbench.xls new file mode 100644 index 0000000000000000000000000000000000000000..7267d417f0818568b386285d0fc711c3f2d8116d GIT binary patch literal 18432 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 literal 0 HcmV?d00001 diff --git a/util/pingpong.result.cc b/util/pingpong.result.cc new file mode 100644 index 0000000..46e120e --- /dev/null +++ b/util/pingpong.result.cc @@ -0,0 +1,40 @@ +-------------- TEST LIBMSG ----------------- +Testing LIBMSG for 10 second(s) with 1 message(s) of 10 byte(s)... +20450 message(s) exchanged (2045 msg/sec) +Testing LIBMSG for 10 second(s) with 1 message(s) of 1000 byte(s)... +20244 message(s) exchanged (2024 msg/sec) +Testing LIBMSG for 10 second(s) with 1 message(s) of 2048 byte(s)... +19520 message(s) exchanged (1952 msg/sec) +--------- +Testing LIBMSG for 10 second(s) with 10 message(s) of 10 byte(s)... +30752 message(s) exchanged (3075 msg/sec) +Testing LIBMSG for 10 second(s) with 10 message(s) of 1000 byte(s)... +30220 message(s) exchanged (3022 msg/sec) +Testing LIBMSG for 10 second(s) with 10 message(s) of 2048 byte(s)... +28590 message(s) exchanged (2859 msg/sec) +--------- +Testing LIBMSG for 10 second(s) with 100 message(s) of 10 byte(s)... +27008 message(s) exchanged (2700 msg/sec) +Testing LIBMSG for 10 second(s) with 100 message(s) of 1000 byte(s)... +24970 message(s) exchanged (2497 msg/sec) +Testing LIBMSG for 10 second(s) with 100 message(s) of 2048 byte(s)... +21838 message(s) exchanged (2183 msg/sec) +-------------- TEST IPC ----------------- +Testing IPC message queue for 10 second (s) with 1 message (s) of 10 byte (s)... +169485 message (s) exchanged (16948 Msg/sec) +Testing IPC message queue for 10 second (s) with 1 message (s) of 1000 byte (s)... +102630 message (s) exchanged (10263 Msg/sec) +Testing IPC message queue for 10 second (s) with 1 message (s) of 2048 byte (s)... +102040 message (s) exchanged (10204 Msg/sec) +--------- +Testing IPC message queue for 10 second (s) with 10 message (s) of 10 byte (s)... +300810 message (s) exchanged (30081 Msg/sec) +Testing IPC message queue for 10 second (s) with 10 message (s) of 1000 byte (s)... +159352 message (s) exchanged (15935 Msg/sec) +Testing IPC message queue for 10 second (s) with 10 message (s) of 2048 byte (s)... +127773 message (s) exchanged (12777 Msg/sec) +--------- +Testing IPC message queue for 10 second (s) with 100 message (s) of 1000 byte (s)... +175376 message (s) exchanged (17537 Msg/sec) +Testing IPC message queue for 10 second (s) with 100 message (s) of 2048 byte (s)... +121655 message (s) exchanged (12165 Msg/sec) diff --git a/util/pingpong.result.gcc b/util/pingpong.result.gcc new file mode 100644 index 0000000..f16b5cc --- /dev/null +++ b/util/pingpong.result.gcc @@ -0,0 +1,40 @@ +-------------- TEST LIBMSG ----------------- +Testing LIBMSG for 10 second(s) with 1 message(s) of 10 byte(s)... +30364 message(s) exchanged (3036 msg/sec) +Testing LIBMSG for 10 second(s) with 1 message(s) of 1000 byte(s)... +29490 message(s) exchanged (2949 msg/sec) +Testing LIBMSG for 10 second(s) with 1 message(s) of 2048 byte(s)... +32788 message(s) exchanged (3278 msg/sec) +--------- +Testing LIBMSG for 10 second(s) with 10 message(s) of 10 byte(s)... +32203 message(s) exchanged (3220 msg/sec) +Testing LIBMSG for 10 second(s) with 10 message(s) of 1000 byte(s)... +36712 message(s) exchanged (3671 msg/sec) +Testing LIBMSG for 10 second(s) with 10 message(s) of 2048 byte(s)... +34887 message(s) exchanged (3488 msg/sec) +--------- +Testing LIBMSG for 10 second(s) with 100 message(s) of 10 byte(s)... +24382 message(s) exchanged (2438 msg/sec) +Testing LIBMSG for 10 second(s) with 100 message(s) of 1000 byte(s)... +24552 message(s) exchanged (2455 msg/sec) +Testing LIBMSG for 10 second(s) with 100 message(s) of 2048 byte(s)... +25862 message(s) exchanged (2586 msg/sec) +-------------- TEST IPC ----------------- +Testing IPC message queue for 10 second (s) with 1 message (s) of 10 byte (s)... +162587 message (s) exchanged (16258 Msg/sec) +Testing IPC message queue for 10 second (s) with 1 message (s) of 1000 byte (s)... +106886 message (s) exchanged (10688 Msg/sec) +Testing IPC message queue for 10 second (s) with 1 message (s) of 2048 byte (s)... +88864 message (s) exchanged (8886 Msg/sec) +--------- +Testing IPC message queue for 10 second (s) with 10 message (s) of 10 byte (s)... +267204 message (s) exchanged (26720 Msg/sec) +Testing IPC message queue for 10 second (s) with 10 message (s) of 1000 byte (s)... +167169 message (s) exchanged (16716 Msg/sec) +Testing IPC message queue for 10 second (s) with 10 message (s) of 2048 byte (s)... +121365 message (s) exchanged (12136 Msg/sec) +--------- +Testing IPC message queue for 10 second (s) with 100 message (s) of 1000 byte (s)... +165790 message (s) exchanged (16579 Msg/sec) +Testing IPC message queue for 10 second (s) with 100 message (s) of 2048 byte (s)... +122897 message (s) exchanged (12289 Msg/sec) diff --git a/util/pingpong_ipc.c b/util/pingpong_ipc.c new file mode 100644 index 0000000..177a6a7 --- /dev/null +++ b/util/pingpong_ipc.c @@ -0,0 +1,579 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_TIMER 60 /* Durée par défaut du test (en secondes) */ +#define DEFAULT_WINSIZE 100 /* Taille par défaut de la fenêtre de messages */ +#define DEFAULT_MSGSIZE 100 /* Taille par défaut de chaque message */ + +#define FATHER_KEY 64 /* Clé du port de messages du père */ +#define CHILD_KEY 65 /* Clé du port de messages du fils */ + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +/*----------------------------------------------------------------*/ + +typedef struct { + long mtype; + char * mtext; +} T_Msg; + +int My_Port, Its_Port; +int Child_Pid, Father_Pid, Its_Pid, My_Pid; +int Verbose; +unsigned int Timer; +unsigned int Win_Size; +unsigned int Msg_Size; +int Cpt_Msg; +T_Msg ** Msg_Window; +int End_Test, End_Sigum; + +char * error_code (void); +void stop_test (int); +void stop_father (void); +void stop_child (void); +void clean (int); +void trace (char *); +void print_result (void); +void parse_arg (int, char **); +extern char * strdup (const char *); + +/*----------------------------------------------------------------*/ +int main (int argc, char ** argv) +{ + unsigned int i, size; + char str [256]; + T_Msg * Msg; + + /* Récupération des arguments de la ligne de commande */ + + parse_arg (argc, argv); + + /* Récupération du no de process courant */ + + Father_Pid = getpid (); + + /* Création d'un process fils avec qui dialoguer */ + + if ((Child_Pid = fork ()) != 0) + { + /*--------- Code pour le process père -----------*/ + + Its_Pid = Child_Pid; + My_Pid = Father_Pid; + + My_Port = 0; + + signal (SIGINT, stop_test); + signal (SIGUSR1, stop_test); + + /* Création d'un port de messages */ + + if ((My_Port = msgget (FATHER_KEY, 0777|IPC_CREAT|IPC_EXCL)) == -1) + { + fprintf (stderr, "Unable to create message queue for the father process : error %d (%s)\n", errno, error_code ()); + clean (TRUE); + + return 0; + } + else + { + sprintf (str, "Message port %d created", My_Port); + trace (str); + } + + /* On attend que le fils ait créé son port de messages */ + + sleep (2); + + /* Initialisation de la fenêtre de messages */ + + Msg_Window = (T_Msg **)malloc (Win_Size); + + for (i = 0; i < Win_Size; i++) + { + Msg_Window[i] = (T_Msg *)malloc (sizeof (T_Msg)); + Msg_Window[i]->mtype = 1; + Msg_Window[i]->mtext = (char *)malloc (Msg_Size); + Msg_Window[i]->mtext[0] = (char)i; + } + + /* Récupération de la port de messages du fils */ + + if ((Its_Port = msgget (CHILD_KEY, 0)) == -1) + { + fprintf (stderr, "Unable to retrieve the message queue of the child process : error %d (%s)\n", errno, error_code ()); + clean (TRUE); + + return 0; + } + + Msg = malloc (sizeof (T_Msg)); + Msg->mtext = (char *)malloc (Msg_Size); + + /* Initialisation du Timer */ + + signal (SIGALRM, stop_test); + + alarm (Timer); + + /* Début du test : traitement des messages */ + + fprintf (stdout, "Testing IPC message queue for %d second (s) with %d message (s) of %d byte (s)...\n", Timer, Win_Size, Msg_Size); + + /* Envoi de tous les messages de la fenêtre au fils */ + + for (i = 0; i < Win_Size; i++) + { + errno = 0; + + if (msgsnd (Its_Port, Msg_Window[i], Msg_Size, IPC_NOWAIT) == 0) + { + if (Verbose) + { + sprintf (str, "Message %d sent to port %d", i, Its_Port); + trace (str); + } + } + + if (errno != 0 && errno != EAGAIN) + fprintf (stderr, "Unable to send message %d to port %d : error %d (%s)\n", i, Its_Port, errno, error_code ()); + } + + Cpt_Msg = 0; + + while (End_Test == FALSE) + { + /* Réception de messages */ + + errno = 0; + + if ((size = msgrcv (My_Port, Msg, Msg_Size, 0, MSG_NOERROR)) > 0) + { + i = (int)(Msg->mtext[0]); + if (Verbose) + { + sprintf (str, "Message %d received from port %d", i, My_Port); + trace (str); + } + + Cpt_Msg++; + + /* Réenvoi du message au fils */ + + errno = 0; + + if (msgsnd (Its_Port, Msg_Window[i], Msg_Size, IPC_NOWAIT) == 0) + { + if (Verbose) + { + sprintf (str, "Message %d replied", i); + trace (str); + } + } + + if (errno != 0 && errno != EAGAIN) + fprintf (stderr, "Unable to reply message %d to port %d (%s)\n", i, Its_Port, error_code ()); + } + + if (errno != 0) + fprintf (stderr, "Unable to receive a message from port %d (%s)\n", My_Port, error_code ()); + } + + stop_father (); + } + else + { + /*---------- Code pour le process fils ----------*/ + + My_Pid = getpid (); + Its_Pid = Father_Pid; + My_Port = 0; + + /* Trap du signal SIGUSR1 envoyé par le process père à la fin du test */ + + signal (SIGUSR1, stop_test); + signal (SIGINT, stop_test); + + /* Création d'un port de messages */ + + if ((My_Port = msgget (CHILD_KEY, 0777|IPC_CREAT|IPC_EXCL)) == -1) + { + fprintf (stderr, "Unable to create message queue for the child process (%s)\n", error_code ()); + clean (TRUE); + + return 0; + } + else + { + sprintf (str, "Message port %d created", My_Port); + trace (str); + } + + /* On attend que le père ait créé son port de messages */ + + sleep (2); + + Msg_Window = (T_Msg **)malloc (Win_Size); + + for (i = 0; i < Win_Size; i++) + { + Msg_Window[i] = (T_Msg *)malloc (sizeof (T_Msg)); + Msg_Window[i]->mtype = 1; + Msg_Window[i]->mtext = (char *)malloc (Msg_Size * sizeof (char)); + Msg_Window[i]->mtext[0] = (char)i; + } + + /* Récupération du port de messages du père */ + + if ((Its_Port = msgget (FATHER_KEY, 0)) == -1) + { + fprintf (stderr, "Unable to retrieve the message queue of the father process (%s)\n", error_code ()); + clean (TRUE); + + return 0; + } + + /* Traitement des messages */ + + Msg = malloc (sizeof (T_Msg)); + Msg->mtext = (char *)malloc (Msg_Size * sizeof (char)); + + while (End_Test == FALSE) + { + /* Réception de messages */ + + errno = 0; + + if ((size = msgrcv (My_Port, Msg, Msg_Size, 0, MSG_NOERROR)) > 0) + { + i = (int)(Msg->mtext[0]); + if (Verbose) + { + sprintf (str, "Message %d received from port %d", i, My_Port); + trace (str); + } + + Cpt_Msg++; + + /* Réenvoi du message au fils */ + + errno = 0; + + if (msgsnd (Its_Port, Msg_Window[i], Msg_Size, IPC_NOWAIT) == 0) + { + if (Verbose) + { + sprintf (str, "Message %d replied", i); + trace (str); + } + } + + if (errno != 0 && errno != EAGAIN) + fprintf (stderr, "Unable to reply message %d to port %d (%s)\n", i, Its_Port, error_code ()); + } + + if (errno != 0) + fprintf (stderr, "Unable to receive a message from port %d (%s)\n", My_Port, error_code ()); + } + + stop_child (); + } + + return 0; +} + +/*----------------------------------------------------------------*/ +void stop_test (int signum) +{ + End_Sigum = signum; + End_Test = TRUE; +} +/*----------------------------------------------------------------*/ +void stop_father (void) +{ + switch (End_Sigum) + { + case SIGINT: + + /* Fin initiée par l'utilisateur : ménage simple */ + + case SIGUSR1: + + /* Fin anormale en provenance du fils : ménage simple */ + + clean (FALSE); + + break; + + case SIGALRM: + + /* Fin normale : ménage + stop du fils + affichage du réultat */ + + clean (TRUE); + print_result (); + + break; + + default: + + /* Fin anormale sur le process père : ménage + avertit le process fils */ + + clean (TRUE); + + break; + } + + exit (1); +} + +/*----------------------------------------------------------------*/ +void print_result (void) +{ + /* Affichage du résultat du test */ + + fprintf (stdout, "%d message (s) exchanged (%d Msg/sec)\n", Cpt_Msg, (int)(Cpt_Msg / Timer)); +} + +/*----------------------------------------------------------------*/ +void stop_child (void) +{ + switch (End_Sigum) + { + case SIGINT: + + /* Fin initiée par l'utilisateur : ménage simple */ + + case SIGUSR1: + + /* Fin initiée par le process père : ménage simple */ + + clean (FALSE); + + break; + + default: + + /* Fin anormale sur le process fils : ménage + avertit le process père */ + + clean (TRUE); + + break; + } + + exit (0); +} +/*----------------------------------------------------------------*/ +void clean (int warn) +{ + unsigned int i; + char str [256]; + + /* On avertit l'autre process */ + + if (warn == TRUE) kill (Its_Pid, SIGUSR1); + + if (Msg_Window != NULL) + { + for (i = 0; i < Win_Size; i++) + { + if (Msg_Window[i] != NULL) + { + if (Msg_Window[i]->mtext != NULL) free (Msg_Window[i]->mtext); + free (Msg_Window[i]); + } + } + free (Msg_Window); + } + + /* Destruction de la port de messages */ + + if (My_Port > 0) + { + if (Verbose) + { + sprintf (str, "Removing message queue %d...\n", My_Port); + trace (str); + } + + msgctl (My_Port, IPC_RMID, NULL); + } +} + +/*----------------------------------------------------------------*/ +char * error_code (void) +{ + static char * str; + + if (str) free (str); + + switch (errno) + { + case EACCES: + str = strdup ("EACCES"); + break; + + case EEXIST: + str = strdup ("EEXIST"); + break; + + case EIDRM: + str = strdup ("EIDRM"); + break; + + case ENOENT: + str = strdup ("ENOENT"); + break; + + case ENOMEM: + str = strdup ("ENOMEM"); + break; + + case ENOSPC: + str = strdup ("ENOSPC"); + break; + + case EFAULT: + str = strdup ("EFAULT"); + break; + + case EINTR: + str = strdup ("EINTR"); + break; + + case EINVAL: + str = strdup ("EINVAL"); + break; + + case E2BIG: + str = strdup ("E2BIG"); + break; + + case ENOMSG: + str = strdup ("ENOMSG"); + break; + + case EAGAIN: + str = strdup ("EAGAIN"); + break; + + default: + str = strdup ("unknown"); + break; + } + + return str; +} + +/*----------------------------------------------------------------*/ +void trace (char *str) +{ + time_t dts; + struct tm *dt; + char current_date [30]; + char str_trace [256]; + + /* Get current date */ + + time (&dts); + dt = localtime (&dts); + sprintf (current_date, "%04d/%02d/%02d %02d:%02d:%02d", dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday, dt->tm_hour, dt->tm_min, dt->tm_sec); + + sprintf (str_trace, "Process %d - %s : %s\n", My_Pid, current_date, str); + fprintf (stderr, str_trace); + fflush (stderr); +} + +/*----------------------------------------------------------------*/ +void parse_arg (int argc, char ** argv) +{ + int i; + + Verbose = FALSE; + + for (i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "--help") || !strcmp (argv[i], "-h")) + { + fprintf (stdout, "Usage : %s [options]\n", argv[0]); + fprintf (stdout,"options :\n"); + fprintf (stdout, "\t --help -h\n"); + fprintf (stdout, "\t --clean\n"); + fprintf (stdout, "\t --verbose\n"); + fprintf (stdout, "\t --duration