Commit 7f17b7bd authored by Kenton Varda's avatar Kenton Varda

Make sure reading far pointers is thread-safe.

parent 3c7505d6
...@@ -63,12 +63,10 @@ SegmentReader* ReaderArena::tryGetSegment(SegmentId id) { ...@@ -63,12 +63,10 @@ SegmentReader* ReaderArena::tryGetSegment(SegmentId id) {
} }
} }
// TODO(someday): Lock a mutex so that reading is thread-safe. Take a reader lock during the auto lock = moreSegments.lockExclusive();
// first lookup, unlock it before calling getSegment(), then take a writer lock to update the
// map. Bleh, lazy initialization is sad.
SegmentMap* segments = nullptr; SegmentMap* segments = nullptr;
KJ_IF_MAYBE(s, moreSegments) { KJ_IF_MAYBE(s, *lock) {
auto iter = s->find(id.value); auto iter = s->find(id.value);
if (iter != s->end()) { if (iter != s->end()) {
return iter->second.get(); return iter->second.get();
...@@ -81,11 +79,11 @@ SegmentReader* ReaderArena::tryGetSegment(SegmentId id) { ...@@ -81,11 +79,11 @@ SegmentReader* ReaderArena::tryGetSegment(SegmentId id) {
return nullptr; return nullptr;
} }
if (moreSegments == nullptr) { if (*lock == nullptr) {
// OK, the segment exists, so allocate the map. // OK, the segment exists, so allocate the map.
auto s = kj::heap<SegmentMap>(); auto s = kj::heap<SegmentMap>();
segments = s; segments = s;
moreSegments = mv(s); *lock = mv(s);
} }
auto segment = kj::heap<SegmentReader>(this, id, newSegment, &readLimiter); auto segment = kj::heap<SegmentReader>(this, id, newSegment, &readLimiter);
......
...@@ -171,7 +171,7 @@ private: ...@@ -171,7 +171,7 @@ private:
SegmentReader segment0; SegmentReader segment0;
typedef std::unordered_map<uint, kj::Own<SegmentReader>> SegmentMap; typedef std::unordered_map<uint, kj::Own<SegmentReader>> SegmentMap;
kj::Maybe<kj::Own<SegmentMap>> moreSegments; kj::MutexGuarded<kj::Maybe<kj::Own<SegmentMap>>> moreSegments;
}; };
class BuilderArena final: public Arena { class BuilderArena final: public Arena {
......
...@@ -124,7 +124,7 @@ private: ...@@ -124,7 +124,7 @@ private:
// because we don't want clients to have to #include arena.h, which itself includes a bunch of // because we don't want clients to have to #include arena.h, which itself includes a bunch of
// big STL headers. We don't use a pointer to a ReaderArena because that would require an // big STL headers. We don't use a pointer to a ReaderArena because that would require an
// extra malloc on every message which could be expensive when processing small messages. // extra malloc on every message which could be expensive when processing small messages.
void* arenaSpace[15]; void* arenaSpace[15 + sizeof(kj::MutexGuarded<void*>) / sizeof(void*)];
bool allocatedArena; bool allocatedArena;
_::ReaderArena* arena() { return reinterpret_cast<_::ReaderArena*>(arenaSpace); } _::ReaderArena* arena() { return reinterpret_cast<_::ReaderArena*>(arenaSpace); }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment