Updated the README and Practical guide so that they have instructions
[barrelfish] / doc / 018-Practical-guide / helloWorldApp.tex
1
2 \section{Writing A Sample Barrelfish Application}
3
4 Here we show how to write a simple program on Barrelfish.  \textbf{XXX:} no
5 error handling yet.  Refer to \texttt{usr/tests/idctest} for code with proper
6 error handling.
7
8 \subsection{A Simple Hello World Program}
9
10 The source for user domains is stored under \begin{verbatim}/usr\end{verbatim}.
11
12 A simple hello world domain consists of a source file, and a Hakefile. e.g.,
13 \begin{verbatim}
14 usr/myapp
15     myapp.c
16     Hakefile
17 \end{verbatim}
18
19 For a simple hello world app, the source is trivial: a simple printf in main
20 will suffice (note that for output printf either uses a debug syscall to print
21 to the serial output, or a proper serial server if one is available).
22
23 \begin{verbatim}
24 #include <stdio.h>
25 int main(void) {
26     printf("Hello World\n");
27     return 0;
28 }
29 \end{verbatim}
30
31 To build the domain, call hake.sh in the build directory. This will create a
32 Config.hs, Makefile, and symbolic\_targets.mk. You can add myapp in the
33 symbolic\_tagets, then run make to build everything. You can also explicitly ask
34 make to build the domain. e.g.:
35 \begin{verbatim}
36 make x86_64/sbin/myapp
37 \end{verbatim}
38
39 After all is built, the menu.lst needs to be modified to add the domain and have
40 it started. Run everything in a simulator using:
41
42 \begin{verbatim}
43 make sim
44 \end{verbatim}
45
46 \section{A Simple Hello World Program Using IDC}
47
48 In this section, we talk how we can write an application that uses Barrelfish
49 IDC mechanism to communicate with other applications.  For purpose of this
50 section, we will develop simple \textbf{Hello World} client and server
51 application.  The client running on core-0 will send an IDC message to a
52 server running on core-1.  This message will contain a string with contents
53 \texttt{"Hello World"}.
54
55 Adding IDC (inter-dispatcher communication) is a bit more complicated. It
56 requires defining an interface in Flounder IDL, updating the interfaces
57 Hakefile, updating the domain's (myapp) Hakefile, and then adding initialization
58 code as well as appropriate callbacks to the source file.
59
60 \begin{figure}
61   \begin{center}
62     \includegraphics[width=0.8\columnwidth]{helloWorld2.pdf}
63   \end{center}
64   \caption{Hello world application overview}
65   \label{fig:helloWorld}
66 \end{figure}
67
68 \subsection{Interface}
69
70 In this subsection, we will create a new interface
71 for our use.  We do this by creating a new interface file called
72 \texttt{hello.if} in the \texttt{if\\} directory. Following is simple interface
73 that will suffice for our requirements of sending single string as a message.
74
75
76 \verbatiminput{if/hello.if}
77 \begin{verbatim}
78 interface hello "Hello World interface" {
79     message hello_msg(string s);
80 };
81 \end{verbatim}
82
83 You can find out more about how to write such interfaces by referring
84 \href{http://www.barrelfish.org/TN-011-IDC.pdf}{IDC-Technote}.
85
86 You also need to modify the \texttt{if/Hakefile} to add this newly created
87 interface into the compilation process.
88
89 \begin{verbatim}
90 [ flounderGenDefs (options arch) f
91       | f <- [ "ahci_mgmt",
92                 ...
93                 ...
94                "hello"],
95              arch <- allArchitectures
96 ] ++
97 \end{verbatim}
98
99 Adding the name of your interface here will make sure that the communication
100 stubs will be automatically generated for by the compilation process.  These
101 can be found in following location in your build directory:
102
103 \begin{verbatim}
104 BUILD/ARCH/include/if/hello_defs.h
105 BUILD/ARCH/include/if/hello_lmp_defs.h
106 BUILD/ARCH/include/if/hello_ump_defs.h
107 BUILD/ARCH/include/if/hello_multihop_defs.h
108 \end{verbatim}
109
110 There will be one for each type of communication mechanism supported by
111 the Barrelfish. You don't need to worry about these files as build mechanism
112 will take care of these files.  Only things developers need to do is
113 write the interface file and include appropriate headers in the application
114 code (discussed in following section)
115
116
117 \subsection{Application}
118
119 In this section, we discuss how would we write the application code,
120 and how to compile it.  For sake of simplicity, we will write both server and
121 client code in same application.  Following is the code for the \texttt{main}
122 function, which runs the client code or server code based on the
123 command line argument.
124
125
126 \begin{verbatim}
127 int main(int argc, char *argv[]) {
128     errval_t err;
129     if ((argc >= 2) && (strcmp(argv[1], "client") == 0)) {
130         start_client();
131     } else if ((argc >= 2) && (strcmp(argv[1], "server") == 0)) {
132         start_server();
133     } else {
134         return EXIT_FAILURE;
135     }
136     /* The dispatch loop */
137     struct waitset *ws = get_default_waitset();
138     while (1) {
139         err = event_dispatch(ws); /* get and handle next event */
140         if (err_is_fail(err)) {
141             DEBUG_ERR(err, "in event_dispatch");
142             break;
143         }
144     }
145     return EXIT_FAILURE;
146 }
147 \end{verbatim}
148
149 The important part of the above is in the dispatch loop where application
150 will wait for events on the default wait-set and handle those events
151 in infinite while loop.
152
153 \subsection{Server side}
154
155 In this section, we will develop the server code in steps of
156 "exporting service", "registering the service" and "handling actual requests".
157
158
159 \subsubsection{Exporting service}
160 As a first step, server needs to export the service it wants to provide
161 by calling export function on the service interface.  In this case, server
162 will call \texttt{hello\_export} as we are providing \textit{Hello World}
163 service.
164
165 \begin{verbatim}
166 static void start_server(void)
167 {
168     errval_t err;
169     err = hello_export(NULL /* state for callbacks */,
170             export_cb, /* Callback for export */
171             connect_cb,  /* Callback for client connects */
172             get_default_waitset(), /* waitset where events will be sent */
173             IDC_EXPORT_FLAGS_DEFAULT);
174     if (err_is_fail(err)) {
175         USER_PANIC_ERR(err, "export failed");
176     }
177 }
178 \end{verbatim}
179
180 This call also registers two callback handles.  Once the service
181 is successfully exported, then the export callback provided.  When any client
182 connects with the service then the connect callback will be called.
183 We will see the use of these callbacks in next few steps.
184
185
186 \subsubsection{Registering service}
187 Server also need to register the service so that other applications can find
188 it.  Following code registers the \texttt{"hello\_service"} on the callback
189 from successful completion of export:
190
191
192 \begin{verbatim}
193 const static char *service_name = "hello_service";
194 static void export_cb(void *st, errval_t err, iref_t iref)
195 {
196     if (err_is_fail(err)) {
197         USER_PANIC_ERR(err, "export failed");
198     }
199     err = nameservice_register(service_name, iref);
200     if (err_is_fail(err)) {
201         USER_PANIC_ERR(err, "nameservice_register failed");
202     }
203 }
204 \end{verbatim}
205
206 The \texttt{nameservice\_register} is a blocking call which will connect
207 to the global nameserver and publish the service name.
208
209 \subsubsection{Connect and handling messages}
210 This section describes how exactly the connection is established and
211 requests are handled.
212
213 \begin{verbatim}
214 static void rx_hello_msg(struct hello_binding *b, char *str)
215 {
216     printf("server: received hello_msg:\n\t%s\n", str);
217     free(str);
218 }
219
220 static struct hello_rx_vtbl rx_vtbl = {
221     .hello_msg = rx_hello_msg,
222 };
223
224 static errval_t connect_cb(void *st, struct hello_binding *b)
225 {
226     b->rx_vtbl = rx_vtbl;
227     return SYS_ERR_OK;
228 }
229 \end{verbatim}
230
231 The above code defines a function \texttt{rx\_hello\_msg} which will be
232 responsible to actually handle the requests.  In our case, we are just
233 printing out the string we received as part of the message.
234
235 We need to create a list of function pointers where one function pointer
236 is assigned for every possible incoming message. So we are creating
237 an instance \texttt{rx\_vtbl} of type \texttt{hello\_rx\_vtbl}.
238
239 On arrival of new connection, we provide this list of function pointers
240 to register which functions to call for handling particular type of message.
241
242
243 \subsection{Client side}
244 Client needs to find the service and connect to it.  Once the connection
245 is successfully established then it can send the actual requests. In this
246 section, we show how it can be done.
247
248
249 \subsubsection{Find and Bind}
250 Following code finds the desired service with given name and binds with
251 the service.
252
253 \begin{verbatim}
254 static void start_client(void)
255 {
256     errval_t err;
257     iref_t iref;
258     err = nameservice_blocking_lookup(service_name,
259             &iref);
260     if (err_is_fail(err)) {
261         USER_PANIC_ERR(err,
262                 "nameservice_blocking_lookup failed");
263     }
264     err = hello_bind(iref, bind_cb, /* Callback function */
265             NULL /* State for the callback */,
266             get_default_waitset(),
267             IDC_BIND_FLAGS_DEFAULT);
268     if (err_is_fail(err)) {
269         USER_PANIC_ERR(err, "bind failed");
270     }
271 }
272 \end{verbatim}
273
274 As the name suggests  \texttt{nameservice\_blocking\_lookup} is a blocking
275 call which will connect with the nameserver and query for the given
276 service name.  The \texttt{iref} handle returned by this call can be used
277 for binding with the service.
278
279 The \texttt{hello\_bind} is part of the code generated from the interface
280 file and will try and connect with the server on appropriate channel.
281
282 Following code is callback function which will be called when client
283 successfully connects with the server.  This code also creates a client
284 state which stores pointer to the communication channel binding.  This code
285 then calls a function \texttt{run\_client} with the client state.
286
287
288 \begin{verbatim}
289 struct client_state {
290     struct hello_binding *binding;
291     int count;
292 };
293
294 static void bind_cb(void *st, errval_t err, struct hello_binding *b)
295 {
296     struct client_state *myst = malloc(sizeof(struct client_state));
297     assert(myst != NULL);
298     myst->binding = b;
299     myst->count = 0;
300     run_client(myst);   /* calling run_client for first time */
301 }
302 \end{verbatim}
303
304
305 \subsubsection{Sending messages}
306
307 Most of the actual work of sending message is done from the \texttt{run\_client}
308 function which is described bellow:
309
310 \begin{verbatim}
311 static void run_client(void *arg)
312 {
313     errval_t err;
314     struct client_state *myst = arg;
315     struct hello_binding *b = myst->binding;
316
317     /* Creating a continuation which will call run_client */
318     struct event_closure txcont = MKCONT(run_client, myst);
319
320     err = b->tx_vtbl.hello_msg(b, txcont, "Hello World");
321     if (err_is_fail(err)) {
322         DEBUG_ERR(err, "error sending message %d\n", myst->count);
323     }
324 }
325 \end{verbatim}
326
327 This function first creates a continuation which calls itself
328 and will be used as a callback function. The next step is to actually
329 send the message by calling an appropriate function on the send side of
330 interface binding (\texttt{tx\_vtbl.hello\_msg}) with actual message
331 and above created continuation.  This call will register a message to be sent
332 and a callback that will be triggered when message is successfully.
333
334 As you can notice, callback function is calling \texttt{run\_client} again,
335 leading an infinite loop of sending messages.
336
337 \subsubsection{Include files}
338
339 Following is a typical set of include files that you will need to add
340 in your code.
341
342 \begin{verbatim}
343 #include <stdio.h>
344 #include <barrelfish/barrelfish.h>
345 #include <barrelfish/nameservice_client.h>
346 #include <if/hello_defs.h>
347 \end{verbatim}
348
349 The \texttt{barrelfish.h} file contains declaration of
350 functionalities related to Barrelfish OS (eg: system calls, capability
351 system related functionalities, etc.)
352 \texttt{nameservice\_client.h} file provides declarations for functions related
353 to registering and looking up services.  The \texttt{hello\_defs.h} file
354 includes the declarations for automatically generated code to support
355 \texttt{if/hello.if} interface.
356
357
358 \subsection{Building and running the application}
359
360 In this section, we talk about how build your application.  For this, you
361 will need to create a \texttt{Hakefile} in the code directory which should
362 look something like bellow:
363
364 \begin{verbatim}
365     [ build application { target = "hello-cs",
366                           cFiles = [ "hello.c" ],
367                           flounderBindings = [ "hello" ]
368                         }
369     ]
370 \end{verbatim}
371
372 This \texttt{Hakefile} specifies that you want to build an application
373 with name \texttt{hello\-cs} from the \texttt{hello.c} file, and also
374 it marks the dependency on the communication interface \texttt{hello}.
375
376 The next step is to modify the \texttt{barrelfish/hake/symbolic\_targets.mk}
377 file to include your newly created application into the build process.
378 Here you can choose an architecture for which your application should be
379 compiled, or you can also add your application in \texttt{MODULES\_COMMON}
380 list so that your application will be compiled for all architectures.
381
382 \begin{verbatim}
383 MODULES_COMMON= \
384         sbin/init_null \
385         ...
386         ...
387         sbin/xcorecapbench \
388         sbin/hello-cs \
389
390 \end{verbatim}
391
392 After this, rebuild the Barrelfish to include newly added application.  On
393 successful compilation the binary will be created in sbin directory of
394 desired architecture.
395
396
397 % ########### Editing menu.lst
398 Next step is to edit one of the \texttt{barrelfish/hake/menu.lst.*} file based
399 on which architecture you are targeting.  Bellow is the minimal
400 \texttt{menu.lst.x86\_64} file to be able to run this newly created application.
401
402 \begin{verbatim}
403 title   Barrelfish
404 root    (nd)
405 kernel  /x86_64/sbin/elver loglevel=4
406 module  /x86_64/sbin/cpu loglevel=4
407 module  /x86_64/sbin/init
408
409 # Domains spawned by init
410 module  /x86_64/sbin/mem_serv
411 module  /x86_64/sbin/monitor
412
413 # Special boot time domains spawned by monitor
414 module  /x86_64/sbin/ramfsd boot
415 module  /x86_64/sbin/skb boot
416 modulenounzip /skb_ramfs.cpio.gz nospawn
417 module  /x86_64/sbin/kaluga boot
418 module  /x86_64/sbin/acpi boot
419 module  /x86_64/sbin/spawnd boot
420 #bootapic-x86_64=1-15
421 module  /x86_64/sbin/startd boot
422 module /x86_64/sbin/routing_setup boot
423
424 # Drivers
425 module /x86_64/sbin/pci auto
426 module /x86_64/sbin/ahcid auto
427
428 # General user domains
429 module  /x86_64/sbin/serial
430
431 # Your hello world application (both server and client)
432 module /x86_64/sbin/hello-cs core=0 server
433 module /x86_64/sbin/hello-cs core=1 client
434 \end{verbatim}
435
436 Now, you can build your application and verify that binary is created as
437 follows:
438
439 \begin{verbatim}
440 $ make
441 $ ls x86_64/sbin/hello-cs
442 \end{verbatim}
443
444 If everything goes fine, you can run the application in \texttt{qemu} simulator
445 with following command:
446 \begin{verbatim}
447 $ make sim
448 \end{verbatim}
449
450 At this moment, you should be able see Barrelfish booting and starting your
451 applications which are then able to communicate by sending "Hello World"
452 message in infinite loop.  Following is a sample output that you may expect
453 while running this setup.
454
455 \begin{verbatim}
456 ...
457 ...
458 ...
459 startd.0: starting app /x86_64/sbin/hello-cs on core 0
460 spawnd.0: spawning /x86_64/sbin/hello-cs on core 0
461 startd.0: starting app /x86_64/sbin/hello-cs on core 1
462 skb.0: waiting for: spawn.1
463 skb.0: waiting for: pci
464 spawnd.0: spawning /x86_64/sbin/ahcid on core 0
465 kernel: 0: installing handler for IRQ 1
466 kernel: 0: installing handler for IRQ 2
467 pci_client.c: got vector 2
468 ahcid: registered device 8086:2922
469 spawnd.1: spawning /x86_64/sbin/hello-cs on core 1
470 No bootscript
471 server: received hello_msg:
472         Hello World
473 server: received hello_msg:
474         Hello World
475 server: received hello_msg:
476         Hello World
477 server: received hello_msg:
478         Hello World
479 server: received hello_msg:
480         Hello World
481 server: received hello_msg:
482         Hello World
483 ...
484 ...
485 ...
486 \end{verbatim}
487
488