httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <>
Subject work in progress: mpm-3.tar.gz
Date Thu, 17 Jun 1999 19:23:59 GMT
This is the beginning of some massive code cleanup... we've been building
so much crap into http_main it's been really difficult for me to work on
the async/sync hybrid (ASH) stuff that I posted a few weeks back.  My main
goal here was to rip out the "multi-processing model", or MPM, so that we
can replace it with whatever we need depending on the platform. 

For example, there could be a prefork MPM, a win32 MPM, a select/thread
hybrid MPM, a tpf MPM, ...

The MPM's job is to listen on sockets and call ap_process_connection (new
function, just the keepalive wrapper around ap_process_request).  It also
handles restarts and shutdown.

Manoj and Ryan started something along these lines, but they weren't
nearly aggressive enough.  The cross dependencies between all the
http_foo.c files in 1.x is atrocious.  I started with apache-apr/pthreads,
but at the moment none of their work in http_main, http_accept, fdqueue,
etc. is used.  All that stuff should become another MPM. 

The new http_main.c is trivial in comparison to the old one. 

I've ripped code out of http_config.c and http_core.c which is related to
the MPM code -- the MPM is a module, it has its own configuration
directives and its own methods.  This way, for example, we don't have crap
such as a "MaxRequestsPerChild" directive that does nothing under win32...
the win32 mpm doesn't need that directive.

There's lots still to do...  If people want to help me (please!), here's
how you can help:

- grep for "TODO:", there's a lot of easy and not so easy ones to handle
- most of the modules still need to be ported to the new module
  structure... but go slowly, we want to be sure that the new init phases
  are the ones we require
- mpm_prefork is a crude port of the apache-1.3 http_main.c to the new
  mpm framework... it's actually my first test case... but there's a long
  list of TODOs still in it, and I haven't really tested it.  I'm not
  going to work on it any longer -- I'm moving onto the ASH MPM.
- write a win32 MPM (heck, write a win95 and a winnt mpm, stop this silly
  pandering to the weaker denominator)
- an mpm/foo/ hierarchy should be created, and Configure should be set up
  to understand a new "mpm" directive... treat them almost identical to
  modules, except that at most one mpm can be selected at compile time,
  and the default for unix should be "prefork".

You can assume that I'm not working on any of those TODOs at the moment --
my focus is going to be the ASH MPM, and then a revamp of BUFF to handle
non-blocking sockets, and then a change to the MPM interface to handle
async models (the message passing stuff). 

Below is more information. 


DEATH TO http_main.c! 

http_main.c is the worst bit of code in apache.  It ties in far too many
details, and we've been utterly lazy when adding new features.  We just
wedge them in.  This has to stop.

My goal is to turn http_main.c into a series of hook calls; and the
various bits of functionality which we currently burden it with --
such as opening logs; maintaining the version strings; ... will all be
moved into modules.  It's only a matter of giving the modules enough
hook points.

I also intend to pluck out the "multiprocessing model", or MPM...
multiprocess, multithreaded, hybrid select/thread, ...

There is a loop around ap_process_request which handles all the
details of a connection (keepalive and such), let's call that loop
ap_process_connection.  From ap_process_connection() on downwards in the
code there is very little which depends on the MPM in use.  For example,
none of the core modules care if they are running within a multithreaded
process, or within multiple single threaded processes.  At the moment
I am not going to consider modules which wish to make use of threads to
improve their behaviour -- that is an issue which APR intends to address.

We will impose an additional restriction on modules -- if threads are in
use, they may not make any assumption that the same thread will be used to
process all phases of a request.  Put another way -- thread local storage
is useless... and there will be no "thread_init_hook" function to tell
modules when threads have been created.  This restriction is to give us
access to hybrid async/sync techniques.  Modules needing information
persisting between request phases should use request-specific data
(or connection-specific data).

Modules may assume that all phases of one request are handled within one

At this point I'm going to ignore everything from ap_process_connection
on down -- there are things which we'd like to change in there for 2.0,
but it's not necessary to consider them when rewriting http_main.c.

For the purposes of this discussion, the "parent" process refers to the
first process which is invoked (may be replaced during detach()); and
"child" refers to any process which is capable of serving requests.
The children may have zero or more threads, it depends on the MPM.

here is the general sequence of events in http_main.c:

- main()
- pglobal = ap_alloc_init();  /* parent of all pools */
- pcommands = ap_sub pool(pglobal);
- pre_command_line_hook(pcommands)
- process command line (or equivalent on win32/etc.)

- pconf = ap_make_sub_pool(pglobal);
- ptemp = ap_make_sub_pool(pconf);
- plog = ap_make_sub_pool(pglobal);

    /* the extra running through of the config... */
- ap_pre_config_hook(pconf, plog, ptemp);
- server_conf = ap_read_config
    - as shared modules are loaded, their pre_config_hook() is called
    (pre_command_line_hook() is only available to modules pre-loaded ?)
- ap_clear_pool(plog);
- ap_open_logs_hook(pconf, plog, ptemp, server_conf);
- ap_post_config_hook(pconf, plog, ptemp, server_conf);
- ap_clear_pool(ptemp);

big loop {
    - ap_clear_pool(pconf);
    - ptemp = ap_make_sub_pool(pconf);
    - ap_pre_config_hook(pconf, plog, ptemp);
    - server_conf = ap_read_config
    - ap_clear_pool(plog);
    - ap_open_logs_hook(pconf, plog, ptemp, server_conf);
    - ap_post_config_hook(pconf, plog, ptemp, server_conf);
    - ap_destroy_pool(ptemp);

    - mpm_run(pconf, plog, server_conf);
	- zero or more processes are created (mpm specific), in each child
	  which will service requests the following occurs:
	    - pchild = ap_make_sub_pool(pconf);
	    - child_init_hook(pchild, server_conf);
	- by some unspecified method, the mpm accepts sockets, and
	  calls ap_process_connection

	- at some point, a restart or shutdown event occurs in parent,
	  and by some unspecified method the mpm notifies its children
	  of the event... and depending on whether it implements
	  graceful/non-graceful restart/shutdown it stops servicing

	- in each child, when there are no outstanding requests, the
	  MPM calls ap_destroy_pool(pchild)
    - at some point, mpm_run() returns
    - if this is a shutdown then
	- ap_clear_pool(pconf);
	- ap_clear_pool(plog);
	- ap_destroy_pool(pglobal);
	- exit
    - else it is a restart... continue

MPM interface:

The MPM is a module, and it implements directives which control its
process/thread/etc. spawning algorithm, such as:


We don't specify what these directives are... in fact, we shouldn't even
attempt to make them look like the apache-1.3 directives, we should take
this opportunity to restore some sanity to the names.

The MPM implements the Listen directive, and any other port listening
directives which it may need (such as directives for binding a process to
a particular IP... in cases where cpu affinity/io affinity are implemented
for examples).

The MPM also implements the User/Group directives (or whatever their
equivalents are)... these directives are for controlling what permissions
the various processes have... they're not to be overloaded with other
meanings for things such as suexec.

The MPM provides the following functions:

    /* run until a restart/shutdown is indicated, return 1 for shutdown
       0 otherwise */
    int ap_mpm_run(pool *pconf, pool *plog, server_rec *server_conf);

    /* predicate indicating if a graceful stop has been requested ...
       used by the connection loop */
    int ap_mpm_graceful_stop(void);


View raw message