Proper maintenance and care of multi-threading locks

Proper maintenance and care of multi-threading locks

The following strategies are used to ensure that the code is dead-lock free (generally by addressing the 4th Coffman condition: circular wait).

  1. structure code such that only one lock will need to be acquired at a time
  2. always acquire shared locks in the same order, as given by the table below
  3. avoid constructs that expect to need unrestricted recursion

Locks

Below are all of the locks that exist in the system and the mechanisms for using them that avoid the potential for deadlocks (no Ostrich algorithm allowed here):

The following are definitely leaf locks (level 1), and must not try to acquire any other lock:

The following is a leaf lock (level 2), and only acquires level 1 locks (safepoint) internally:

The following is a level 3 lock, which can only acquire level 1 or level 2 locks internally:

The following is a level 4 lock, which can only recurse to acquire level 1, 2, or 3 locks:

No Julia code may be called while holding a lock above this point.

The following is a level 6 lock, which can only recurse to acquire locks at lower levels:

The following is an almost root lock (level end-1), meaning only the root look may be held when trying to acquire it:

The following is the root lock, meaning no other lock shall be held when trying to acquire it:

Broken Locks

The following locks are broken:

Shared Global Data Structures

These data structures each need locks due to being shared mutable global state. It is the inverse list for the above lock priority list. This list does not include level 1 leaf resources due to their simplicity.

MethodTable modifications (def, cache, kwsorter type) : MethodTable->writelock

Type declarations : toplevel lock

Type application : typecache lock

Module serializer : toplevel lock

JIT & type-inference : codegen lock

MethodInstance updates : codegen lock

LLVMContext : codegen lock

Method : Method->writelock