Skip to content

Commit e09b0ed

Browse files
chinmaygardednfield
authored andcommitted
Add static thread safety analysis ready synchronization primitives. (flutter#117)
1 parent f2e297c commit e09b0ed

12 files changed

+268
-10
lines changed

impeller/base/BUILD.gn

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ impeller_component("base") {
1717
"promise.h",
1818
"strings.cc",
1919
"strings.h",
20+
"thread.cc",
21+
"thread.h",
22+
"thread_safety.cc",
23+
"thread_safety.h",
2024
"validation.cc",
2125
"validation.h",
2226
]
@@ -26,7 +30,7 @@ impeller_component("base") {
2630

2731
impeller_component("base_unittests") {
2832
testonly = true
29-
sources = []
33+
sources = [ "base_unittests.cc" ]
3034
deps = [
3135
":base",
3236
"//flutter/testing",

impeller/base/base_unittests.cc

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/testing/testing.h"
6+
#include "impeller/base/thread.h"
7+
8+
namespace impeller {
9+
namespace testing {
10+
11+
struct Foo {
12+
Mutex mtx;
13+
int a IPLR_GUARDED_BY(mtx);
14+
};
15+
16+
struct RWFoo {
17+
RWMutex mtx;
18+
int a IPLR_GUARDED_BY(mtx);
19+
};
20+
21+
TEST(ThreadTest, CanCreateMutex) {
22+
Foo f = {};
23+
24+
// f.a = 100; <--- Static analysis error.
25+
f.mtx.Lock();
26+
f.a = 100;
27+
f.mtx.Unlock();
28+
}
29+
30+
TEST(ThreadTest, CanCreateMutexLock) {
31+
Foo f = {};
32+
33+
// f.a = 100; <--- Static analysis error.
34+
auto a = Lock(f.mtx);
35+
f.a = 100;
36+
}
37+
38+
TEST(ThreadTest, CanCreateRWMutex) {
39+
RWFoo f = {};
40+
41+
// f.a = 100; <--- Static analysis error.
42+
f.mtx.LockWriter();
43+
f.a = 100;
44+
f.mtx.UnlockWriter();
45+
// int b = f.a; <--- Static analysis error.
46+
f.mtx.LockReader();
47+
int b = f.a;
48+
FML_ALLOW_UNUSED_LOCAL(b);
49+
f.mtx.UnlockReader();
50+
}
51+
52+
TEST(ThreadTest, CanCreateRWMutexLock) {
53+
RWFoo f = {};
54+
55+
// f.a = 100; <--- Static analysis error.
56+
{
57+
auto write_lock = WriterLock{f.mtx};
58+
f.a = 100;
59+
}
60+
61+
// int b = f.a; <--- Static analysis error.
62+
{
63+
auto read_lock = ReaderLock(f.mtx);
64+
int b = f.a;
65+
FML_ALLOW_UNUSED_LOCAL(b);
66+
}
67+
68+
// f.mtx.UnlockReader(); <--- Static analysis error.
69+
}
70+
71+
} // namespace testing
72+
} // namespace impeller

impeller/base/base.h renamed to impeller/base/thread.cc

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
#pragma once
5+
#include "impeller/base/thread.h"
66

7-
#include "impeller/base/promise.h"
8-
#include "impeller/base/strings.h"
9-
#include "impeller/base/validation.h"
7+
namespace impeller {
8+
9+
//
10+
11+
} // namespace impeller

impeller/base/thread.h

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#include <memory>
8+
#include <thread>
9+
10+
#include "flutter/fml/macros.h"
11+
#include "flutter/fml/synchronization/shared_mutex.h"
12+
#include "impeller/base/thread_safety.h"
13+
14+
namespace impeller {
15+
16+
class IPLR_CAPABILITY("mutex") Mutex {
17+
public:
18+
Mutex() = default;
19+
20+
~Mutex() = default;
21+
22+
void Lock() IPLR_ACQUIRE() { mutex_.lock(); }
23+
24+
void Unlock() IPLR_RELEASE() { mutex_.unlock(); }
25+
26+
private:
27+
std::mutex mutex_;
28+
29+
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(Mutex);
30+
};
31+
32+
class IPLR_CAPABILITY("mutex") RWMutex {
33+
public:
34+
RWMutex()
35+
: mutex_(std::unique_ptr<fml::SharedMutex>(fml::SharedMutex::Create())) {}
36+
37+
~RWMutex() = default;
38+
39+
void LockWriter() IPLR_ACQUIRE() { mutex_->Lock(); }
40+
41+
void UnlockWriter() IPLR_RELEASE() { mutex_->Unlock(); }
42+
43+
void LockReader() IPLR_ACQUIRE_SHARED() { mutex_->LockShared(); }
44+
45+
void UnlockReader() IPLR_RELEASE_SHARED() { mutex_->UnlockShared(); }
46+
47+
private:
48+
std::unique_ptr<fml::SharedMutex> mutex_;
49+
50+
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(RWMutex);
51+
};
52+
53+
class IPLR_SCOPED_CAPABILITY Lock {
54+
public:
55+
Lock(Mutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) { mutex_.Lock(); }
56+
57+
~Lock() IPLR_RELEASE() { mutex_.Unlock(); }
58+
59+
private:
60+
Mutex& mutex_;
61+
62+
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(Lock);
63+
};
64+
65+
class IPLR_SCOPED_CAPABILITY ReaderLock {
66+
public:
67+
ReaderLock(RWMutex& mutex) IPLR_ACQUIRE_SHARED(mutex) : mutex_(mutex) {
68+
mutex_.LockReader();
69+
}
70+
71+
~ReaderLock() IPLR_RELEASE() { mutex_.UnlockReader(); }
72+
73+
private:
74+
RWMutex& mutex_;
75+
76+
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(ReaderLock);
77+
};
78+
79+
class IPLR_SCOPED_CAPABILITY WriterLock {
80+
public:
81+
WriterLock(RWMutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) {
82+
mutex_.LockWriter();
83+
}
84+
85+
~WriterLock() IPLR_RELEASE() { mutex_.UnlockWriter(); }
86+
87+
private:
88+
RWMutex& mutex_;
89+
90+
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(WriterLock);
91+
};
92+
93+
} // namespace impeller

impeller/base/thread_safety.cc

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "impeller/base/thread_safety.h"
6+
7+
namespace impeller {
8+
9+
//
10+
11+
} // namespace impeller

impeller/base/thread_safety.h

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#if defined(__clang__)
8+
#define IPLR_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
9+
#else
10+
#define IPLR_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
11+
#endif
12+
13+
#define IPLR_CAPABILITY(x) IPLR_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
14+
15+
#define IPLR_SCOPED_CAPABILITY \
16+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
17+
18+
#define IPLR_GUARDED_BY(x) IPLR_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
19+
20+
#define IPLR_PT_GUARDED_BY(x) \
21+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
22+
23+
#define IPLR_ACQUIRED_BEFORE(...) \
24+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
25+
26+
#define IPLR_ACQUIRED_AFTER(...) \
27+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
28+
29+
#define IPLR_REQUIRES(...) \
30+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
31+
32+
#define IPLR_REQUIRES_SHARED(...) \
33+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
34+
35+
#define IPLR_ACQUIRE(...) \
36+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
37+
38+
#define IPLR_ACQUIRE_SHARED(...) \
39+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
40+
41+
#define IPLR_RELEASE(...) \
42+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
43+
44+
#define IPLR_RELEASE_SHARED(...) \
45+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
46+
47+
#define IPLR_RELEASE_GENERIC(...) \
48+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
49+
50+
#define IPLR_TRY_ACQUIRE(...) \
51+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
52+
53+
#define IPLR_TRY_ACQUIRE_SHARED(...) \
54+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
55+
56+
#define IPLR_EXCLUDES(...) \
57+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
58+
59+
#define IPLR_ASSERT_CAPABILITY(x) \
60+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
61+
62+
#define IPLR_ASSERT_SHARED_CAPABILITY(x) \
63+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
64+
65+
#define IPLR_RETURN_CAPABILITY(x) \
66+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
67+
68+
#define IPLR_NO_THREAD_SAFETY_ANALYSIS \
69+
IPLR_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)

impeller/renderer/backend/metal/render_pass_mtl.mm

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include "flutter/fml/closure.h"
88
#include "flutter/fml/logging.h"
99
#include "flutter/fml/trace_event.h"
10-
#include "impeller/base/base.h"
10+
#include "impeller/base/backend_cast.h"
1111
#include "impeller/renderer/backend/metal/device_buffer_mtl.h"
1212
#include "impeller/renderer/backend/metal/formats_mtl.h"
1313
#include "impeller/renderer/backend/metal/pipeline_mtl.h"

impeller/renderer/pipeline.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#include "impeller/renderer/pipeline.h"
66

7-
#include "impeller/base/base.h"
7+
#include "impeller/base/promise.h"
88
#include "impeller/renderer/context.h"
99
#include "impeller/renderer/pipeline_library.h"
1010

impeller/renderer/pipeline_builder.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
#include "flutter/fml/logging.h"
88
#include "flutter/fml/macros.h"
9-
#include "impeller/base/base.h"
9+
#include "impeller/base/strings.h"
10+
#include "impeller/base/validation.h"
1011
#include "impeller/renderer/context.h"
1112
#include "impeller/renderer/formats.h"
1213
#include "impeller/renderer/pipeline_descriptor.h"

impeller/renderer/render_target.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
#include "impeller/renderer/render_target.h"
66

7-
#include "impeller/base/base.h"
7+
#include "impeller/base/strings.h"
8+
#include "impeller/base/validation.h"
89
#include "impeller/renderer/allocator.h"
910
#include "impeller/renderer/context.h"
1011
#include "impeller/renderer/texture.h"

impeller/renderer/vertex_buffer_builder.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <vector>
1010

1111
#include "flutter/fml/macros.h"
12-
#include "impeller/base/base.h"
12+
#include "impeller/base/strings.h"
1313
#include "impeller/geometry/vector.h"
1414
#include "impeller/renderer/allocator.h"
1515
#include "impeller/renderer/device_buffer.h"

impeller/tools/impeller.gni

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ template("impeller_component") {
3737

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

40+
if (!defined(invoker.cflags)) {
41+
cflags = []
42+
}
43+
cflags += [ "-Wthread-safety-analysis" ]
44+
4045
if (!defined(invoker.cflags_objc)) {
4146
cflags_objc = []
4247
}

0 commit comments

Comments
 (0)