Fix bug due to std:🧵:id being reused

After a thread is destroyed, a thread id might be reused. This is true for pthread_self() and hence std:🧵:id. We were hitting this in Chrome debug mode because the "worker" thread was being destroyed and a new one immediately created when reloading. The thread id would be the same, and therefore we'd get back the SharedRealm for the previously destroyed thread (which had yet to be garbage collected.

The new implementation uses an atomically incremented, thread-local identifier, which serves our needs very well.

Fixes #473
This commit is contained in:
Scott Kyle 2016-06-08 18:24:10 -07:00
parent 7c2518c01f
commit 446cb0245e
6 changed files with 61 additions and 8 deletions

View File

@ -189,6 +189,7 @@
F620F0571CB766DA0082977B /* node_init.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node_init.cpp; sourceTree = "<group>"; };
F620F0591CB7B4C80082977B /* js_object_accessor.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_object_accessor.hpp; sourceTree = "<group>"; };
F620F0741CB9F60C0082977B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
F6242B291D08EE9600BE1E03 /* thread_id.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = thread_id.hpp; sourceTree = "<group>"; };
F6267BC91CADC30000AC36B1 /* js_util.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_util.hpp; sourceTree = "<group>"; };
F6267BCA1CADC49200AC36B1 /* node_dummy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node_dummy.cpp; sourceTree = "<group>"; };
F62BF8FB1CAC71780022BCDC /* libRealmNode.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libRealmNode.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
@ -363,6 +364,7 @@
02E008D11D10AB1B00F3AA37 /* atomic_shared_ptr.hpp */,
02E008D21D10AB1B00F3AA37 /* format.cpp */,
02E008D31D10AB1B00F3AA37 /* format.hpp */,
F6242B291D08EE9600BE1E03 /* thread_id.hpp */,
);
name = util;
path = src/util;

View File

@ -19,8 +19,9 @@
#ifndef REALM_WEAK_REALM_NOTIFIER_BASE_HPP
#define REALM_WEAK_REALM_NOTIFIER_BASE_HPP
#include "util/thread_id.hpp"
#include <memory>
#include <thread>
namespace realm {
class Realm;
@ -48,11 +49,11 @@ public:
// Is this a WeakRealmNotifierBase for the given Realm instance?
bool is_for_realm(Realm* realm) const { return realm == m_realm_key; }
bool is_for_current_thread() const { return m_thread_id == std::this_thread::get_id(); }
bool is_for_current_thread() const { return m_thread_id == util::get_thread_id(); }
private:
std::weak_ptr<Realm> m_realm;
std::thread::id m_thread_id = std::this_thread::get_id();
thread_id_t m_thread_id = util::get_thread_id();
void* m_realm_key;
bool m_cache = false;
};

View File

@ -306,7 +306,7 @@ static void check_read_write(Realm *realm)
void Realm::verify_thread() const
{
if (m_thread_id != std::this_thread::get_id()) {
if (m_thread_id != util::get_thread_id()) {
throw IncorrectThreadException();
}
}

View File

@ -19,9 +19,11 @@
#ifndef REALM_REALM_HPP
#define REALM_REALM_HPP
#include "util/thread_id.hpp"
#include <functional>
#include <memory>
#include <string>
#include <thread>
#include <vector>
namespace realm {
@ -128,7 +130,7 @@ namespace realm {
bool compact();
void write_copy(StringData path, BinaryData encryption_key);
std::thread::id thread_id() const { return m_thread_id; }
thread_id_t thread_id() const { return m_thread_id; }
void verify_thread() const;
void verify_in_write() const;
@ -174,7 +176,7 @@ namespace realm {
private:
Config m_config;
std::thread::id m_thread_id = std::this_thread::get_id();
thread_id_t m_thread_id = util::get_thread_id();
bool m_auto_refresh = true;
std::unique_ptr<Replication> m_history;

View File

@ -134,4 +134,4 @@ private:
}
}
#endif // REALM_ASYNC_QUERY_HPP
#endif // REALM_ATOMIC_SHARED_PTR_HPP

View File

@ -0,0 +1,48 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#ifndef REALM_THREAD_ID_HPP
#define REALM_THREAD_ID_HPP
#include <realm/util/features.h>
#include <atomic>
namespace realm {
using thread_id_t = std::size_t;
namespace util {
// Since std::thread::id may be reused after a thread is destroyed, we use
// an atomically incremented, thread-local identifier instead.
inline thread_id_t get_thread_id() {
static std::atomic<thread_id_t> id_counter;
static REALM_THREAD_LOCAL thread_id_t thread_id = 0;
if (REALM_UNLIKELY(!thread_id)) {
thread_id = ++id_counter;
}
return thread_id;
}
} // namespace util
} // namespace realm
#endif // REALM_THREAD_ID_HPP