commit 961ddc46da8e00ce8757fce089dc9b624807e626 Author: smas Date: Fri Jul 28 15:34:22 2000 +0000 Première version 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 0000000..d8344d9 Binary files /dev/null and b/lib/libmsg.doc differ 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 0000000..7267d41 Binary files /dev/null and b/util/msgbench.xls differ 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