mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Fix semaphore waiting on killed process (#8505)
Signed-off-by: Ryszard Rozak <[email protected]>
This commit is contained in:
@@ -763,6 +763,7 @@ GENHTML_OPT += --rc branch_coverage=1
|
||||
GENHTML_OPT += --rc genhtml_hi_limit=100
|
||||
GENHTML_OPT += --ignore-errors negative
|
||||
GENHTML_OPT += --ignore-errors inconsistent
|
||||
GENHTML_OPT += --ignore-errors empty
|
||||
ifeq ($(COVERAGE_REF_BASE),)
|
||||
GENHTML_OPT += --header-title "Code coverage for Verilator $(shell git describe --dirty)"
|
||||
else
|
||||
|
||||
+50
-40
@@ -99,46 +99,6 @@ package std;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// IEEE 1800-specified standard "semaphore"
|
||||
class semaphore;
|
||||
protected int m_keyCount;
|
||||
protected int m_nextKeyCount = '1;
|
||||
protected longint unsigned m_ticket = 0;
|
||||
protected longint unsigned m_nextTicket = 0;
|
||||
|
||||
function new(int keyCount = 0);
|
||||
m_keyCount = keyCount;
|
||||
endfunction
|
||||
|
||||
function void put(int keyCount = 1);
|
||||
m_keyCount += keyCount;
|
||||
endfunction
|
||||
|
||||
task get(int keyCount = 1);
|
||||
`ifdef VERILATOR_TIMING
|
||||
longint unsigned ticket;
|
||||
// Fast path: take if keys fit AND either no one is queued, or
|
||||
// the head still doesn't fit (so we're not stealing its keys).
|
||||
if (m_keyCount >= keyCount && m_nextKeyCount > m_keyCount) begin
|
||||
m_keyCount -= keyCount;
|
||||
return;
|
||||
end
|
||||
ticket = m_nextTicket++;
|
||||
wait (m_ticket == ticket);
|
||||
m_nextKeyCount = keyCount;
|
||||
wait (m_keyCount >= keyCount);
|
||||
m_keyCount -= keyCount;
|
||||
m_ticket++;
|
||||
`endif
|
||||
endtask
|
||||
|
||||
function int try_get(int keyCount = 1);
|
||||
if (m_keyCount < keyCount) return 0;
|
||||
m_keyCount -= keyCount;
|
||||
return 1;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// IEEE 1800-specified standard "process"
|
||||
class process;
|
||||
typedef enum {
|
||||
@@ -243,6 +203,56 @@ inline bool VlClassRef<`systemc_class_name>::operator<(const VlClassRef<`systemc
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// IEEE 1800-specified standard "semaphore"
|
||||
class semaphore;
|
||||
typedef struct {
|
||||
process proc;
|
||||
int reqKeys;
|
||||
} procKeys;
|
||||
procKeys m_queue[$];
|
||||
protected int m_keyCount;
|
||||
|
||||
local task dropKilled;
|
||||
// Drop killed processes from the queue
|
||||
`ifdef VERILATOR_TIMING
|
||||
while (m_queue.size() > 0 && m_queue[0].proc.status() == process::KILLED) m_queue.pop_front();
|
||||
`endif
|
||||
endtask
|
||||
function new(int keyCount = 0);
|
||||
m_keyCount = keyCount;
|
||||
endfunction
|
||||
|
||||
function void put(int keyCount = 1);
|
||||
m_keyCount += keyCount;
|
||||
endfunction
|
||||
|
||||
task get(int keyCount = 1);
|
||||
`ifdef VERILATOR_TIMING
|
||||
dropKilled();
|
||||
// Fast path: take if keys fit AND either no one is queued, or
|
||||
// the head still doesn't fit (so we're not stealing its keys).
|
||||
if (m_keyCount >= keyCount && (m_queue.size() == 0 || m_queue[0].reqKeys > keyCount)) begin
|
||||
m_keyCount -= keyCount;
|
||||
return;
|
||||
end
|
||||
m_queue.push_back('{process::self(), keyCount});
|
||||
while (m_queue[0].proc != process::self()) begin
|
||||
wait (m_queue[0].proc.status() == process::KILLED || m_queue[0].proc == process::self());
|
||||
dropKilled();
|
||||
end
|
||||
wait (m_keyCount >= keyCount);
|
||||
m_keyCount -= keyCount;
|
||||
m_queue.pop_front();
|
||||
`endif
|
||||
endtask
|
||||
|
||||
function int try_get(int keyCount = 1);
|
||||
if (m_keyCount < keyCount) return 0;
|
||||
m_keyCount -= keyCount;
|
||||
return 1;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// IEEE 1800-specified standard "std::randomize"
|
||||
function int randomize();
|
||||
randomize = 0;
|
||||
|
||||
@@ -22,6 +22,6 @@ cg7.cp.rev[0]: 1
|
||||
cg7.cp.rev[1]: 0
|
||||
cg8.cp.w[0]: 0
|
||||
cg8.cp.w[1]: 1
|
||||
cg9.__cross7.ok_x_lo [cross]: 1
|
||||
cg9.__cross8.ok_x_lo [cross]: 1
|
||||
cg9.cpA.ok: 1
|
||||
cg9.cpB.lo: 1
|
||||
|
||||
@@ -169,10 +169,10 @@ cg_trans.cp_v.v5: 2
|
||||
cg_trans.cp_v.v6: 1
|
||||
cg_trans.tx.t01_x_v5 [cross]: 1
|
||||
cg_trans.tx.t01_x_v6 [cross]: 0
|
||||
cg_unnamed_cross.__cross8.a0_x_read [cross]: 1
|
||||
cg_unnamed_cross.__cross8.a0_x_write [cross]: 0
|
||||
cg_unnamed_cross.__cross8.a1_x_read [cross]: 0
|
||||
cg_unnamed_cross.__cross8.a1_x_write [cross]: 1
|
||||
cg_unnamed_cross.__cross9.a0_x_read [cross]: 1
|
||||
cg_unnamed_cross.__cross9.a0_x_write [cross]: 0
|
||||
cg_unnamed_cross.__cross9.a1_x_read [cross]: 0
|
||||
cg_unnamed_cross.__cross9.a1_x_write [cross]: 1
|
||||
cg_unnamed_cross.cp_a.a0: 1
|
||||
cg_unnamed_cross.cp_a.a1: 1
|
||||
cg_unnamed_cross.cp_c.read: 1
|
||||
|
||||
@@ -18,7 +18,7 @@ cg_cross_coverpoint_iff.cross_ab.one_x_one [cross]: 1
|
||||
cg_cross_iff.cp_a.one: 3
|
||||
cg_cross_iff.cp_b.one: 3
|
||||
cg_cross_iff.cross_ab.one_x_one [cross]: 1
|
||||
cg_cross_iff_unnamed.__cross7.one_x_one [cross]: 1
|
||||
cg_cross_iff_unnamed.__cross8.one_x_one [cross]: 1
|
||||
cg_cross_iff_unnamed.cp_a.one: 2
|
||||
cg_cross_iff_unnamed.cp_b.one: 2
|
||||
cg_default_iff.cp.def [default]: 1
|
||||
|
||||
@@ -1228,64 +1228,9 @@ package Vt_debug_emitv___024unit;
|
||||
disable label3;
|
||||
end
|
||||
endfunction
|
||||
string __Venumtab_enum_name34[1:0];
|
||||
string __Venumtab_enum_name36[1:0];
|
||||
endpackage
|
||||
package Vt_debug_emitv_std;
|
||||
class Vt_debug_emitv_semaphore;
|
||||
int signed m_keyCount;
|
||||
int signed m_nextKeyCount;
|
||||
m_nextKeyCount = 32'hffffffff;
|
||||
longint m_ticket;
|
||||
m_ticket = 64'h0;
|
||||
longint m_nextTicket;
|
||||
m_nextTicket = 64'h0;
|
||||
function new;
|
||||
input int signed keyCount;
|
||||
m_keyCount = keyCount;
|
||||
endfunction
|
||||
task put;
|
||||
input int signed keyCount;
|
||||
m_keyCount = (m_keyCount + keyCount);
|
||||
endtask
|
||||
task get;
|
||||
longint __Vincrement1;
|
||||
input int signed keyCount;
|
||||
longint ticket;
|
||||
begin : label4
|
||||
ticket = /*CRESET*/;
|
||||
if (((m_keyCount >= keyCount) && (m_nextKeyCount
|
||||
>
|
||||
m_keyCount))) begin
|
||||
begin
|
||||
m_keyCount = (m_keyCount -
|
||||
keyCount);
|
||||
disable label4;
|
||||
end
|
||||
end
|
||||
__Vincrement1 = m_nextTicket;
|
||||
m_nextTicket = (m_nextTicket + 64'h1);
|
||||
ticket = __Vincrement1;
|
||||
wait((m_ticket == ticket));
|
||||
m_nextKeyCount = keyCount;
|
||||
wait((m_keyCount >= keyCount));
|
||||
m_keyCount = (m_keyCount - keyCount);
|
||||
m_ticket = (m_ticket + 64'h1);
|
||||
end
|
||||
endtask
|
||||
function try_get;
|
||||
input int signed keyCount;
|
||||
begin : label5
|
||||
try_get = /*CRESET*/;
|
||||
if ((m_keyCount < keyCount)) begin
|
||||
try_get = 'sh0;
|
||||
disable label5;
|
||||
end
|
||||
m_keyCount = (m_keyCount - keyCount);
|
||||
try_get = 'sh1;
|
||||
disable label5;
|
||||
end
|
||||
endfunction
|
||||
endclass
|
||||
class Vt_debug_emitv_process;
|
||||
typedef enum int signed{
|
||||
FINISHED = 32'h0,
|
||||
@@ -1297,12 +1242,12 @@ package Vt_debug_emitv_std;
|
||||
VlProcessRef m_process;
|
||||
function self;
|
||||
Vt_debug_emitv_process pVt_debug_emitv_process;
|
||||
begin : label6
|
||||
begin : label4
|
||||
self = /*CRESET*/;
|
||||
p = new();
|
||||
$c(p.m_process = vlProcess;);
|
||||
self = p;
|
||||
disable label6;
|
||||
disable label4;
|
||||
end
|
||||
endfunction
|
||||
task set_status;
|
||||
@@ -1310,10 +1255,10 @@ package Vt_debug_emitv_std;
|
||||
$c(m_process->state(s););
|
||||
endtask
|
||||
function status;
|
||||
begin : label7
|
||||
begin : label5
|
||||
status = /*CRESET*/;
|
||||
status = ($c(m_process->state()));
|
||||
disable label7;
|
||||
disable label5;
|
||||
end
|
||||
endfunction
|
||||
task kill;
|
||||
@@ -1385,12 +1330,12 @@ package Vt_debug_emitv_std;
|
||||
???? // SYSTEMCSECTION
|
||||
function get_randstate;
|
||||
string s;
|
||||
begin : label8
|
||||
begin : label6
|
||||
get_randstate = /*CRESET*/;
|
||||
s = string'($c(0));
|
||||
$c(s = m_process->randstate(););
|
||||
get_randstate = s;
|
||||
disable label8;
|
||||
disable label6;
|
||||
end
|
||||
endfunction
|
||||
task set_randstate;
|
||||
@@ -1400,6 +1345,85 @@ package Vt_debug_emitv_std;
|
||||
function new;
|
||||
endfunction
|
||||
process::FINISHEDprocess::KILLEDprocess::RUNNINGprocess::SUSPENDEDprocess::WAITINGendclass
|
||||
class Vt_debug_emitv_semaphore;
|
||||
typedef struct {
|
||||
Vt_debug_emitv_process proc;
|
||||
int signed reqKeys;
|
||||
} procKeys;
|
||||
struct {
|
||||
Vt_debug_emitv_process proc;
|
||||
int signed reqKeys;
|
||||
} m_queue[$];
|
||||
int signed m_keyCount;
|
||||
task dropKilled;
|
||||
while (((m_queue.size() > 'sh0) && (status()
|
||||
==
|
||||
process::
|
||||
KILLED))) begin
|
||||
m_queue.pop_front();
|
||||
end
|
||||
endtask
|
||||
function new;
|
||||
input int signed keyCount;
|
||||
m_keyCount = keyCount;
|
||||
endfunction
|
||||
task put;
|
||||
input int signed keyCount;
|
||||
m_keyCount = (m_keyCount + keyCount);
|
||||
endtask
|
||||
task get;
|
||||
input int signed keyCount;
|
||||
begin : label7
|
||||
dropKilled();
|
||||
if (((m_keyCount >= keyCount) && ((
|
||||
m_queue.size()
|
||||
==
|
||||
'sh0)
|
||||
|| (m_queue.at(
|
||||
'sh0).reqKeys
|
||||
>
|
||||
keyCount)))) begin
|
||||
begin
|
||||
m_keyCount = (m_keyCount -
|
||||
keyCount);
|
||||
disable label7;
|
||||
end
|
||||
end
|
||||
m_queue.push_back(
|
||||
???? // CONSPACKUORSTRUCT
|
||||
|
||||
???? // CONSPACKMEMBER
|
||||
self()
|
||||
???? // CONSPACKMEMBER
|
||||
keyCount);
|
||||
while ((m_queue.at('sh0).proc != self())) begin
|
||||
begin
|
||||
wait(((status() == process::
|
||||
KILLED) || (m_queue.at(
|
||||
'sh0).proc
|
||||
== self())));
|
||||
dropKilled();
|
||||
end
|
||||
end
|
||||
wait((m_keyCount >= keyCount));
|
||||
m_keyCount = (m_keyCount - keyCount);
|
||||
m_queue.pop_front();
|
||||
end
|
||||
endtask
|
||||
function try_get;
|
||||
input int signed keyCount;
|
||||
begin : label8
|
||||
try_get = /*CRESET*/;
|
||||
if ((m_keyCount < keyCount)) begin
|
||||
try_get = 'sh0;
|
||||
disable label8;
|
||||
end
|
||||
m_keyCount = (m_keyCount - keyCount);
|
||||
try_get = 'sh1;
|
||||
disable label8;
|
||||
end
|
||||
endfunction
|
||||
endclass
|
||||
function randomize;
|
||||
randomize = 'sh0;
|
||||
endfunction
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,37 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
semaphore sem = new(0);
|
||||
process first_waiter;
|
||||
process second_waiter;
|
||||
bit acquired;
|
||||
|
||||
initial begin
|
||||
fork
|
||||
begin
|
||||
first_waiter = process::self();
|
||||
sem.get(1);
|
||||
$stop;
|
||||
end
|
||||
begin
|
||||
second_waiter = process::self();
|
||||
sem.get(1);
|
||||
acquired = 1;
|
||||
end
|
||||
join_none
|
||||
|
||||
wait (first_waiter != null && second_waiter != null);
|
||||
#1;
|
||||
first_waiter.kill();
|
||||
sem.put(1);
|
||||
|
||||
#1;
|
||||
if (!acquired) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -444,13 +444,13 @@
|
||||
-000001 point: type=covergroup comment= hier=cg_unnamed_cross.cp_c.read
|
||||
-000001 point: type=covergroup comment= hier=cg_unnamed_cross.cp_c.write
|
||||
%000001 cross cp_a, cp_c; // no label: reported under the default cross name
|
||||
-000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a0_x_read
|
||||
-000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross9.a0_x_read
|
||||
// cross: [a0, read]
|
||||
-000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a0_x_write
|
||||
-000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross9.a0_x_write
|
||||
// cross: [a0, write]
|
||||
-000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a1_x_read
|
||||
-000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross9.a1_x_read
|
||||
// cross: [a1, read]
|
||||
-000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a1_x_write
|
||||
-000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross9.a1_x_write
|
||||
// cross: [a1, write]
|
||||
endgroup
|
||||
|
||||
|
||||
Reference in New Issue
Block a user