Notifiers is a light-weight publish-subscribe mechanism introduced in Simics 6. Unlike the hap system, which also follows a publish-subscribe pattern, notifiers are always tied to a specific object and they do not have any parameters.
An object can subscribe to a notifier published by another object by using the SIM_add_notifier
function. This is illustrated by the example below, where a subscriber
class is defined which subscribes to frequency changed notifications produced by an object implementing the frequency
interface.
class subscriber(pyobj.ConfObject):
# Notifier invoked when the frequency has changed
def notifier(self, obj, src, data):
self.frequency = src.iface.frequency.get()
print("New Frequency", self.frequency)
class frequency_provider(pyobj.Attribute):
"Object implementing the 'frequency' interface"
attrtype = "o|n"
def getter(self):
return self.obj
def setter(self, obj):
# Delete any old notifier
if self.handle:
SIM_delete_notifier(self.obj, self.handle)
self.handle = None
# Subscribe to the new notifier
self.obj = obj
if not obj:
return
self.handle = SIM_add_notifier(
obj, Sim_Notify_Frequency_Change, self._up.obj,
self._up.notifier, None)
# Get current frequency
self._up.frequency = obj.iface.frequency.get()
def _initialize(self):
self.obj = None
self.handle = None
The notifier callback function takes three parameters: the subscriber, the notifier and the data passed by the last argument of the SIM_add_notifier
function. The function looks a bit different in different modeling languages. The Python notifier callback is shown in the above example. In DML, it is defined as:
method on_notify(conf_object_t *notifier, void *data) {
...
}
In C/C++, it is defined as:
void on_notify(conf_object_t *obj, conf_object_t *notifier, void *data) {
...
}
Some things should be noted in the example above:
Simics objects are only allowed to trigger notifiers of types which have been registered with the corresponding Simics class. The exception to this rule is certain notifiers triggered by Simics Core, like the Sim_Notify_Queue_Change
notifier or the Sim_Notify_Cell_Change
notifier, which can be triggered by any object.
The following example illustrates how a class implementing the frequency
interface registers a Sim_Notify_Frequency_Change
notifier with the class and triggers it when the frequency has changed:
class provider(pyobj.ConfObject):
"Object implementing the 'frequency' interface"
class frequency(pyobj.Interface):
def get(self):
return self._up.frequency
class freq(pyobj.Attribute):
"Frequency in Hz"
attrtype = "f"
def getter(self):
return self._up.frequency
def setter(self, val):
self._up.frequency = val
SIM_notify(self._up.obj, Sim_Notify_Frequency_Change)
def _initialize(self):
super()._initialize()
self.frequency = 0
SIM_register_notifier(
"provider", Sim_Notify_Frequency_Change,
"Notifier that is triggered when frequency changes. New frequency can"
" be read via the frequency interface of the object.")
It is possible to create custom notifier types. Both the producer and the consumer calls SIM_notifier_type
to convert a string specifying the notifier to a notifier type:
notifier_type_t sample = SIM_notifier_type("sample-change");
By convention the string should be expressed as a noun, in all lowercase, with words separated by dash.
There are also global notifiers, which do not have a specific publisher object. The semantics is similar to notifiers with a publisher, but is not meant for low-latency communication between objects, so the API functions require Global Context. Global notifiers are manipulated using SIM_add_global_notifier
, SIM_add_global_notifier_once
and SIM_remove_global_notifier
.
Additional code samples demonstrating notifiers usage can be found in the sample-notifier-dml
and sample-notifier-c++
modules.