h.b.furuseth@usit.uio.no wrote:
I wrote in the tpool.c 1.66 -> 1.67 patch:
API changes, need review - I'm not sure what's indented here:
- setkey(data=NULL, kfree!=NULL) searched as if intended to reset the key, but updated by setting the key. Now always updates.
Right. That matches the one place it can happen: In bdb_locker_id() with setkey(,,data=(void *)(long)lockid,). I don't know if lockid can be 0, but it doesn't need to for data to be NULL.
lockid will never be zero.
But it would cleaner to ch_malloc an integer instead of the (void*) cast. Then it won't depend on integer->pointer->integer conversions preserving the value either.
Ugh. That's just silly. We should just typedef a union that's big enough to hold a pointer or an integer...
BTW, is there a reason for the cast to long? lockid is u_int32_t, and the getkey 'long' result is restored to a u_int32_t.
I don't recall.
Howard Chu wrote:
Also if ctx is invalid (another thread handled it) and a new pending request has gotten the now-unused ctx, then the 'if (pool->ltp_open_count == 0)' code will free that new pending request instead of the old one.
Most likely this is due to unlocking and relocking the mutex around the semaphore code. Axe that, remove the gratuitous unlock/relock, and then that problem goes away.
Was that an instruction/permission to axe it or not?
Yes, go ahead.
If not I'll just move the unlock/lock into the #ifdef for now.
Thus far we've only had to worry about a single pool. If anyone can come up with a reason to need multiple pools, I guess we need to hear it.
I'll insert "static int initialized; assert(!initialized++);" in pool_init() and see if anyone complains.
Sounds fine.
- setkey does not free the old data with ltk_free. Possibly that's intentional, but if so that requires weird code elsewhere.
Yes, that's intentional. ltk_free is only intended for cleanup if a key is still set by the time a thread exits. All of the keys we set are live for the entire life of a thread, they don't get re-assigned.
Even the (void*)slap_sasl_bind key? lutil_passwd() looks like it can be recursive: Register a password scheme which finds an entry in LDAP and authenticates via that entry's userPassword - which again could call lutil_passwd().
If that's legal, this code in be_isroot_pw()/slap_passwd_check() can break: pool_setkey(, slap_sasl_bind, <ctx>, <freefunc> ); ... /* slap_passwd_check() does access_allowed() here */ lutil_passwd(); ... pool_setkey(, slap_sasl_bind, NULL, NULL); The final setkey would need to restore the old key.
I guess so.
I'm not sure of contrib/slapd-modules/smbk5pwd/smbk5pwd.c + some overlay either. rwm + back-relay which uses another smbk5pwd or something. (And I have no idea of the BDB cache stuff, but since you wrote it I assume you know:-)
If it's a problem, we can replace code like that with void *data = <ctx>; ldap_pvt_thread_pool_keyfree_t *kfree = <freefunc>; pool_swapkey(, slap_sasl_bind, &data, &kfree ); /* new function */ lutil_passwd(); pool_setkey(, slap_sasl_bind, data, kfree ); or if setkey reverts to ignoring kfree when it checks whether we are setting or deleting a key, the kfree function can be passed directly.
I wrote:
But this reminds me: How much should an ltk_free() function be allowed to do?
- pool_context_reset() calls ltk_free(). Should pool_wrapper() go active (wait for !pause, increment ltp_active_count, unlock ltp_mutex) before calling pool_context_reset()?
I think so. It makes slapi safer, and I don't see that it can hurt: context_reset() can call connection_fake_destroy(), which via slapi_int_free_object_extensions() calls slapi module destructors, which can do who-knows-what.
Another stray thought: It would similarly be safer for context_reset() and purgekey() to delete the key before calling ltk_free, so that function can't access the key's data after freeing it. OTOH that would break any slapi module whose ltk_free calls a function which uses the key before freeing it. I'll leave it alone unless someone says otherwise.
Other matters:
pool->ltp_active_list is maintained but not used for anything. Do I delete it? Or does tpool maintain the list to ease debugging?
No idea.
Use of tpool:
Another bug: Slapd does not always check if pool_submit() and pool_setkey() succeed, even though failure is not a bug. (They can run into some limits.)
I do not understand the calls to ldap_pvt_thread_pool_context_reset() in slapd (init.c and bconfig.c). That frees the thread's sl_malloc memory with slap_sl_mem_destroy(), which seems rather hazardous until the thread is really, really done.
Those calls are from the main thread, and only occur during startup. The point is to free up that memory since the main thread will never need it again.
For that matter, I guess that means context_reset() had better release keys in the reverse order of how they were set. That usually happened, but not always, and my clear_key_idx() made the "not always" more common. So to close the gap from a deleted key I'll make it move all later keys forward, instead of just moving the latest key to the gap.
I don't think the order is really important... ??
Bdb uses the database environment address as a key to pool_setkey(). So there can be at most ~30 BDB databases with an active key at the same time in the same thread. What does that mean - 30 overlays all using bdb? Access control groups spanning 30 databases?
Seems so. We could raise this limit if it's a problem, but I don't see why anyone would use 30 separate databases instead of just one. Configuring the caches would be a real bear...
Nitpick: Slapd uses both function pointers and data pointers as keys to pool_[sg]etkey(). That makes it possible for two "different" keys to compare equal, on a host where functions and data live in different segments that otherwise share the same address space. So I guess I should clean up and replace (void*)<function> keys with the address of static char <function>_key;
Hosts such as ... ? Not even OS/390 is so strange.
The use of function pointers was just a convenience, since the address is guaranteed to be a unique value within the process and easily recognizable in a debugger. We could easily use addresses of static variables instead but it's silly to introduce new variables just for this purpose.