mirror of
https://github.com/verilator/verilator.git
synced 2025-01-19 12:54:02 +00:00
Internals: Add V3ThreadSafety (#4477)
This commit is contained in:
parent
839a8fa4d9
commit
8bd6d7c5b1
@ -94,20 +94,6 @@
|
|||||||
// Function requires a capability inbound (-fthread-safety)
|
// Function requires a capability inbound (-fthread-safety)
|
||||||
#define VL_CAPABILITY(x) \
|
#define VL_CAPABILITY(x) \
|
||||||
VL_CLANG_ATTR(capability(x))
|
VL_CLANG_ATTR(capability(x))
|
||||||
// Function requires not having a capability inbound (-fthread-safety)
|
|
||||||
#define VL_REQUIRES(x) \
|
|
||||||
VL_CLANG_ATTR(annotate("REQUIRES")) \
|
|
||||||
VL_CLANG_ATTR(requires_capability(x))
|
|
||||||
// Name of capability/lock (-fthread-safety)
|
|
||||||
#define VL_GUARDED_BY(x) \
|
|
||||||
VL_CLANG_ATTR(annotate("GUARDED_BY")) \
|
|
||||||
VL_CLANG_ATTR(guarded_by(x))
|
|
||||||
// The data that the annotated pointer points to is protected by the given capability.
|
|
||||||
// The pointer itself is not protected.
|
|
||||||
// Allowed on: pointer data member. (-fthread-safety)
|
|
||||||
#define VL_PT_GUARDED_BY(x) \
|
|
||||||
VL_CLANG_ATTR(annotate("PT_GUARDED_BY")) \
|
|
||||||
VL_CLANG_ATTR(pt_guarded_by(x))
|
|
||||||
// Name of mutex protecting this variable (-fthread-safety)
|
// Name of mutex protecting this variable (-fthread-safety)
|
||||||
#define VL_EXCLUDES(x) \
|
#define VL_EXCLUDES(x) \
|
||||||
VL_CLANG_ATTR(annotate("EXCLUDES")) \
|
VL_CLANG_ATTR(annotate("EXCLUDES")) \
|
||||||
@ -124,6 +110,32 @@
|
|||||||
#define VL_ASSERT_CAPABILITY(x) \
|
#define VL_ASSERT_CAPABILITY(x) \
|
||||||
VL_CLANG_ATTR(assert_capability(x))
|
VL_CLANG_ATTR(assert_capability(x))
|
||||||
|
|
||||||
|
// Require mutex locks only in code units which work with enabled multi-threading.
|
||||||
|
#if !defined(VL_MT_DISABLED_CODE_UNIT)
|
||||||
|
// Function requires not having a capability inbound (-fthread-safety)
|
||||||
|
# define VL_REQUIRES(x) \
|
||||||
|
VL_CLANG_ATTR(annotate("REQUIRES")) \
|
||||||
|
VL_CLANG_ATTR(requires_capability(x))
|
||||||
|
// Name of capability/lock (-fthread-safety)
|
||||||
|
# define VL_GUARDED_BY(x) \
|
||||||
|
VL_CLANG_ATTR(annotate("GUARDED_BY")) \
|
||||||
|
VL_CLANG_ATTR(guarded_by(x))
|
||||||
|
// The data that the annotated pointer points to is protected by the given capability.
|
||||||
|
// The pointer itself is not protected.
|
||||||
|
// Allowed on: pointer data member. (-fthread-safety)
|
||||||
|
# define VL_PT_GUARDED_BY(x) \
|
||||||
|
VL_CLANG_ATTR(annotate("PT_GUARDED_BY")) \
|
||||||
|
VL_CLANG_ATTR(pt_guarded_by(x))
|
||||||
|
#else
|
||||||
|
// Keep annotations for clang_check_attributes
|
||||||
|
# define VL_REQUIRES(x) \
|
||||||
|
VL_CLANG_ATTR(annotate("REQUIRES"))
|
||||||
|
# define VL_GUARDED_BY(x) \
|
||||||
|
VL_CLANG_ATTR(annotate("GUARDED_BY"))
|
||||||
|
# define VL_PT_GUARDED_BY(x) \
|
||||||
|
VL_CLANG_ATTR(annotate("PT_GUARDED_BY"))
|
||||||
|
#endif
|
||||||
|
|
||||||
// Defaults for unsupported compiler features
|
// Defaults for unsupported compiler features
|
||||||
#ifndef VL_ATTR_ALWINLINE
|
#ifndef VL_ATTR_ALWINLINE
|
||||||
# define VL_ATTR_ALWINLINE ///< Attribute to inline, even when not optimizing
|
# define VL_ATTR_ALWINLINE ///< Attribute to inline, even when not optimizing
|
||||||
@ -430,6 +442,11 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
|
|||||||
Type(const Type& other) = delete; \
|
Type(const Type& other) = delete; \
|
||||||
Type& operator=(const Type&) = delete
|
Type& operator=(const Type&) = delete
|
||||||
|
|
||||||
|
// Declare a class as unmovable; put after a private:
|
||||||
|
#define VL_UNMOVABLE(Type) \
|
||||||
|
Type(Type&& other) = delete; \
|
||||||
|
Type& operator=(Type&&) = delete
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Verilated function size macros
|
// Verilated function size macros
|
||||||
|
|
||||||
|
@ -151,6 +151,7 @@ set(HEADERS
|
|||||||
V3Table.h
|
V3Table.h
|
||||||
V3Task.h
|
V3Task.h
|
||||||
V3ThreadPool.h
|
V3ThreadPool.h
|
||||||
|
V3ThreadSafety.h
|
||||||
V3Timing.h
|
V3Timing.h
|
||||||
V3Trace.h
|
V3Trace.h
|
||||||
V3TraceDecl.h
|
V3TraceDecl.h
|
||||||
|
@ -289,6 +289,7 @@ NON_STANDALONE_HEADERS = \
|
|||||||
V3AstNodeExpr.h \
|
V3AstNodeExpr.h \
|
||||||
V3AstNodeOther.h \
|
V3AstNodeOther.h \
|
||||||
V3DfgVertices.h \
|
V3DfgVertices.h \
|
||||||
|
V3ThreadPool.h \
|
||||||
V3WidthCommit.h \
|
V3WidthCommit.h \
|
||||||
|
|
||||||
AST_DEFS := \
|
AST_DEFS := \
|
||||||
|
@ -111,6 +111,10 @@ void V3ThreadPool::stopOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex)
|
|||||||
--m_stoppedJobs;
|
--m_stoppedJobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void V3ThreadPool::selfTestMtDisabled() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
void V3ThreadPool::selfTest() {
|
void V3ThreadPool::selfTest() {
|
||||||
V3Mutex commonMutex;
|
V3Mutex commonMutex;
|
||||||
int commonValue{0};
|
int commonValue{0};
|
||||||
@ -164,4 +168,10 @@ void V3ThreadPool::selfTest() {
|
|||||||
futuresInt.push_back(s().enqueue(forthJob));
|
futuresInt.push_back(s().enqueue(forthJob));
|
||||||
auto result = V3ThreadPool::waitForFutures(futuresInt);
|
auto result = V3ThreadPool::waitForFutures(futuresInt);
|
||||||
UASSERT(result.back() == 1234, "unexpected future result = " << result.back());
|
UASSERT(result.back() == 1234, "unexpected future result = " << result.back());
|
||||||
|
{
|
||||||
|
const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()};
|
||||||
|
selfTestMtDisabled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
V3MtDisabledLock V3MtDisabledLock::s_mtDisabledLock;
|
||||||
|
@ -17,7 +17,12 @@
|
|||||||
#ifndef _V3THREADPOOL_H_
|
#ifndef _V3THREADPOOL_H_
|
||||||
#define _V3THREADPOOL_H_ 1
|
#define _V3THREADPOOL_H_ 1
|
||||||
|
|
||||||
|
#if defined(VL_MT_DISABLED_CODE_UNIT)
|
||||||
|
#error "Source file has been declared as MT_DISABLED, threads use is prohibited."
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "V3Mutex.h"
|
#include "V3Mutex.h"
|
||||||
|
#include "V3ThreadSafety.h"
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -163,6 +168,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void selfTest();
|
static void selfTest();
|
||||||
|
static void selfTestMtDisabled() VL_MT_DISABLED;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
71
src/V3ThreadSafety.h
Normal file
71
src/V3ThreadSafety.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: Definitions for thread safety checing
|
||||||
|
//
|
||||||
|
// Code available from: https://verilator.org
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2023 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#ifndef VERILATOR_V3THREADSAFETY_H_
|
||||||
|
#define VERILATOR_V3THREADSAFETY_H_
|
||||||
|
|
||||||
|
#include <verilatedos.h>
|
||||||
|
|
||||||
|
#include <V3Mutex.h>
|
||||||
|
|
||||||
|
// A class that works as an indicator of MT_DISABLED context.
|
||||||
|
// It uses Clang's thread safety analysis (-fthread-safety) to do its work.
|
||||||
|
// Its use will most likely be optimized out (or at least reduced to a few insignificant symbols
|
||||||
|
// or instructions) during compilation.
|
||||||
|
class VL_CAPABILITY("lock") V3MtDisabledLock final {
|
||||||
|
friend class V3MtDisabledLockInstanceAccessor;
|
||||||
|
|
||||||
|
static V3MtDisabledLock s_mtDisabledLock;
|
||||||
|
|
||||||
|
constexpr V3MtDisabledLock() = default;
|
||||||
|
~V3MtDisabledLock() = default;
|
||||||
|
VL_UNCOPYABLE(V3MtDisabledLock);
|
||||||
|
VL_UNMOVABLE(V3MtDisabledLock);
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr void lock() VL_ACQUIRE() VL_MT_SAFE {}
|
||||||
|
constexpr void unlock() VL_RELEASE() VL_MT_SAFE {}
|
||||||
|
|
||||||
|
static constexpr V3MtDisabledLock& instance()
|
||||||
|
VL_RETURN_CAPABILITY(V3MtDisabledLock::s_mtDisabledLock) {
|
||||||
|
return s_mtDisabledLock;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A class providing mutable access to V3MtDisabledLock::s_mtDisabledLock.
|
||||||
|
// This is a class because VL_RETURN_CAPABILITY works only on methods, not free functions.
|
||||||
|
// This is not a method in V3MtDisabledLock itself as a method declaration inside #ifdef block
|
||||||
|
// woudl break ODR.
|
||||||
|
class V3MtDisabledLockInstanceAccessor final {
|
||||||
|
public:
|
||||||
|
constexpr V3MtDisabledLock& operator()() const
|
||||||
|
VL_RETURN_CAPABILITY(V3MtDisabledLock::s_mtDisabledLock) {
|
||||||
|
return V3MtDisabledLock::s_mtDisabledLock;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Create a global object which can be called like a function.
|
||||||
|
static constexpr V3MtDisabledLockInstanceAccessor v3MtDisabledLock VL_ATTR_UNUSED;
|
||||||
|
|
||||||
|
using V3MtDisabledLockGuard = V3LockGuardImp<V3MtDisabledLock>;
|
||||||
|
|
||||||
|
// Annotated function can be called only in MT_DISABLED context, i.e. either in a code unit
|
||||||
|
// compiled with VL_MT_DISABLED_CODE_UNIT preprocessor definition, or after obtaining a lock on
|
||||||
|
// v3MtDisabledLock().
|
||||||
|
#define VL_MT_DISABLED \
|
||||||
|
VL_CLANG_ATTR(annotate("MT_DISABLED")) \
|
||||||
|
VL_REQUIRES(V3MtDisabledLock::instance())
|
||||||
|
|
||||||
|
#endif // guard
|
Loading…
Reference in New Issue
Block a user