1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //*************************************************************************
3 //
4 // Copyright 2018-2018 by Wilson Snyder. This program is free software; you can
5 // redistribute it and/or modify it under the terms of either the GNU
6 // Lesser General Public License Version 3 or the Perl Artistic License
7 // Version 2.0.
8 // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
9 //
10 //*************************************************************************
11 
12 #include <atomic>
13 #include <cstdio>
14 #include <iostream>
15 #include <unistd.h>
16 #include "svdpi.h"
17 
18 //======================================================================
19 
20 // clang-format off
21 #if defined(VERILATOR)
22 # ifdef T_DPI_THREADS_COLLIDE
23 #  include "Vt_dpi_threads_collide__Dpi.h"
24 # else
25 #  include "Vt_dpi_threads__Dpi.h"
26 # endif
27 #elif defined(VCS)
28 # include "../vc_hdrs.h"
29 #elif defined(CADENCE)
30 # define NEED_EXTERNS
31 #else
32 # error "Unknown simulator for DPI test"
33 #endif
34 // clang-format on
35 
36 #ifdef NEED_EXTERNS
37 extern "C" {
38 extern void dpii_sys_task();
39 extern int dpii_failure();
40 }
41 #endif
42 
43 //======================================================================
44 
45 struct state {
46     std::atomic<bool> task_is_running;
47     std::atomic<int> failure;
statestate48     state()
49         : task_is_running(false)
50         , failure(false) {}
51 };
52 
53 static state st;
54 
dpii_sys_task()55 void dpii_sys_task() {
56     bool other_task_running = atomic_exchange(&st.task_is_running, true);
57     if (other_task_running) {
58         // Another task is running. This is a collision.
59         st.failure = 1;
60         std::cerr << "t_dpi_threads_c.cpp dpii_sys_task() saw threads collide.\n";
61     } else {
62         std::cerr << "t_dpi_threads_c.cpp dpii_sys_task() no collision. @" << &st.task_is_running
63                   << "\n";
64     }
65 
66     // Spend some time in the DPI call, so that if we can have a collision
67     // we probably will. Technically this is not guaranteed to detect every
68     // race. However, one second is so much greater than the expected
69     // runtime of everything else in the test, it really should pick up on
70     // races just about all of the time.
71     sleep(1);
72 
73     atomic_exchange(&st.task_is_running, false);
74 }
75 
dpii_failure()76 int dpii_failure() { return st.failure; }
77