Hi, I have a little situation with cbdata...
in the cache_cf routines we essentially have types (ie acl_access) and
names (http_access is a acl_access).
We have to be able to register new types (string,
parsefunc,freefunc,dumpfunc) dynamically (so modules can provide types).
We have to be able to deregister types dynamically (so modules that are
inactived can stop providing the parsing code)
We have to be able to register names dynamically (string,type pointer,
location pointer) so that modules can have configuration data without
changing the global Config struct.
And likewise when module is deactivated, it needs to be able to
deregister the names it's registered so that any inactive config file
entries can be told to the user, letting them know that they are not
going to be used.
All of that is working ok, but I think there is a race..
Currently, we parse the config file by,
freeing all the config entries,
set any defaults for the config entries,
parse the file
default any entries that are default-if-none.
sanity check
The new one looks like this:
free all the config entries
Deregister all builtin (from cf.data.pre) names
Deregister all builtin (from cf.data.pre) types
Register All builtin (from cf.data.pre) types
Register All builtin (from cf.data.pre) names
set any defaults for the config entries,
parse the file
default any entries that are default-if-none.
sanity check
What I do at the moment is allocated each type entry with CBDATA_ALLOC
with a free function. Then I cbdatalock it for each name that refers to
it.
When the names are deregistered they cbdataunlock it.
When the type is deregistered it cbdatafree's.
The issue:
some config data doesn't get freed by free_all. (ie authentication
settings, cache_dir entries). So the Names won't deregister (by design).
and then the types won't deregister (by design).
All the deregistration and actual removing from lists etc is coordinated
by when the cbdatafree function gets called. When the following happens:
registertype foo
registername bar (cbdataLocks foo)
parse bar (cbdatalocks bar)
free bar (doesn't free.. still in use (doesn't cbdataunlock either))
deregistername bar (calls cbdatafree bar, but the cbdataLock on bar
means it never executes)
deregistertype foo (calls cbdatafree foo, but the cbdataLock on foo
means it never executes)
...
* registertype foo (still registered from before. Checks the functions
are still the same)
* registername bar (still registered from before. Checks the type and
location are still the same)
parse bar (notes its already parsed and locked, so doesn't cbdatalock)
free bar (this time around it frees cleanly , so cbdata unlocks)
==== race - the deregistername & deregistertype free function callbacks
occur here ===
deregistername bar but bar is not registered!
deregistertype foo but foo is not registered!
Note that the second parsing of bar could just cbdatalock anyway, but
that will leads to a never ever freed struct.
I want to introduce a cbdataUnFree(void *) that the registerfunctions
marked with * can use to mark the existing structures as now being valid
again. It would only do this if there were locks on the object.
Comments?
Rob
Received on Tue Feb 20 2001 - 15:52:42 MST
This archive was generated by hypermail pre-2.1.9 : Tue Dec 09 2003 - 16:13:33 MST