- \ref GRAS_ex_ping
- \ref GRAS_ex_mmrpc
+ - \ref GRAS_ex_token
- \ref GRAS_ex_timer
@{ */
- \ref GRAS_ex_ping
- \ref GRAS_ex_mmrpc
+ - \ref GRAS_ex_token
- \ref GRAS_ex_timer
\htmlonly <!--
DOXYGEN_NAVBAR_CHILD "Ping-Pong"=GRAS_ex_ping.html
DOXYGEN_NAVBAR_CHILD "RPC"=GRAS_ex_mmrpc.html
+ DOXYGEN_NAVBAR_CHILD "Token Ring"=GRAS_ex_token.html
DOXYGEN_NAVBAR_CHILD "Timers"=GRAS_ex_timer.html
--> \endhtmlonly
[Back to \ref GRAS_ex_ping_toc]
*/
+---------------------------------------------------------------------
+--------------------- Simple Token Ring -----------------------------
+---------------------------------------------------------------------
+
+/** \page GRAS_ex_token Token Ring example
+
+ This example implements the token ring algorithm. It involves several
+ nodes arranged in a ring (each of them have a left and a right neighbour)
+ and exchanging a "token". This algorithm is one of the solution to ensure
+ the mutual exclusion between distributed processes. There is only one
+ token at any time, so the process in its possession is ensured to be the
+ only one having it. So, if there is an action you want all processes to
+ do alternativly, but you cannot afford to have two processes doing it at
+ the same time, let the process having the token doing it.
+
+ Actually, there is a lot of different token ring algorithms in the
+ litterature, so this example implements one of them: the simplest one.
+ The ring is static (no new node can join it, and you'll get trouble if
+ one node dies or leaves), and nothing is done for the case in which the
+ token is lost.
+
+ - \ref GRAS_ex_stoken_deploy
+ - \ref GRAS_ex_stoken_global
+ - \ref GRAS_ex_stoken_callback
+ - \ref GRAS_ex_stoken_main
+
+ \section GRAS_ex_stoken_deploy 1) Deployment file
+
+ Here is the deployment file:
+ \include examples/gras/tokenS/tokenS_deployment.xml
+
+ The neighbour of each node is given at startup as command line argument.
+ Moreover, one of the nodes is instructed by a specific argument (the one
+ on Tremblay here) to create the token at the begining of the algorithm.
+
+ \section GRAS_ex_stoken_global 2) Global definition
+
+ The token is incarned by a specific message, which circulates from node
+ to node (the payload is an integer incremented at each hop). So, the most
+ important part of the code is the message callback, which forwards the
+ message to the next node. That is why we have to store all variable in a
+ global, as explained in the \ref GRAS_globals section.
+
+ \dontinclude examples/gras/tokenS/tokenS.c
+ \skip typedef
+ \until }
+
+ \section GRAS_ex_stoken_callback 3) The callback
+
+ Even if this is the core of this algorithm, this function is quite
+ straightforward.
+
+ \skip node_cb_stoken_handler
+ \until end_of_node_cb_stoken_handler
+
+ \section GRAS_ex_stoken_main 4) The main function
+
+ This function is splited in two parts: The first one performs all the
+ needed initialisations (points 1-7) while the end (point 8. below) calls
+ gras_msg_handle() as long as the planned amount of ring loops are not
+ performed.
+
+ \skip node
+ \until end_of_node
+
+*/
+
---------------------------------------------------------------------
-------------------------- MM RPC -----------------------------------
---------------------------------------------------------------------
XBT_LOG_NEW_DEFAULT_CATEGORY(Token,"Messages specific to this example");
-/* register messages which may be sent */
-static void register_messages(void) {
- gras_msgtype_declare("stoken", gras_datadesc_by_name("int"));
-}
-
/* Function prototypes */
int node (int argc,char *argv[]);
/* Global private data */
typedef struct {
gras_socket_t sock; /* server socket on which I hear */
- int remaining_loop; /* loop to do until done */
- int create; /* I have to create the token */
- gras_socket_t tosuccessor; /* how to connect to next peer on ring */
+ int remaining_loop; /* number of loops to do until done */
+ int create; /* whether I have to create the token */
+ gras_socket_t tosuccessor; /* how to connect to the successor on ring */
} node_data_t;
node_data_t *globals=(node_data_t*)gras_userdata_get();
/* 3. Log which predecessor connected */
- int supersteps = 1;
+ int supersteps = 1; /* only log every superstep loop */
if (NBLOOPS >= 1000) {
supersteps = 100;
} else if (NBLOOPS >= 100) {
msg, gras_socket_peer_name(expeditor),globals->remaining_loop);
}
+ /* 4. If the right shouldn't be stopped yet */
if (globals->remaining_loop > 0) {
-
msg += 1;
- /* 5. I forward it to my successor */
- DEBUG3("Send token(%d) to %s:%d",
- msg,
+ DEBUG3("Send token(%d) to %s:%d", msg,
gras_socket_peer_name(globals->tosuccessor),
gras_socket_peer_port(globals->tosuccessor));
-
- /* 6. Send it as payload of a stoken message to the successor */
+ /* 5. Send the token as payload of a stoken message to the successor */
TRY {
gras_msg_send(globals->tosuccessor,
gras_msgtype_by_name("stoken"), &msg);
- /* 7. Deal with errors */
+ /* 6. Deal with errors */
} CATCH(e) {
gras_socket_close(globals->sock);
RETHROW0("Unable to forward token: %s");
reused by our predecessor.
Closing this side would thus create troubles */
- /* 8. Decrease the remaining_loop integer. */
+ /* 7. Decrease the remaining_loop integer. */
globals->remaining_loop -= 1;
- /* 9. Repport the hop number to the user at the end */
+ /* 8. Repport the hop number to the user at the end */
if (globals->remaining_loop == -1 && globals->create) {
INFO1("Shut down the token-ring. There was %d hops.",msg);
}
- /* 10. Tell GRAS that we consummed this message */
+ /* 9. Tell GRAS that we consummed this message */
return 1;
} /* end_of_node_cb_stoken_handler */
-
int node (int argc,char *argv[]) {
node_data_t *globals;
globals->tosuccessor = gras_socket_client(host,peerport);
- /* 6. Register the known messages. This function is called twice here,
- but it's because this file also acts as regression test.
- No need to do so yourself of course. */
- register_messages();
- register_messages(); /* just to make sure it works ;) */
+ /* 6. Register the known messages. */
+ gras_msgtype_declare("stoken", gras_datadesc_by_name("int"));
/* 7. Register my callback */
- gras_cb_register(gras_msgtype_by_name("stoken"),&node_cb_stoken_handler);
-
+ gras_cb_register(gras_msgtype_by_name("stoken"),&node_cb_stoken_handler);
/* 8. One node has to create the token at startup.
It's specified by a command line argument */
-<?xml version='1.0'?>
-<!DOCTYPE platform_description SYSTEM "surfxml.dtd">
+<?xml version='1.0'?><!DOCTYPE platform_description SYSTEM "surfxml.dtd">
<platform_description>
<process host="Tremblay" function="node">
- <argument value="4000"/> <!-- port on which I am listening -->
- <argument value="Fafard"/> <!-- peer (successor) host -->
- <argument value="4000"/> <!-- port on which peer is listening -->
- <argument value="--create-token"/> <!-- I'm first client, ie I have to create the token -->
+ <argument value="4000"/> <!-- port on which I am listening -->
+ <argument value="Fafard"/><argument value="4000"/> <!-- peer (successor) host name and port-->
+ <argument value="--create-token"/> <!-- I'm first client, ie I have to create the token -->
</process>
<process host="Fafard" function="node">
- <argument value="4000"/> <!-- port on which I am listening -->
- <argument value="Jupiter"/> <!-- peer (successor) host -->
- <argument value="4000"/> <!-- port on which peer is listening -->
+ <argument value="4000"/> <!-- port on which I am listening -->
+ <argument value="Jupiter"/><argument value="4000"/><!-- peer (successor) host name and port-->
</process>
<process host="Jupiter" function="node">
- <argument value="4000"/> <!-- port on which I am listening -->
- <argument value="Ginette"/> <!-- peer (successor) host -->
- <argument value="4000"/> <!-- port on which peer is listening -->
+ <argument value="4000"/> <!-- port on which I am listening -->
+ <argument value="Ginette"/><argument value="4000"/> <!-- peer (successor) host name and port-->
</process>
<process host="Ginette" function="node">
- <argument value="4000"/> <!-- port on which I am listening -->
- <argument value="Bourassa"/> <!-- peer (successor) host -->
- <argument value="4000"/> <!-- port on which peer is listening -->
+ <argument value="4000"/> <!-- port on which I am listening -->
+ <argument value="Bourassa"/><argument value="4000"/><!-- peer (successor) host name and port-->
</process>
<process host="Bourassa" function="node">
- <argument value="4000"/> <!-- port on which I am listening -->
- <argument value="Tremblay"/> <!-- peer (successor) host -->
- <argument value="4000"/> <!-- port on which peer is listening -->
+ <argument value="4000"/> <!-- port on which I am listening -->
+ <argument value="Tremblay"/><argument value="4000"/><!-- peer (successor) host name and port-->
</process>
</platform_description>