You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by Rodent of Unusual Size <co...@hyperreal.com> on 1997/05/05 12:47:10 UTC

cvs commit: apache/src/modules/example mod_example.c

coar        97/05/05 03:47:09

  Modified:    src/modules/example  mod_example.c
  Log:
  	Latest cure for memory bloat; some additional documentation about
  	read-only nature of module configuration records and command-handler
  	return values; display broken into `static' and `this-request'
  	segments.
  
  Revision  Changes    Path
  1.9       +201 -60   apache/src/modules/example/mod_example.c
  
  Index: mod_example.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/modules/example/mod_example.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -C3 -r1.8 -r1.9
  *** mod_example.c	1997/04/22 15:52:06	1.8
  --- mod_example.c	1997/05/05 10:47:08	1.9
  ***************
  *** 83,88 ****
  --- 83,94 ----
     * both, though, so the handlers need to be able to tell them apart.  One
     * possibility is for both structures to start with an int which is zero for
     * one and 1 for the other.
  +  *
  +  * Note that while the per-directory and per-server configuration records are
  +  * available to most of the module handlers, they should be treated as
  +  * READ-ONLY by all except the command and merge handlers.  Sometimes handlers
  +  * are handed a record that applies to the current location by implication or
  +  * inheritance, and modifying it will change the rules for other locations.
     */
    typedef struct example_config {
        int	    cmode;	/* Environment to which record applies (directory,  */
  ***************
  *** 99,107 ****
    /*
     * Let's set up a module-local static cell to point to the accreting callback
     * trace.  As each API callback is made to us, we'll tack on the particulars
  !  * to whatever we've already recorded.
     */
    static char *trace = NULL;
    
    /*
     * To avoid leaking memory from pools other than the per-request one, we
  --- 105,117 ----
    /*
     * Let's set up a module-local static cell to point to the accreting callback
     * trace.  As each API callback is made to us, we'll tack on the particulars
  !  * to whatever we've already recorded.  To avoid massive memory bloat as
  !  * directories are walked again and again, we record the routine/environment
  !  * the first time (non-request context only), and ignore subsequent calls for
  !  * the same routine/environment.
     */
    static char *trace = NULL;
  + static table *static_calls_made = NULL;
    
    /*
     * To avoid leaking memory from pools other than the per-request one, we
  ***************
  *** 261,296 ****
    }
    
    /*
  !  * This routine is used to add a trace of a callback to the list.  We're
  !  * passed the server record (if available), an allocation pool, a pointer to
  !  * our private configuration record (if available) for the environment to
  !  * which the callback is supposed to apply, and some text.  We turn this into
  !  * a textual representation and add it to the tail of the list.  The list can
  !  * be displayed by the example_handler() routine.
     */
  ! static void trace_add
  ! 	(server_rec *s, example_config *mconfig, const char *note) {
    
  !     char    *sofar;
  !     char    *addon;
  !     char    *where;
  !     pool    *subpool;
    
        /*
  !      * Make a new sub-pool and copy any existing trace to it.
         */
  !     subpool = make_sub_pool (example_pool);
  !     if (trace != NULL) {
  ! 	addon = pstrcat (subpool, trace, NULL);
  !     }
        /*
  !      * Now, if we have a sub-pool from before, nuke it and replace with the
  !      * one we just allocated.
         */
  !     if (example_subpool != NULL) {
  ! 	destroy_pool (example_subpool);
        }
  -     example_subpool = subpool;
        /*
         * If we weren't passed a configuration record, we can't figure out to
         * what location this call applies.  This only happens for co-routines
  --- 271,405 ----
    }
    
    /*
  !  * Likewise for our configuration record for the specified request.
     */
  ! static example_config *our_rconfig
  ! 	(request_rec *r) {
    
  !     return (example_config *) get_module_config
  ! 				(
  ! 				    r->request_config,
  ! 				    &example_module
  ! 				);
  ! }
    
  + /*
  +  * This routine sets up some module-wide cells if they haven't been already.
  +  */
  + static void setup_module_cells () {
        /*
  !      * If we haven't already allocated our module-private pool, do so now.
         */
  !     if (example_pool == NULL) {
  ! 	example_pool = make_sub_pool (NULL);
  !     };
        /*
  !      * Likewise for the table of routine/environment pairs we visit outside of
  !      * request context.
         */
  !     if (static_calls_made == NULL) {
  ! 	static_calls_made = make_table (example_pool, 16);
  !     };
  ! }
  ! 
  ! /*
  !  * This routine is used to add a trace of a callback to the list.  We're
  !  * passed the server record (if available), the request record (if available),
  !  * a pointer to our private configuration record (if available) for the
  !  * environment to which the callback is supposed to apply, and some text.  We
  !  * turn this into a textual representation and add it to the tail of the list.
  !  * The list can be displayed by the example_handler() routine.
  !  *
  !  * If the call occurs within a request context (i.e., we're passed a request
  !  * record), we put the trace into the request pool and attach it to the
  !  * request via the request_config mechanism.  Otherwise, the trace gets added
  !  * to the static (non-request-specific)  list.
  !  *
  !  * Note that this method is not a formal part of the API.  The use of the
  !  * request_config field in the request_rec record is not currently defined.
  !  * However, the only defined method of maintaining per-request information,
  !  * the r->notes table, is string-oriented and can't conveniently handle
  !  * arbitrary data.
  !  *
  !  * In any other context, what we're doing here - accessing components outside
  !  * our scope, like the main request - would be considered a technical
  !  * violation of the API.  However, we can do what we want with undefined
  !  * aspects, as long as we're prepared for them to have undefined results.
  !  */
  ! static void trace_add
  ! 	(server_rec *s, request_rec *r, example_config *mconfig,
  ! 	 const char *note) {
  ! 
  !     char    *sofar;
  !     char    *addon;
  !     char    *where;
  !     pool    *p;
  !     char    **ctrace;
  !     request_rec
  ! 	    *req = r;
  !     example_config
  ! 	    *rconfig;
  ! 
  !     /*
  !      * Make sure our pools and tables are set up - we need 'em.
  !      */
  !     setup_module_cells ();
  !     /*
  !      * Now, if we're in request-context, we use the request pool.
  !      */
  !     if (r != NULL) {
  ! 	/*
  ! 	 * Make sure that we're storing our trace in the main request; we want
  ! 	 * to track all activities for subrequests as well.
  ! 	 */
  ! 	if (req->main != NULL) {
  ! 	    req = req->main;
  ! 	}
  ! 	p = req->pool;
  ! 	/*
  ! 	 * Find our per-request configuration record, which holds the trace
  ! 	 * of activities specific to the request  itself.
  ! 	 */
  ! 	rconfig = (example_config *) get_module_config
  ! 					(req->request_config, &example_module);
  ! 	/*
  ! 	 * If there isn't one, create one and add it.
  ! 	 */
  ! 	if (rconfig == NULL) {
  ! 	    rconfig = pcalloc (req->pool, sizeof(example_config));
  ! 	    set_module_config (req->request_config, &example_module, rconfig);
  ! 	    rconfig->trace = NULL;
  ! 	}
  ! 	/*
  ! 	 * Note that the trace data from this call go into the per-request
  ! 	 * list, not the static one.
  ! 	 */
  ! 	 ctrace = &rconfig->trace;
  !     } else {
  ! 	/*
  ! 	 * We're not in request context, so the trace gets attached to our
  ! 	 * module-wide pool.  We do the create/destroy every time we're called
  ! 	 * in non-request context; this avoids leaking memory in some of
  ! 	 * the subsequent calls that allocate memory only once (such as the
  ! 	 * key formation below).
  ! 	 *
  ! 	 * Make a new sub-pool and copy any existing trace to it.  Point the
  ! 	 * trace cell at the copied value.
  ! 	 */
  ! 	p = make_sub_pool (example_pool);
  ! 	if (trace != NULL) {
  ! 	    trace = pstrdup (p, trace);
  ! 	}
  ! 	/*
  ! 	 * Now, if we have a sub-pool from before, nuke it and replace with
  ! 	 * the one we just allocated.
  ! 	 */
  ! 	if (example_subpool != NULL) {
  ! 	    destroy_pool (example_subpool);
  ! 	}
  ! 	example_subpool = p;
  ! 	ctrace = &trace;
        }
        /*
         * If we weren't passed a configuration record, we can't figure out to
         * what location this call applies.  This only happens for co-routines
  ***************
  *** 300,308 ****
         */
        where = (mconfig != NULL) ? mconfig->loc : "nowhere";
        where = (where != NULL) ? where : "";
        addon = pstrcat 
    		(
  ! 		    subpool,
    		    "   <LI>\n",
    		    "    <DL>\n",
    		    "     <DT><SAMP>",
  --- 409,439 ----
         */
        where = (mconfig != NULL) ? mconfig->loc : "nowhere";
        where = (where != NULL) ? where : "";
  +     /*
  +      * Now, if we're not in request context, see if we've been called with
  +      * this particular combination before.  The table is allocated in the
  +      * module's private pool, which doesn't get destroyed.
  +      */
  +     if (req == NULL) {
  + 	char	*key;
  + 
  + 	key = pstrcat (p, note, ":", where, NULL);
  + 	if (table_get (static_calls_made, key) != NULL) {
  + 	    /*
  + 	     * Been here, done this.
  + 	     */
  + 	    return;
  + 	} else {
  + 	    /*
  + 	     * First time for this combination of routine and environment -
  + 	     * log it so we don't do it again.
  + 	     */
  + 	    table_set (static_calls_made, key, "been here");
  + 	}
  +     }
        addon = pstrcat 
    		(
  ! 		    p,
    		    "   <LI>\n",
    		    "    <DL>\n",
    		    "     <DT><SAMP>",
  ***************
  *** 317,332 ****
    		    "   </LI>\n",
    		    NULL
    		);
  !     sofar = (trace == NULL) ? "" : trace;
  !     trace = pstrcat (subpool, sofar, addon, NULL);
  !     /*
  !      * Store a copy of the same information in the configuration record, if
  !      * there is one.
  !      */
  !     if (mconfig != NULL) {
  ! 	sofar = (mconfig->trace == NULL) ? "" : mconfig->trace;
  ! 	mconfig->trace = pstrcat (subpool, sofar, addon, NULL);
  !     }
        /*
         * You *could* uncomment the following if you wanted to see the calling
         * sequence reported in the server's error_log, but beware - almost all of
  --- 448,455 ----
    		    "   </LI>\n",
    		    NULL
    		);
  !     sofar = (*ctrace == NULL) ? "" : *ctrace;
  !     *ctrace = pstrcat (p, sofar, addon, NULL);
        /*
         * You *could* uncomment the following if you wanted to see the calling
         * sequence reported in the server's error_log, but beware - almost all of
  ***************
  *** 341,347 ****
    }
    
    /*--------------------------------------------------------------------------*/
  - /*									    */
    /* We prototyped the various syntax for command handlers (routines that     */
    /* are called when the configuration parser detects a directive declared    */
    /* by our module) earlier.  Now we actually declare a "real" routine that   */
  --- 464,469 ----
  ***************
  *** 351,356 ****
  --- 473,485 ----
    /* If a command handler encounters a problem processing the directive, it   */
    /* signals this fact by returning a non-NULL pointer to a string	    */
    /* describing the problem.						    */
  + /*									    */
  + /* The magic return value DECLINE_CMD is used to deal with directives	    */
  + /* that might be declared by multiple modules.  If the command handler	    */
  + /* returns NULL, the directive was processed; if it returns DECLINE_CMD,    */
  + /* the next module (if any) that declares the directive is given a chance   */
  + /* at it.  If it returns any other value, it's treated as the text of an    */
  + /* error message.							    */
    /*--------------------------------------------------------------------------*/
    /* 
     * Command handler for the NO_ARGS "Example" directive.  All we do is mark the
  ***************
  *** 367,373 ****
         * "Example Wuz Here"
         */
        cfg->local = 1;
  !     trace_add (cmd->server, cfg, "cmd_example()");
        return NULL;
    }
    
  --- 496,502 ----
         * "Example Wuz Here"
         */
        cfg->local = 1;
  !     trace_add (cmd->server, NULL, cfg, "cmd_example()");
        return NULL;
    }
    
  ***************
  *** 399,408 ****
    	(request_rec *r) {
    
        example_config
  ! 	    *cfg;
    
  !     cfg = our_dconfig (r);
  !     trace_add (r->server, cfg, "example_handler()");
        /*
         * We're about to start sending content, so we need to force the HTTP
         * headers to be sent at this point.  Otherwise, no headers will be sent
  --- 528,540 ----
    	(request_rec *r) {
    
        example_config
  ! 	    *dcfg;
  !     example_config
  ! 	    *rcfg;
    
  !     dcfg = our_dconfig (r);
  !     rcfg = our_rconfig (r);
  !     trace_add (r->server, r, dcfg, "example_handler()");
        /*
         * We're about to start sending content, so we need to force the HTTP
         * headers to be sent at this point.  Otherwise, no headers will be sent
  ***************
  *** 461,481 ****
        rputs ("  indicates a location in the URL or filesystem\n", r);
        rputs ("  namespace.\n", r);
        rputs ("  </P>\n", r);
  !     rprintf (r, "  <H2>Callbacks so far:</H2>\n  <OL>\n%s  </OL>\n", trace);
        rputs ("  <H2>Environment for <EM>this</EM> call:</H2>\n", r);
        rputs ("  <UL>\n", r);
  !     rprintf (r, "   <LI>Applies-to: <SAMP>%s</SAMP>\n   </LI>\n", cfg->loc);
        rprintf
    	(
    	    r,
    	    "   <LI>\"Example\" directive declared here: %s\n   </LI>\n",
  ! 	    (cfg->local ? "YES" : "NO")
    	);
        rprintf
    	(
    	    r,
    	    "   <LI>\"Example\" inherited: %s\n   </LI>\n",
  ! 	    (cfg->congenital ? "YES" : "NO")
    	);
        rputs ("  </UL>\n", r);
        rputs (" </BODY>\n", r);
  --- 593,624 ----
        rputs ("  indicates a location in the URL or filesystem\n", r);
        rputs ("  namespace.\n", r);
        rputs ("  </P>\n", r);
  !     rprintf
  ! 	(
  ! 	    r,
  ! 	    "  <H2>Static callbacks so far:</H2>\n  <OL>\n%s  </OL>\n",
  ! 	    trace
  ! 	);
  !     rprintf
  ! 	(
  ! 	    r,
  ! 	    "  <H2>Request-specific callbacks so far:</H2>\n  <OL>\n%s  </OL>\n",
  ! 	    rcfg->trace
  ! 	);
        rputs ("  <H2>Environment for <EM>this</EM> call:</H2>\n", r);
        rputs ("  <UL>\n", r);
  !     rprintf (r, "   <LI>Applies-to: <SAMP>%s</SAMP>\n   </LI>\n", dcfg->loc);
        rprintf
    	(
    	    r,
    	    "   <LI>\"Example\" directive declared here: %s\n   </LI>\n",
  ! 	    (dcfg->local ? "YES" : "NO")
    	);
        rprintf
    	(
    	    r,
    	    "   <LI>\"Example\" inherited: %s\n   </LI>\n",
  ! 	    (dcfg->congenital ? "YES" : "NO")
    	);
        rputs ("  </UL>\n", r);
        rputs (" </BODY>\n", r);
  ***************
  *** 541,558 ****
        char    *sname = s->server_hostname;
    
        /*
  !      * If we haven't already allocated our module-private pool, do so now.
         */
  !     if (example_pool == NULL) {
  ! 	example_pool = make_sub_pool (NULL);
  !     };
        /*
         * The arbitrary text we add to our trace entry indicates for which server
         * we're being called.
         */
        sname = (sname != NULL) ? sname : "";
        note = pstrcat (p, "example_init(", sname, ")", NULL);
  !     trace_add (s, NULL, note);
    }
    
    /*
  --- 684,699 ----
        char    *sname = s->server_hostname;
    
        /*
  !      * Set up any module cells that ought to be initialised.
         */
  !     setup_module_cells ();
        /*
         * The arbitrary text we add to our trace entry indicates for which server
         * we're being called.
         */
        sname = (sname != NULL) ? sname : "";
        note = pstrcat (p, "example_init(", sname, ")", NULL);
  !     trace_add (s, NULL, NULL, note);
    }
    
    /*
  ***************
  *** 590,596 ****
         */
        dname = (dname != NULL) ? dname : "";
        cfg->loc = pstrcat (p, "DIR(", dname, ")", NULL);
  !     trace_add (NULL, cfg, "example_dir_create()");
        return (void *) cfg;
    }
    
  --- 731,737 ----
         */
        dname = (dname != NULL) ? dname : "";
        cfg->loc = pstrcat (p, "DIR(", dname, ")", NULL);
  !     trace_add (NULL, NULL, cfg, "example_dir_create()");
        return (void *) cfg;
    }
    
  ***************
  *** 654,660 ****
    		"\")",
    		NULL
    	    );
  !     trace_add (NULL, merged_config, note);
        return (void *) merged_config;
    }
    
  --- 795,801 ----
    		"\")",
    		NULL
    	    );
  !     trace_add (NULL, NULL, merged_config, note);
        return (void *) merged_config;
    }
    
  ***************
  *** 685,691 ****
         */
        sname = (sname != NULL) ? sname : "";
        cfg->loc = pstrcat (p, "SVR(", sname, ")", NULL);
  !     trace_add (s, cfg, "example_server_create()");
        return (void *) cfg;
    }
    
  --- 826,832 ----
         */
        sname = (sname != NULL) ? sname : "";
        cfg->loc = pstrcat (p, "SVR(", sname, ")", NULL);
  !     trace_add (s, NULL, cfg, "example_server_create()");
        return (void *) cfg;
    }
    
  ***************
  *** 736,742 ****
    		"\")",
    		NULL
    	    );
  !     trace_add (NULL, merged_config, note);
        return (void *) merged_config;
    }
    
  --- 877,883 ----
    		"\")",
    		NULL
    	    );
  !     trace_add (NULL, NULL, merged_config, note);
        return (void *) merged_config;
    }
    
  ***************
  *** 759,765 ****
         * We don't actually *do* anything here, except note the fact that we were
         * called.
         */
  !     trace_add (r->server, cfg, "example_xlate()");
        return DECLINED;
    }
    
  --- 900,906 ----
         * We don't actually *do* anything here, except note the fact that we were
         * called.
         */
  !     trace_add (r->server, r, cfg, "example_xlate()");
        return DECLINED;
    }
    
  ***************
  *** 782,788 ****
        /*
         * Don't do anything except log the call.
         */
  !     trace_add (r->server, cfg, "example_ckuser()");
        return DECLINED;
    }
    
  --- 923,929 ----
        /*
         * Don't do anything except log the call.
         */
  !     trace_add (r->server, r, cfg, "example_ckuser()");
        return DECLINED;
    }
    
  ***************
  *** 807,813 ****
         * Log the call and return OK, or access will be denied (even though we
         * didn't actually do anything).
         */
  !     trace_add (r->server, cfg, "example_ckauth()");
        return OK;
    }
    
  --- 948,954 ----
         * Log the call and return OK, or access will be denied (even though we
         * didn't actually do anything).
         */
  !     trace_add (r->server, r, cfg, "example_ckauth()");
        return OK;
    }
    
  ***************
  *** 827,833 ****
    	    *cfg;
    
        cfg = our_dconfig (r);
  !     trace_add (r->server, cfg, "example_ckaccess()");
        return OK;
    }
    
  --- 968,974 ----
    	    *cfg;
    
        cfg = our_dconfig (r);
  !     trace_add (r->server, r, cfg, "example_ckaccess()");
        return OK;
    }
    
  ***************
  *** 850,856 ****
         * Log the call, but don't do anything else - and report truthfully that
         * we didn't do anything.
         */
  !     trace_add (r->server, cfg, "example_typer()");
        return DECLINED;
    }
    
  --- 991,997 ----
         * Log the call, but don't do anything else - and report truthfully that
         * we didn't do anything.
         */
  !     trace_add (r->server, r, cfg, "example_typer()");
        return DECLINED;
    }
    
  ***************
  *** 872,878 ****
        /*
         * Log the call and exit.
         */
  !     trace_add (r->server, cfg, "example_fixer()");
        return OK;
    }
    
  --- 1013,1019 ----
        /*
         * Log the call and exit.
         */
  !     trace_add (r->server, r, cfg, "example_fixer()");
        return OK;
    }
    
  ***************
  *** 890,896 ****
    	    *cfg;
    
        cfg = our_dconfig (r);
  !     trace_add (r->server, cfg, "example_logger()");
        return DECLINED;
    }
    
  --- 1031,1037 ----
    	    *cfg;
    
        cfg = our_dconfig (r);
  !     trace_add (r->server, r, cfg, "example_logger()");
        return DECLINED;
    }
    
  ***************
  *** 909,915 ****
    	    *cfg;
    
        cfg = our_dconfig (r);
  !     trace_add (r->server, cfg, "example_hparser()");
        return DECLINED;
    }
    
  --- 1050,1056 ----
    	    *cfg;
    
        cfg = our_dconfig (r);
  !     trace_add (r->server, r, cfg, "example_hparser()");
        return DECLINED;
    }