From d294cef35bcf12a367aa4e444b6e52ed8aff99ee Mon Sep 17 00:00:00 2001 From: mquinson Date: Sun, 16 Jul 2006 11:00:10 +0000 Subject: [PATCH] Split gtut in several pages, add lesson 5 git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@2586 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- doc/Doxyfile.in | 9 +- doc/Makefile.am | 2 +- doc/gtut-files/1-bones.output | 4 +- doc/gtut-files/3-args.output | 4 +- doc/gtut-files/4-callback.c | 1 - doc/gtut-files/4-callback.output | 4 +- doc/gtut-files/5-globals.c | 78 ++++++ doc/gtut-files/5-globals.output | 22 ++ doc/gtut-files/Makefile | 25 +- doc/gtut-tour-1-bones.doc | 184 +++++++++++++ doc/gtut-tour-2-simple.doc | 117 ++++++++ doc/gtut-tour-3-args.doc | 42 +++ doc/gtut-tour-4-callback.doc | 76 +++++ doc/gtut-tour-5-globals.doc | 82 ++++++ doc/gtut-tour.doc | 460 +++---------------------------- 15 files changed, 676 insertions(+), 434 deletions(-) create mode 100644 doc/gtut-files/5-globals.c create mode 100644 doc/gtut-files/5-globals.output create mode 100644 doc/gtut-tour-1-bones.doc create mode 100644 doc/gtut-tour-2-simple.doc create mode 100644 doc/gtut-tour-3-args.doc create mode 100644 doc/gtut-tour-4-callback.doc create mode 100644 doc/gtut-tour-5-globals.doc diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index be6ecea3ba..290202ff3c 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -407,8 +407,13 @@ INPUT = @srcdir@/index.doc \ @srcdir@/module-sd.doc \ \ @srcdir@/gtut-main.doc \ - @srcdir@/gtut-introduction.doc \ - @srcdir@/gtut-tour.doc \ + @srcdir@/gtut-introduction.doc \ + @srcdir@/gtut-tour.doc \ + @srcdir@/gtut-tour-1-bones.doc \ + @srcdir@/gtut-tour-2-simple.doc \ + @srcdir@/gtut-tour-3-args.doc \ + @srcdir@/gtut-tour-4-callback.doc \ + @srcdir@/gtut-tour-5-globals.doc \ \ ./logcategories.doc \ \ diff --git a/doc/Makefile.am b/doc/Makefile.am index c0661e8e3a..fe67e0c0d0 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -34,7 +34,7 @@ html: Doxyfile ./logcategories.doc simgrid_modules.map $(PNGS) $(DOCSOURCES) @top_srcdir@/tools/doxygen/index_create.pl simgrid.tag index-API.doc @top_srcdir@/tools/doxygen/toc_create.pl \ @srcdir@/FAQ.doc @srcdir@/index.doc @srcdir@/contrib.doc \ - @srcdir@/gtut-introduction.doc @srcdir@/gtut-tour.doc + @srcdir@/gtut-introduction.doc : # Second pass doxygen Doxyfile >/dev/null : # Post-processing diff --git a/doc/gtut-files/1-bones.output b/doc/gtut-files/1-bones.output index 014775c1e5..046ad734b8 100644 --- a/doc/gtut-files/1-bones.output +++ b/doc/gtut-files/1-bones.output @@ -1,7 +1,7 @@ $ ./test_client -[blaise:client:(22033) 0.000005] gras/gras.c:79: [gras/INFO] Exiting GRAS +[blaise:client:(6328) 0.000004] gras/gras.c:79: [gras/INFO] Exiting GRAS $ ./test_server -[blaise:server:(22036) 0.000004] gras/gras.c:79: [gras/INFO] Exiting GRAS +[blaise:server:(6331) 0.000005] gras/gras.c:79: [gras/INFO] Exiting GRAS $ ./test_simulator platform.xml test.xml [Jacquelin:server:(1) 0.000000] gras/gras.c:79: [gras/INFO] Exiting GRAS [Boivin:client:(2) 0.000000] gras/gras.c:79: [gras/INFO] Exiting GRAS diff --git a/doc/gtut-files/3-args.output b/doc/gtut-files/3-args.output index d284cc7ea0..42084bce4a 100644 --- a/doc/gtut-files/3-args.output +++ b/doc/gtut-files/3-args.output @@ -1,9 +1,9 @@ $ ./test_server 12345 & ./test_client 127.0.0.1 12345 Client ready; listening on 1024 That's it, we sent the data to the server on 127.0.0.1 -[blaise:client:(23315) 0.000005] gras/gras.c:79: [gras/INFO] Exiting GRAS +[blaise:client:(6454) 0.000005] gras/gras.c:79: [gras/INFO] Exiting GRAS Cool, we received the message from 127.0.0.1:1024. -[blaise:server:(23313) 0.000004] gras/gras.c:79: [gras/INFO] Exiting GRAS +[blaise:server:(6452) 0.000004] gras/gras.c:79: [gras/INFO] Exiting GRAS $ ./test_simulator platform.xml test.xml Client ready; listening on 1024 That's it, we sent the data to the server on Jacquelin diff --git a/doc/gtut-files/4-callback.c b/doc/gtut-files/4-callback.c index 15fbb14d4f..1749ef2133 100644 --- a/doc/gtut-files/4-callback.c +++ b/doc/gtut-files/4-callback.c @@ -11,7 +11,6 @@ int server_hello_cb(gras_msg_cb_ctx_t ctx, void *payload) { int server(int argc, char *argv[]) { gras_socket_t mysock; /* socket on which I listen */ - gras_socket_t toclient; /* socket used to write to the client */ gras_init(&argc,argv); diff --git a/doc/gtut-files/4-callback.output b/doc/gtut-files/4-callback.output index 2391af1636..36c3e29c0e 100644 --- a/doc/gtut-files/4-callback.output +++ b/doc/gtut-files/4-callback.output @@ -1,9 +1,9 @@ $ ./test_server 12345 & ./test_client 127.0.0.1 12345 Client ready; listening on 1024 That's it, we sent the data to the server on 127.0.0.1 -[blaise:client:(19066) 0.000005] gras/gras.c:79: [gras/INFO] Exiting GRAS +[blaise:client:(7454) 0.000004] gras/gras.c:79: [gras/INFO] Exiting GRAS Cool, we received the message from 127.0.0.1:1024. -[blaise:server:(19064) 0.000005] gras/gras.c:79: [gras/INFO] Exiting GRAS +[blaise:server:(7452) 0.000004] gras/gras.c:79: [gras/INFO] Exiting GRAS $ ./test_simulator platform.xml test.xml Client ready; listening on 1024 That's it, we sent the data to the server on Jacquelin diff --git a/doc/gtut-files/5-globals.c b/doc/gtut-files/5-globals.c new file mode 100644 index 0000000000..3f551f408d --- /dev/null +++ b/doc/gtut-files/5-globals.c @@ -0,0 +1,78 @@ +#include + +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(); + + fprintf(stderr,"Argh, killed by %s:%d! Bye folks...\n", + 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); + + fprintf(stderr,"Cool, we received the message from %s:%d.\n", + 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(-1); /* blocking */ + } + + gras_exit(); + return 0; +} + +int client(int argc, char *argv[]) { + gras_socket_t mysock; /* socket on which I listen */ + gras_socket_t toserver; /* socket used to write to the server */ + + gras_init(&argc,argv); + + gras_msgtype_declare("hello", NULL); + gras_msgtype_declare("kill", NULL); + mysock = gras_socket_server_range(1024, 10000, 0, 0); + + fprintf(stderr,"Client ready; listening on %d\n", gras_socket_my_port(mysock)); + + gras_os_sleep(1.5); /* sleep 1 second and half */ + toserver = gras_socket_client(argv[1], atoi(argv[2])); + + gras_msg_send(toserver,gras_msgtype_by_name("hello"), NULL); + fprintf(stderr,"we sent the data to the server on %s. Let's do it again for fun\n", gras_socket_peer_name(toserver)); + gras_msg_send(toserver,gras_msgtype_by_name("hello"), NULL); + + fprintf(stderr,"Ok. Enough. Have a rest, and then kill the server\n"); + gras_os_sleep(5); /* sleep 1 second and half */ + gras_msg_send(toserver,gras_msgtype_by_name("kill"), NULL); + + gras_exit(); + return 0; +} diff --git a/doc/gtut-files/5-globals.output b/doc/gtut-files/5-globals.output new file mode 100644 index 0000000000..d212c62e4a --- /dev/null +++ b/doc/gtut-files/5-globals.output @@ -0,0 +1,22 @@ +$ ./test_server 12345 & ./test_client 127.0.0.1 12345 +Client ready; listening on 1024 +we sent the data to the server on 127.0.0.1. Let's do it again for fun +Ok. Enough. Have a rest, and then kill the server +Cool, we received the message from 127.0.0.1:1024. +[blaise:client:(18581) 0.000005] gras/gras.c:79: [gras/INFO] Exiting GRAS +Cool, we received the message from 127.0.0.1:1024. +Argh, killed by 127.0.0.1:1024! Bye folks... +$ ./test_simulator platform.xml test.xml +Client ready; listening on 1024 +we sent the data to the server on Jacquelin. Let's do it again for fun +Cool, we received the message from Boivin:1024. +Ok. Enough. Have a rest, and then kill the server +Cool, we received the message from Boivin:1024. +[Boivin:client:(2) 0.000000] gras/gras.c:79: [gras/INFO] Exiting GRAS +Argh, killed by Boivin:1024! Bye folks... +[0.000000] msg/global.c:478: [msg_kernel/INFO] Oops ! Deadlock or code not perfectly clean. +[0.000000] msg/global.c:293: [msg_kernel/INFO] MSG: 1 processes are still running, waiting for something. +[0.000000] msg/global.c:295: [msg_kernel/INFO] MSG: () on : . +[0.000000] msg/global.c:309: [msg_kernel/INFO] MSG: server(1) on Jacquelin: [blocked] Listening on channel 0 +[0.000000] msg/global.c:486: [msg_kernel/INFO] Return a Warning. +$ diff --git a/doc/gtut-files/Makefile b/doc/gtut-files/Makefile index d762cd36e5..3e31aa606a 100644 --- a/doc/gtut-files/Makefile +++ b/doc/gtut-files/Makefile @@ -1,7 +1,8 @@ # This works mainly on my box for now export LD_LIBRARY_PATH=$(GRAS_ROOT)/lib -all: 1-bones.output 2-simple.output 3-args.output 4-callback.output +all: 1-bones.output 2-simple.output 3-args.output 4-callback.output \ + 5-globals.output veryclean: clean rm *.output @@ -90,3 +91,25 @@ clean:: if [ -e 4-callback.mk ] ; then make -f 4-callback.mk clean; fi rm -f _4-callback_client.c _4-callback_server.c _4-callback_simulator.c 4-callback.trace 4-callback.mk +# Lesson 5: globals +######################################## + +5-globals.output: 5-globals_client 5-globals_server 5-globals_simulator + echo '$$ ./test_server 12345 & ./test_client 127.0.0.1 12345' > $@ + ./5-globals_server 12345 >> $@ 2>&1& + ./5-globals_client 127.0.0.1 12345 >> $@ 2>&1 + sleep 1 + echo '$$ ./test_simulator platform.xml test.xml' >> $@ + ./5-globals_simulator gtut-platform.xml 3-args.xml >> $@ 2>&1 + echo '$$' >> $@ + +5-globals_client 5-globals_server 5-globals_simulator: _5-globals_client.c _5-globals_server.c _5-globals_simulator.c + make -f 5-globals.mk + +_5-globals_client.c _5-globals_server.c _5-globals_simulator.c: 5-globals.c 3-args.xml + ../../tools/gras/gras_stub_generator 5-globals 3-args.xml >/dev/null + +clean:: + if [ -e 5-globals.mk ] ; then make -f 5-globals.mk clean; fi + rm -f _5-globals_client.c _5-globals_server.c _5-globals_simulator.c 5-globals.trace 5-globals.mk + diff --git a/doc/gtut-tour-1-bones.doc b/doc/gtut-tour-1-bones.doc new file mode 100644 index 0000000000..cd8a02b4d1 --- /dev/null +++ b/doc/gtut-tour-1-bones.doc @@ -0,0 +1,184 @@ + +/** +@page GRAS_tut_tour_setup Lesson 1: Setting up your own project + +Any GRAS project should be constituted of at least 3 files, and possibly +much more. + + - <project>.c: A source file providing the source code of your + processes. + + - <platform>.xml: A platform description file. It describes + the virtual platform you want to run your application onto following the + SurfXML formatting so that the simulator can parse it. This file is only + needed in SG, and you don't need any to run on real platforms (of + course). The simplest is to use one of the pre-existing one. + + - <project>.xml: A deployment file. It describes which of + your processes to start, on which machine and with which arguments. + + - A makefile is often needed, too, even if it's not mandatory. + +If we start a project called test, we have to write 3 files: +test.c, platform.xml and test.xml + +\section GRAS_tut_tour_setup_C The C source file + +Let's look at the C source file first. It should contain one main function +for each type of processes in your overlay. Let's assume that you want to +code a simple client/server communication. For this, the source file should +read as: + +\verbatim #include + +int client(int argc, char *argv[]) { + ... +} + +int server(int argc, char *argv[]) { + ... +} +\endverbatim + +Note that each of the processes's main function have the exact same +prototype of the classical main() function in C. + +This is on purpose, each of them can assume this role when running in RL. +But you shouldn't write a main() function yourself since all processes will +run as threads within the same regular process in simulation mode. That is +why the real main function of GRAS programs are generated +automatically. This will be detailled in time (section \ref +GRAS_tut_tour_setup_glue), but for now just note the similarity between the +"main" functions you have to write for each processes and a "real main" +function. + +Then, each process must initialize the GRAS framework at the beginning (with +\ref gras_init) and should finalize it at the end (with \ref gras_exit). + +You should pass to \ref gras_init the argc and argv you +received in your "main" function so that the users of your application can +pass some configuration flags to the framework. + +It is not enough to have one of the processes initializing the framework +since in RL, each of them will run on a different host. If you use some AMOK +modules, you have to initialize them in each process too. + +The source file then reads: \include 1-bones.c + +That's it. You have a working GRAS application with two processes. They +don't do anything useful, but that's a beginning. Let's see how to bring +them to life. + +\section GRAS_tut_tour_setup_plat The platform file + +The platform file is used by the simulator to know about the existing hosts +and their interactions. Its exact syntax is at the same time very simple and +a bit beyond the topic of this document. Here is a very simple example +describin two hosts named Jacquelin and Boivin and how they +are interconnected. + +\include gtut-platform.xml + +At this point, you should not try to write your own platform file, but use +one of the existing ones. There is a few of them in the examples/msg +directory of the project. The only information we need from those files are +the names of the existing hosts. It will be mandatory to write the +deployment file. + +\section GRAS_tut_tour_setup_deploy The deployment file + +This file explains which of your processes should be started on the +different hosts. It is mainly used in simulation. In real life, you will +have to start your processes manually (see below). We we dream of a system +able to apply a deployment file in real life and TakTuk may be the right +tool for this, but this is still to be done. + +Here is an example of such file, describing that a server process +must be started onto the Jacquelin host and a client +process must be started on the Boivin host. + +\include test.xml + +Actually, you should write such a file also if you only plan to use GRAS in +RL since this file is also used to glue your code to GRAS, as explained in +the next section. + +\section GRAS_tut_tour_setup_glue Glueing things together + +As explained above, you shouldn't write any real main function +since its content depends on whether you run in RL ou in SG. Instead, you +use a tool gras_stub_generator to get the proper glue around your +code generated. If you installed SimGrid in a regular place, this program is +now in your path. Its source resides in the tools/gras/ directory of the +archive, if you wonder. + +Here is the calling syntax: +\verbatim gras_stub_generator \endverbatim + +It parses the deployment file (called test.xml in our example), +searching for all the kind of processes you have in your project. It +then generates the following C files: + + - a _<project_name>_<process_kind>.c file for each process kind you + have.\n + They are used to launch your project in real life. They + contain a main() in charge of initializing the GRAS infrastructure and + launching your code afterward. + - a _<project_name>_simulator.c file.\n + This file is suited to the simulation mode. It contains a main() + function initializing the simulator and launching your project within. + - a <project_name>.mk file.\n + This is a makefile to regenerate any files on need. See next section. + +In our example, we will thus obtain _test_server.c, +_test_client.c, _test_simulator.c and test.mk. + +There is a pitfall: no verification is made on your actual source code, so +if you have a typo on the process name in the deployment file, the generated +code will be wrong, and the linker will spit error messages at you. Also +remember that those names are in fact C function names, so they are +case-sensitive. + +\section GRAS_tut_tour_setup_make A typical Makefile + +Now, we want to compile all the source files to build the actual binaries. +It can be done manually, but it is much more convenient to use a makefile. +Fortunately, gras_stub_generator generates a makefile for you under the name +<project>.mk. This file is sufficient for now. To compile our test +application, just type: +\verbatim make -f test.mk \endverbatim + +You may want to rename this file to Makefile so that typing make +without argument becomes sufficient. In any case, do not edit this file +without renaming it, or your changes will get overwritten at the next glue +generation. + +If you already have a Makefile (or a Makefile.am for automake users), you +can also add the following chunk at the end of your file: +\verbatim NAME=your_project_name + PROCESSES=list of processes type in your project + + $(foreach proc, $(PROCESSES), _$(NAME)_$(proc).c) _$(NAME)_simulator.c: $(NAME).c $(NAME)_deployment.xml + path/to/gras_stub_generator $(NAME) $(NAME)_deployment.xml >/dev/null +\endverbatim + +A simpler solution in our example would be to add: +\verbatim _test_client.c _test_server.c _test_simulator.c: test.c test.xml + path/to/gras_stub_generator test test.xml >/dev/null +\endverbatim + +\section GRAS_tut_tour_setup_start Actually running the processes + +There is nothing to know to start your processes in RL. Simply call the +generated binaries, and that's it. To start the simulation, simply call: +\verbatim ./_simulator platform.xml deployment.xml\endverbatim + +Here is an example of execution: \include 1-bones.output + +That's it. You are done with this lesson and can now write, build and +execute GRAS applications as long as they don't do anything ;) Move +to the next lessons to add some flesh on these bones. + +\ref GRAS_tut_tour_simpleexchange + +*/ diff --git a/doc/gtut-tour-2-simple.doc b/doc/gtut-tour-2-simple.doc new file mode 100644 index 0000000000..b7bb396226 --- /dev/null +++ b/doc/gtut-tour-2-simple.doc @@ -0,0 +1,117 @@ + +/** +@page GRAS_tut_tour_simpleexchange Lesson 2: Exchanging simple messages + +\section GRAS_tut_tour_simpleexchange_msgtype Declaring the messages to be exchanged + +We will now see how to exchange messages between hosts. As explained in +section \ref GRAS_tut_intro_model, every GRAS message is (strongly) typed. A +message type is described by its name and the datatype of the data it can +convey. Each process which may exchange a given type of message should +declare it before sending or receiving it. If the description used by the +sender doesn't match the one used by the receiver, you'll get into trouble. +Fortunately, such discrepency will be detected in SG. + +We won't convey any payload in this lesson, so we just have to give the name +of message to declare them: +\dontinclude 2-simple.c +\skip gras_msgtype_declare +\until gras_msgtype_declare + +Remember that all processes should declare the message types they use. + +\section GRAS_tut_tour_simpleexchange_socks Identifying peers you want to communicate with + +Then, you need to specify with who you want to communicate. This is done +by opening sockets. GRAS sockets are loosely inspirated by the regular BSD +sockets, but with several simplifications. + +If you want to eventually receive messages, you have to open a so-called +server socket. Actually, any GRAS process should open a server socket +since it will allows to identify it uniquely in the system. A socket is +defined by an host name and a port number (just like with BSD sockets). + +Since server socket are on the current host, opening a socket to receive +messages on the port 12345 is as easy as: +\skip gras_socket_server +\until gras_socket_server + +Hardcoding port numbers that way may lead to difficulties on RL (at least) +since at most one process can listen on a given port. So, if you can, prefer +the \ref gras_socket_server_range, which picks a working port from a range +of value. Of course, if you want your processes to find each others, at +least one port must be hardcoded in the system. Then, any other processes +contact the one listening on that port, which acts as a coordinator. + +Our client should also open a server socket, but the picked port don't +matter, so we use: +\skip gras_socket_server +\until gras_socket_server + +It will select a port between 1024 (ports below 1024 are reserved under +UNIX) and 10000. You can safely ignore the two last arguments for now and +pass 0. + +So, you now know how to create sockets allowing to receive messages. To send +messages, you have to create a so-called client socket. For this, use +\ref gras_socket_client with the hostname and the port of the process you +want to contact as arguments. Our client should simply do: + +\dontinclude 2-simple.c +\skip socket_client +\until socket_client + +The corresponding server socket must be opened before any client socket can +connect to it. It is thus safe to add a little delay before creating the +client socket. But you cannot use the classical sleep() function for this, +or you will delay the simulator in SG, not your processes. Use \ref +gras_os_sleep instead. + +\section GRAS_tut_tour_simpleexchange_exchange Actually exchanging messages + +GRAS offers a plenty of ways to communicate. The simple one is to use \ref +gras_msg_send on the sender side, and \ref gras_msg_wait on the receiver side. + +\ref gras_msg_send expects 3 arguments: the socket on which to send the +message, the message type, and a pointer to the actual content of the +message. The simplest way to retrive a message type from its name is to use +\ref gras_msgtype_by_name. Since we don't have any payload, this becomes: + +\dontinclude 2-simple.c +\skip msg_send +\until msg_send + +\ref gras_msg_wait accepts 4 arguments. The first one is the delay you are +disposed to wait for messages, while the the type of message you are +expecting. Then come output arguments. The third argument should be the +address of a gras_socket_t variable which will indicate who wrote the +message you received while the last argument is where to put the payload. + +Since our server is willing to wait up to 60 seconds for a message, the +following will do it: +\dontinclude 2-simple.c +\skip msg_wait +\until msg_wait + +\section GRAS_tut_tour_simpleexchange_recaping Recaping everything together + +Here is the complete code of this example. Note the use of the functions +\ref gras_socket_my_port, \ref gras_socket_peer_name and \ref +gras_socket_peer_port to retrieve information about who you are connected to. + +\include 2-simple.c + +Here is the output of the simulator. Note that \ref gras_socket_peer_port +actually returns the port number of the server of the peer. This may +sound a bit strange to BSD experts, but it is actually really useful: you +can store this value, and contact your peer afterward passing this number to +\ref gras_socket_client . +\include 2-simple.output + +Here we are, you now know how to exchange messages between peers. There is +still a large room for improvement, such as adding payload to messages. But +there some little things you should know before we speak of payloads. + +\ref GRAS_tut_tour_args + +*/ diff --git a/doc/gtut-tour-3-args.doc b/doc/gtut-tour-3-args.doc new file mode 100644 index 0000000000..9ea00566f4 --- /dev/null +++ b/doc/gtut-tour-3-args.doc @@ -0,0 +1,42 @@ + +/** +@page GRAS_tut_tour_args Lesson 3: Passing arguments to the processes (in SG) + +The most problematic issue with the code of previous lesson is that it does +not work in RL since we hardcoded the server hostname in the client code. We +will thus learn you how to pass arguments to your processes to overcome this +situation. + +\section GRAS_tut_tour_args_use Using command line arguments from user code + +In RL, the situation is quite simple: we just have to use the command line +arguments as we would do in a usual C program. In the server, only change +concern the opennong of the master socket: +\dontinclude 3-args.c +\skip gras_socket_server +\until gras_socket_server + +In the client, we only need to change the way we open the client socket: +\skip gras_socket_client +\until gras_socket_client + +The rest of the program remains inchanged. + +\section GRAS_tut_tour_args_sg Passing command line arguments in deployment files + +At this point, the problem is to pass arguments to the processes in SG. +Fortunately, it is quite simple. You just have to edit your deployment file +so that it reads: \include 3-args.xml +The syntax should be self-explanatory at this point. + +\section GRAS_tut_tour_args_recap Recaping everything together + +The whole program now reads: +\include 3-args.c + +And here is the output: +\include 3-args.output + +\ref GRAS_tut_tour_callbacks + +*/ diff --git a/doc/gtut-tour-4-callback.doc b/doc/gtut-tour-4-callback.doc new file mode 100644 index 0000000000..82ff58790e --- /dev/null +++ b/doc/gtut-tour-4-callback.doc @@ -0,0 +1,76 @@ + +/** +@page GRAS_tut_tour_callbacks Lesson 4: Attaching callbacks to messages + +Our program is well and good, but if we had to write a longer program, +explicitely waiting for messages of a given type would not be really +practical. To add some more dynamism, what we want to do is to attach +callbacks to the several messages types, and tell GRAS that we are ready to +deal with new messages. That's what we will do now. + +\section GRAS_tut_tour_callbacks_declare Declaring callbacks + +First of all, we define the callback we want to attach to the arrival of the +"hello" message on the server. Its signature is fixed: it accepts two +arguments of relative types gras_msg_cb_ctx_t ctx and void +*. The first one is a working context we should pass to GRAS when +speaking about the message we are handling while the second is the payload. +The callbackreturns an integer indicating whether we managed to deal with +the message. I admit that this semantic is a bit troublesome, it should be 0 +if we managed to deal properly with the message to mimic "main()" semantic. +That's historical, but I may change this in the future (no worry, I'll add +backward compatibility solutions). Here is the actual code of our callback: + +\dontinclude 4-callback.c +\skip gras_msg_cb_ctx_t +\until end_of_callback + +\section GRAS_tut_tour_callbacks_attach Attaching callbacks + +Then, we have to change the server code to use this callback instead of +gras_msg_wait. This simply done by a construct like the following: + +\skip cb_register +\until cb_register + +\section GRAS_tut_tour_callbacks_handle Handling incoming messages + +Once the callback is declared and attached, the server simply has to call +\ref gras_msg_handle to tell GRAS it's ready to handle for incoming +messages. The only argument is the maximum delay we are disposed to wait for +a message. If the delay is negative, the process will block until a message +arrives. With delay=0, the process just polls for already arrived messages, +but do not wait at all if none arrived yet. If the delay is greater than 0, +the process will wait for at most that amount of seconds. If a message +arrives in the meanwhile, it won't even wait that long. + +Sometimes, you want to handle all messages arriving in a given period +without really knowing how much messages will come (this is often the case +during the initialization phase of an algorithm). In that case, use \ref +gras_msg_handleall . It has the same prototype than \ref gras_msg_handle, +but waits exactly the passed delay, dealing with all the messages arriving +in the meanwhile. + +We have no such needs in our example, so the code simply reads: +\skip handle +\until handle + +\section GRAS_tut_tour_callback_recap Recaping everything together + +The whole program now reads: +\include 4-callback.c + +And here is the output (unchanged wrt previous version): +\include 4-callback.output + +Our little example turns slowly to a quite advanced GRAS program. It entails +most of the mecanism most program will use. + +There is one last thing you should know about callbacks: you can stack them, +ie attach several callbacks to the same message. GRAS will pass it to the +lastly attached first, and if the return value is 0, it will pass it also to +the next one, and so on. I'm not sure there is any sensible use of this +feature, but it's possible ;) + +\ref GRAS_tut_tour_globals +*/ diff --git a/doc/gtut-tour-5-globals.doc b/doc/gtut-tour-5-globals.doc new file mode 100644 index 0000000000..641cecdbd7 --- /dev/null +++ b/doc/gtut-tour-5-globals.doc @@ -0,0 +1,82 @@ +/** +@page GRAS_tut_tour_globals Lesson 5: Using globals in processes + +Callbacks are great to express your processes as state machines, but they +pose another problem: callbacks don't have acces to the variable declared +within the scope of the process' main function (of course). You should +however resist to the temptation to declare globals outside of the scope of +the functions, or you won't be able to use more than one process of each +type in the simulation. Remember, all gras processes run as thread +within the same naming space in SG so your globals will be shared between +the several instances of your process, leading to bad problems. + +Instead, you you have to put all globals in a structure, and let GRAS handle +it with the gras_userdata_* functions (there is only 3 of them ;). + +We will now modify the example to add a "kill" message, and let the server +loop on incoming messages until it gets such a message. We only need a +boolean, so the structure is quite simple: +\dontinclude 5-globals.c +\skip struct +\until server_data + +Then, we need to create this structure in the process main function. We +could use either gras_userdata_new() or gras_userdata_set(). The former is an +helper macro mallocing the space needed by the structure and passing it to +gras using the latter function. If you go for gras_userdata_set(), you +should pass it a pointer to your data you want to retrieve afterward. + +\dontinclude 5-globals.c +\skip userdata_new +\until userdata_new + +Once you declared a global that way, retriving this (for example in a +callback) is really easy: +\dontinclude 5-globals.c +\skip userdata_get +\until userdata_get + +We can now write the callback, which simply retrive the globals and change +the value of the kileld field. +\dontinclude 5-globals.c +\skip kill_cb +\until end_of_kill_callback + +And we replace the single gras_msg_handle() of the server main function by a +loop: +\skip while +\until } + +\section GRAS_tut_tour_callback_pitfall Common pitfall of globals + +There is an error that I do myself every other day using globals in GRAS. +This is to write something like: +\verbatim int server(int argc, char *argv[]) { + server_data_t globals=gras_user_new(server_data_t); + /* other variable definition */ + + gras_init(&argc, argv); + + /* rest of the code */ +}\endverbatim + +The problem is that you call gras_userdata_new() before gras_init(). Doing so, +embarass GRAS since it does not have its internal buffer initialized yet, +and cannot store your data anywhere. That is why doing so triggers an error +at run time. + +\section GRAS_tut_tour_callback_recap Recaping everything together + +The whole program now reads: +\include 5-globals.c + +And here is the output (unchanged wrt previous version): +\include 5-globals.output + +That's it, we're done. We have a server able to handle any number of +messages, which the client can stop remotely properly. That's already +something, hu? + +\ref GRAS_tut_tour_timer + +*/ diff --git a/doc/gtut-tour.doc b/doc/gtut-tour.doc index efd7935b6b..8db2d2f9c9 100644 --- a/doc/gtut-tour.doc +++ b/doc/gtut-tour.doc @@ -2,434 +2,34 @@ /** @page GRAS_tut_tour GRAS initiatic tour -On this page, you will learn all you need to write your own GRAS -applications, from the installation of the framework to the use of all -features available in GRAS. - -\htmlinclude .gtut-tour.doc.toc - -
-\section GRAS_tut_tour_install Lesson 0: Installing GRAS - -Since GRAS is technically part of the SimGrid project, you have to install -SimGrid to install GRAS. Doing so is explained in the relevant FAQ section -(\ref faq_installation). - -Newcommers should install the stable release from the tarball, since the cvs -snapshots may suffer from (additionnal;) stability issues. Only go for the CVS if you -really need features not present in the stable releases yet. - -
-\section GRAS_tut_tour_setup Lesson 1: Setting up your own project - -Any GRAS project should be constituted of at least 3 files, and possibly -much more. - - - <project>.c: A source file providing the source code of your - processes. - - - <platform>.xml: A platform description file. It describes - the virtual platform you want to run your application onto following the - SurfXML formatting so that the simulator can parse it. This file is only - needed in SG, and you don't need any to run on real platforms (of - course). The simplest is to use one of the pre-existing one. - - - <project>.xml: A deployment file. It describes which of - your processes to start, on which machine and with which arguments. - - - A makefile is often needed, too, even if it's not mandatory. - -If we start a project called test, we have to write 3 files: -test.c, platform.xml and test.xml - -\subsection GRAS_tut_tour_setup_C The C source file - -Let's look at the C source file first. It should contain one main function -for each type of processes in your overlay. Let's assume that you want to -code a simple client/server communication. For this, the source file should -read as: - -\verbatim #include - -int client(int argc, char *argv[]) { - ... -} - -int server(int argc, char *argv[]) { - ... -} -\endverbatim - -Note that each of the processes's main function have the exact same -prototype of the classical main() function in C. - -This is on purpose, each of them can assume this role when running in RL. -But you shouldn't write a main() function yourself since all processes will -run as threads within the same regular process in simulation mode. That is -why the real main function of GRAS programs are generated -automatically. This will be detailled in time (section \ref -GRAS_tut_tour_setup_glue), but for now just note the similarity between the -"main" functions you have to write for each processes and a "real main" -function. - -Then, each process must initialize the GRAS framework at the beginning (with -\ref gras_init) and should finalize it at the end (with \ref gras_exit). - -You should pass to \ref gras_init the argc and argv you -received in your "main" function so that the users of your application can -pass some configuration flags to the framework. - -It is not enough to have one of the processes initializing the framework -since in RL, each of them will run on a different host. If you use some AMOK -modules, you have to initialize them in each process too. - -The source file then reads: \include 1-bones.c - -That's it. You have a working GRAS application with two processes. They -don't do anything useful, but that's a beginning. Let's see how to bring -them to life. - -\subsection GRAS_tut_tour_setup_plat The platform file - -The platform file is used by the simulator to know about the existing hosts -and their interactions. Its exact syntax is at the same time very simple and -a bit beyond the topic of this document. Here is a very simple example -describin two hosts named Jacquelin and Boivin and how they -are interconnected. - -\include gtut-platform.xml - -At this point, you should not try to write your own platform file, but use -one of the existing ones. There is a few of them in the examples/msg -directory of the project. The only information we need from those files are -the names of the existing hosts. It will be mandatory to write the -deployment file. - -\subsection GRAS_tut_tour_setup_deploy The deployment file - -This file explains which of your processes should be started on the -different hosts. It is mainly used in simulation. In real life, you will -have to start your processes manually (see below). We we dream of a system -able to apply a deployment file in real life and TakTuk may be the right -tool for this, but this is still to be done. - -Here is an example of such file, describing that a server process -must be started onto the Jacquelin host and a client -process must be started on the Boivin host. - -\include test.xml - -Actually, you should write such a file also if you only plan to use GRAS in -RL since this file is also used to glue your code to GRAS, as explained in -the next section. - -\subsection GRAS_tut_tour_setup_glue Glueing things together - -As explained above, you shouldn't write any real main function -since its content depends on whether you run in RL ou in SG. Instead, you -use a tool gras_stub_generator to get the proper glue around your -code generated. If you installed SimGrid in a regular place, this program is -now in your path. Its source resides in the tools/gras/ directory of the -archive, if you wonder. - -Here is the calling syntax: -\verbatim gras_stub_generator \endverbatim - -It parses the deployment file (called test.xml in our example), -searching for all the kind of processes you have in your project. It -then generates the following C files: - - - a _<project_name>_<process_kind>.c file for each process kind you - have.\n - They are used to launch your project in real life. They - contain a main() in charge of initializing the GRAS infrastructure and - launching your code afterward. - - a _<project_name>_simulator.c file.\n - This file is suited to the simulation mode. It contains a main() - function initializing the simulator and launching your project within. - - a <project_name>.mk file.\n - This is a makefile to regenerate any files on need. See next section. - -In our example, we will thus obtain _test_server.c, -_test_client.c, _test_simulator.c and test.mk. - -There is a pitfall: no verification is made on your actual source code, so -if you have a typo on the process name in the deployment file, the generated -code will be wrong, and the linker will spit error messages at you. Also -remember that those names are in fact C function names, so they are -case-sensitive. - -\subsection GRAS_tut_tour_setup_make A typical Makefile - -Now, we want to compile all the source files to build the actual binaries. -It can be done manually, but it is much more convenient to use a makefile. -Fortunately, gras_stub_generator generates a makefile for you under the name -<project>.mk. This file is sufficient for now. To compile our test -application, just type: -\verbatim make -f test.mk \endverbatim - -You may want to rename this file to Makefile so that typing make -without argument becomes sufficient. In any case, do not edit this file -without renaming it, or your changes will get overwritten at the next glue -generation. - -If you already have a Makefile (or a Makefile.am for automake users), you -can also add the following chunk at the end of your file: -\verbatim NAME=your_project_name - PROCESSES=list of processes type in your project - - $(foreach proc, $(PROCESSES), _$(NAME)_$(proc).c) _$(NAME)_simulator.c: $(NAME).c $(NAME)_deployment.xml - path/to/gras_stub_generator $(NAME) $(NAME)_deployment.xml >/dev/null -\endverbatim - -A simpler solution in our example would be to add: -\verbatim _test_client.c _test_server.c _test_simulator.c: test.c test.xml - path/to/gras_stub_generator test test.xml >/dev/null -\endverbatim - - - -\subsection GRAS_tut_tour_setup_start Actually running the processes - -There is nothing to know to start your processes in RL. Simply call the -generated binaries, and that's it. To start the simulation, simply call: -\verbatim ./_simulator platform.xml deployment.xml\endverbatim - -Here is an example of execution: \include 1-bones.output - -That's it. You are done with this lesson and can now write, build and -execute GRAS applications as long as they don't do anything ;) Simply read on -to add some flesh on these bones. - -(back to the top of the \ref GRAS_tut_tour) -
- -\section GRAS_tut_tour_simpleexchange Lesson 2: Exchanging simple messages - -\subsection GRAS_tut_tour_simpleexchange_msgtype Declaring the messages to be exchanged - -We will now see how to exchange messages between hosts. As explained in -section \ref GRAS_tut_intro_model, every GRAS message is (strongly) typed. A -message type is described by its name and the datatype of the data it can -convey. Each process which may exchange a given type of message should -declare it before sending or receiving it. If the description used by the -sender doesn't match the one used by the receiver, you'll get into trouble. -Fortunately, such discrepency will be detected in SG. - -We won't convey any payload in this lesson, so we just have to give the name -of message to declare them: -\dontinclude 2-simple.c -\skip gras_msgtype_declare -\until gras_msgtype_declare - -Remember that all processes should declare the message types they use. - -\subsection GRAS_tut_tour_simpleexchange_socks Identifying peers you want to communicate with - -Then, you need to specify with who you want to communicate. This is done -by opening sockets. GRAS sockets are loosely inspirated by the regular BSD -sockets, but with several simplifications. - -If you want to eventually receive messages, you have to open a so-called -server socket. Actually, any GRAS process should open a server socket -since it will allows to identify it uniquely in the system. A socket is -defined by an host name and a port number (just like with BSD sockets). - -Since server socket are on the current host, opening a socket to receive -messages on the port 12345 is as easy as: -\skip gras_socket_server -\until gras_socket_server - -Hardcoding port numbers that way may lead to difficulties on RL (at least) -since at most one process can listen on a given port. So, if you can, prefer -the \ref gras_socket_server_range, which picks a working port from a range -of value. Of course, if you want your processes to find each others, at -least one port must be hardcoded in the system. Then, any other processes -contact the one listening on that port, which acts as a coordinator. - -Our client should also open a server socket, but the picked port don't -matter, so we use: -\skip gras_socket_server -\until gras_socket_server - -It will select a port between 1024 (ports below 1024 are reserved under -UNIX) and 10000. You can safely ignore the two last arguments for now and -pass 0. - -So, you now know how to create sockets allowing to receive messages. To send -messages, you have to create a so-called client socket. For this, use -\ref gras_socket_client with the hostname and the port of the process you -want to contact as arguments. Our client should simply do: - -\dontinclude 2-simple.c -\skip socket_client -\until socket_client - -The corresponding server socket must be opened before any client socket can -connect to it. It is thus safe to add a little delay before creating the -client socket. But you cannot use the classical sleep() function for this, -or you will delay the simulator in SG, not your processes. Use \ref -gras_os_sleep instead. - -\subsection GRAS_tut_tour_simpleexchange_exchange Actually exchanging messages - -GRAS offers a plenty of ways to communicate. The simple one is to use \ref -gras_msg_send on the sender side, and \ref gras_msg_wait on the receiver side. - -\ref gras_msg_send expects 3 arguments: the socket on which to send the -message, the message type, and a pointer to the actual content of the -message. The simplest way to retrive a message type from its name is to use -\ref gras_msgtype_by_name. Since we don't have any payload, this becomes: - -\dontinclude 2-simple.c -\skip msg_send -\until msg_send - -\ref gras_msg_wait accepts 4 arguments. The first one is the delay you are -disposed to wait for messages, while the the type of message you are -expecting. Then come output arguments. The third argument should be the -address of a gras_socket_t variable which will indicate who wrote the -message you received while the last argument is where to put the payload. - -Since our server is willing to wait up to 60 seconds for a message, the -following will do it: -\dontinclude 2-simple.c -\skip msg_wait -\until msg_wait - -\subsection GRAS_tut_tour_simpleexchange_recaping Recaping everything together - -Here is the complete code of this example. Note the use of the functions -\ref gras_socket_my_port, \ref gras_socket_peer_name and \ref -gras_socket_peer_port to retrieve information about who you are connected to. - -\include 2-simple.c - -Here is the output of the simulator. Note that \ref gras_socket_peer_port -actually returns the port number of the server of the peer. This may -sound a bit strange to BSD experts, but it is actually really useful: you -can store this value, and contact your peer afterward passing this number to -\ref gras_socket_client . -\include 2-simple.output - -Here we are, you now know how to exchange messages between peers. There is -still a large room for improvement, such as adding payload to messages. - - -(back to the top of the \ref GRAS_tut_tour) -
-\section GRAS_tut_tour_args Lesson 3: Passing arguments to the processes (in SG) - -The most problematic issue with the code of previous lesson is that it does -not work in RL since we hardcoded the server hostname in the client code. We -will thus learn you how to pass arguments to your processes to overcome this -situation. - -\subsection GRAS_tut_tour_args_use Using command line arguments from user code - -In RL, the situation is quite simple: we just have to use the command line -arguments as we would do in a usual C program. In the server, only change -concern the opennong of the master socket: -\dontinclude 3-args.c -\skip gras_socket_server -\until gras_socket_server - -In the client, we only need to change the way we open the client socket: -\skip gras_socket_client -\until gras_socket_client - -The rest of the program remains inchanged. - -\subsection GRAS_tut_tour_args_sg Passing command line arguments in deployment files - -At this point, the problem is to pass arguments to the processes in SG. -Fortunately, it is quite simple. You just have to edit your deployment file -so that it reads: \include 3-args.xml -The syntax should be self-explanatory at this point. - -\subsection GRAS_tut_tour_args_recap Recaping everything together - -The whole program now reads: -\include 3-args.c - -And here is the output: -\include 3-args.output - -(back to the top of the \ref GRAS_tut_tour) -
- -\section GRAS_tut_tour_callbacks Lesson 4: Attaching callbacks to messages - -Our program is well and good, but if we had to write a longer message, -explicitely waiting for messages of a given type would not be really -practical. To add some more dynamism, what we want to do is to attach -callbacks to the several messages types, and tell GRAS that we are ready to -deal with new messages. That's what we will do now. - -\subsection GRAS_tut_tour_callbacks_declare Declaring callbacks - -First of all, we define the callback we want to attach to the arrival of the -"hello" message on the server. Its signature is fixed: it accepts two -arguments of relative types gras_msg_cb_ctx_t ctx and void -*. The first one is a working context we should pass to GRAS when -speaking about the message we are handling while the second is the payload. -The callbackreturns an integer indicating whether we managed to deal with -the message. I admit that this semantic is a bit troublesome, it should be 0 -if we managed to deal properly with the message to mimic "main()" semantic. -That's historical, but I may change this in the future (no worry, I'll add -backward compatibility solutions). Here is the actual code of our callback: - -\dontinclude 4-callback.c -\skip gras_msg_cb_ctx_t -\until end_of_callback - -\subsection GRAS_tut_tour_callbacks_attach Attaching callbacks - -Then, we have to change the server code to use this callback instead of -gras_msg_wait. This simply done by a construct like the following: - -\skip cb_register -\until cb_register - -\subsection GRAS_tut_tour_callbacks_handle Handling incoming messages - -Once the callback is declared and attached, the server simply has to call -\ref gras_msg_handle to tell GRAS it's ready to handle for incoming -messages. The only argument is the maximum delay we are disposed to wait for -a message. If the delay is negative, the process will block until a message -arrives. With delay=0, the process just polls for already arrived messages, -but do not wait at all if none arrived yet. If the delay is greater than 0, -the process will wait for at most that amount of seconds. If a message -arrives in the meanwhile, it won't even wait that long. - -Sometimes, you want to handle all messages arriving in a given period -without really knowing how much messages will come (this is often the case -during the initialization phase of an algorithm). In that case, use \ref -gras_msg_handleall . It has the same prototype than \ref gras_msg_handle, -but waits exactly the passed delay, dealing with all the messages arriving -in the meanwhile. - -We have no such needs in our example, so the code simply reads: -\skip handle -\until handle - -\subsection GRAS_tut_tour_callback_recap Recaping everything together - -The whole program now reads: -\include 4-callback.c - -And here is the output (unchanged wrt previous version): -\include 4-callback.output - -Our little example turns slowly to a quite advanced GRAS program. It entails -most of the mecanism most program will use. - -(back to the top of the \ref GRAS_tut_tour) +During this tour, you will learn all you need to write your own GRAS +applications, from the installation of the framework to the use of (almost) +all features available in GRAS. + + \htmlonly \endhtmlonly + + - \ref GRAS_tut_tour_install + - \ref GRAS_tut_tour_setup + - \ref GRAS_tut_tour_simpleexchange + - \ref GRAS_tut_tour_args + - \ref GRAS_tut_tour_callbacks + - \ref GRAS_tut_tour_globals +
\section GRAS_tut_tour_todo TODO +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 @@ -446,3 +46,17 @@ most of the mecanism most program will use. - Lesson : Doing proper modules */ + +/** +@page GRAS_tut_tour_install Lesson 0: Installing GRAS + +Since GRAS is technically part of the SimGrid project, you have to install +SimGrid to install GRAS. Doing so is explained in the relevant FAQ section +(\ref faq_installation). + +Newcommers should install the stable release from the tarball, since the cvs +snapshots may suffer from (additionnal;) stability issues. Only go for the +CVS if you really need features not present in the stable releases yet (or +if you plan to help us improving the tool, what is always welcomed). + +*/ -- 2.20.1