Quantcast
Viewing all articles
Browse latest Browse all 6

OOPs! 3 Issues That Show System Verilog Threads are Not OOP Safe!

b'

Verilog has a very limited and simple hierarchy. All processes are present in static modules. In some ways, System Verilog extends this concept of hierarchy with the support for dynamic data type of class. In System Verilog processes are also present inside dynamic objects. System Verilog updates to fork-join constructs, make the process more flexible and dynamic.

However, this also increases complexity of using processes in System Verilog.  What makes it tricky is process usage in the context of object oriented programming. I know that sounds counter intuitive. Object Oriented Programming is good, right? What I mean is, not all the constructs of System Verilog are compatible with object-oriented interpretation. This limited support of object-oriented programming leads to confusion.

In this article I plan to provide the details of three such sources of confusion I have faced.  I start off with a refresher about the updates to the fork-join construct in System Verilog. The refresher is followed by top three sources of confusion with examples. These are:

  • #1: Block names used for process do not belong to object
  • #2: Processes started in class does not belong to object
  • #3: Processes are not destroyed when the object is destroyed

Even if you do know that System Verilog processes are not truly object oriented, these are “gotcha’s” that you learn only when you experience it in real time or experience it through the examples of this blog!

Refresher: System Verilog Updates to Fork-Join

Fork-join statement originated from Verilog. It is used to run parallel processes while verifying in the test bench environment. System Verilog substantially improved fork/join construct to have much more controllability in process creation, destruction, and waiting for end of the process.
The basic syntax of fork join block looks like this:

fork

  begin : thread_1

    //Body of thread 1

  end :  thread_1

  begin : thread_2 

    //Body of thread 2

  end : thread_2

join     

There are 3 different kind of join keyword in System Verilog, each specifying a different way of waiting for completion of the threads/process created by the fork.

  • join: The parent process blocks until all the processes spawned by this fork completes.
  • join_any: The parent process blocks until any one of the processes spawned by this fork completes.
  • join_none: The parent process continues to execute concurrently with all processes spawned by the fork. The spawned processes do not start executing until the parent thread executes a blocking statement.

In addition to the above there are new process control constructs provided.

"wait fork"  statement waits till the completion of all the child processes (processes created by the calling process). Typically, the previous fork usage will have completed their execution.

"disable fork" statement terminates all active descendants(sub processes) of the calling process.

If only the 2nd thread is to be killed after exiting the loop, then add "disable thread_2;" at the point where you want to disable the second thread only.    

With this quick refresher on the fork-join and new updates of System Verilog to it, lets jump in to sources of confusion. 

Issue#1: Block names used for the processes do not belong to object 

Names of blocks used for spawning process inside a class, are not specific to a particular instance of the class. Hence disabling a process, by its block name in one-object results in process with similar name gets disabled in all objects of that class.

The following example illustrates this issue.

Example :      

Image may be NSFW.
Clik here to view.
Thread Class

Image may be NSFW.
Clik here to view.
Thread Class

Image may be NSFW.
Clik here to view.
Main Program

Image may be NSFW.
Clik here to view.
Main Program

Image may be NSFW.
Clik here to view.
Main Program

Image may be NSFW.
Clik here to view.
Main Program

The three objects of  the thread_block_name_object_orientedclass were declared in the main program of example1. Object allocation of all 3 objects with different arguments was done to distinguish them from one another. Then the run task of all 3 objects was called simultaneously using initial statement.

This created 2 threads namely thread_1 and thread_2 for each object. Thread 1 prints the value of the loop counter with a delay of 1ns upto a maximum value of 15 and thread 2 has an event stop activity which when triggered disables the thread 1.

All the threads were supposed to run for a min time of 15ns because of #15ns delay in all the three initial statements. But after 5ns when the stop_activity event of the first object was triggered it disabled the thread_1 of not only the first object  but also the other two objects.

This observation can be made from the above example where the last printed value for all the three objects' run task is 5 after which the  stop_activity event of the first object was triggered.

This happens because the named blocks spawned by threads in a class are not specific to object.

Conclusion: Named block based process control is not a good idea.  

Issue#2: Processes started in a class does not belong to objects of that class 

Process spawned inside the class, gets affected by the disable fork of the calling process for that class.

Consider an instance where a main thread creates child1 and child2 objects and launches their threads. When the disable fork intended to kill the main thread is called, it kills the threads spawned inside the child1 and child2 objects as well.

The following example illustrates this surprise.

Example :

Image may be NSFW.
Clik here to view.
Thread Class

Image may be NSFW.
Clik here to view.
Main Program

Image may be NSFW.
Clik here to view.
Main Program

Image may be NSFW.
Clik here to view.
Main Program

Two handles thread_1 and thread_2 of thread class were declared in the main program of example2. Object allocation of all 2 objects with different arguments was done to distinguish them from one another. The run task of the thread class has a “for loop” within a join_none thread. This “for loop” prints the value of the counter with a delay of 1ns.

When the run task of both the objects was called, it created 2 separate parallel threads. After that 2 more threads “t1” and “t2” were launched, out of which one would wait for 5ns and the other for10ns. Since it is a join_none thread the 5ns' thread(t2) got completed first and executed disable fork which is supposed to disable “t1” . But this disable fork killed not only 10ns' thread(t1) but also the threads which were launched by thread_1 and thread_2.

This observation can be seen from the fact that the count of thread_1 and thread_2 stops after 4ns in example 2.

Conclusion: Be careful with the placement of the disable fork.

Issue#3: Processes are not destroyed when the container object is destroyed 

When an object is destroyed the threads spawned by the container object are not destroyed. They will continue to run as long the main thread, which spawned the threads of object continues to run.

The following example illustrates this surprise.                

Example :

Image may be NSFW.
Clik here to view.
Thread Class

Image may be NSFW.
Clik here to view.
Main Program

Image may be NSFW.
Clik here to view.
Main Program

In the above example, first we declared an object of destroy_object_destroy_thread class in the main program. Then we called run task of object which started the thread. “run task” prints the value of the counter after every iteration with a 1ns delay.

After 5ns the object was nullified in the main program. When the object was nullified, it was expected that the thread would stop or get killed or get deactivated. But the thread remained active and continued printing the remaining values.  

Conclusion: Make sure all the threads spawned by the object are destroyed before destroying the object.

Wish you a safe journey in object oriented threading!

Author: Laxman Sahoo 

'

Viewing all articles
Browse latest Browse all 6

Trending Articles