libmsg/lib/msg.h
2000-07-28 15:34:22 +00:00

517 lines
27 KiB
C

#ifndef _LIBMSG
#define _LIBMSG
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/time.h>
#include <ver.h>
#include <node.h>
#include <shmem.h>
#include <datastr.h>
/* 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