Skip to content

Commit

Permalink
Add static thread safety analysis ready synchronization primitives. (f…
Browse files Browse the repository at this point in the history
  • Loading branch information
chinmaygarde authored and dnfield committed Apr 27, 2022
1 parent f2e297c commit e09b0ed
Show file tree
Hide file tree
Showing 12 changed files with 268 additions and 10 deletions.
6 changes: 5 additions & 1 deletion impeller/base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ impeller_component("base") {
"promise.h",
"strings.cc",
"strings.h",
"thread.cc",
"thread.h",
"thread_safety.cc",
"thread_safety.h",
"validation.cc",
"validation.h",
]
Expand All @@ -26,7 +30,7 @@ impeller_component("base") {

impeller_component("base_unittests") {
testonly = true
sources = []
sources = [ "base_unittests.cc" ]
deps = [
":base",
"//flutter/testing",
Expand Down
72 changes: 72 additions & 0 deletions impeller/base/base_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/testing/testing.h"
#include "impeller/base/thread.h"

namespace impeller {
namespace testing {

struct Foo {
Mutex mtx;
int a IPLR_GUARDED_BY(mtx);
};

struct RWFoo {
RWMutex mtx;
int a IPLR_GUARDED_BY(mtx);
};

TEST(ThreadTest, CanCreateMutex) {
Foo f = {};

// f.a = 100; <--- Static analysis error.
f.mtx.Lock();
f.a = 100;
f.mtx.Unlock();
}

TEST(ThreadTest, CanCreateMutexLock) {
Foo f = {};

// f.a = 100; <--- Static analysis error.
auto a = Lock(f.mtx);
f.a = 100;
}

TEST(ThreadTest, CanCreateRWMutex) {
RWFoo f = {};

// f.a = 100; <--- Static analysis error.
f.mtx.LockWriter();
f.a = 100;
f.mtx.UnlockWriter();
// int b = f.a; <--- Static analysis error.
f.mtx.LockReader();
int b = f.a;
FML_ALLOW_UNUSED_LOCAL(b);
f.mtx.UnlockReader();
}

TEST(ThreadTest, CanCreateRWMutexLock) {
RWFoo f = {};

// f.a = 100; <--- Static analysis error.
{
auto write_lock = WriterLock{f.mtx};
f.a = 100;
}

// int b = f.a; <--- Static analysis error.
{
auto read_lock = ReaderLock(f.mtx);
int b = f.a;
FML_ALLOW_UNUSED_LOCAL(b);
}

// f.mtx.UnlockReader(); <--- Static analysis error.
}

} // namespace testing
} // namespace impeller
10 changes: 6 additions & 4 deletions impeller/base/base.h → impeller/base/thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once
#include "impeller/base/thread.h"

#include "impeller/base/promise.h"
#include "impeller/base/strings.h"
#include "impeller/base/validation.h"
namespace impeller {

//

} // namespace impeller
93 changes: 93 additions & 0 deletions impeller/base/thread.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#include <memory>
#include <thread>

#include "flutter/fml/macros.h"
#include "flutter/fml/synchronization/shared_mutex.h"
#include "impeller/base/thread_safety.h"

namespace impeller {

class IPLR_CAPABILITY("mutex") Mutex {
public:
Mutex() = default;

~Mutex() = default;

void Lock() IPLR_ACQUIRE() { mutex_.lock(); }

void Unlock() IPLR_RELEASE() { mutex_.unlock(); }

private:
std::mutex mutex_;

FML_DISALLOW_COPY_ASSIGN_AND_MOVE(Mutex);
};

class IPLR_CAPABILITY("mutex") RWMutex {
public:
RWMutex()
: mutex_(std::unique_ptr<fml::SharedMutex>(fml::SharedMutex::Create())) {}

~RWMutex() = default;

void LockWriter() IPLR_ACQUIRE() { mutex_->Lock(); }

void UnlockWriter() IPLR_RELEASE() { mutex_->Unlock(); }

void LockReader() IPLR_ACQUIRE_SHARED() { mutex_->LockShared(); }

void UnlockReader() IPLR_RELEASE_SHARED() { mutex_->UnlockShared(); }

private:
std::unique_ptr<fml::SharedMutex> mutex_;

FML_DISALLOW_COPY_ASSIGN_AND_MOVE(RWMutex);
};

class IPLR_SCOPED_CAPABILITY Lock {
public:
Lock(Mutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) { mutex_.Lock(); }

~Lock() IPLR_RELEASE() { mutex_.Unlock(); }

private:
Mutex& mutex_;

FML_DISALLOW_COPY_ASSIGN_AND_MOVE(Lock);
};

class IPLR_SCOPED_CAPABILITY ReaderLock {
public:
ReaderLock(RWMutex& mutex) IPLR_ACQUIRE_SHARED(mutex) : mutex_(mutex) {
mutex_.LockReader();
}

~ReaderLock() IPLR_RELEASE() { mutex_.UnlockReader(); }

private:
RWMutex& mutex_;

FML_DISALLOW_COPY_ASSIGN_AND_MOVE(ReaderLock);
};

class IPLR_SCOPED_CAPABILITY WriterLock {
public:
WriterLock(RWMutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) {
mutex_.LockWriter();
}

~WriterLock() IPLR_RELEASE() { mutex_.UnlockWriter(); }

private:
RWMutex& mutex_;

FML_DISALLOW_COPY_ASSIGN_AND_MOVE(WriterLock);
};

} // namespace impeller
11 changes: 11 additions & 0 deletions impeller/base/thread_safety.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "impeller/base/thread_safety.h"

namespace impeller {

//

} // namespace impeller
69 changes: 69 additions & 0 deletions impeller/base/thread_safety.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#if defined(__clang__)
#define IPLR_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define IPLR_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif

#define IPLR_CAPABILITY(x) IPLR_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))

#define IPLR_SCOPED_CAPABILITY \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)

#define IPLR_GUARDED_BY(x) IPLR_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))

#define IPLR_PT_GUARDED_BY(x) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))

#define IPLR_ACQUIRED_BEFORE(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))

#define IPLR_ACQUIRED_AFTER(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))

#define IPLR_REQUIRES(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))

#define IPLR_REQUIRES_SHARED(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))

#define IPLR_ACQUIRE(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))

#define IPLR_ACQUIRE_SHARED(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))

#define IPLR_RELEASE(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))

#define IPLR_RELEASE_SHARED(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))

#define IPLR_RELEASE_GENERIC(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))

#define IPLR_TRY_ACQUIRE(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))

#define IPLR_TRY_ACQUIRE_SHARED(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))

#define IPLR_EXCLUDES(...) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))

#define IPLR_ASSERT_CAPABILITY(x) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))

#define IPLR_ASSERT_SHARED_CAPABILITY(x) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))

#define IPLR_RETURN_CAPABILITY(x) \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))

#define IPLR_NO_THREAD_SAFETY_ANALYSIS \
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
2 changes: 1 addition & 1 deletion impeller/renderer/backend/metal/render_pass_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "flutter/fml/closure.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
#include "impeller/base/base.h"
#include "impeller/base/backend_cast.h"
#include "impeller/renderer/backend/metal/device_buffer_mtl.h"
#include "impeller/renderer/backend/metal/formats_mtl.h"
#include "impeller/renderer/backend/metal/pipeline_mtl.h"
Expand Down
2 changes: 1 addition & 1 deletion impeller/renderer/pipeline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include "impeller/renderer/pipeline.h"

#include "impeller/base/base.h"
#include "impeller/base/promise.h"
#include "impeller/renderer/context.h"
#include "impeller/renderer/pipeline_library.h"

Expand Down
3 changes: 2 additions & 1 deletion impeller/renderer/pipeline_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

#include "flutter/fml/logging.h"
#include "flutter/fml/macros.h"
#include "impeller/base/base.h"
#include "impeller/base/strings.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/context.h"
#include "impeller/renderer/formats.h"
#include "impeller/renderer/pipeline_descriptor.h"
Expand Down
3 changes: 2 additions & 1 deletion impeller/renderer/render_target.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

#include "impeller/renderer/render_target.h"

#include "impeller/base/base.h"
#include "impeller/base/strings.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/allocator.h"
#include "impeller/renderer/context.h"
#include "impeller/renderer/texture.h"
Expand Down
2 changes: 1 addition & 1 deletion impeller/renderer/vertex_buffer_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <vector>

#include "flutter/fml/macros.h"
#include "impeller/base/base.h"
#include "impeller/base/strings.h"
#include "impeller/geometry/vector.h"
#include "impeller/renderer/allocator.h"
#include "impeller/renderer/device_buffer.h"
Expand Down
5 changes: 5 additions & 0 deletions impeller/tools/impeller.gni
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ template("impeller_component") {

public_configs += [ "//flutter/impeller:impeller_public_config" ]

if (!defined(invoker.cflags)) {
cflags = []
}
cflags += [ "-Wthread-safety-analysis" ]

if (!defined(invoker.cflags_objc)) {
cflags_objc = []
}
Expand Down

0 comments on commit e09b0ed

Please sign in to comment.