/* 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; }