Skip to content

Commit dbd2bbc

Browse files
author
Fcitx Bot
committed
Merge remote-tracking branch 'origin/master' into fcitx
2 parents 1bb7509 + 8746917 commit dbd2bbc

28 files changed

+271
-212
lines changed

src/base/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,9 @@ mozc_cc_library(
10321032
name = "thread",
10331033
hdrs = ["thread.h"],
10341034
deps = [
1035+
"@com_google_absl//absl/base",
10351036
"@com_google_absl//absl/base:core_headers",
1037+
"@com_google_absl//absl/log:check",
10361038
"@com_google_absl//absl/synchronization",
10371039
],
10381040
)

src/base/thread.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@
3131
#define MOZC_BASE_THREAD_H_
3232

3333
#include <atomic>
34+
#include <cstdint>
3435
#include <functional>
3536
#include <memory>
3637
#include <optional>
3738
#include <utility>
3839

40+
#include "absl/base/internal/sysinfo.h"
3941
#include "absl/base/thread_annotations.h"
42+
#include "absl/log/check.h"
4043
#include "absl/synchronization/mutex.h"
4144
#include "absl/synchronization/notification.h"
4245

@@ -307,6 +310,83 @@ class CopyableAtomic : public std::atomic<T> {
307310
}
308311
};
309312

313+
// Simple recursive mutex based on absl::Mutex.
314+
// The lock() requests from the same thread are not repeated.
315+
// Recursive locks are used in extremely limited situations, e.g.,
316+
// introducing thread-safeness to legacy non-thread-safety classes
317+
// without breaking the current design.
318+
class ABSL_LOCKABLE RecursiveMutex {
319+
public:
320+
~RecursiveMutex() {
321+
// when lock/unlock are constantly called, these conditions must be true.
322+
DCHECK_EQ(owner_.load(std::memory_order_acquire), 0);
323+
DCHECK_EQ(recursion_depth_, 0);
324+
}
325+
326+
void lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
327+
const uint32_t current_tid = GetTID();
328+
329+
// Check if the `current_tid` is the owner
330+
if (owner_.load(std::memory_order_acquire) == current_tid) {
331+
// Since the owner is guaranteed to be the current thread,
332+
// recursion_depth_ can be safely incremented without a lock.
333+
++recursion_depth_;
334+
return;
335+
}
336+
337+
// Wait until no one is the owner (owner_ == 0).
338+
mutex_.LockWhen(absl::Condition(
339+
+[](std::atomic<uint32_t>* owner) {
340+
return owner->load(std::memory_order_relaxed) == 0;
341+
},
342+
&owner_));
343+
344+
// Acquiring the lock, and set the owner and recursion_depth_.
345+
DCHECK_EQ(recursion_depth_, 0);
346+
owner_.store(current_tid, std::memory_order_release);
347+
recursion_depth_ = 1;
348+
}
349+
350+
void unlock() ABSL_UNLOCK_FUNCTION() {
351+
// Assuming the current thread is the owner, no internal Mutex lock is
352+
// needed. Decrement the depth.
353+
DCHECK(owns_lock());
354+
if (--recursion_depth_ > 0) {
355+
return;
356+
}
357+
358+
// Depth reached 0, so clear the owner and release the internal Mutex so
359+
// other thread can start the task.
360+
owner_.store(0, std::memory_order_release);
361+
mutex_.unlock();
362+
}
363+
364+
// Returns true if the mute is owned by the current thread.
365+
bool owns_lock() const {
366+
return owner_.load(std::memory_order_acquire) == GetTID();
367+
}
368+
369+
// Upper case versions are deprecated in absl::Mutex too.
370+
// They are not compatible with std::lock_gurad<>/std::unique_lock<>.
371+
inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { lock(); }
372+
inline void Unlock() ABSL_UNLOCK_FUNCTION() { unlock(); }
373+
374+
private:
375+
static inline uint32_t GetTID() {
376+
// NOLINTBEGIN(abseil-no-internal-dependencies)
377+
// Abseil's cached version is 100 times faster.
378+
// Since `pid_t` is not used in all architectures, use uint32_t.
379+
return static_cast<uint32_t>(absl::base_internal::GetCachedTID());
380+
// NOLINTEND(abseil-no-internal-dependencies)
381+
}
382+
383+
absl::Mutex mutex_;
384+
std::atomic<uint32_t> owner_{0};
385+
// Accessed only by the thread indicated by owner_, so atomicity is
386+
// unnecessary.
387+
int recursion_depth_ = 0;
388+
};
389+
310390
} // namespace mozc
311391

312392
#endif // MOZC_BASE_THREAD_H_

src/base/thread_test.cc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@
3030
#include "base/thread.h"
3131

3232
#include <atomic>
33+
#include <functional>
3334
#include <memory>
35+
#include <mutex>
3436
#include <optional>
37+
#include <string>
3538
#include <utility>
39+
#include <vector>
3640

3741
#include "absl/synchronization/notification.h"
3842
#include "absl/time/clock.h"
@@ -227,5 +231,34 @@ TEST(CopyableAtomicTest, BasicTest) {
227231
EXPECT_EQ(f3, 10);
228232
}
229233

234+
TEST(RecursiveMutexTest, BasicTest) {
235+
// Edits the `buffer` from multiple threads.
236+
std::string buffer;
237+
238+
RecursiveMutex mutex;
239+
std::vector<Thread> threads;
240+
241+
// `fib` is recursively called.
242+
std::function<int(int)> fib = [&](int n) {
243+
std::unique_lock<RecursiveMutex> lock(mutex);
244+
buffer += ' ';
245+
if (n <= 1) {
246+
return n;
247+
}
248+
return fib(n - 1) + fib(n - 2);
249+
};
250+
251+
constexpr int kNumThreads = 16;
252+
for (int i = 0; i < kNumThreads; ++i) {
253+
threads.emplace_back([&, i] { fib(i); });
254+
}
255+
256+
for (Thread& thread : threads) {
257+
thread.Join();
258+
}
259+
260+
EXPECT_TRUE(true); // Expect to reach here
261+
}
262+
230263
} // namespace
231264
} // namespace mozc

src/config/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ mozc_cc_test(
137137
"//protocol:config_cc_proto",
138138
],
139139
windows = [
140+
"//base:bits",
140141
"//base/win32:win_api_test_helper",
141142
"@com_google_absl//absl/base",
142143
"@com_google_absl//absl/container:flat_hash_map",
@@ -164,6 +165,7 @@ mozc_cc_library(
164165
],
165166
deps = [
166167
":config_handler",
168+
"//base:bits",
167169
"//base:config_file_stream",
168170
"//base:number_util",
169171
"//base:singleton",

src/config/character_form_manager.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "absl/strings/str_cat.h"
4545
#include "absl/strings/string_view.h"
4646
#include "absl/types/span.h"
47+
#include "base/bits.h"
4748
#include "base/config_file_stream.h"
4849
#include "base/number_util.h"
4950
#include "base/singleton.h"
@@ -379,7 +380,7 @@ Config::CharacterForm CharacterFormManagerImpl::GetCharacterFormFromStorage(
379380
if (value == nullptr) {
380381
return Config::FULL_WIDTH; // Return default setting
381382
}
382-
const uint32_t ivalue = *reinterpret_cast<const uint32_t*>(value);
383+
const uint32_t ivalue = LoadUnaligned<uint32_t>(value);
383384
return static_cast<Config::CharacterForm>(ivalue);
384385
}
385386

src/config/stats_config_util_test.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <bit>
4343

4444
#include "absl/container/flat_hash_map.h"
45+
#include "base/bits.h"
4546
#include "base/singleton.h"
4647
#include "base/win32/win_api_test_helper.h"
4748
#endif // _WIN32
@@ -228,7 +229,7 @@ class RegistryEmulator {
228229
if (!CheckWritable(key)) {
229230
return ERROR_ACCESS_DENIED;
230231
}
231-
SetUsagestatsValue(key, *reinterpret_cast<const DWORD*>(data));
232+
SetUsagestatsValue(key, LoadUnaligned<DWORD>(data));
232233
return ERROR_SUCCESS;
233234
}
234235
static LSTATUS WINAPI TestRegCloseKey(HKEY key) { return ERROR_SUCCESS; }

src/converter/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ mozc_cc_library(
222222
"//prediction:__pkg__",
223223
],
224224
deps = [
225+
"//base:bits",
225226
"//data_manager",
226227
"//storage/louds:simple_succinct_bit_vector_index",
227228
"@com_google_absl//absl/status",
@@ -241,6 +242,7 @@ mozc_cc_test(
241242
],
242243
deps = [
243244
":connector",
245+
"//base:bits",
244246
"//base:mmap",
245247
"//base:vlog",
246248
"//data_manager:connection_file_reader",

src/converter/connector.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "absl/strings/escaping.h"
4646
#include "absl/strings/str_cat.h"
4747
#include "absl/strings/string_view.h"
48+
#include "base/bits.h"
4849
#include "data_manager/data_manager.h"
4950
#include "storage/louds/simple_succinct_bit_vector_index.h"
5051

@@ -245,11 +246,11 @@ absl::Status Connector::Init(absl::string_view connection_data) {
245246
// |ptr| points to here now. Every uint8_t[] block needs to be aligned at
246247
// 32-bit boundary.
247248
VALIDATE_SIZE(ptr, 2, "Compact bits size of row ", i, "/", rsize);
248-
const uint16_t compact_bits_size = *reinterpret_cast<const uint16_t*>(ptr);
249+
const uint16_t compact_bits_size = LoadUnaligned<uint16_t>(ptr);
249250
ptr += 2;
250251

251252
VALIDATE_SIZE(ptr, 2, "Values size of row ", i, "/", rsize);
252-
const uint16_t values_size = *reinterpret_cast<const uint16_t*>(ptr);
253+
const uint16_t values_size = LoadUnaligned<uint16_t>(ptr);
253254
ptr += 2;
254255

255256
VALIDATE_SIZE(ptr, chunk_bits_size, "Chunk bits of row ", i, "/", rsize);

src/converter/connector_test.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "absl/random/random.h"
4040
#include "absl/status/statusor.h"
4141
#include "absl/strings/string_view.h"
42+
#include "base/bits.h"
4243
#include "base/mmap.h"
4344
#include "base/vlog.h"
4445
#include "data_manager/connection_file_reader.h"
@@ -102,7 +103,7 @@ TEST(ConnectorTest, BrokenData) {
102103
// Invalid magic number.
103104
{
104105
data.assign(cmmap->begin(), cmmap->size());
105-
*reinterpret_cast<uint16_t*>(&data[0]) = 0;
106+
StoreUnaligned<uint16_t>(0, &data[0]);
106107
const auto status = Connector::Create(data).status();
107108
MOZC_VLOG(1) << status;
108109
EXPECT_FALSE(status.ok());

src/converter/inner_segment.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#define MOZC_CONVERTER_INNER_SEGMENT_H_
3232

3333
#include <algorithm>
34+
#include <bit>
3435
#include <cstddef>
3536
#include <cstdint>
3637
#include <iterator>
@@ -94,11 +95,11 @@ inline std::optional<uint32_t> EncodeLengths(uint32_t key_len,
9495

9596
const internal::LengthData data{key_len, value_len, content_key_len,
9697
content_value_len};
97-
return *reinterpret_cast<const uint32_t*>(&data);
98+
return std::bit_cast<uint32_t>(data);
9899
}
99100

100101
inline internal::LengthData DecodeLengths(uint32_t encoded) {
101-
return *reinterpret_cast<const struct internal::LengthData*>(&encoded);
102+
return std::bit_cast<internal::LengthData>(encoded);
102103
}
103104

104105
// Iterator class to access inner segments.

0 commit comments

Comments
 (0)