Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-18 Thread Luke Kenneth Casson Leighton

On Tue, Jul 17, 2001 at 10:12:35AM -0700, Aaron Bannert wrote:

 - Optionally creating a child-pool for each thread. This provides us two
 things in my mind:
   1) Allowing the application to choose an SMS for this thread-pool (which
  could very well be a special SMS created just for this purpose).

for example, you may wish to create a special 'security' thread.
it uses an apr_sms_mlock_t instance.  this special thread handles
all of your security, keeping private keys and plain-text user
passwords in-memory.  

luke



RE: [PATCH] Problems with MPM threaded

2001-07-18 Thread Benjamin W. Ritcey

As an end-user of apache, I'd like to chime in: please, please, please leave
the N processes with M threads model available -- the hypothetical buggy
3rd party modules should be fixed rather than hacked around is fine in
theory, but in practice I'd rather have an Apache that can soldier on
regardless of the crappy modules it's forced to run.  Tuxedo has used the N
x M model for a long time with good results for similar reasons.

My $0.02

Thanks,

-b

-Original Message-
From: dean gaudet [mailto:[EMAIL PROTECTED]]
Sent: Tuesday, July 17, 2001 4:13 AM
To: [EMAIL PROTECTED]
Subject: Re: [PATCH] Problems with MPM threaded


On Sat, 14 Jul 2001 [EMAIL PROTECTED] wrote:

 Having multiple processes each with multiple threads provides for FAR
 more robustness than just a single process with multiple threads.

ya know, i'm not really convinced of the desirability of this explanation
anymore.  maybe the hypothetical buggy 3rd party modules should be fixed
rather than hacked around.  and they won't be fixed as long as apache
continues to hide the problem.

however i can provide two more justifications which are pretty weak:

- userland thread libraries need multiple processes in order to get disk
  i/o parallelism (and multi-cpu parallelism)

- suppose you configure apache with exactly the number of children as
  you have processors.  and suppose that somehow magically the CPU
  requirements of each process' threads is about even.  then a good
  (kernel) scheduler will likely migrate each process to its own CPU and
  time slice just the threads within that process.  this will tend to
  decrease the overall memory system traffic (because L2 caches won't be
  competing for the same process' memory), and increase the TLB hit rate.
  it may even be possible to avoid interprocessor interrupts every
  time the memory map is changed (to make sure that remote TLBs are
  up to date).

  that's a lot of conditionals to get right.

-dean




Re: [PATCH] Problems with MPM threaded

2001-07-17 Thread dean gaudet

On Sat, 14 Jul 2001 [EMAIL PROTECTED] wrote:

 Having multiple processes each with multiple threads provides for FAR
 more robustness than just a single process with multiple threads.

ya know, i'm not really convinced of the desirability of this explanation
anymore.  maybe the hypothetical buggy 3rd party modules should be fixed
rather than hacked around.  and they won't be fixed as long as apache
continues to hide the problem.

however i can provide two more justifications which are pretty weak:

- userland thread libraries need multiple processes in order to get disk
  i/o parallelism (and multi-cpu parallelism)

- suppose you configure apache with exactly the number of children as
  you have processors.  and suppose that somehow magically the CPU
  requirements of each process' threads is about even.  then a good
  (kernel) scheduler will likely migrate each process to its own CPU and
  time slice just the threads within that process.  this will tend to
  decrease the overall memory system traffic (because L2 caches won't be
  competing for the same process' memory), and increase the TLB hit rate.
  it may even be possible to avoid interprocessor interrupts every
  time the memory map is changed (to make sure that remote TLBs are
  up to date).

  that's a lot of conditionals to get right.

-dean




Re: [PATCH] Problems with MPM threaded

2001-07-17 Thread dean gaudet



On Sat, 14 Jul 2001, Roy T. Fielding wrote:

  The correct fix, as I see it, is to kill off the interprocess
  accept lock by removing the possibility of having other processes
  in a *threaded* MPM.  -- justin

 That architecture was explored in detail by Netscape.  It isn't reliable
 and slows your web server to a crawl whenever dynamic content is produced.
 It should only be used for static file servers and caching gateways, and
 people implementing those might as well use an in-kernel server like TUX.

i'm confused... what architecture has that problem with dynamic content?

i can believe it if you're referring to a userland threading library,
single process server.

i can't believe it if the threads are scheduled by the kernel (either as
1:1 or 1:many).

NSPR threading was probably to blame, no?

-dean




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Aaron Bannert

Normally this would be done (in POSIX) with pthread_cancel(), passing it
the pthread_t from the other thread.

Unfortunately, this is not a part of APR because many of the current OS
implementations of this mechanism will leak resources (aparently in the
kernel), and that is bad.

-aaron


On Tue, Jul 17, 2001 at 01:32:52AM -0700, dean gaudet wrote:
 On Sat, 14 Jul 2001, Sander Striker wrote:
 
  The way I see it, each process has a single pool instance as the parent
  for all the threads. Resetting or destroying that pool should effectively
  kill all threads. What am I missing?
 
 how does a thread kill another thread?
 
 -dean




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Aaron Bannert

On Tue, Jul 17, 2001 at 01:29:47AM -0700, dean gaudet wrote:
 On Sun, 15 Jul 2001, Sander Striker wrote:
 
  Why are we so desperate in opting out the child-pool creation?
  I don't really have problems with a child pool for each thread. Actually,
  it will make the dynamic locking a lot easier to implement if it stays.
 
 all threads MUST have their own private pool root.
 
 otherwise you're just throwing scalability away in locks.  (which is
 proved by the claim i saw that ian got better performance by defining
 ALLOC_USE_MALLOC on an 8-way.)

I totally agree, but only as a solution in httpd.


I also believe that we should provide this [application-specific requirement]
outside of the basic thread support in APR.

Please allow me to use pseudocode:

void * worker_function(void * opaque_application_data) {

   apr_pool_t *thread_pool;

   create_child_pool(thread_pool, global_root_pool);

   do_thread_stuff();

   cleanup_child_pool(thread_pool);

   if (apr_thread_exit_makes_sense_to_call_from_inside_worker_function) {
  int rv = APR_SUCCESS;
  apr_thread_exit(rv);
   }

   return NULL;
}

What I mean by this gibberish is that the pool-handling code can exist
completely outside of our thread_creation-type functions in APR. Is there
any reason for APR threads to do more than this (that is, just simple thread
creation)?

-aaron




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Aaron Bannert

Uh...you knew that already, didn't you... duh...

jeez now i'm the smartass ;)

-aaron


On Tue, Jul 17, 2001 at 08:43:18AM -0700, Aaron Bannert wrote:
 Normally this would be done (in POSIX) with pthread_cancel(), passing it
 the pthread_t from the other thread.
 
 Unfortunately, this is not a part of APR because many of the current OS
 implementations of this mechanism will leak resources (aparently in the
 kernel), and that is bad.
 
 -aaron
 
 
 On Tue, Jul 17, 2001 at 01:32:52AM -0700, dean gaudet wrote:
  On Sat, 14 Jul 2001, Sander Striker wrote:
  
   The way I see it, each process has a single pool instance as the parent
   for all the threads. Resetting or destroying that pool should effectively
   kill all threads. What am I missing?
  
  how does a thread kill another thread?
  
  -dean




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread William A. Rowe, Jr.

From: [EMAIL PROTECTED]
Sent: Tuesday, July 17, 2001 11:13 AM
 
 I believe that the problem is that the threaded code is creating the
 pool, and not advertising it to the thread itself.  This is an easy thing
 to fix.  I do not agree that every APR app that uses threads should have
 to create their own thread pools.  That is wasted effort by every APR app.
 
 I would like to see a conclusion to this thread quickly.  So, could people
 please post their desires quickly, and what they want to see from this.

thread-local pools would be a nice improvement, perhaps as an argument to
apr_thread_create.  They can be flagged such that they avoid locking their own
own allocations (of course their 'parent' allocator, malloc, or the parent
free-list management, may still need to lock based on platform and so forth). 

But _unless_ they remain rooted to the top level pool, in apr_process_create 
they become orphaned, and their cleanups are never executed.  That isn't workable.

It sounds like (forgive me if I'm stating the obvious) that a pool needs two
kinds of parent sms pools.  One is the 'heirarchy' for purposes of setup and
teardown.  The other is the 'allocator', where the blocks will be allocated from.

Want to use the conventional 1.3 model?  The heirarchial parent is the parent pool,
but the allocatation parent is the single top level pool.

Want to flip to a malloc, that trusts the clib to 'do the right thing'(sm) with
cpu/thread specific free lists?  Then we build a very simple malloc/free sms that
can be passed as the allocation parent when the pool is created.

If I've abused the sms concept here, then correct me, but I don't see any issues
remaining beyond semantics and syntax.

Bill





Re: Terminating threads in a process,WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Brian Pane

William A. Rowe, Jr. wrote:

From: [EMAIL PROTECTED]
Sent: Tuesday, July 17, 2001 11:13 AM

I believe that the problem is that the threaded code is creating the
pool, and not advertising it to the thread itself.  This is an easy thing
to fix.  I do not agree that every APR app that uses threads should have
to create their own thread pools.  That is wasted effort by every APR app.

I would like to see a conclusion to this thread quickly.  So, could people
please post their desires quickly, and what they want to see from this.


thread-local pools would be a nice improvement, perhaps as an argument to
apr_thread_create.  They can be flagged such that they avoid locking their own
own allocations (of course their 'parent' allocator, malloc, or the parent
free-list management, may still need to lock based on platform and so forth). 

But _unless_ they remain rooted to the top level pool, in apr_process_create 
they become orphaned, and their cleanups are never executed.  That isn't workable.

I'm not sure that the alternative is workable, either.

At the time of the fork, when the child process gets a snapshot of
the parent's memory, it's possible that some thread other than the one
invoking fork could be halfway through registering a new resource (e.g.,
file descriptor) in its pool.  There's no guarantee that it's safe to
attempt a cleanup of that other thread's pool in the child process;
if the fork has caught the data structures in an intermediate state,
attempting to destroy that pool might yield a segv.

--Brian






Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Aaron Bannert

 I'm not sure that the alternative is workable, either.
 
 At the time of the fork, when the child process gets a snapshot of
 the parent's memory, it's possible that some thread other than the one
 invoking fork could be halfway through registering a new resource (e.g.,
 file descriptor) in its pool.  There's no guarantee that it's safe to
 attempt a cleanup of that other thread's pool in the child process;
 if the fork has caught the data structures in an intermediate state,
 attempting to destroy that pool might yield a segv.

Correct me if I'm wrong, but that would be a property of a buggy MPM.
If the MPM chooses to mix non-synchronized fork()s and thread invocation,
than that's what it gets.

-aaron




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Aaron Bannert

 We have hit an impass in my mind.  Dean and I are saying that having each
 thread have it's own pool is a requirement.  Not just for httpd, but for
 anything using pools.  Dean, if I am mis-interpreting you, then I am
 sorry, and please correct me.
 
 Aaron,  you disagree.  you want each app to make that decision on their
 own.  I see no way to implement that in a thread-safe manner.

(Just as a side note, I don't remember seeing anything refuting the technical
aspects of such an implementation. I would be interested in one, of course,
if you think it is infeasible.)


 So, I would suggest that we approach this problem in another way.  My ONLY
 goal for APR is to make a library that is useful for cross-platform
 development and eases the pain of cross-platform development for
 developers.  That was the goal when I created APR, and my original test
 case was the Apache web server.
 
 I believe that the problem is that the threaded code is creating the
 pool, and not advertising it to the thread itself.  This is an easy thing
 to fix.  I do not agree that every APR app that uses threads should have
 to create their own thread pools.  That is wasted effort by every APR app.
 
 I would like to see a conclusion to this thread quickly.  So, could people
 please post their desires quickly, and what they want to see from this.

In my mind, there are really only two major points that need addressing:

- Optionally creating a child-pool for each thread. This provides us two
things in my mind:
  1) Allowing the application to choose an SMS for this thread-pool (which
 could very well be a special SMS created just for this purpose).
  2) Allowing an application to refrain from creating a child-pool.

- Like you [Ryan] said, it is a problem that the thread creation routines
right now are not advertising the pool to the thread itself. This to
me can be corrected with a better API. The two things I've brought up
here are:
  1) void * worker_fn(void *opaque_data) should have an additional
 pool param.
  2) apr_thread_exit() is unacceptable. It currently requires a
 apr_thread_t structure. I would be happy if either the worker_fn was
 extended to pass in the apr_thread_t OR if we could architect a way
 for apr_thread_exit() to not need the apr_thread_t struct.


I have a feeling the second point will be more palatable, and as such
I'll volunteer to cook up a patch illustrating these changes.

As for the first point, which is the reason this thread has been going on
so long, I'm willing to compromise on the idea of forcefully creating
a childpool always, if it necessary, merely because I see it only as
overhead for some applications, but not a functional defect.

-aaron




Re: Terminating threads in a process,WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Brian Pane

Aaron Bannert wrote:

I'm not sure that the alternative is workable, either.

At the time of the fork, when the child process gets a snapshot of
the parent's memory, it's possible that some thread other than the one
invoking fork could be halfway through registering a new resource (e.g.,
file descriptor) in its pool.  There's no guarantee that it's safe to
attempt a cleanup of that other thread's pool in the child process;
if the fork has caught the data structures in an intermediate state,
attempting to destroy that pool might yield a segv.


Correct me if I'm wrong, but that would be a property of a buggy MPM.
If the MPM chooses to mix non-synchronized fork()s and thread invocation,
than that's what it gets.

Synchronizing the forks with pool resource registration isn't a scalable
design; it requires locking a process-wide lock every time you want to
register a resource in a per-thread pool.  It would be a huge mistake
to slow down the routine operation of the httpd in order to optimize for
fork.

--Brian





Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Aaron Bannert

On Tue, Jul 17, 2001 at 10:17:01AM -0700, Brian Pane wrote:
 Aaron Bannert wrote:
 
 I'm not sure that the alternative is workable, either.
 
 At the time of the fork, when the child process gets a snapshot of
 the parent's memory, it's possible that some thread other than the one
 invoking fork could be halfway through registering a new resource (e.g.,
 file descriptor) in its pool.  There's no guarantee that it's safe to
 attempt a cleanup of that other thread's pool in the child process;
 if the fork has caught the data structures in an intermediate state,
 attempting to destroy that pool might yield a segv.
 
 
 Correct me if I'm wrong, but that would be a property of a buggy MPM.
 If the MPM chooses to mix non-synchronized fork()s and thread invocation,
 than that's what it gets.
 
 Synchronizing the forks with pool resource registration isn't a scalable
 design; it requires locking a process-wide lock every time you want to
 register a resource in a per-thread pool.  It would be a huge mistake
 to slow down the routine operation of the httpd in order to optimize for
 fork.

I wasn't suggesting that, I was suggesting that it's a bad idea to start
fork()ing off processes from an MPM that's also doing threads and you
want that fork()ed of process to later do cleanups.

My point is it's solely an MPM architecture decision. Are you saying that
this is a typical scenario?

-aaron




Re: Terminating threads in a process,WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Brian Pane

Aaron Bannert wrote:

On Tue, Jul 17, 2001 at 10:17:01AM -0700, Brian Pane wrote:

Aaron Bannert wrote:

I'm not sure that the alternative is workable, either.

At the time of the fork, when the child process gets a snapshot of
the parent's memory, it's possible that some thread other than the one
invoking fork could be halfway through registering a new resource (e.g.,
file descriptor) in its pool.  There's no guarantee that it's safe to
attempt a cleanup of that other thread's pool in the child process;
if the fork has caught the data structures in an intermediate state,
attempting to destroy that pool might yield a segv.

Correct me if I'm wrong, but that would be a property of a buggy MPM.
If the MPM chooses to mix non-synchronized fork()s and thread invocation,
than that's what it gets.

Synchronizing the forks with pool resource registration isn't a scalable
design; it requires locking a process-wide lock every time you want to
register a resource in a per-thread pool.  It would be a huge mistake
to slow down the routine operation of the httpd in order to optimize for
fork.


I wasn't suggesting that, I was suggesting that it's a bad idea to start
fork()ing off processes from an MPM that's also doing threads and you
want that fork()ed of process to later do cleanups.

I agree.

My point is it's solely an MPM architecture decision. Are you saying that
this is a typical scenario?

I think it's an atypical scenario, and one that can't be implemented very
well anyway.  (The synchronized approach has a performance problem, and
the unsynchronized approach can crash due to a race condition.)  Thus my
argument is that this scenario (forking from a threaded MPM and then trying
to clean up the other threads' resources in the child process) isn't a
valid use case for the design of the pools.

--Brian







Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread William A. Rowe, Jr.

From: dean gaudet [EMAIL PROTECTED]
Sent: Tuesday, July 17, 2001 6:15 PM


 if you assume that you want some form of notification, but you want to
 leave it unspecified because you're not sure what each apr thread will be
 used for, then you can make a somewhat generic kill off other threads
 cleanup.
 
 so for example, when an httpd thread is created it would register
 http_thread_cleanup which would use whatever magic global int
 die_now_please = 1, and release some condition variable, or throw
 something into a queue / and so on.
 
 that would be registered in the parent thread's pool -- and would only
 be invoked by the parent thread.
 
 pools let you do this, you don't need the mutexes for it, you just have to
 be explicit about parallelism.  (combine that with a root pool per thread
 and then we can remove alloc_mutex and free lists and push the real gnarly
 problems into the libc malloc where it's probably best solved.)

Yes, yes, yes.  Can we please split the concept of a heirarchial parent (the
'creator' thread's or process pool, in this case) from the allocation parent
(the actual give me memory for my pool from ... here!)  Then we have an 
OS Knows Best malloc/free mpm for threading, just as you suggest.

This solves your thread-specific requirements and our scoping issues, along
with fixing the 'walk the chain of pools for a block' problem, both at once.






Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Aaron Bannert

[snip]
  that would be registered in the parent thread's pool -- and would only
  be invoked by the parent thread.
  
  pools let you do this, you don't need the mutexes for it, you just have to
  be explicit about parallelism.  (combine that with a root pool per thread
  and then we can remove alloc_mutex and free lists and push the real gnarly
  problems into the libc malloc where it's probably best solved.)
 
 Yes, yes, yes.  Can we please split the concept of a heirarchial parent (the
 'creator' thread's or process pool, in this case) from the allocation parent
 (the actual give me memory for my pool from ... here!)  Then we have an 
 OS Knows Best malloc/free mpm for threading, just as you suggest.
 
 This solves your thread-specific requirements and our scoping issues, along
 with fixing the 'walk the chain of pools for a block' problem, both at once.

It's probably just me, but I'm having trouble parsing this (I think I'm
getting a cold :( ).

Are you saying you want the thread function to have access to both a
scope pool as well as an allocator pool, in case they are different?

-aaron




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread William A. Rowe, Jr.

From: Aaron Bannert [EMAIL PROTECTED]
Sent: Tuesday, July 17, 2001 6:41 PM


 [snip]
   that would be registered in the parent thread's pool -- and would only
   be invoked by the parent thread.
   
   pools let you do this, you don't need the mutexes for it, you just have to
   be explicit about parallelism.  (combine that with a root pool per thread
   and then we can remove alloc_mutex and free lists and push the real gnarly
   problems into the libc malloc where it's probably best solved.)
  
  Yes, yes, yes.  Can we please split the concept of a heirarchial parent (the
  'creator' thread's or process pool, in this case) from the allocation parent
  (the actual give me memory for my pool from ... here!)  Then we have an 
  OS Knows Best malloc/free mpm for threading, just as you suggest.
  
  This solves your thread-specific requirements and our scoping issues, along
  with fixing the 'walk the chain of pools for a block' problem, both at once.
 
 It's probably just me, but I'm having trouble parsing this (I think I'm
 getting a cold :( ).
 
 Are you saying you want the thread function to have access to both a
 scope pool as well as an allocator pool, in case they are different?

I've officially graduated to the rbb (insert a decent name here) club :-)

Thank you, yes, scope pool defines teardowns such as cleanups, while the allocator
pool addresses our performance concerns :)

An obvious test is that 'allocator' is unique (e.g. thread private), a parent 
(at any depth) of the 'scope' pool, or the 'scope' pool itself.




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-17 Thread Aaron Bannert

  I totally agree, but only as a solution in httpd.
 
 no, everywhere.
 
  I also believe that we should provide this [application-specific requirement]
  outside of the basic thread support in APR.
 
  Please allow me to use pseudocode:
 
  void * worker_function(void * opaque_application_data) {
 
 apr_pool_t *thread_pool;
 
 create_child_pool(thread_pool, global_root_pool);
 
 now you've got mutexes in global_root_pool.  see my performance comment
 above.

I'm not advocating this scenario as a real solution, but merely trying
to illustrate how the child-pool creation routines don't really have to
be in apr_thread_create(). The application using APR threads can do this
before calling apr_thread_create() or it can do it in it's worker_function.

Either way, it is better to leave it totally up to the application, no?

-aaron




Re: [PATCH] Problems with MPM threaded

2001-07-17 Thread Roy T. Fielding

  That architecture was explored in detail by Netscape.  It isn't reliable
  and slows your web server to a crawl whenever dynamic content is produced.
  It should only be used for static file servers and caching gateways, and
  people implementing those might as well use an in-kernel server like TUX.
 
 i'm confused... what architecture has that problem with dynamic content?
 
 i can believe it if you're referring to a userland threading library,
 single process server.
 
 i can't believe it if the threads are scheduled by the kernel (either as
 1:1 or 1:many).
 
 NSPR threading was probably to blame, no?

Does NSPR do userland threading on Solaris?  I thought they were using native
threads.  But you are right, the dynamic content problem was for libraries
that are not thread-safe and for platforms that had userland threads.  They
ended up with some funky stuff in NSAPI that made the generic API slower
than mollasses (internal modules used another API).

Roy




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-16 Thread Aaron Bannert

  I have some use cases that just want a thread. Since no child-pool is
  required in this case, it becomes unnecessary overhead (that is currently
  broken, as the child-pool is only cleaned in apr_thread_exit() but that
  whole thing is screwey).
 
 Again, that is incorrect.  The THREAD-pool is cleaned whenever the parent
 pool is cleaned.  Yes, there is some extra overhead, but remember that the
 problem with pools (as the originally existed, and are still implemented
 in the server), is that you can't have two threads working with the same
 pool.

You are correct, I failed to mention that it is not *only* cleaned in
apr_thread_exit(), but also when the parent pool is cleaned. It is,
however, inappropriate to assume that the parent pool will ever get
cleaned.

Right now, if my application were to have a global/root pool that
repeatedly created short-lived threads (as it does, BTW), it would
eventually run out of memory. So, like I said, if apr_thread_exit()
is not called (and in all of apr, apr-util, and httpd is is never
called, not even in the test* programs), then that application is wholly
dependent on the ability of the thread's parent pool to clean up the
memory.


 IF SMS's replace all pools, then that might change.  As things stand
 today though, that hasn't happened, and may not happen quickly.
 
  So if apr threads didn't know anything about child-pools, then they
  would just simply create a thread that called my worker_function().
  I could pass in my opaque data to that worker_function(), and do
  the child-pool creations and destruction right there. I just don't see
  how child-pool creation MUST be in apr_thread_create()
 
 Yes, you could do that, but then EVERYBODY who wanted to create a thread
 would have to do that, and why are we forcing people to duplicate that
 code everytime a thread is created?

I agree that this is a useful function *at some level*, and so I propose
that this particular utility be built on top of a lower-level set of APR
thread routines. I will even write these routines myself, just because
I believe they are useful.

-aaron




RE: [PATCH] Add intraprocess mutex to threaded MPM (WAS Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded)

2001-07-16 Thread GUMMALAM,MOHAN (HP-Cupertino,ex2)

Since a lot has happened in the mailing list, since the last time I checked
(on Friday), I am responding only to the questions that still hold
significance, from the original mail I had sent..  Do find my answers
embedded below.

 -Original Message-
 From: Justin Erenkrantz [mailto:[EMAIL PROTECTED]]
 Sent: Friday, July 13, 2001 11:49 PM
 To: [EMAIL PROTECTED]
 Subject: Re: [PATCH] Problems with MPM threaded
 
 
 On Sat, Jul 14, 2001 at 12:42:29AM -0400, GUMMALAM,MOHAN 
 (HP-Cupertino,ex2) wrote:

 snip
 
 Have you taken a look at the patch I posted that merges the 
 POD code in threaded with the version in mpm_common.c?  Threaded 
 shouldn't be doing POD checks in threaded.c.  It's redundant and
 it's done incorrectly anyway in the threaded MPM.  
 
 Admittedly, this doesn't fix the issue of having a child who 
 received a POD kill its sibling threads.  More on that in a sec.

Yes, I did try the patch - as you mention, it did not resolve the problem.
Probably I was missing the right mpm_common.c file, since I had to tinker
around with the code a little to make it work with your patch.  Where can I
find the right one?

 snip
 
 A pthread_cond_wait() and fcntl() are viable options according to the
 manpage.  But, I'd much prefer us to use pthread_mutex_t if at all
 possible for cross-process locking.

pthread_cond_wait() is what I was thinking of - I am still not convinced
that it is a bad alternative (it does use pthread_mutex_t).  I would try to
make it as clean as possible.  Lets see how it pans out.

The current patch that you have posted is good, in the sense that it will
work.  It has one problem though: At any given time, there are only 5 worker
threads (one from each child process), waiting to grab accept_mutex - others
are waiting for their per-process worker_accept_mutex.  Also, each thread
would have to grab two locks, instead of one.  I am sure there would be a
noticeable performance hit at peak loads.  Any comments?

M



Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-15 Thread Luke Kenneth Casson Leighton

On Sat, Jul 14, 2001 at 12:40:06PM -0700, Aaron Bannert wrote:

 APR threads, when created, would now take an additional parameter that
 is the mechanism (an sms implementation) by which it should create child
 pools. As it is now, the pool that is passed in to apr_thread_create()
 serves as the parent pool for the new thread-specific sms.  If this
 parameter were null, the apr_thread_create() function would not create
 a sub-pool or register cleanup routines (which satisfies my requirements).

if at all possible, the behaviour should match as closely as possible
the existing situation, when this parameter is NULL, even if the
current situation has bugs / is not very nice.

this is mainly so that people do not object to having the behaviour
of existing code disrupted.

luke



Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-15 Thread Aaron Bannert

On Sun, Jul 15, 2001 at 06:49:51PM +0200, Luke Kenneth Casson Leighton wrote:
 On Sat, Jul 14, 2001 at 12:40:06PM -0700, Aaron Bannert wrote:
 
  APR threads, when created, would now take an additional parameter that
  is the mechanism (an sms implementation) by which it should create child
  pools. As it is now, the pool that is passed in to apr_thread_create()
  serves as the parent pool for the new thread-specific sms.  If this
  parameter were null, the apr_thread_create() function would not create
  a sub-pool or register cleanup routines (which satisfies my requirements).
 
 if at all possible, the behaviour should match as closely as possible
 the existing situation, when this parameter is NULL, even if the
 current situation has bugs / is not very nice.
 
 this is mainly so that people do not object to having the behaviour
 of existing code disrupted.

Fair enough. It's just that in order to opt-out of the child-pool creating
process in apr_thread_create, we're going to have to add a parameter
to the call and that means changing programs that currently using it,
like httpd.

Would it be nicer to just add new parallel apr_smsthread_create [name is not
important] functions that do this and allow for the opting-out also? I can
provide a patch for this.

-aaron




RE: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-15 Thread Sander Striker

 Fair enough. It's just that in order to opt-out of the child-pool creating
 process in apr_thread_create, we're going to have to add a parameter

Why are we so desperate in opting out the child-pool creation?
I don't really have problems with a child pool for each thread. Actually,
it will make the dynamic locking a lot easier to implement if it stays.

 to the call and that means changing programs that currently using it,
 like httpd.

 Would it be nicer to just add new parallel apr_smsthread_create
 [name is not
 important] functions that do this and allow for the opting-out also? I can
 provide a patch for this.

Hmmm, the thought of a double interface doesn't bring out happy feelings
with me I'm afraid.

Sander




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-15 Thread Aaron Bannert

On Sun, Jul 15, 2001 at 07:16:35PM +0200, Sander Striker wrote:
  Fair enough. It's just that in order to opt-out of the child-pool creating
  process in apr_thread_create, we're going to have to add a parameter
 
 Why are we so desperate in opting out the child-pool creation?
 I don't really have problems with a child pool for each thread. Actually,
 it will make the dynamic locking a lot easier to implement if it stays.

I have some use cases that just want a thread. Since no child-pool is
required in this case, it becomes unnecessary overhead (that is currently
broken, as the child-pool is only cleaned in apr_thread_exit() but that
whole thing is screwey).

So if apr threads didn't know anything about child-pools, then they
would just simply create a thread that called my worker_function().
I could pass in my opaque data to that worker_function(), and do
the child-pool creations and destruction right there. I just don't see
how child-pool creation MUST be in apr_thread_create()

-aaron




RE: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-15 Thread Sander Striker

  Why are we so desperate in opting out the child-pool creation?
  I don't really have problems with a child pool for each thread. 
 Actually,
  it will make the dynamic locking a lot easier to implement if it stays.
 
 I have some use cases that just want a thread. Since no child-pool is
 required in this case, it becomes unnecessary overhead (that is currently
 broken, as the child-pool is only cleaned in apr_thread_exit() but that
 whole thing is screwey).
 
 So if apr threads didn't know anything about child-pools, then they
 would just simply create a thread that called my worker_function().
 I could pass in my opaque data to that worker_function(), and do
 the child-pool creations and destruction right there. I just don't see
 how child-pool creation MUST be in apr_thread_create()

Ah, ok, I'm getting the picture now. Well, for my purposes, the child
pool creation doesn't have to be in apr_thread_create. There doesn't
have to be child pool creation at all. But, I do want the worker fn
to be able to create a child pool from the pool passed into
apr_thread_create. So, we need a way to pass in the data to the
worker fn.

The only thing I need is something like this for the sms locking scheme:

struct thread_data
{
...
apr_sms_t *sms;
void (*worker_fn)(void *data);
void  *data;
};

void thread_stub(void *data)
{
apr_sms_t *pms;
apr_os_thread_t thread;
struct thread_data *td = (struct thread_data *)data;

thread = apr_os_thread_current();

pms = td-sms;
apr_sms_thread_register(pms, thread);

td-worker_fn(td-data);

apr_sms_thread_unregister(pms, thread);
}
 
In apr_thread_create an instance of thread_data is created
and initialized, then instead of running the worker function
in the thread, we launch the stub which in turn calls the
worker.

Possibly we can use the stub for more than only this?

Sander




Re: [PATCH] Problems with MPM threaded

2001-07-14 Thread Justin Erenkrantz

On Sat, Jul 14, 2001 at 12:42:29AM -0400, GUMMALAM,MOHAN (HP-Cupertino,ex2) wrote:
 I propose the following patch [PATCH A]: It will partially fix the unwanted
 child deaths problem (symptoms mentioned in the mails included below).  It
 fixes the problem by making sure that perform_idle_server_maintenance() does
 not count the threads of the process that recd the POD, in the calculation
 of idle_thread_count.  To do that I have used
 ap_scoreboard_image-parent[process_slot]-process_status field.  I am
 temporarily using an already defined value, SB_IDLE_DIE.  If the general
 idea is acceptable, I can work on solidifying the details.  PATCH A is
 attached below.

Have you taken a look at the patch I posted that merges the POD code in
threaded with the version in mpm_common.c?  Threaded shouldn't be doing
POD checks in threaded.c.  It's redundant and it's done incorrectly
anyway in the threaded MPM.  

Admittedly, this doesn't fix the issue of having a child who received a
POD kill its sibling threads.  More on that in a sec.

 However this patch exposes another problem in the code - by this new fix,
 although the untargetted childs do not get a POD, the targetted child
 process does not die immediately either.  Here is why that happens:  In the
 worker_thread() routine in threaded.c, at the instant when worker 1.0
 (represented in the process_slot.thread_slot format, i.e, 1 is the
 process_slot and 0 is the thread_slot) gets the POD, the remaining threads
 of process 1 are all waiting at the apr_lock_acquire(accept_mutex).  If the
 web-server is really idle, the chances are slim that all the remaining
 worker threads for process 1 would acquire the lock in a very short time.
 As an effect, the remaining worker threads of process 1 do not die
 immediately.  To resolve this:
 
 SOLUTION 1:  I plan to temporarily implement a new
 apr_lock_acquire_timeout() function, which would cause the threads waiting
 on the mutex to give-up after sometime.  The piece of code would look
 something like this:
 
 while ((rv = SAFE_ACCEPT(apr_lock_acquire_timeout(accept_mutex, timevalue)))
   != APR_SUCCESS) {
   if (check_if_timer_popped)
   if (workers_may_exit)
   break;
   else { /* apr_lock_acquire failed */
   ap_log_error();
   workers_may_exit = 1;
   }
 }
 
 I know that this would cause some performance impact, but my guess is that
 it would not be a lot, especially if we keep the timevalue reasonably high.
 However, in order to get the functionality of
 perform_idle_server_maintenance() working right, we _will_ have to implement
 the above solution (or maybe something similar)!

-1 (my veto only matters in APR-land).  This is ugly.  How are you going 
to implement this?  The problem is that we need to wake the system up from 
holding the mutex.  But, that is almost impossible to implement portably
AFAIK.  Please enlighten me if you know of a way to do this.  You can't 
do a trylock (assuming you can do so with all variants) and then sleep 
for the timeout value.  That doesn't work either.  (All of the threads are 
sleeping after trying a held lock when someone comes along?  Oops.)

The only alternative that I can think of is pthread_cancel(), BUT (at 
least Solaris) says (man cancellation):

 A mutex is explicitly  not a cancellation point  and  should
 be held for only the minimal essential time.

A pthread_cond_wait() and fcntl() are viable options according to the
manpage.  But, I'd much prefer us to use pthread_mutex_t if at all
possible for cross-process locking.  (Yeah, yeah, we require Solaris 8+ 
to do pthread_mutex_t for a cross-process lock now for robust locking.
That's what you get for having child processes - see below...)

 SOLUTION 2: One could use a slightly more _involved_ approach, where the
 dying thread could send a signal to its sibling threads, each of which will
 then handle that signal with a graceful exit.

How?  A thread doesn't have a process id associated with it.  And, I'm
curious to whether the signal would somehow kick us out of the acquire
function.  Doubtful.  I may be wrong (probably am).  Please correct me.
We need to be able to tell the threads they need to exit, but you can't
force them to just exit (which is why pthread_cancel wouldn't work).
They need to exit on their own - otherwise, they won't cleanup.

 SOLUTION 3: We could turn our heads the other way by not worrying about this
 situation at all, since these threads would eventually die (when more
 requests are handled by the webserver).  However, by ignoring the problem,
 the purpose of perform_idle_server_maintenance() would be lost!!

And, based on my interpretation and analysis of the threaded MPM and its
intentions, we shouldn't even need to worry about this case.  Let me 
explain: 

The problem you are stating is that the POD is received by one thread in
one child process, it marks workers_may_exit and then 

Re: [PATCH] Problems with MPM threaded

2001-07-14 Thread Aaron Bannert

On Sat, Jul 14, 2001 at 12:42:29AM -0400, GUMMALAM,MOHAN (HP-Cupertino,ex2) wrote:
[snip]
 SOLUTION 1:  I plan to temporarily implement a new
 apr_lock_acquire_timeout() function, which would cause the threads waiting
 on the mutex to give-up after sometime.  The piece of code would look
 something like this:
 
 while ((rv = SAFE_ACCEPT(apr_lock_acquire_timeout(accept_mutex, timevalue)))
   != APR_SUCCESS) {
   if (check_if_timer_popped)
   if (workers_may_exit)
   break;
   else { /* apr_lock_acquire failed */
   ap_log_error();
   workers_may_exit = 1;
   }
 }
 
 I know that this would cause some performance impact, but my guess is that
 it would not be a lot, especially if we keep the timevalue reasonably high.
 However, in order to get the functionality of
 perform_idle_server_maintenance() working right, we _will_ have to implement
 the above solution (or maybe something similar)!


This looks like a job for condition variables. Using condition
variables you can control exactly when threads get woken up to check
on the condition.  For example, when one thread returns from accept(),
it can signal another thread to move to the accept() state (and as an
optimization that I think Ryan suggested, now you don't need to have
an intraprocess accept lock, since only one thread can be listening in
accept() at a time). The other threads are blocked waiting for some
condition, either allowing them to pass to the accept() state or the
workers_may_exit state.

If this sounds like something you could use here, I can probably elaborate
on this some more, maybe even give some [pseudo]code.

-aaron




Re: [PATCH] Problems with MPM threaded

2001-07-14 Thread rbb


  SOLUTION 2: One could use a slightly more _involved_ approach, where the
  dying thread could send a signal to its sibling threads, each of which will
  then handle that signal with a graceful exit.

 How?  A thread doesn't have a process id associated with it.  And, I'm
 curious to whether the signal would somehow kick us out of the acquire
 function.  Doubtful.  I may be wrong (probably am).  Please correct me.
 We need to be able to tell the threads they need to exit, but you can't
 force them to just exit (which is why pthread_cancel wouldn't work).
 They need to exit on their own - otherwise, they won't cleanup.

  SOLUTION 3: We could turn our heads the other way by not worrying about this
  situation at all, since these threads would eventually die (when more
  requests are handled by the webserver).  However, by ignoring the problem,
  the purpose of perform_idle_server_maintenance() would be lost!!

 And, based on my interpretation and analysis of the threaded MPM and its
 intentions, we shouldn't even need to worry about this case.  Let me
 explain:

 The problem you are stating is that the POD is received by one thread in
 one child process, it marks workers_may_exit and then quits.  The accept
 mutex is then shifted over to another child process which doesn't have
 workers_may_exit set and goes on its merry way.  The only time we check
 for workers_may_exit is after the mutex has been acquired.  Therefore,
 it can take a while to have all of the threads in that POD-receiving
 process to see workers_may_exit.

 Threaded MPM is designed (rather should be - the implementation
 doesn't suggest this) to only have ONE child process that does the

No!  The threaded MPM does NOT and was not intended to implement a
thread-only server.  It was designed to implement a hybrid thread/process
server.  Because we expect both threads and processes, the rest of this
message is based on a misconception.  Having multiple processes each with
multiple threads provides for FAR more robustness than just a single
process with multiple threads.  If you want that, then you want the
perchild MPM, so that the number of threads can grow and shrink correctly.

Ryan

_
Ryan Bloom  [EMAIL PROTECTED]
Covalent Technologies   [EMAIL PROTECTED]
-




Re: [PATCH] Problems with MPM threaded

2001-07-14 Thread Justin Erenkrantz

On Sat, Jul 14, 2001 at 09:19:17AM -0700, [EMAIL PROTECTED] wrote:
 No!  The threaded MPM does NOT and was not intended to implement a
 thread-only server.  It was designed to implement a hybrid thread/process
 server.  Because we expect both threads and processes, the rest of this
 message is based on a misconception.  Having multiple processes each with
 multiple threads provides for FAR more robustness than just a single
 process with multiple threads.  If you want that, then you want the
 perchild MPM, so that the number of threads can grow and shrink correctly.

What are we gaining by having multiple children processes?  I certainly
don't think the robustness gained by having multiple children processes
is all that great.  And, it serves to make the threaded MPM code almost
unmaintainble.  Perchild looks a little closer, but I still think it is
tainted by having multiple children processes.  Oh, and it needs the 
POD fix as well.

By having the possibility of having other children processes, you now
need a mechanism to kill all threads in the same process efficiently.
You'd need to kick them out of the accept mutex, but I'm not seeing
how that's going to happen quickly.  -- justin




Re: [PATCH] Problems with MPM threaded

2001-07-14 Thread rbb

On Sat, 14 Jul 2001, Justin Erenkrantz wrote:

 On Sat, Jul 14, 2001 at 09:19:17AM -0700, [EMAIL PROTECTED] wrote:
  No!  The threaded MPM does NOT and was not intended to implement a
  thread-only server.  It was designed to implement a hybrid thread/process
  server.  Because we expect both threads and processes, the rest of this
  message is based on a misconception.  Having multiple processes each with
  multiple threads provides for FAR more robustness than just a single
  process with multiple threads.  If you want that, then you want the
  perchild MPM, so that the number of threads can grow and shrink correctly.

 What are we gaining by having multiple children processes?  I certainly
 don't think the robustness gained by having multiple children processes
 is all that great.  And, it serves to make the threaded MPM code almost

Apache allows 3rd-party modules, which makes it much more likely that the
server will seg fault.  If you only have one process, then your server
won't be serving any requests during the time it takes to start a second
server.  Add to that the time it takes for the parent process to notice
that the child has died (up to 1 second), and you have missed serving a
lot of requests.

Now, add scalability concerns.  The threaded MPM creates a set number of
threads per child process.  This means that at ALL times, you have to have
enough threads to handle the maximum number of concurrent connections.
That is bogus.  I realize that threads are less expensive than processes,
but come on.  Why should have my enough threads in my server to handle my
peak load at all times?

The Perchild MPM was designed to allow you to grow the number of threads
in a given process.  So, you can bring the number of threads down to 10 or
20, and grow as needed.

 unmaintainble.  Perchild looks a little closer, but I still think it is
 tainted by having multiple children processes.  Oh, and it needs the
 POD fix as well.

Perchild can have as few children as you want.  Set it up to run 1 child,
and it will just have one child.

 By having the possibility of having other children processes, you now
 need a mechanism to kill all threads in the same process efficiently.
 You'd need to kick them out of the accept mutex, but I'm not seeing
 how that's going to happen quickly.  -- justin

You need to be able to kill all threads in a process efficiently
regardless.  We will always need to be able to re-spawn processes that
die, and we will always have the concept of MaxRequestsPerChild.  If a
process is going to die and be replaced, then we need to kill all the
threads in that process as quickly as possible.  Only allowing one
process at a time doesn't remove that requirement.

Feel free to create an MPM that only allows one process at a time, that is
why the MPM mechanism exists, but Threaded and Perchild were both designed
to allow multiple child processes for a reason.

Ryan

_
Ryan Bloom  [EMAIL PROTECTED]
Covalent Technologies   [EMAIL PROTECTED]
-




Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Sander Striker

 By having the possibility of having other children processes, you now
 need a mechanism to kill all threads in the same process efficiently.
 You'd need to kick them out of the accept mutex, but I'm not seeing
 how that's going to happen quickly.  -- justin
 
 You need to be able to kill all threads in a process efficiently
 regardless.  We will always need to be able to re-spawn processes that
 die, and we will always have the concept of MaxRequestsPerChild.  If a
 process is going to die and be replaced, then we need to kill all the
 threads in that process as quickly as possible.  Only allowing one
 process at a time doesn't remove that requirement.

The way I see it, each process has a single pool instance as the parent
for all the threads. Resetting or destroying that pool should effectively
kill all threads. What am I missing?

Sander




Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Justin Erenkrantz

On Sat, Jul 14, 2001 at 09:13:08PM +0200, Sander Striker wrote:
 The way I see it, each process has a single pool instance as the parent
 for all the threads. Resetting or destroying that pool should effectively
 kill all threads. What am I missing?

As I see it, the problem is:

[ Platforms with SAFE_ACCEPT == APR_SUCCESS rather than the lock don't
  apply here. ]

All threads are stuck in the accept mutex except for one.  It reads the
POD.  And, it is time to die.  It sets workers_may_exit to 1.  It then
releases the accept mutex and exits.  Another *child process* acquires 
the accept mutex.  Depending upon how many child processes you have, it 
may take a while for all of the threads in the doomed child process to
acquire the mutex, wake up, check workers_may_exit, release the mutex,
and then exit.  Only when all of the threads in the doomed child process
are exited does any cleanup occur.

These sibling threads are blocked until they receive the mutex.  They 
aren't going to be going anywhere until the mutex is turned over to 
them.  They can't check the value of workers_may_exit *until* they
acquire the mutex.  Condition variables help *somewhat*, but the
problem is now of scope - you have an interprocess condition and a
intraprocess condition to check.  Does this work?  I don't know.

And, you can't kick the thread out of the mutex acquire (pthread_cancel 
or similar strategies don't cancel a mutex operation), so you are
screwed.  And, destroying its parent pool does *NOT* destroy the 
thread.  Look at the code again.  The only person that can call
pthread_exit() is the actual thread itself.  You can't call 
pthread_exit on behalf of another thread (i.e. from the thread that
knows it is doomed or a cleanup thread).  It just doesn't work like 
that.

I just don't agree with Ryan's assessment here.  But, it's possible 
I'm missing some major piece of code.  -- justin




RE: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Sander Striker

  The way I see it, each process has a single pool instance as the parent
  for all the threads. Resetting or destroying that pool should 
 effectively
  kill all threads. What am I missing?
 
 As I see it, the problem is:
 
 [ Platforms with SAFE_ACCEPT == APR_SUCCESS rather than the lock don't
   apply here. ]
 
 All threads are stuck in the accept mutex except for one.  It reads the
 POD.  And, it is time to die.  It sets workers_may_exit to 1.  It then
 releases the accept mutex and exits.  Another *child process* acquires 
 the accept mutex.  Depending upon how many child processes you have, it 
 may take a while for all of the threads in the doomed child process to
 acquire the mutex, wake up, check workers_may_exit, release the mutex,
 and then exit.  Only when all of the threads in the doomed child process
 are exited does any cleanup occur.
 
 These sibling threads are blocked until they receive the mutex.  They 
 aren't going to be going anywhere until the mutex is turned over to 
 them.  They can't check the value of workers_may_exit *until* they
 acquire the mutex.  Condition variables help *somewhat*, but the
 problem is now of scope - you have an interprocess condition and a
 intraprocess condition to check.  Does this work?  I don't know.
 
 And, you can't kick the thread out of the mutex acquire (pthread_cancel 
 or similar strategies don't cancel a mutex operation), so you are
 screwed.  

Err, doesn't destruction of the mutex wake everyone up?
Oh, wait, does every process share the same mutex?

 And, destroying its parent pool does *NOT* destroy the thread.
 Look at the code again.  

Well, it should, although it may not do so now.

 The only person that can call
 pthread_exit() is the actual thread itself.  You can't call 
 pthread_exit on behalf of another thread (i.e. from the thread that
 knows it is doomed or a cleanup thread).  It just doesn't work like 
 that.
 
 I just don't agree with Ryan's assessment here.  But, it's possible 
 I'm missing some major piece of code.  -- justin

Could be I'm way off too.

Sander




Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Aaron Bannert

On Sat, Jul 14, 2001 at 12:27:05PM -0700, Justin Erenkrantz wrote:
 And, you can't kick the thread out of the mutex acquire (pthread_cancel 
 or similar strategies don't cancel a mutex operation), so you are
 screwed.  And, destroying its parent pool does *NOT* destroy the 
 thread.  Look at the code again.  The only person that can call
 pthread_exit() is the actual thread itself.  You can't call 
 pthread_exit on behalf of another thread (i.e. from the thread that
 knows it is doomed or a cleanup thread).  It just doesn't work like 
 that.

Here's what my box's pthread_cancel man page says:

   Cancellation points are those points in the program execu­
   tion where a test for  pending  cancellation  requests  is
   performed  and  cancellation  is executed if positive. The
   following POSIX threads functions are cancellation points:

   pthread_join(3)
   pthread_cond_wait(3)
   pthread_cond_timedwait(3)
   pthread_testcancel(3)
   sem_wait(3)
   sigwait(3)

Doesn't pthread_mutex_acquire sit in sem_wait() or sigwait()? That'll
let it be cancel()ed.


Anyway, yes the pool cleanup routines that are supposed to be calling
apr_thread_exit() are broken because nothing in httpd is calling
apr_thread_exit() (AFA-my-grep-says). So let's either let the thread
creator (aka httpd) do the cleanup registration, or put it in apr
(as an optional feature).

-aaron




Re: Terminating threads in a process, WAS: RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Justin Erenkrantz

On Sat, Jul 14, 2001 at 09:43:53PM +0200, Sander Striker wrote:
 Err, doesn't destruction of the mutex wake everyone up?
 Oh, wait, does every process share the same mutex?

Yup.  accept_mutex is CROSS_PROCESS.  See?

That's the rub.  You can't destroy it.  Otherwise, you'd screw the
other child processes which shouldn't be killed off.

Which is why I'm saying it is invalid to have multiple child process
in a threaded MPM.

  And, destroying its parent pool does *NOT* destroy the thread.
  Look at the code again.  
 
 Well, it should, although it may not do so now.

That's impossible to do.  Another thread can not indicate that a thread
should exit with the threading libraries (safely).  It must have some
OOB way of doing so (which we have).  The only problem is that our 
thread is stuck in an *uninterruptable* operation.  If that operation 
were interruptable OR that thread received the mutex, then it'd check 
the workers_may_exit flag.  Then, it'd exit.   -- justin




Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Justin Erenkrantz

On Sat, Jul 14, 2001 at 12:49:51PM -0700, Aaron Bannert wrote:
 Doesn't pthread_mutex_acquire sit in sem_wait() or sigwait()? That'll
 let it be cancel()ed.

Nope.

As I posted earlier, man cancellation on Solaris 8 says:

 A mutex is explicitly  not a cancellation point  and  should
 be held for only the minimal essential time.

pthread_cancel wouldn't work.  And as Ryan pointed out, it is bad to try
and forcibly kill a thread.  -- justin




Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Aaron Bannert

 Async cancellation of threads is VERY bad ju-ju.  We don't do it because
 it causes most, if not all, thread libraries to leak.  The cleanups are
 called because the child pool is destroyed when all the threads die.

Right, but we're about to kill the processes anyway, so who cares if
it leaks on some platforms. Anyway, we're writing to a specification,
not an implementation. If Apache isn't going to encourage OS vendors to
properly implement their own APIs, who is?

(Just think how easy it would be for us if all these platforms fully supported
a single API, be it posix or whatever. Heaven!)

Anyway, to me this is what pools were designed for.

-aaron




Standards compliance in Apache code WAS Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Justin Erenkrantz

On Sat, Jul 14, 2001 at 01:19:43PM -0700, Aaron Bannert wrote:
  Async cancellation of threads is VERY bad ju-ju.  We don't do it because
  it causes most, if not all, thread libraries to leak.  The cleanups are
  called because the child pool is destroyed when all the threads die.
 
 Right, but we're about to kill the processes anyway, so who cares if
 it leaks on some platforms. Anyway, we're writing to a specification,
 not an implementation. If Apache isn't going to encourage OS vendors to
 properly implement their own APIs, who is?

Eh, it's probably the other way around.  Otherwise, we'd have no need
for #ifdefs.  =)  Standards are only as good as their implementations.
Most users of Apache couldn't care less if their favorite OS didn't
implement a particular feature correctly.  It's *our* problem to work
around it.  Ideally, yes, we could just write to a spec, but that's in
fantasy land.  I live in the real world with lots of sub-par
implementations flying around.

 (Just think how easy it would be for us if all these platforms fully supported
 a single API, be it posix or whatever. Heaven!)
 
 Anyway, to me this is what pools were designed for.

I'd still like to know how you are going to interrupt the cross-process
mutex.  

It doesn't matter if it implemented Posix or whatever.  That's not the
problem here.  We're in the middle of an uninterruptable call and that
mutex can not be destroyed because it is *cross-process*.  -- justin




Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Aaron Bannert

On Sat, Jul 14, 2001 at 01:18:04PM -0700, Justin Erenkrantz wrote:
 On Sat, Jul 14, 2001 at 12:49:51PM -0700, Aaron Bannert wrote:
  Doesn't pthread_mutex_acquire sit in sem_wait() or sigwait()? That'll
  let it be cancel()ed.
 
 Nope.
 
 As I posted earlier, man cancellation on Solaris 8 says:
 
  A mutex is explicitly  not a cancellation point  and  should
  be held for only the minimal essential time.

Hmmm..that sounds like we're using mutexes incorrectly.

-aaron




Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Justin Erenkrantz

On Sat, Jul 14, 2001 at 01:29:35PM -0700, [EMAIL PROTECTED] wrote:
 What you are missing is the history.  All of the problems that we are
 trying to solve were solved already in the original code.  These problem
 are solved most easily by using two mutexes, one for keeping only one
 process in the inner loop, and the inner one for the threads in the
 process.  Then, when you are killing a process, you can easily wake up all
 the threads in the process that are sitting on a lock.

Ah.  Yes, that makes more sense.  But, that's not what's there now.

Shall I submit a patch to threaded MPM to do this?  -- justin




Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Aaron Bannert

On Sat, Jul 14, 2001 at 01:29:35PM -0700, [EMAIL PROTECTED] wrote:
 This is why the original code, in apache-apr, written by Manoj back at IBM
 used two mutexes.  The first was cross-process, the second was
 cross-threads.  It allowed us to handle this much cleaner.  I didn't
 realize this had been removed.
 
[snip]
 
 What you are missing is the history.  All of the problems that we are
 trying to solve were solved already in the original code.  These problem
 are solved most easily by using two mutexes, one for keeping only one
 process in the inner loop, and the inner one for the threads in the
 process.  Then, when you are killing a process, you can easily wake up all
 the threads in the process that are sitting on a lock.

[bird's eye view observation follows:]

I'm beginning to understand why I keep running across parts of APR that
seem inconsistent, overly complicated, disjoint, not generally applicable,
and sometimes seemingly suboptimal. They are holdovers from when they
provided a solution in httpd. I can see how it would be difficult to
form APR for general use when it started out just being code ripped out
of apache. I do think that many of these problems are because APR is
in some places still striving to support the needs of httpd directly,
instead of just providing the basic building blocks that both httpd and
other programs need.

So where to start?

-aaron




[PATCH] Add intraprocess mutex to threaded MPM WAS Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

2001-07-14 Thread Justin Erenkrantz

  Ah.  Yes, that makes more sense.  But, that's not what's there now.
 
  Shall I submit a patch to threaded MPM to do this?  -- justin
 
 Please.

This also includes my POD patch.  I can separate it out if you don't
want the POD code merged yet.  -- justin

Index: threaded.c
===
RCS file: /home/cvs/httpd-2.0/server/mpm/threaded/threaded.c,v
retrieving revision 1.44
diff -u -r1.44 threaded.c
--- threaded.c  2001/07/03 13:58:10 1.44
+++ threaded.c  2001/07/14 20:48:04
@@ -143,10 +143,7 @@
 
 char ap_coredump_dir[MAX_STRING_LEN];
 
-static apr_file_t *pipe_of_death_in = NULL;
-static apr_file_t *pipe_of_death_out = NULL;
-static apr_lock_t *pipe_of_death_mutex;   /* insures that a child process only
- consumes one character */
+static ap_pod_t *pipe_of_death;
 
 /* *Non*-shared http_main globals... */
 
@@ -178,7 +175,13 @@
 static int worker_thread_count;
 static apr_lock_t *worker_thread_count_mutex;
 
-/* Locks for accept serialization */
+/* Locks for accept serialization
+ * worker_accept_mutex ensures that only one thread in a child process
+ * may be in accept.  It also ensures that when we have 
+ * workers_may_exit=1 that we exit.
+ * accept_mutex is the cross-process mutex which all children have.
+ */
+static apr_lock_t *worker_accept_mutex;
 static apr_lock_t *accept_mutex;
 static apr_lockmech_e_np accept_lock_mech = APR_LOCK_DEFAULT;
 static const char *lock_fname;
@@ -494,29 +497,6 @@
 }
 }
 
-/* Sets workers_may_exit if we received a character on the pipe_of_death */
-static void check_pipe_of_death(void)
-{
-apr_lock_acquire(pipe_of_death_mutex);
-if (!workers_may_exit) {
-apr_status_t ret;
-char pipe_read_char;
-   apr_size_t n = 1;
-
-ret = apr_recv(listensocks[0], pipe_read_char, n);
-if (APR_STATUS_IS_EAGAIN(ret)) {
-/* It lost the lottery. It must continue to suffer
- * through a life of servitude. */
-}
-else {
-/* It won the lottery (or something else is very
- * wrong). Embrace death with open arms. */
-workers_may_exit = 1;
-}
-}
-apr_lock_release(pipe_of_death_mutex);
-}
-
 static void * worker_thread(void * dummy)
 {
 proc_info * ti = dummy;
@@ -539,8 +519,8 @@
 worker_thread_count++;
 apr_lock_release(worker_thread_count_mutex);
 
-apr_poll_setup(pollset, num_listensocks+1, tpool);
-for(n=0 ; n = num_listensocks ; ++n)
+apr_poll_setup(pollset, num_listensocks, tpool);
+for(n = 0; n  num_listensocks; ++n)
apr_poll_socket_add(pollset, listensocks[n], APR_POLLIN);
 
 /* TODO: Switch to a system where threads reuse the results from earlier
@@ -553,7 +533,10 @@
 
 (void) ap_update_child_status(process_slot, thread_slot, SERVER_READY, 
   (request_rec *) NULL);
-if ((rv = SAFE_ACCEPT(apr_lock_acquire(accept_mutex)))
+
+apr_lock_acquire(worker_accept_mutex);
+if (!workers_may_exit  
+(rv = SAFE_ACCEPT(apr_lock_acquire(accept_mutex)))
 != APR_SUCCESS) {
 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
  apr_lock_acquire failed. Attempting to shutdown 
@@ -580,12 +563,8 @@
 
 if (workers_may_exit) break;
 
-   apr_poll_revents_get(event, listensocks[0], pollset);
-if (event  APR_POLLIN) {
-/* A process got a signal on the shutdown pipe. Check if we're
- * the lucky process to die. */
-check_pipe_of_death();
-continue;
+if (!ap_mpm_pod_check(pipe_of_death)) {
+workers_may_exit = 1;
 }
 
 if (num_listensocks == 1) {
@@ -624,6 +603,12 @@
  process gracefully.);
 workers_may_exit = 1;
 }
+if ((rv = apr_lock_release(worker_accept_mutex)) != APR_SUCCESS) {
+ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+ apr_lock_release failed. Attempting to shutdown 
+ process gracefully.);
+workers_may_exit = 1;
+}
 if (csd != NULL) {
 process_socket(ptrans, csd, process_slot, thread_slot);
 requests_this_child--;
@@ -637,6 +622,12 @@
  process gracefully.);
 workers_may_exit = 1;
 }
+if ((rv = apr_lock_release(worker_accept_mutex)) != APR_SUCCESS) {
+ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+ apr_lock_release failed. Attempting to shutdown 
+ process gracefully.);
+workers_may_exit = 1;
+}
 break;
 }
 

Re: [PATCH] Problems with MPM threaded

2001-07-14 Thread Roy T. Fielding

 The correct fix, as I see it, is to kill off the interprocess 
 accept lock by removing the possibility of having other processes
 in a *threaded* MPM.  -- justin

That architecture was explored in detail by Netscape.  It isn't reliable
and slows your web server to a crawl whenever dynamic content is produced.
It should only be used for static file servers and caching gateways, and
people implementing those might as well use an in-kernel server like TUX.

Roy