Show Contents Previous Page Next Page Chapter 11 - C API Reference Guide, Part II / Launching Subprocesses We are going to say "Goodbye World" now but this time in a very big way. We will add a "goodbye-banner" handler to mod_hello. This handler will run the Unix banner command to print out a large, vertically oriented "Goodbye World" message. Although this is a very simple example compared to what happens inside mod_cgi, it does show you everything you need to write basic fork/exec code. For advanced tricks and subtleties, we recommend you peruse the source code for mod_cgi and mod_include. The additions to mod_hello.c are shown in Example 11-6. At the top, we add util_script.h to the list of included files and hardcode the absolute path to the banner program in the #define BANNER_PGM. Example 11-6. Additions to mod_hello.c to Launch a Child Process #include "util_script.h" #define BANNER_PGM "/usr/bin/banner" /* Forward declaration so that ap_get_module_config() can find us. */ module hello_module; static int banner_child(void *rp, child_info *pinfo) { char **env; int child_pid; request_rec *r = (request_rec *)rp; env = ap_create_environment(r->pool, r->subprocess_env); ap_error_log2stderr(r->server); r->filename = BANNER_PGM; r->args = "-w80+Goodbye%20World"; ap_cleanup_for_exec(); child_pid = ap_call_exec(r, pinfo, r->filename, env, 0); #ifdef WIN32 return(child_pid); #else ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", r->filename); static int goodbye_banner_handler(request_rec *r) { BUFF *pipe_output; if (!ap_bspawn_child(r->pool, banner_child, (void *) r, kill_after_timeout, NULL, &pipe_output, NULL)) { ap_log_error(APLOG_MARK, APLOG_ERR, r->server, "couldn't spawn child process: %s", BANNER_PGM); return HTTP_INTERNAL_SERVER_ERROR; } r->content_type = "text/plain"; ap_send_http_header(r); ap_send_fb(pipe_output, r); ap_bclose(pipe_output); return OK; } static handler_rec hello_handlers[] = { {"hello-handler", hello_handler}, {"goodbye-banner-handler", goodbye_banner_handler}, {NULL} };
Skipping over the definition of banner_child() for now, look at goodbye_banner_handler(). This is the content handler for the request. We are going to access the output of the banner command, so we declare a
If ap_bspawn_child() succeeds, there will now be two processes. In the child process, ap_bspawn_child() immediately invokes the banner_child() function, which we will examine momentarily. In the parent process, ap_bspawn_child() returns the process ID of the child. If it encounters an error it will return 0, and the parent logs an error and returns
The remainder of what we have to do in the handler is simple. We set the outgoing response's content type to text/plain and send the HTTP header with ap_send_http_header(). Next we forward the child process's output to the browser by calling ap_send_fb(), which reads from the child and sends to the client in a single step. When this is done, we clean up by closing
The banner_child() function is called within the child spawned by ap_bspawn_child(). We're going to set up the environment, do a little cleanup, and then replace the process with the banner program. We begin by recovering the request record and passings its We want to call banner as if it had been invoked by this command at the shell: % banner -w80 "Goodbye World"
This specifies a banner 80 characters wide with a message of "Goodbye World". To do this, we place the command's full path in the request record's
Before we launch banner we should invoke any cleanup handlers that have been registered for the current request. We do so by calling ap_cleanup_for_exec(). Now we call ap_call_exec() to run banner, passing the routine the request record, the If all goes well, the next line is never reached on Unix platforms. But if for some reason Apache couldn't exec the banner program, we log an error and immediately exit. The return statement at the end of the routine is never reached but is there to keep the C compiler from generating a warning. As noted above, ap_call_exec() behaves differently on Win32 platforms because the function launches a new process rather than overlaying the current one. We handle this difference with conditional compilation. If the Win32 define is present, banner_child() returns the process ID generated by ap_call_exec(). We do this even though it isn't likely that the banner program will ever be ported to Windows platforms!
There's only one thing more to do to make the goodbye_banner_handler() available for use, which is to add it and a symbolic handler name to the <Location /goodbye> SetHandler goodbye-banner-handler </Location> Figure 11-1 shows our handler in action, and this seems to be a good place to say goodbye as well. Figure 11-1. "goodbye-banner-handler" re-creates a burst page from a circa-1960 line printer. Footnotes 4 Note that the source code for ap_call_exec() refers to the return value as the "pid." This is misleading. Show Contents Previous Page Next PageCopyright © 1999 by O'Reilly & Associates, Inc. |
HIVE: All information for read only. Please respect copyright! |