2.3 Simulation Cells 2.5 Concurrency Modes
API Reference Manual  /  2 Threading Model  / 

2.4 Thread Domains

Each object in the simulation has a thread domain associated with it. The same thread domain can be associated with multiple objects.

The basic rule is that before the state of an object is accessed, the corresponding thread domain needs to be held by the thread performing the access. This ensures that an object is never accessed concurrently by two different threads.

The thread domain containing the cell object, the cell thread domain (cell TD), has some special properties. Sometimes it is referred to as just the "cell" for brevity, as in "acquiring the cell", and "holding the cell", which should be read as "acquiring the cell thread domain", and "holding the cell thread domain" respectively.

Division of a cell into thread domains

The cell TD should be thought of as a single-threaded domain. To a model in the cell TD, everything in the entire cell appears to be simulated from a single thread, even if this is not the case.

Note: In most cases, the appropriate thread domain is already held, and no special action needs to be taken. This is for instance the case for normal device models, which run in Cell Context, or for code running in Global Context.

Only models which use custom threads or use the Threaded Device Model need to acquire thread domains explicitly.

2.4.1 Relationship with API Execution Context

The relationship between the API execution context, defined in section 1.3.2, and thread domains is as follows:

Global Context
All thread domains (and by implication, all cells) in the simulation are held by the thread. The thread has exclusive access to all objects. CLI scripts, Python scripts, CLI commands, script-branches, and object initialization code, all run in Global Context.

Cell Context
The cell TD is held by the thread. The thread can freely access all other objects in the cell. Normal device models (i.e. models which are not thread-aware) can assume that they are invoked in this context.

Threaded Context
No thread domains are required to be held, but thread-aware models often hold their own thread domain.

Note: The locking model in Simics is asymmetrical. Models running in Cell Context can call interface functions on any object in the cell without taking any special measures, and this includes interfaces on objects belonging to a different TD. This is possible since thread-aware models are required to guard model entry points by acquiring their own domains. Conversely, thread-aware models are required to enter Cell Context explicitly, by using a special API call, before calling interface functions on objects in the cell TD.

2.4.2 Lock Semantics

A thread domain has the following basic properties:

The following macros are used to acquire thread domains.

SIM_ACQUIRE_OBJECT
Acquires the thread domain associated with the object.

This function is intended to be used by thread-aware objects to obtain its own thread domain before modifying internal state protected by the domain.

This primitive does not enter Cell Context, even if the cell TD is acquired. The reason is that the retention mechanism is not activated (see below).

SIM_ACQUIRE_TARGET
Enters Cell Context if the specified object belongs to the cell TD. As part of entering Cell Context, the cell TD is acquired.

This primitive does nothing if the object does not belong to the cell TD. In other words, it is a no-op if the specified object is thread-aware.

Thread-aware code, which is not running in Cell Context, uses this function before invoking an interface method on an external object.

SIM_ACQUIRE_CELL
Enters Cell Context unconditionally. The specified object is associated with a cell whose TD is acquired as part of entering Cell Context.

The function should be used before calling an API function, or callback, requiring Cell Context.

Each primitive above should be used together with the corresponding release function. Macros are used in order to allow lock statistics to be collected with information about where the lock was acquired. There are also corresponding SIM-functions available.

Note: If multiple thread domains are acquired, then they must be released in strict reverse order. Failure to do so will result in a hard error and a complaint about locks being released in an incorrect order.
Note: The difference between SIM_ACQUIRE_CELL and SIM_ACQUIRE_TARGET is really that the former always acquires the cell thread domain and enters Cell Context, whereas the latter is a no-op when a thread-aware object is specified.

The reason for the distinction is that thread-aware objects are required to protect incoming as needed; this self-protection usually involves a call to SIM_ACQUIRE_OBJECT, but models are free to use alternate locking schemes.

2.4.3 Contention

Note: This section describes how Simics handles thread domain contention, and it is mostly provided to allow for a deeper understanding of the Simics threading model.
When a thread tries to acquire a thread domain which is already held or requested by another thread, then the following happens:

The priority is assigned as follows:

 
Priority Name    Situation
1Execute TD acquired for instruction execution (lowest priority)
2Yield domains reacquired after explicit yield
3Entry TD acquired, no other domains held
4Entry 2 TD acquired, other TDs already held
5Cell Entry cell acquired with SIM_ACQUIRE_CELL/TARGET
6Elevated TD acquired in Cell Context
7Message TD acquired for delivery of direct memory message

In the table above, TD stands for a thread domain which is not the cell TD.

A contended thread domain is always assigned to the waiting thread with the highest priority. The domain is never released to a thread with lower priority, even if the domain is unused and the highest priority thread is waiting upon some other domain.

The priority scheme serves two purposes:

Note: For performance reasons, a thread waiting for a thread domain will typically spin for a certain amount of time before falling back to sleeping on some condition variable.

2.4.4 Domain Retention

In Cell Context, a special mechanism is used when additionally acquired thread domains are released:

Domain retention mechanism
The release of additionally acquired domains is deferred until Cell Context is exited, or in other words, until the cell TD is released.

As an example, consider a thread doing the following, with CPU1 belonging to thread domain TD_cpu1, CPU2 to TD_cpu2, and device DEV to TD_cell, respectively:

  1. CPU1 is simulated while holding TD_cpu1
  2. EC is entered before the model calls an interface on DEV. TD_cell is acquired when EC is entered.
  3. device DEV queries CPU2 for its cycle count. The TD_cpu2 domain is acquired and released during this operation, but the actual release of TD_cpu2 is deferred by the retention mechanism
  4. device DEV posts an event on CPU2, again taking and releasing TD_cpu2
  5. TD_cell is released when the DEV interface call returns, and the thread leaves Cell Context. The retention mechanism causes TD_cpu2 to be released for real at this point
The retention mechanism ensures that TD_cpu2, in the example above, is held until the device access is complete. Between point 3 and point 5, CPU2 will not be simulated, and its state will be stable.
Note: The retention mechanism ensures that a device model sees a stable state for all objects it interacts with. The mechanism allows CPUs to run concurrently with device models, but when a device model interacts with a CPU, it is stopped until the device operation is complete.
2.3 Simulation Cells 2.5 Concurrency Modes