diff options
author | Zoltan Varga <vargaz@gmail.com> | 2003-08-27 18:34:03 +0400 |
---|---|---|
committer | Zoltan Varga <vargaz@gmail.com> | 2003-08-27 18:34:03 +0400 |
commit | 8b508eeed80d99f1e0832035b192bf3f67d47142 (patch) | |
tree | 8904ab23ff3514393a52cd136802015e79d8f8b1 | |
parent | 3046397311caf0ed5cd61c5ba05acbd695a5d447 (diff) |
2003-08-27 Zoltan Varga <vargaz@freemail.hu>
* NOTES: New file.
svn path=/trunk/mono/; revision=17665
-rw-r--r-- | mono/metadata/ChangeLog | 2 | ||||
-rw-r--r-- | mono/metadata/NOTES | 113 |
2 files changed, 115 insertions, 0 deletions
diff --git a/mono/metadata/ChangeLog b/mono/metadata/ChangeLog index 76dd147acd9..c0830b1c32a 100644 --- a/mono/metadata/ChangeLog +++ b/mono/metadata/ChangeLog @@ -1,5 +1,7 @@ 2003-08-27 Zoltan Varga <vargaz@freemail.hu> + * NOTES: New file. + * object.c (mono_class_proxy_vtable): Make it thread safe. * pedump.c: Fix warning. diff --git a/mono/metadata/NOTES b/mono/metadata/NOTES new file mode 100644 index 00000000000..4edf1cd699c --- /dev/null +++ b/mono/metadata/NOTES @@ -0,0 +1,113 @@ + +1. Thread safety of metadata structures +---------------------------------------- + +1.1 Synchronization of read-only data +------------------------------------- + +Read-only data is data which is not modified after creation, like the +actual binary metadata in the metadata tables. + +There are three kinds of threads with regards to read-only data: +- readers +- the creator of the data +- the destroyer of the data + +Most threads are readers. + +- synchronization between readers is not neccesary +- synchronization between the writers is done using locks. +- synchronization between the readers and the creator is done by not exposing + the data to readers before it is fully constructed. +- synchronization between the readers and the destroyer: TBD. + +1.2 Deadlock prevention plan +---------------------------- + +Hold locks for the shortest time possible. Avoid calling functions inside +locks which might obtain global locks (i.e. locks known outside this module). + +1.3 Locks +---------- + +1.3.1 Simple locks +------------------ + + There are a lot of global data structures which can be protected by a 'simple' lock. Simple means: + - the lock protects only this data structure or it only protects the data structures in a given C module. + An example would be the appdomains list in domain.c + - the lock is only held for a short amount of time, and no other lock is acquired inside this simple lock. Thus there is + no possibility of deadlock. + +1.3.2 The class loader lock +--------------------------- + +This locks is held by the class loading routines in class.c and loader.c. It +protects the various caches inside MonoImage which are used by these modules. + +1.3.3 The domain lock +--------------------- + +Each appdomain has a lock which protects the per-domain data structures. + +1.3.4 The locking hierarchy +--------------------------- + +It is useful to model locks by a locking hierarchy, which is a relation between locks, which is reflexive, transitive, +and antisymmetric, in other words, a lattice. If a thread wants to acquire a lock B, while already holding A, it can only +do it if A < B. If all threads work this way, then no deadlocks can occur. + +Our locking hierarchy so far looks like this: + <DOMAIN LOCK> + \ + <CLASS LOADER LOCK> + \ \ + <SIMPLE LOCK 1> <SIMPLE LOCK 2> + +1.4 Notes +---------- + +Some common scenarios: +- if a function needs to access a data structure, then it should lock it itself, and do not count on its caller locking it. + So for example, the image->class_cache hash table would be locked by mono_class_get(). + +- there are lots of places where a runtime data structure is created and stored in a cache. In these places, care must be + taken to avoid multiple threads creating the same runtime structure, for example, two threads might call mono_class_get () + with the same class name. There are two choices here: + + <enter mutex> + <check that item is created> + if (created) { + <leave mutex> + return item + } + <create item> + <store it in cache> + <leave mutex> + + This is the easiest solution, but it requires holding the lock for the whole time which might create a scalability problem, and could also lead to deadlock. + + <enter mutex> + <check that item is created> + <leave mutex> + if (created) { + return item + } + <create item> + <enter mutex> + <check that item is created> + if (created) { + /* Another thread already created and stored the same item */ + <free our item> + <leave mutex> + return orig item + } + else { + <store item in cache> + <leave mutex> + return item + } + + This solution does not present scalability problems, but the created item might be hard to destroy (like a MonoClass). + +- lazy initialization of hashtables etc. is not thread safe |