[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: (ITS#4943) tpool.c pause vs. finish

Hallvard B Furuseth wrote:
> hyc@symas.com writes:
>> h.b.furuseth@usit.uio.no wrote:
>>> * When a thread is finishing, make it go active for context_reset().
>>>   Should make slapi module destructors safer, and I don't see that it
>>>   can hurt.
>> I don't understand this.
> Let me dig a bit back in the ITS...
>   "context_reset() can call connection_fake_destroy(), which via
>   slapi_int_free_object_extensions() calls slapi module destructors,
>   which can do who-knows-what."

context_reset() can only be called from the main thread. It can (must) never be 
called by anything running from the pool.

>>> * Scheduling: If several threads call pool_pause(), then once there is a
>>>   pause tpool does not schedule them all.  They could get handled then,
>>>   or another thread could undo the pause so tpool would wait to pause
>>>   again.  Is that deliberate?
>> I don't understand the question. The point of the pause is to prevent
>> any other thread (in the pool) from running. Why should tpool schedule
>> any other threads at this point?
> Two threads call pool_pause().  Eventually the pool gets paused, and one
> pool_pause() call returns.  When that thread calls pool_resume(), the
> other thread waiting in pool_pause() may or may not get scheduled.

OK, that sounds like a bug.

>>>   - pool_context() breaks if several ldap_pvt_thread_t bit patterns can
>>>     represent the same thread ID: TID_HASH() would give different hashes
>>>     for the same thread, and pool_context() stops searching when it hits
>>>     a slot with ctx == NULL.  (My previous bug report was a bit wrong.)
>> How can a single thread ID be represented by multiple bit patterns?
> A struct/union with padding bytes seems the least unlikely possibility.

Any implementation that leaves uninitialized padding bytes would be a bug. 
Tools like valgrind would barf all over them.

> A pointer in hardware where several address representations map to the
> same physical address, and the compiler handles that by normalizing
> pointers when they are compared/subtracted.  Like DOS "huge" pointers
> would have been if the compiler normalized them when comparing them
> instead of when incrementing/decrementing them.  20-bit address bus,
> 32-bit pointers, physical address = 16 * <segment half of pointer> +
> <offset half of pointer>.

Nobody voluntarily uses such memory models today. The very mention of "DOS" 
invalidates this discussion since there is no threading environment there.

>>>     The best fix would be to use use real thread-specific data instead.
>>>     Just one key with the ctx for now, that minimizes the changes.  OTOH
>>>     it also means we'll do thread-specific key lookup twice - first in
>>>     pthread to get the ctx, and then in ltu_key[] to find our data.
>>>     Anyway, I said I'd do that later but might as well get on with it,
>>>     at least for pthreads.  Except I don't know if that's OS-dependent
>>>     enough that it should wait for RE24?
>> The best fix may be to just use the address of the thread's stack as the
>> thread ID. That's actually perfect for our purpose.
> How does a function called from somewhere inside the thread know that
> address?  That's almost what the user context is, and thus what
> thread_keys[] maps the thread ID to.

It requires some degree of machine-dependence, which is why I never bothered to 
code it. The principle is simple though - all of our thread stacks are some 
multiple of 1MB in size. Take the address of any local variable, mask off the 
low 20 bits, and you have a unique thread ID (+/- some additional 
masking/shifting based on the actual thread stack size).

   -- Howard Chu
   Chief Architect, Symas Corp.  http://www.symas.com
   Director, Highland Sun        http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP     http://www.openldap.org/project/