Skip to content

Commit

Permalink
Improved identity integration in com.
Browse files Browse the repository at this point in the history
  • Loading branch information
LarsAsplund committed Jan 14, 2023
1 parent 9ddbc36 commit d8f71f5
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 31 deletions.
28 changes: 20 additions & 8 deletions docs/com/user_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ actor.
constant my_receiver : actor_t := new_actor("my receiver");
Internally an identity (see :ref:`identity package <id_user_guide>`) will be created for each actor
and it is also possible to create an actor directly from an identity.

constant my_receiver_id : id_t := get_id("my receiver");
constant my_receiver : actor_t := new_actor(my_receiver_id);

To send a message to the receiver the sender must have access to the value of the ``my_receiver`` constant.
If the receiver made ``my_receiver`` publically available, for example with a package, it can be accessed
directly. If not, it can be found with the ``find`` function providing it has been given an explict name.
Expand All @@ -70,6 +76,12 @@ directly. If not, it can be found with the ``find`` function providing it has be
constant found_receiver : actor_t := find("my receiver");
or

.. code-block:: vhdl
constant found_receiver : actor_t := find(my_receiver_id);
The next step is to create a message to send and we start by creating an empty message

.. code-block:: vhdl
Expand Down Expand Up @@ -523,7 +535,7 @@ It's also possible to wait for a reply with a timeout.
Deferred Actor Creation
-----------------------------
-----------------------

When finding an actor using the ``find`` function there is a potential race condition. What if the actor hasn't been
created yet? The default VUnit solution is that the ``find`` function creates a temporary actor with limited
Expand Down Expand Up @@ -693,27 +705,27 @@ be aware of:
* A subscription on the inbound traffic of an actor won't pick up replies to an anonymously request.

Blocking subscribers
-------------------------
--------------------

Although the intent of the publisher/subscriber pattern is to decouple the publisher from the subscribers it can still
be affected if a subscriber inbox is full. A message transaction will be blocked until all of its subscribers and any
regular receiver have available space in their inboxes.

Unsubscribing
-----------------
-------------

An actor can unsubscribe from a subscription at any time by calling ``unsubscribe`` with the same parameters used when
calling the ``subscribe`` procedure.

****************************
*********
Debugging
****************************
*********
Message passing provides a communication mechanism an abstraction level above the normal signalling in VHDL.
This also means that there is a need for an equally elevated level of debugging. To support that ``com`` has
a number of built-in features specially targeting debugging.

Logging Messages
-----------------
----------------

One way of debugging is to inspect the messages that flow through the system, for example by subscribing to actor
traffic. You can use previously presented functions to find out sender, receiver and message content but you can
Expand Down Expand Up @@ -861,9 +873,9 @@ all deferred actors.
messenger_state := get_messenger_state;
debug(get_messenger_state_string);
****************************
***************
Deprecated APIs
****************************
***************

``com`` maintains a number of deprecated APIs for better backward compatibility. Using these APIs will result in
a runtime error unless enabled by calling the ``allow_deprecated`` procedure.
Expand Down
19 changes: 19 additions & 0 deletions vunit/vhdl/com/src/com.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,35 @@ package body com_pkg is
return messenger.create(name, inbox_size, outbox_size);
end;

impure function new_actor (
id : id_t;
inbox_size : positive := positive'high;
outbox_size : positive := positive'high
) return actor_t is
begin
return messenger.create(id, inbox_size, outbox_size);
end;

impure function find (name : string; enable_deferred_creation : boolean := true) return actor_t is
begin
return messenger.find(name, enable_deferred_creation);
end;

impure function find (id : id_t; enable_deferred_creation : boolean := true) return actor_t is
begin
return messenger.find(id, enable_deferred_creation);
end;

impure function name (actor : actor_t) return string is
begin
return messenger.name(actor);
end;

impure function get_id(actor : actor_t) return id_t is
begin
return messenger.get_id(actor);
end;

procedure destroy (actor : inout actor_t) is
begin
messenger.destroy(actor);
Expand Down
24 changes: 21 additions & 3 deletions vunit/vhdl/com/src/com_api.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use work.com_types_pkg.all;
use work.queue_pkg.all;
use work.integer_vector_ptr_pkg.all;
use work.string_ptr_pkg.all;
use work.id_pkg.all;

package com_pkg is
-- Global predefined network. See network_t description in com_types.vhd for
Expand All @@ -23,21 +24,38 @@ package com_pkg is
-----------------------------------------------------------------------------
-- Handling of actors
-----------------------------------------------------------------------------
-- Create a new actor. Any number of unnamed actors (name = "") can be
-- created. Named actors must be unique
-- Create a new actor from name. Names must be unique and if no name is given
-- (name = "") the actor will be assigned a unique name internally. For each
-- new actor an identity for that name will be created if it doesn't already
-- exist.
impure function new_actor (
name : string := "";
inbox_size : positive := positive'high;
outbox_size : positive := positive'high
) return actor_t;
) return actor_t;

-- Create a new actor an identity. Only one actor can be created for each
-- identity.
impure function new_actor (
id : id_t;
inbox_size : positive := positive'high;
outbox_size : positive := positive'high
) return actor_t;

-- Find named actor by name. Enable deferred creation to create a deferred
-- actor when no actor is found
impure function find (name : string; enable_deferred_creation : boolean := true) return actor_t;

-- Find named actor by identity. Enable deferred creation to create a deferred
-- actor when no actor is found
impure function find (id : id_t; enable_deferred_creation : boolean := true) return actor_t;

-- Name of actor
impure function name (actor : actor_t) return string;

-- Return identity of actor
impure function get_id(actor : actor_t) return id_t;

-- Destroy actor. Mailboxes are deallocated and dependent subscriptions are
-- removed. Returns null_actor.
procedure destroy (actor : inout actor_t);
Expand Down
89 changes: 80 additions & 9 deletions vunit/vhdl/com/src/com_messenger.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,20 @@ package com_messenger_pkg is
-----------------------------------------------------------------------------
-- Handling of actors
-----------------------------------------------------------------------------
impure function create (
id : id_t;
inbox_size : positive := positive'high;
outbox_size : positive := positive'high
) return actor_t;
impure function create (
name : string := "";
inbox_size : positive := positive'high;
outbox_size : positive := positive'high
) return actor_t;
impure function find (name : string; enable_deferred_creation : boolean := true) return actor_t;
impure function find (id : id_t; enable_deferred_creation : boolean := true) return actor_t;
impure function name (actor : actor_t) return string;
impure function get_id (actor : actor_t) return id_t;

procedure destroy (actor : inout actor_t);
procedure reset_messenger;
Expand Down Expand Up @@ -277,15 +284,28 @@ package body com_messenger_pkg is
return ret_val;
end;

impure function find_actor (id : id_t) return actor_t is
variable ret_val : actor_t;
begin
for i in actors'reverse_range loop
ret_val := actors(i).actor;
if actors(i).id /= null_id then
exit when actors(i).id = id;
end if;
end loop;

return ret_val;
end;

impure function create_actor (
name : string := "";
id : id_t;
deferred_creation : in boolean := false;
inbox_size : in natural := natural'high;
outbox_size : in natural := natural'high)
return actor_t is
variable old_actors : actor_item_array_ptr_t;
variable id : id_t;
variable actor_id : integer;
variable actor_id_number : integer;
variable resolved_id : id_t;
begin
old_actors := actors;
actors := new actor_item_array_t(0 to actors'length);
Expand All @@ -294,18 +314,43 @@ package body com_messenger_pkg is
actors(i) := old_actors(i);
end loop;
deallocate(old_actors);
actor_id := actors'length - 1;
if name = "" then
id := get_id("_actor_" & to_string(actor_id));
actor_id_number := actors'length - 1;
if id = null_id then
resolved_id := get_id("_actor_" & to_string(actor_id_number));
else
id := get_id(name);
resolved_id := id;
end if;
actors(actors'length - 1) := ((p_id_number => actor_id), id,
actors(actors'length - 1) := ((p_id_number => actor_id_number), resolved_id,
deferred_creation, create(inbox_size), create(outbox_size), null, (null, null, null));

return actors(actors'length - 1).actor;
end function;

impure function create_actor (
name : string := "";
deferred_creation : in boolean := false;
inbox_size : in natural := natural'high;
outbox_size : in natural := natural'high)
return actor_t is
variable id : id_t;
begin
id := null_id when name = "" else get_id(name);

return create_actor(id, deferred_creation, inbox_size, outbox_size);
end function;

impure function find (id : id_t; enable_deferred_creation : boolean := true) return actor_t is
constant actor : actor_t := find_actor(id);
begin
if (id = null_id) or (id = root_id) then
return null_actor;
elsif (actor = null_actor) and enable_deferred_creation then
return create_actor(id, true, 1);
else
return actor;
end if;
end;

impure function find (name : string; enable_deferred_creation : boolean := true) return actor_t is
constant actor : actor_t := find_actor(name);
begin
Expand All @@ -328,6 +373,32 @@ package body com_messenger_pkg is

end;

impure function get_id (actor : actor_t) return id_t is
begin
return actors(actor.p_id_number).id;
end;

impure function create (
id : id_t;
inbox_size : positive := positive'high;
outbox_size : positive := positive'high
) return actor_t is
variable actor : actor_t := find_actor(id);
begin
if id = root_id then
check_failed(new_actor_from_root_id_error);
elsif actor = null_actor then
actor := create_actor(id, false, inbox_size, outbox_size);
elsif actors(actor.p_id_number).deferred_creation then
actors(actor.p_id_number).deferred_creation := false;
actors(actor.p_id_number).inbox.size := inbox_size;
actors(actor.p_id_number).outbox.size := outbox_size;
else
check_failed(duplicate_actor_name_error);
end if;

return actor;
end;

impure function create (
name : string := "";
Expand All @@ -336,7 +407,7 @@ package body com_messenger_pkg is
) return actor_t is
variable actor : actor_t := find_actor(name);
begin
if (actor = null_actor) or (name = "") then
if actor = null_actor then
actor := create_actor(name, false, inbox_size, outbox_size);
elsif actors(actor.p_id_number).deferred_creation then
actors(actor.p_id_number).deferred_creation := false;
Expand Down
5 changes: 3 additions & 2 deletions vunit/vhdl/com/src/com_types.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ package com_types_pkg is
unknown_request_id_error,
deprecated_interface_error,
insufficient_size_error,
duplicate_actor_name_error);
duplicate_actor_name_error,
new_actor_from_root_id_error);

subtype com_error_t is com_status_t range timeout to duplicate_actor_name_error;
subtype com_error_t is com_status_t range timeout to new_actor_from_root_id_error;

-- All fields of the actor type are private
type actor_t is record
Expand Down
Loading

0 comments on commit d8f71f5

Please sign in to comment.