Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZoltan Varga <vargaz@gmail.com>2003-08-27 18:34:03 +0400
committerZoltan Varga <vargaz@gmail.com>2003-08-27 18:34:03 +0400
commit8b508eeed80d99f1e0832035b192bf3f67d47142 (patch)
tree8904ab23ff3514393a52cd136802015e79d8f8b1
parent3046397311caf0ed5cd61c5ba05acbd695a5d447 (diff)
2003-08-27 Zoltan Varga <vargaz@freemail.hu>
* NOTES: New file. svn path=/trunk/mono/; revision=17665
-rw-r--r--mono/metadata/ChangeLog2
-rw-r--r--mono/metadata/NOTES113
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