diff --git a/legacy/ecore/doc/examples.dox b/legacy/ecore/doc/examples.dox index 5ee08a9d79..d7867a98b4 100644 --- a/legacy/ecore/doc/examples.dox +++ b/legacy/ecore/doc/examples.dox @@ -21,6 +21,7 @@ * @li @ref Ecore_Evas_Window_Sizes_Example_c * @li @ref Ecore_Evas_Buffer_Example_01_c * @li @ref Ecore_Evas_Buffer_Example_02_c + * @li @ref Ecore_exe_simple_example_c */ /** @@ -914,6 +915,20 @@ * See @ref ecore_timer_example_c "the example explained". */ +/** + * @example ecore_exe_example_child.c + * This is a child process used to receive messages and send it back + * to its father. + * Check the @ref Ecore_exe_simple_example_c "Full tutorial" + */ + +/** + * @example ecore_exe_example.c + * This is a process that will send messages to a child and it will stop + * when it receives "quit". + * Check the @ref Ecore_exe_simple_example_c "Full tutorial" + */ + /** * @example ecore_fd_handler_example.c * This example shows how to setup and use an fd_handler. See @@ -1527,3 +1542,128 @@ * @include ecore_evas_buffer_example_02.c * @example ecore_evas_buffer_example_02.c */ + +/** + * @page Ecore_exe_simple_example_c Ecore_exe + * Creating a processes and IPC (Inter process communication) + * + * In this example we will show how to create a new process and communicate + * with it in a portable way using the Ecore_exe module. + * + * In this example we will have two process and both will communicate with each + * other using messages. A father process will start a child process and it will + * keep sending messages to the child until it receives a message to quit. + * To see the full source use the links: + * @li @ref ecore_exe_example.c "Father" + * @li @ref ecore_exe_example_child.c "Child" + * + * Let's start the tutorial. The implementation of the child it's pretty simple. + * We just read strings from stdin and write a message in the stdout. But you + * should be asking yourself right know. "If I'm receiving data from an other + * process why I'm reading and writing in stdin/stdout?". That's because, when + * you spawn a process using the Ecore_Exe module it will create a pipe between + * the father and the child process and the stdin/stdout of the child process + * will be redirected to the pipe. So when the child wants to receive or send + * data to the father, just use the stdin/stdout. + * However the steps to send data from the father to the child is quite + * different, but we will get there. + * + * The child will register a fd handler to monitor the stdin. + * So we start registering the ecore FD handler: + * @dontinclude ecore_exe_example_child.c + * @skip ecore_main_fd_handler_add + * @until ; + * + * If you don't remenber the parameters of @ref ecore_main_fd_handler_add, + * please check its documentation. + * + * Now that we have our handler registered we will start the ecore's main loop: + * @skipline ecore_main_loop_begin + * + * Now let's take a look in the callback function. Its a simple function + * that will read from stdin 3 times and at the third time will say + * to the father: "quit". + * @dontinclude ecore_exe_example_child.c + * @skip static Eina_Bool + * @until } + * @until } + * @until } + * @until } + * + * You may notice that we are sending the messages to stdout, and our father + * will receive it. Also our string must have a "\n" because the string will + * be buffered in the pipe until it finds EOF or a "newline" in our case we + * won't have a EOF unless we close the pipe, so we use the "\n" char. + * + * One more thing, we use fflush(stdout) because probably our message won't + * fill our entire buffer and the father would never receive the message. So we + * use this function to flush the buffer and the father can receive as fast as + * possible. + * + * Now that we have our child ready, let's start our work in the father's source + * code. + * + * We start creating the child process like this: + * @dontinclude ecore_exe_example.c + * @skip childHandle = ecore_exe_pipe_run + * @until ; + * + * With the command above we are creating our child process, the first + * parameter is the command to be executed, the second are the pipe flags and + * in our case we will write and read in the pipe so we must say what we are + * doing in the pipe. You may notice the flag ECORE_EXE_PIPE_READ_LINE_BUFFERED, + * this means that reads are buffered until I find a newline. And the third + * parameter is data that we would like to send to the process in its creating. + * This case we are sending nothing, so just use NULL. + * + * Then we check if the process was created: + * @skip if + * @until } + * + * After this we get the PID of the child process and just print it in the screen. + * The PID stands for Process identification. This is just an internal + * identifier of your process: + * + * @skip childPid + * @until fprintf + * @until fprintf + * + * The way that Ecore_exe works is: when we want to read data sent from + * our child we must use an ecore event. + * So let's start register our event listener: + * @skipline ecore_event_handler_add + * + * Now to send messages to our child we will use a timer, so every 1 second we + * will send a message to the child. + * @skipline ecore_timer_add + * + * After all this we start the main loop. Now let's pass to the callback + * functions. + * + * Now we will see how we actually send the data and receive it. + * Let's start with _sendMessage: + * @dontinclude ecore_exe_example.c + * @skip _sendMessage(void *data) + * @until } + * + * We use ecore_exe_send to send data to the child process, it's pretty simple. + * To know what the parameters stands for, check the docs. + * + * @note The function @b ecore_exe_send will never block your program, also + * there is no partial send of the data. This means either the function will + * send all the data or it will fail. + * + * Now let's take a look in our event callback and see how we retrieve the + * messages. + * @dontinclude ecore_exe_example.c + * @skip static Eina_Bool + * @until } + * @until } + * + * It's just like an normal event, we get a reference to Ecore_Exe_Event_Data, + * extract the data and then show it in the screen. + * + * And that's it, after all it's not complicated to create a process and + * communicate with it. + * + */ diff --git a/legacy/ecore/src/examples/Makefile.am b/legacy/ecore/src/examples/Makefile.am index 11f2e492d6..00ea91df39 100644 --- a/legacy/ecore/src/examples/Makefile.am +++ b/legacy/ecore/src/examples/Makefile.am @@ -55,7 +55,9 @@ SRCS = \ ecore_evas_basics_example.c \ ecore_evas_buffer_example_01.c \ ecore_evas_buffer_example_02.c \ - ecore_evas_ews_example.c + ecore_evas_ews_example.c \ + ecore_exe_example.c \ + ecore_exe_example_child.c EXTRA_DIST = $(SRCS) \ $(srcdir)/red.png @@ -95,7 +97,9 @@ examples_PROGRAMS += \ ecore_evas_buffer_example_02 \ ecore_evas_ews_example \ ecore_client_bench \ - ecore_server_bench + ecore_server_bench \ + ecore_exe_example \ + ecore_exe_example_child ecore_con_lookup_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la ecore_con_url_headers_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la diff --git a/legacy/ecore/src/examples/ecore_exe_example.c b/legacy/ecore/src/examples/ecore_exe_example.c new file mode 100644 index 0000000000..c0a00f728b --- /dev/null +++ b/legacy/ecore/src/examples/ecore_exe_example.c @@ -0,0 +1,93 @@ +/** +Compile with gcc -o ecore_exe_example ecore_exe_example.c `pkg-config --cflags --libs ecore` +*/ + +#include +#include +#include + +#define BUFFER_SIZE 1024 + +static Eina_Bool +_msg_from_child_handler(void *data, int type, void *event) +{ + Ecore_Exe_Event_Data *dataFromProcess = (Ecore_Exe_Event_Data *)event; + char *msg = (char *) dataFromProcess->data; + + if (strcmp(msg, "quit") == 0) + { + fprintf(stdout, "My child said to me, QUIT!\n"); + ecore_main_loop_quit(); + } + else + fprintf(stdout, "I received a message from my child: %s\n", msg); + + return ECORE_CALLBACK_DONE; + +} + +static Eina_Bool +_sendMessage(void *data) +{ + static int numberOfMessages = 0; + Ecore_Exe *childHandle = (Ecore_Exe*) data; + char msg[BUFFER_SIZE]; + + sprintf(msg, " Message: %d\n", numberOfMessages); + numberOfMessages++; + + if (ecore_exe_send(childHandle, msg, strlen(msg)) != EINA_TRUE) + fprintf(stderr, "Could not send my name to the child\n"); + else + fprintf(stdout, + "I'm the father and I sent this message to the child: %s\n", msg); + + + + return ECORE_CALLBACK_RENEW; +} + +int +main(int argc, char **argv) +{ + pid_t childPid; + Ecore_Exe *childHandle; + + if (!ecore_init()) + goto exit; + + childHandle = ecore_exe_pipe_run("./ecore_exe_example_child", + ECORE_EXE_PIPE_WRITE | + ECORE_EXE_PIPE_READ_LINE_BUFFERED | + ECORE_EXE_PIPE_READ, NULL); + + if (childHandle == NULL) + { + fprintf(stderr, "Could not create a child process!\n"); + goto ecore_shutdown; + } + + childPid = ecore_exe_pid_get(childHandle); + + if (childPid == -1) + fprintf(stderr, "Could not retrive the PID!\n"); + else + fprintf(stdout, "The child process has PID:%d\n", childPid); + + ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _msg_from_child_handler, NULL); + ecore_timer_add(1, _sendMessage, childHandle); + + ecore_main_loop_begin(); + + ecore_exe_free(childHandle); //This will not affect the child process + + ecore_shutdown(); + + return EXIT_SUCCESS; + +ecore_shutdown: + ecore_shutdown(); + +exit: + return EXIT_FAILURE; +} diff --git a/legacy/ecore/src/examples/ecore_exe_example_child.c b/legacy/ecore/src/examples/ecore_exe_example_child.c new file mode 100644 index 0000000000..332b66f1f5 --- /dev/null +++ b/legacy/ecore/src/examples/ecore_exe_example_child.c @@ -0,0 +1,57 @@ +/** + Compile with gcc -o ecore_exe_example_child ecore_exe_example_child.c `pkg-config --cflags --libs ecore` +*/ + +#include +#include +#include + + +#define BUFFER_SIZE 1024 + +static Eina_Bool +_fd_handler_cb(void *data, Ecore_Fd_Handler + *fd_handler) +{ + static int numberOfMessages = 0; + char message[BUFFER_SIZE]; + + fgets(message, BUFFER_SIZE, stdin); + + numberOfMessages++; + + if (numberOfMessages < 3) + { + fprintf(stdout, "My father sent this message to me:%s\n", message); + fflush(stdout); + return ECORE_CALLBACK_RENEW; + } + else + { + fprintf(stdout, "quit\n"); + fflush(stdout); + ecore_main_loop_quit(); + return ECORE_CALLBACK_DONE; + } +} + +int +main(int argc, char **argv) +{ + + if (!ecore_init()) + goto error; + + ecore_main_fd_handler_add(STDIN_FILENO, + ECORE_FD_READ, + _fd_handler_cb, + NULL, NULL, NULL); + ecore_main_loop_begin(); + + ecore_shutdown(); + + return EXIT_SUCCESS; + +error: + return EXIT_FAILURE; +} diff --git a/legacy/ecore/src/lib/ecore/Ecore.h b/legacy/ecore/src/lib/ecore/Ecore.h index 2e93edffa1..7aaf6b9c31 100644 --- a/legacy/ecore/src/lib/ecore/Ecore.h +++ b/legacy/ecore/src/lib/ecore/Ecore.h @@ -838,9 +838,13 @@ EAPI void *ecore_event_current_event_get(void); * @defgroup Ecore_Exe_Group Process Spawning Functions * * This module is responsible for managing portable processes using Ecore. - * With this module you're able to spawn processes and you also can pause, quit your spawned processes - * An interaction between your process and those spawned is possible using pipes or signals. + * With this module you're able to spawn processes and you also can pause, + * quit your spawned processes. + * An interaction between your process and those spawned is possible + * using pipes or signals. * + * Example + * @li @ref Ecore_exe_simple_example_c * * @ingroup Ecore_Main_Loop_Group * diff --git a/legacy/ecore/src/lib/ecore/ecore_exe.c b/legacy/ecore/src/lib/ecore/ecore_exe.c index 719bc17542..7931a96c35 100644 --- a/legacy/ecore/src/lib/ecore/ecore_exe.c +++ b/legacy/ecore/src/lib/ecore/ecore_exe.c @@ -368,6 +368,10 @@ ecore_exe_run_priority_get(void) * Spawns a child process. * * This is now just a thin wrapper around ecore_exe_pipe_run() + * @note When you use this function you will have no permissions + * to write or read on the pipe that connects you with the spwaned process. + * If you need to do that use ecore_exe_pipe_run() with the + * appropriated flags. * * @param exe_cmd The command to run with @c /bin/sh. * @param data Data to attach to the returned process handle.