-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
190 lines (171 loc) · 7.67 KB
/
app.py
File metadata and controls
190 lines (171 loc) · 7.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
from flask import Flask, render_template, request, redirect, url_for, session
import json
app = Flask(__name__)
app.secret_key = 'your_secret_key' # Needed for session management
# --- Hard-coded user credentials ---
USERNAME = 'user'
PASSWORD = 'pass123'
@app.route('/', methods=['GET', 'POST'])
def login():
"""
Route for login page. Accepts username/password. If valid, sets session and redirects to the simulator.
"""
error = None
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if username == USERNAME and password == PASSWORD:
session['logged_in'] = True
return redirect(url_for('index'))
else:
error = 'Invalid username or password.'
return render_template('login.html', error=error)
@app.route('/logout')
def logout():
""" Log out and clear the session. """
session.pop('logged_in', None)
return redirect(url_for('login'))
def bankers_algorithm(available, allocation, max_demand):
"""
Implements the Banker's Algorithm to find a safe sequence.
- available: list of available resources.
- allocation: list of lists (allocation[i][j] = resources of type j held by process i).
- max_demand: list of lists (max_demand[i][j] = max resources of type j needed by process i).
Returns (is_safe, safe_sequence_list).
"""
n = len(allocation) # number of processes
m = len(available) # number of resource types
# Calculate the need matrix: need[i][j] = max_demand[i][j] - allocation[i][j]
need = [[max_demand[i][j] - allocation[i][j] for j in range(m)] for i in range(n)]
finish = [False] * n
work = available.copy()
safe_seq = []
# Safety algorithm loop
while len(safe_seq) < n:
progressed = False
for i in range(n):
if not finish[i] and all(need[i][j] <= work[j] for j in range(m)):
# If process i can be satisfied with current work, allocate and mark finished
for j in range(m):
work[j] += allocation[i][j]
finish[i] = True
safe_seq.append(f"P{i}")
progressed = True
if not progressed:
# No further progress can be made
break
return (len(safe_seq) == n, safe_seq)
def detect_cycle(graph):
"""
Detects a directed cycle in the graph (a dict of adjacency lists).
Returns True if a cycle exists.
"""
visited = set()
rec_stack = set()
def dfs(v):
visited.add(v)
rec_stack.add(v)
for neigh in graph.get(v, []):
if neigh not in visited:
if dfs(neigh):
return True
elif neigh in rec_stack:
return True
rec_stack.remove(v)
return False
for node in graph:
if node not in visited:
if dfs(node):
return True
return False
@app.route('/index', methods=['GET', 'POST'])
def index():
"""
Main simulator page. Requires login. On GET, shows form.
On POST, processes the input and computes according to selected algorithm.
"""
if not session.get('logged_in'):
return redirect(url_for('login'))
result = {}
nodes = []
edges = []
if request.method == 'POST':
# Parse form data
alg = request.form.get('algorithm')
# Available resources input (space-separated)
available = list(map(int, request.form.get('available', '').split()))
# Allocation matrix input: each line is a process, numbers space-separated
alloc_input = request.form.get('allocation', '').strip().splitlines()
allocation = [list(map(int, row.split())) for row in alloc_input if row.strip()]
# Max demand matrix input
max_input = request.form.get('maxdemand', '').strip().splitlines()
max_demand = [list(map(int, row.split())) for row in max_input if row.strip()]
# Ensure all matrices have consistent dimensions
num_processes = len(allocation)
num_resources = len(available)
# Compute need matrix
need = [[max_demand[i][j] - allocation[i][j] for j in range(num_resources)] for i in range(num_processes)]
# ---- Banker's Algorithm (Deadlock Avoidance) ----
if alg == 'banker':
is_safe, safe_seq = bankers_algorithm(available, allocation, max_demand)
result['algorithm'] = 'Banker\'s Algorithm'
if is_safe:
result['message'] = f"System is in a safe state. Safe sequence: {' → '.join(safe_seq)}"
else:
result['message'] = "System is NOT in a safe state. Deadlock may occur."
# ---- Resource Allocation Graph (Single-instance Deadlock Detection) ----
elif alg == 'rag':
result['algorithm'] = 'Resource Allocation Graph'
# Build the RAG: nodes are processes and resources (e.g., 'P0', 'R0')
for i in range(num_processes):
nodes.append({'id': f'P{i}', 'label': f'P{i}', 'color': '#8ad2eb'})
for j in range(num_resources):
nodes.append({'id': f'R{j}', 'label': f'R{j}', 'color': '#ebc08a', 'shape': 'box'})
graph = {}
# Edges: Rj -> Pi if allocated, Pi -> Rj if process Pi needs resource Rj
for i in range(num_processes):
for j in range(num_resources):
if allocation[i][j] > 0:
graph.setdefault(f'R{j}', []).append(f'P{i}')
edges.append({'from': f'R{j}', 'to': f'P{i}'})
if need[i][j] > 0:
graph.setdefault(f'P{i}', []).append(f'R{j}')
edges.append({'from': f'P{i}', 'to': f'R{j}'})
deadlock = detect_cycle(graph)
if deadlock:
result['message'] = "Cycle detected in Resource Allocation Graph: *Deadlock exists.*"
else:
result['message'] = "No cycles in Resource Allocation Graph: system is *safe*."
# ---- Wait-for Graph (Simplified Deadlock Detection) ----
elif alg == 'waitfor':
result['algorithm'] = 'Wait-for Graph'
# Build Wait-for graph (processes only)
for i in range(num_processes):
nodes.append({'id': f'P{i}', 'label': f'P{i}', 'color': '#8ad2eb'})
graph = {}
for i in range(num_processes):
for j in range(num_resources):
if need[i][j] > 0:
# If resource Rj is held by process k, add edge i -> k
for k in range(num_processes):
if k != i and allocation[k][j] > 0:
graph.setdefault(f'P{i}', []).append(f'P{k}')
edges.append({'from': f'P{i}', 'to': f'P{k}'})
deadlock = detect_cycle(graph)
if deadlock:
result['message'] = "Cycle detected in Wait-for Graph: *Deadlock exists.*"
else:
result['message'] = "No cycles in Wait-for Graph: system is *safe*."
# Prepare JSON data for export
result['available'] = available
result['allocation'] = allocation
result['max_demand'] = max_demand
result_json = json.dumps(result)
# Pass data to template
return render_template('index.html',
result=result,
nodes_json=json.dumps(nodes),
edges_json=json.dumps(edges),
result_json=result_json)
# GET request (or no submission yet): just render the page
return render_template('index.html')