The objective of this virtual lab is to provide a comprehensive understanding of Resource Allocation Graphs (RAGs) and their usage for the allocation of resources to processes and to detect potential deadlocks for two conditions (hold-and-wait and circular-wait) through interactive simulation. RAG is explained with respect to its usage in resource allocation to different processes maintained by the operating system
- Resource Allocation Graph (RAG)
- Deadlock
- Finding Deadlock
- Mutual Exclusion: Each resource can be held by only one process.
- No Preemption: Resources must be released manually from a process before being reassigned a request by another process.
- Hold and Wait: A process is already holding a resource while requesting the same instance or another resource that is currently held.
- Circular Wait: A hold and wait condition occurs in a circular form in the RAG
It is a directed graph with two types of nodes representing either processes or resources, and arrows representing either allocation of a resource to a process (i.e. assignment edge), or the request by a process to access a resource resource (i.e. request edge). It is useful for visualising if a resource is free or in use, and which resources a process is requesting for.
A deadlock is a situation where processes are stuck and cannot continue with their execution. This happens when a set of processes cannot acquire the resources they need to complete their work because those resources are held by other processes, a circular path of such conditions in a RAG leads to a stuck situation
The procedure of finding a deadlock depends on whether the resources are single instance or multi-instance. Detection of deadlock in a single instance scenario is straightforward, but gets complicated in case of multi-instance. Generally, it can be said that a deadlock may be present if the following 4 conditions are present in the RAG:
- Server Load Balancing – To evenly distribute requests across available servers and avoid bottlenecks.
- Operating Systems – Managing process-resource allocation to detect and prevent deadlocks in CPU and memory usage.
- Database Management – Efficient transaction scheduling which avoids deadlocks.
- Cloud Resource Management – Allocating virtual machines and storage resources efficiently to various services.
- Traffic Systems – Coordinating traffic light resources and vehicle flows to prevent circular wait deadlocks.
Following two steps are followed to detect deadlocks in RAG:
- Create RAG using the input given by the user:
- Enter the number of resources and specify the instances for each resource.
- Enter the number of processes to be included in RAG.
- To add a request edge, right-click on a process icon, then right-click on the resource it is requesting.
- To add an assignment edge, right-click on a resource icon, then right-click on the process that holds it.
- Find Deadlock in the given Graph:
- Hold and Wait: For each process, check if it is holding a resource while requesting the same instance or another resource that is currently held. If true, the edge is highlighted in yellow. (toggle 'view hold & wait')
- Circular Wait: Use Depth First Search on each node to check for a cycle. If a cycle is found, the edge is highlighted in green. (toggle 'view circular wait')
Following two conditions are checked to find potential deadlock:
// JavaScript Code Example
// Node Structure: Defines the processes and resources in the system
const nodes = [
{ id: 'P1', type: 'process' },
{ id: 'P2', type: 'process' },
{ id: 'R1.1', type: 'resource', group: 'R1' },
{ id: 'R1.2', type: 'resource', group: 'R1' },
{ id: 'R2.1', type: 'resource', group: 'R2' }
];
// Links Structure: Defines the relationships (edges) between processes and resources
const links = [
{ source: 'P1', target: 'R1.1' },
{ source: 'R1.2', target: 'P2' },
{ source: 'P2', target: 'R2.1' }
];
// Function to detect all circular waits (causing deadlocks) and return involved edges
function detectAllCycleEdges(links) {
let visited = new Set(); // Tracks nodes that have been fully processed
let stack = new Set(); // Tracks nodes in the current DFS recursion
let edgeStack = []; // Tracks the edges being traversed in the current DFS path
let allCycleEdges = []; // To store all the cycles detected
// Helper function to perform Depth-First Search (DFS) to find cycles
function dfs(node) {
if (stack.has(node)) {
// Cycle found: return the edges involved in this cycle
allCycleEdges.push([...edgeStack]); // Save a copy of the current edge stack
return;
}
if (visited.has(node)) {
// Node has already been fully processed, skip it
return;
}
// Mark the node as visited and add to the current recursion stack
visited.add(node);
stack.add(node);
// Traverse all outgoing edges from the current node
for (let link of links) {
if (link.source === node) {
// Add the current edge to the edge stack
edgeStack.push(link);
dfs(link.target); // Continue DFS to the target node
// Backtrack: remove the edge from the stack if no cycle found
edgeStack.pop();
}
}
// Backtrack: remove the node from the recursion stack
stack.delete(node);
}
// Start DFS from each node in nodes1
for (let node of nodes) {
dfs(node.id); // Perform DFS starting from the node's ID
}
return allCycleEdges; // Return all cycles found
}
// Function to calculate hold-wait edges (potential deadlock scenarios)
function calc_hold_wait_edges(){
yellowLinks=[];//empty
for(let link of links){
const sourceNode = nodes.find(node => node.id === link.source.id || node.id === link.source);
const targetNode = nodes.find(node => node.id === link.target.id || node.id === link.target);
if(sourceNode.type==="resource" && targetNode.type==="process"){//hold wait can only form
//resource to process and + process to another resource
for (let link1 of links){
if(link.target===link1.source){
for(let link2 of links){
if(link2.source===link1.target){
yellowLinks.push(link)
yellowLinks.push(link1)
}
}
}
}
}
}
console.log("Yellow_links calculated : " , yellowLinks);
}
// Function to add a new process node
function addNode(value) {
const numberOfNodes = value;
// Check if the input is a valid number
if (isNaN(numberOfNodes) || numberOfNodes <= 0) {
let message="Please Enter a Valid Number that is greater than 1";
show_message(message);
return;
}
for (let i = 0; i < numberOfNodes; i++) {
const newNodeId = `P${nodes.filter((node) => node.type === "process").length + 1}`;
const newNode = {
id: newNodeId,
type: "process",
x: width / 2,
y: height / 2,};
nodes.push(newNode);
}
console.log("nodes : ", nodes);
hide_addProcess() //hide the form
renderGraph(); // Call renderGraph() once after adding all nodes
}
// Function to add multiple resources (Adds m resource each having n resource instances)
function addMultipleResources(value,value1) {
let m = value;
let n = value1
// Validate inputs: Must be natural numbers (positive integers)
if (isNaN(m) || isNaN(n) || m < 1 || n < 1 || !Number.isInteger(m) || !Number.isInteger(n)) {
let message="Please Enter a Valid Number that is greater than 1";
show_message(message);
return;
}
// Find the highest existing resource number
const resourceNumbers = nodes
.filter(node => node.type === 'resource')
.map(node => parseInt(node.id.split('.')[0].substring(1)))
.filter(num => !isNaN(num));
let startingResourceNumber = (resourceNumbers.length > 0 ? Math.max(...resourceNumbers) : 0) + 1;
// Create m resources, each with n instances
for (let i = 0; i < m; i++) {
let resourceNumber = startingResourceNumber + i;
for (let j = 1; j <= n; j++) {
const newResourceId = `R${resourceNumber}.${j}`;
const newResource = { id: newResourceId, type: 'resource', group: `R${resourceNumber}` };
nodes.push(newResource);
}
}
console.log("nodes:", nodes);
renderGraph();
}
// Function to add a new resource instance
function addResourceInstance(value) {
const resourceNumber =value;
if (resourceNumber) {
const existingResources = nodes.filter(node =>
node.type === 'resource' && node.id.startsWith(`R${resourceNumber}.`)
);
if (existingResources.length > 0) {
let maxNumber = 0;
nodes.forEach(node => {
if (node.type === "resource" && node.id.startsWith(`R${resourceNumber}.`)) {
let match = node.id.match(/R\d+\.(\d+)$/); // Extract only the last numeric part
if (match) {
let num = parseInt(match[1]); // Convert to number
maxNumber = Math.max(maxNumber, num);
}
}
});
const newInstanceNumber = maxNumber + 1;
const newResourceId = `R${resourceNumber}.${newInstanceNumber}`;
const newResource = { id: newResourceId, type: 'resource', group: `R${resourceNumber}` };
nodes.push(newResource);
console.log("nodes : " , nodes);
} else {
const newResourceId = `R${resourceNumber}.1`;
const newResource = { id: newResourceId, type: 'resource', group: `R${resourceNumber}` };
nodes.push(newResource);
console.log("nodes : " , nodes);
}
renderGraph();
}
}
Instructions to Use
1. Process: Process nodes are represented by blue-colored circles and are numbered as P1, P2, P3, ..., Pn if the graph has ‘n’ processes.
2. Resource: Each resource is represented by a gray-colored rectangle box containing one or more resource instances, represented by orange-colored rectangles. A resource must have at least one resource instance.
3. Resource Instance: Each resource instance is represented by an orange-colored rectangle box and is numbered as Rm.n, where ‘m’ denotes the resource number and ‘n’ denotes the instance number within that resource. For example: R1.1, R1.2 ; R2.1, R2.2
4. Selection: Right-click (or long-press on mobile devices) on any process or resource instance to select it. The selected item will have a green boundary. To deselect, right-click (or long-press) again.
5. Drag/Movement: Drag any process or resource in the graph simulation using a left-click (or a simple tap on mobile devices).
6. Assignment Edge Creation: First, right-click (or long-press) on any resource instance, and then right-click (or long-press) on any process. This will create an assignment edge (blue in color) from that resource instance to the process. (Note: A single resource instance cannot be assigned to two different processes.)
7. Requesting Edge Creation: First, right-click (or long-press) on any process, and then right-click (or long-press) on any resource instance. This will create a requesting edge (red in color) from that process to the resource instance. (Note: A single process cannot request two different resource instances of the same resource.)
8. Assignment/Requesting Edge Deletion: To delete an edge (either assignment or requesting), right-click (or long-press) on it is tail process/resource instance and then right-click (or long-press) on it is head process/resource instance.
Note: Use long-press instead of right-click on mobile devices.
Button functionalities
Following buttons are provided for graph simulation ( Click on any button to see it is functionality)
1.Add Processes: Use to add “n” number of processes into the graph.
2.Add Resources: Use to add “r” number of resources with each having minimum “s” number of resource-instances.
3.Add Resource-Instance: Use this button to add 1 more Resource-Instance to any of the existing resources.
4.View Hold-wait: Activate the Visualisation of Hold-wait condition in the graph. The edges in hold-wait condition will then be highlighted with yellow color.
5.View Circular-wait: Activate the Visualisation of Circular-wait condition in the graph. The edges in circular-wait will then be highlighted with green color.
6.Delete: Activate deletion mode, after this right-click(long press for mobiles) on any Process or Resource-Instance to delete it.
7.Reset: Make the graph simulation empty or delete everything.
8.Edge Creation/ Edge Deletion: Use to read instructions to create or delete edges.(Both of these buttons do not toggle any functionality.)
Note: Buttons having activation can be deactivated if again left-click (simple click for mobiles) on the button. The activated button is deactivated on left-click (simple click for mobiles).
How many Processes, you want to add in the graph ?
In which Resource, you want to add 1 more Resource-Instance ?
How many Resources, you want to add in the graph and the minimum Resource Instances does they all have ?
In this experiment, an interactive RAG is created to simulate the allocation and request of resources by processes. The provision to add multiple processes, multiple resources with more than one instance empowers realistic simulation of RAGs. The necessary conditions like hold-and-wait and circular-wait are detected and shown visually for quick grasping of concepts related to deadlock detection
Through the graphical interface, occurrences of deadlock conditions are identified in real time. Furthermore, the provided simulation emphasized on the necessity of careful resource management and controlled request handling for preventing deadlock issues in concurrent systems.
INSTRUCTIONS
- There are 4 questions in total
- Read each question carefully before answering.
- Select the correct option(s) (multiple options CAN be correct).
- Click Next to move to the following question.
- At the end, you can view your quiz report and retake the quiz if needed.
- [1] Mike Bostock. D3.js: Data-Driven Documents. 2025. Available at: https://d3js.org/. Accessed on: 20 February 2026.
- [2] Mike Bostock. D3-force: Force-Directed Graph Layout. 2025. Available at: https://github.com/d3/d3-force. Accessed on: 20 February 2026.
- [3] Deadlock, CS 341: System Programming Coursebook, University of Illinois. Available at: https://cs341.cs.illinois.edu/coursebook/Deadlock. Accessed on: 20 February 2026.
- [4] Silberschatz, A., Galvin, P. B., & Gagne, G. (2009). Chapter 7: Deadlocks. In Operating System Concepts with Java (8th ed.). University of Tennessee at Chattanooga. Availabe at https://www.utc.edu/sites/default/files/2021-04/2800-lecture7-deadlocks.pdf. Accessed on: 20 February 2026.
Students
- Jayesh Raj Neti, 3rd year, B.Sc. (Hons.) Computer Science (2025-26)
- Nitesh Verma, 3rd year, B.Sc. (Hons.) Computer Science (2025-26),
Mentor
- Prof. Sharanjit Kaur, Department of Computer Science
Tools Used
- Vanilla HTML, CSS, JS - for creating the web page D3 - for graph simulation