@srcdir@/gtut-tour-4-callback.doc \
@srcdir@/gtut-tour-5-globals.doc \
@srcdir@/gtut-tour-6-logs.doc \
+ @srcdir@/gtut-tour-7-timers.doc \
\
./logcategories.doc \
\
_6-logs_client.c
_6-logs_server.c
_6-logs_simulator.c
+
+7-timers.mk
+7-timers.trace
+7-timers_client
+7-timers_server
+7-timers_simulator
+_7-timers_client.c
+_7-timers_server.c
+_7-timers_simulator.c
--- /dev/null
+#include <gras.h>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(test,"My little example");
+
+/* *********************** Server *********************** */
+typedef struct {
+ int killed;
+} server_data_t;
+
+int server_kill_cb(gras_msg_cb_ctx_t ctx, void *payload) {
+ gras_socket_t client = gras_msg_cb_ctx_from(ctx);
+ server_data_t *globals=(server_data_t*)gras_userdata_get();
+
+ CRITICAL2("Argh, killed by %s:%d! Bye folks...",
+ gras_socket_peer_name(client), gras_socket_peer_port(client));
+
+ globals->killed = 1;
+
+ return 1;
+} /* end_of_kill_callback */
+
+int server_hello_cb(gras_msg_cb_ctx_t ctx, void *payload) {
+ gras_socket_t client = gras_msg_cb_ctx_from(ctx);
+
+ INFO2("Cool, we received the message from %s:%d.",
+ gras_socket_peer_name(client), gras_socket_peer_port(client));
+
+ return 1;
+} /* end_of_hello_callback */
+
+int server(int argc, char *argv[]) {
+ gras_socket_t mysock; /* socket on which I listen */
+ server_data_t *globals;
+
+ gras_init(&argc,argv);
+
+ globals=gras_userdata_new(server_data_t*);
+ globals->killed=0;
+
+ gras_msgtype_declare("hello", NULL);
+ gras_msgtype_declare("kill", NULL);
+ mysock = gras_socket_server(atoi(argv[1]));
+
+ gras_cb_register(gras_msgtype_by_name("hello"),&server_hello_cb);
+ gras_cb_register(gras_msgtype_by_name("kill"),&server_kill_cb);
+
+ while (!globals->killed) {
+ gras_msg_handle(60);
+ }
+
+ gras_exit();
+ return 0;
+}
+
+/* *********************** Client *********************** */
+/* client_data */
+typedef struct {
+ gras_socket_t toserver;
+ int done;
+} client_data_t;
+
+
+void client_do_hello(void) {
+ client_data_t *globals=(client_data_t*)gras_userdata_get();
+
+ gras_msg_send(globals->toserver,gras_msgtype_by_name("hello"), NULL);
+ INFO0("Hello sent to server");
+} /* end_of_client_do_hello */
+
+void client_do_stop(void) {
+ client_data_t *globals=(client_data_t*)gras_userdata_get();
+
+ gras_msg_send(globals->toserver,gras_msgtype_by_name("kill"), NULL);
+ INFO0("Kill sent to server");
+
+ gras_timer_cancel_repeat(0.5,client_do_hello);
+
+ globals->done = 1;
+ INFO0("Break the client's while loop");
+} /* end_of_client_do_stop */
+
+int client(int argc, char *argv[]) {
+ gras_socket_t mysock; /* socket on which I listen */
+ client_data_t *globals;
+
+ gras_init(&argc,argv);
+
+ gras_msgtype_declare("hello", NULL);
+ gras_msgtype_declare("kill", NULL);
+ mysock = gras_socket_server_range(1024, 10000, 0, 0);
+
+ VERB1("Client ready; listening on %d", gras_socket_my_port(mysock));
+
+ globals=gras_userdata_new(server_data_t*);
+ globals->done = 0;
+
+ gras_os_sleep(1.5); /* sleep 1 second and half */
+ globals->toserver = gras_socket_client(argv[1], atoi(argv[2]));
+
+ INFO0("Programming the repetitive action with a frequency of 0.5 sec");
+ gras_timer_repeat(0.5,client_do_hello);
+
+ INFO0("Programming the delayed action in 5 secs");
+ gras_timer_delay(5,client_do_stop);
+
+ while (!globals->done) {
+ gras_msg_handle(60);
+ }
+
+ gras_exit();
+ return 0;
+}
+
--- /dev/null
+$ ./test_server 12345 & ./test_client 127.0.0.1 12345
+[blaise:server:(23608) 0.000005] test.c:26: [test/INFO] Cool, we received the message from 127.0.0.1:1024.
+[blaise:server:(23608) 0.500361] test.c:26: [test/INFO] Cool, we received the message from 127.0.0.1:1024.
+[blaise:server:(23608) 1.003121] test.c:26: [test/INFO] Cool, we received the message from 127.0.0.1:1024.
+[blaise:server:(23608) 1.507935] test.c:26: [test/INFO] Cool, we received the message from 127.0.0.1:1024.
+[blaise:server:(23608) 2.010545] test.c:26: [test/INFO] Cool, we received the message from 127.0.0.1:1024.
+[blaise:server:(23608) 2.516219] test.c:26: [test/INFO] Cool, we received the message from 127.0.0.1:1024.
+[blaise:server:(23608) 3.018509] test.c:26: [test/INFO] Cool, we received the message from 127.0.0.1:1024.
+[blaise:server:(23608) 3.518713] test.c:26: [test/INFO] Cool, we received the message from 127.0.0.1:1024.
+[blaise:server:(23608) 4.022585] test.c:26: [test/INFO] Cool, we received the message from 127.0.0.1:1024.
+[blaise:server:(23608) 4.482905] test.c:15: [test/CRITICAL] Argh, killed by 127.0.0.1:1024! Bye folks...
+[blaise:server:(23608) 4.482930] gras/gras.c:79: [gras/INFO] Exiting GRAS
+[blaise:client:(23611) 0.000005] test.c:99: [test/INFO] Programming the repetitive action with a frequency of 0.5 sec
+[blaise:client:(23611) 0.000071] test.c:102: [test/INFO] Programming the delayed action in 5 secs
+[blaise:client:(23611) 0.518553] test.c:66: [test/INFO] Hello sent to server
+[blaise:client:(23611) 1.020515] test.c:66: [test/INFO] Hello sent to server
+[blaise:client:(23611) 1.523454] test.c:66: [test/INFO] Hello sent to server
+[blaise:client:(23611) 2.027895] test.c:66: [test/INFO] Hello sent to server
+[blaise:client:(23611) 2.530948] test.c:66: [test/INFO] Hello sent to server
+[blaise:client:(23611) 3.035530] test.c:66: [test/INFO] Hello sent to server
+[blaise:client:(23611) 3.538912] test.c:66: [test/INFO] Hello sent to server
+[blaise:client:(23611) 4.038965] test.c:66: [test/INFO] Hello sent to server
+[blaise:client:(23611) 4.542989] test.c:66: [test/INFO] Hello sent to server
+[blaise:client:(23611) 5.003026] test.c:73: [test/INFO] Kill sent to server
+[blaise:client:(23611) 5.003056] test.c:78: [test/INFO] Break the client's while loop
+[blaise:client:(23611) 5.003071] gras/gras.c:79: [gras/INFO] Exiting GRAS
+$
+$ ./test_simulator platform.xml test.xml
+[Boivin:client:(2) 0.000000] test.c:99: [test/INFO] Programming the repetitive action with a frequency of 0.5 sec
+[Boivin:client:(2) 0.000000] test.c:102: [test/INFO] Programming the delayed action in 5 secs
+[Boivin:client:(2) 0.500537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 0.500537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 1.000537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 1.000537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 1.500537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 1.500537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 2.000537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 2.000537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 2.500537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 2.500537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 3.000537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 3.000537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 3.500537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 3.500537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 4.000537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 4.000537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 4.500537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 4.500537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 5.000537] test.c:66: [test/INFO] Hello sent to server
+[Jacquelin:server:(1) 5.000537] test.c:26: [test/INFO] Cool, we received the message from Boivin:1024.
+[Boivin:client:(2) 5.001074] test.c:73: [test/INFO] Kill sent to server
+[Boivin:client:(2) 5.001074] test.c:78: [test/INFO] Break the client's while loop
+[Boivin:client:(2) 5.001074] gras/gras.c:79: [gras/INFO] Exiting GRAS
+[Jacquelin:server:(1) 5.001074] test.c:15: [test/CRITICAL] Argh, killed by Boivin:1024! Bye folks...
+[Jacquelin:server:(1) 5.001074] gras/gras.c:79: [gras/INFO] Exiting GRAS
+[5.001074] msg/global.c:475: [msg_kernel/INFO] Congratulations ! Simulation terminated : all processes are over
+$
export LD_LIBRARY_PATH=$(GRAS_ROOT)/lib
all: 1-bones.output 2-simple.output 3-args.output 4-callback.output \
- 5-globals.output 6-logs.output
+ 5-globals.output 6-logs.output 7-timers.output
veryclean: clean
rm *.output*
if [ -e 6-logs.mk ] ; then make -f 6-logs.mk clean; fi
rm -f _6-logs_client.c _6-logs_server.c _6-logs_simulator.c 6-logs.trace 6-logs.mk
+
+# Lesson 7: timers
+########################################
+
+7-timers.output: 7-timers_client 7-timers_server 7-timers_simulator
+ echo '$$ ./test_server 12345 & ./test_client 127.0.0.1 12345' > $@
+ ./7-timers_server 12345 2>&1 |sed s/7-timers/test/ >> $@ 2>&1&
+ ./7-timers_client 127.0.0.1 12345 2>&1 |sed s/7-timers/test/ >> $@ 2>&1
+ sleep 1
+ echo '$$' >> $@
+ echo '$$ ./test_simulator platform.xml test.xml' >> $@
+ ./7-timers_simulator gtut-platform.xml 3-args.xml 2>&1 |sed s/7-timers/test/ >> $@ 2>&1
+ echo '$$' >> $@
+ killall 7-timers_server 7-timers_client 2>/dev/null || true
+
+7-timers_client 7-timers_server 7-timers_simulator: _7-timers_client.c _7-timers_server.c _7-timers_simulator.c
+ make -f 7-timers.mk
+
+_7-timers_client.c _7-timers_server.c _7-timers_simulator.c: 7-timers.c 3-args.xml
+ ../../tools/gras/gras_stub_generator 7-timers 3-args.xml >/dev/null
+
+clean::
+ if [ -e 7-timers.mk ] ; then make -f 7-timers.mk clean; fi
+ rm -f _7-timers_client.c _7-timers_server.c _7-timers_simulator.c 7-timers.trace 7-timers.mk
+
- \ref GRAS_tut_tour_callbacks
- \ref GRAS_tut_tour_globals
- \ref GRAS_tut_tour_logs
+ - \ref GRAS_tut_tour_timers
+ - \ref GRAS_tut_tour_exceptions
\htmlonly <!--
DOXYGEN_NAVBAR_LABEL="Tutorial"
Ie, VERB10 does not exist, but VERB0 does exist. I may add more if someone
wants more, but that should be enough for most purposes.
+Note also that there is no need to add a '\n' at the end of your format
+line, it gets automatically added.
+
\section GRAS_tut_tour_logs_recap Recapping everything together
Once we changed any fprintf of our code to some of these macros, the program
how to configure the logs. Or you can proceed with the next lesson, of
course.
-\ref GRAS_tut_tour_timer
+\ref GRAS_tut_tour_timers
*/
--- /dev/null
+/**
+@page GRAS_tut_tour_timers Lesson 7: Using internal timers
+
+\section GRAS_tut_tour_timers_intro Introduction
+
+The messaging primitives we saw until now allow the processes to react to
+external events. This is good, but sometimes, you want the same action to be
+done periodically. Think of a system based on a group of processes. If you
+want to give some adaptability to this system, you shouldn't hardcode the
+memberships but have the members send a message to a coordinator to register
+to the system.
+
+This add some dynamism to your system since new members can join at any
+time. To have a process leaving the system, you can imagine an "unregister"
+message symetric to the "register" one. But how will you deal with failures?
+What if a process leaves without being given the ability to inform the
+coordinator?
+
+One solution is to have the members re-register periodically, so that the
+coordinator can detect the processes which didn't do so since a while, and
+dismiss them.
+
+To implement this in GRAS, we need some more functions: gras_timer_repeat()
+allows to specify a periodic action and gras_timer_delay() allows to get an
+action done once a given delay expires. gras_timer_cancel_delay() and
+gras_timer_cancel_repeat() allow to remove already declared timers. Actions
+must be function without argument nor result (<tt>void my_action(void){
+... }</tt>).
+
+It is important to note that timers are not prehemptive. They will not start
+as soon as they are ready. Instead, they get served when you go into
+gras_msg_handle() (and they are served before incomming messages). This is
+because allowing timers to run in parallel to the callbacks would add
+parallelism to the user code, which would have to protect data with mutexes.
+This is a level of complexity I really don't want for user code. If you
+really need several running entities, simply run several processes (see \ref
+GRAS_tut_intro_model for more details).
+
+\section GRAS_tut_tour_timers_use Putting timers into action
+
+We will change the client of our example so that it send an hello message
+every half second to the server. Then we will add a delayed action scheduled
+5 seconds later in charge of stopping every processes. For this to work, we
+first need to add a global to the server too, containing the socket binded
+onto the server (to send messages) and a boolean indicating whether we are
+done or not, just like we did on the server side in \ref
+GRAS_tut_tour_globals. Here is the resulting global structure:
+\dontinclude 7-timers.c
+\skip client_data
+\until client_data_t
+
+Then, we define the repetitive action in charge of sending messages to the
+server:
+
+\skip client_do_hello
+\until end_of_client_do_hello
+
+This timer is installed the following way. You simply tell the action to
+schedule and its periodicity.
+\skip gras_timer_repeat
+\until gras_timer_repeat
+
+Desinstalling this is not harder. You tell the action to unschedule, and the
+periodicity at which it was desinstalled (so that the same action can be
+scheduled at different intervals, and each of them be desinstallable
+separately).
+\dontinclude 7-timers.c
+\skip gras_timer_cancel_repeat
+\until gras_timer_cancel_repeat
+
+Then comes the delayed action in charge of stopping everything, which should
+be self-explanatory at this point. It could be cancelled before its
+expiration using gras_timer_cancel_delay(), which accepts exactly the same
+kind of arguments than gras_timer_cancel_repeat().
+\dontinclude 7-timers.c
+\skip client_do_stop
+\until end_of_client_do_stop
+
+Finally, we should change the client main function to adapt to these
+modifications, as you can see in the recapping below.
+
+\section GRAS_tut_tour_timers_recap Recapping everything together
+
+The program now reads:
+\include 7-timers.c
+
+Which produces the expected output:
+\include 7-timers.output
+
+\ref GRAS_tut_tour_exceptions
+
+*/
DOXYGEN_NAVBAR_CHILD "2: Simple messaging"=GRAS_tut_tour_simpleexchange.html
DOXYGEN_NAVBAR_CHILD "3: Process args"=GRAS_tut_tour_args.html
DOXYGEN_NAVBAR_CHILD "4: Callbacks"=GRAS_tut_tour_callbacks.html
- DOXYGEN_NAVBAR_CHILD "5: Callbacks"=GRAS_tut_tour_globals.html
+ DOXYGEN_NAVBAR_CHILD "5: Globals"=GRAS_tut_tour_globals.html
DOXYGEN_NAVBAR_CHILD "6: Logs"=GRAS_tut_tour_logs.html
+ DOXYGEN_NAVBAR_CHILD "7: Timers"=GRAS_tut_tour_timers.html
--> \endhtmlonly
- \ref GRAS_tut_tour_install
- \ref GRAS_tut_tour_callbacks
- \ref GRAS_tut_tour_globals
- \ref GRAS_tut_tour_logs
+ - \ref GRAS_tut_tour_timers
<hr>
Unfortunately, the tour is not terminated yet, and here are some ideas of
missing missi^W lessons:
-- Lesson 5: Globals (for a kill message)
-- Lesson 6: Timers
-- Lesson 7: Using logs
+- Lesson 8: Timers
+- Lesson 7: Exceptions
- Lesson 8: Exchanging simple data through ping-pong
- Lesson 9: More complex data description (automatic parsing, manual description) and example