Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,7 @@ jobs:

lint:
name: lint
# Held on 24.04: 26.04's clang-tidy (21+) enables checks that flag ~180
# sites (modernize-use-scoped-lock, -use-designated-initializers, ...).
# Move with that cleanup, not with a runner bump.
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- uses: actions/checkout@v7
# Boost headers so clang-tidy can process the Beast transport. libboost-dev
Expand Down
4 changes: 2 additions & 2 deletions examples/simplerestjson/serve_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ class InMemoryBookstore final : public BookstoreHandler {
public:
opal::Outcome<AddBookOutput> AddBook(const AddBookInput& input,
const opal::server::RequestContext& /*context*/) override {
const std::lock_guard<std::mutex> lock(mu_);
const std::scoped_lock lock(mu_);
titles_[input.isbn] = input.title;
return AddBookOutput{.status = 201, .isbn = input.isbn};
}

opal::Outcome<GetBookOutput> GetBook(const GetBookInput& input,
const opal::server::RequestContext& /*context*/) override {
const std::lock_guard<std::mutex> lock(mu_);
const std::scoped_lock lock(mu_);
const auto it = titles_.find(input.isbn);
if (it == titles_.end()) {
const std::string message = "no book: " + input.isbn;
Expand Down
2 changes: 1 addition & 1 deletion examples/weather/handwritten/weather_types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Outcome<ListCitiesOutput> DeserializeListCitiesOutput(const Document& doc) {
const Document* name = entry.Find("name");
if (city_id == nullptr || name == nullptr) return MissingMember("items[].*");
if (!city_id->is_string() || !name->is_string()) return WrongType("items[].*");
out.items.push_back(CitySummary{city_id->as_string(), name->as_string()});
out.items.push_back(CitySummary{.cityId = city_id->as_string(), .name = name->as_string()});
}
return out;
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/include/opal/core/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class Document {
Document(DocumentMap value) : value_(std::move(value)) {} // NOLINT

static Document FromTimestamp(Timestamp ts, TimestampFormat format) {
return Document(TimestampValue{ts, format});
return Document(TimestampValue{.value = ts, .format = format});
}

bool is_null() const { return std::holds_alternative<std::nullptr_t>(value_); }
Expand Down
4 changes: 2 additions & 2 deletions runtime/include/opal/core/exception_guard.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include <utility>

#if defined(__cpp_exceptions)
#ifdef __cpp_exceptions
#include <exception>
#endif

Expand All @@ -29,7 +29,7 @@ namespace opal::internal {
// `on_throw` must return the same type as `body` (or both must be void).
template <typename Body, typename OnThrow>
auto Contain(Body&& body, OnThrow&& on_throw) -> decltype(std::forward<Body>(body)()) {
#if defined(__cpp_exceptions)
#ifdef __cpp_exceptions
try {
return std::forward<Body>(body)();
} catch (const std::exception& e) {
Expand Down
4 changes: 2 additions & 2 deletions runtime/include/opal/eventstream/async_event_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct Detached {
// A coroutine promise must declare unhandled_exception(), but under
// -fno-exceptions it is unreachable — nothing can throw — so the
// containment body compiles only when exceptions are enabled.
#if defined(__cpp_exceptions)
#ifdef __cpp_exceptions
try {
std::rethrow_exception(std::current_exception());
} catch (const std::exception& e) {
Expand Down Expand Up @@ -90,7 +90,7 @@ class [[nodiscard]] StreamTask {
void unhandled_exception() noexcept {
// Required by the coroutine machinery, but unreachable under
// -fno-exceptions; the containment body compiles only with exceptions.
#if defined(__cpp_exceptions)
#ifdef __cpp_exceptions
try {
std::rethrow_exception(std::current_exception());
} catch (const std::exception& e) {
Expand Down
6 changes: 3 additions & 3 deletions runtime/include/opal/eventstream/event_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct SharedSessionState {
// Drops one pin; the revoking stream's drain wait wakes at zero. Free so
// async completions can release with only the state in hand (ADR-0019).
inline void ReleasePin(SharedSessionState& state) {
const std::lock_guard<std::mutex> lock(state.mutex);
const std::scoped_lock lock(state.mutex);
if (--state.active == 0) state.idle.notify_all();
}

Expand Down Expand Up @@ -103,7 +103,7 @@ class SharedViewOwner {
if (state_ == nullptr) return;
const std::shared_ptr<SharedSessionState> state = std::move(state_);
{
const std::lock_guard<std::mutex> lock(state->mutex);
const std::scoped_lock lock(state->mutex);
state->socket = nullptr;
}
socket_->Close();
Expand Down Expand Up @@ -219,7 +219,7 @@ class EventStreamHandle {
// session ended (or this handle was moved from).
http::WebSocket* Acquire() const {
if (state_ == nullptr) return nullptr;
const std::lock_guard<std::mutex> lock(state_->mutex);
const std::scoped_lock lock(state_->mutex);
if (state_->socket == nullptr) return nullptr;
++state_->active;
return state_->socket;
Expand Down
52 changes: 26 additions & 26 deletions runtime/include/opal/server/session_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class SessionRegistry {
ExpireDetachedNow();
std::vector<std::shared_ptr<Entry>> all;
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
for (auto& [id, entry] : sessions_) all.push_back(std::move(entry));
sessions_.clear();
all.insert(all.end(), std::make_move_iterator(retired_.begin()),
Expand Down Expand Up @@ -214,7 +214,7 @@ class SessionRegistry {
const bool async_mode = options_.async_delivery && handle.SupportsAsync();
auto entry = std::make_shared<Entry>(std::move(handle));
entry->async_mode = async_mode;
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
ReapLocked();
if (!sessions_.emplace(std::move(id), entry).second) return false;
// Async entries drain through completion chains and hold no thread;
Expand All @@ -236,7 +236,7 @@ class SessionRegistry {
bool Remove(const Id& id) {
std::shared_ptr<Entry> entry;
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
const auto it = sessions_.find(id);
if (it == sessions_.end()) return false;
entry = std::move(it->second);
Expand All @@ -250,7 +250,7 @@ class SessionRegistry {
// its own shared_ptr.
bool has_writer = false;
{
const std::lock_guard<std::mutex> entry_lock(entry->mutex);
const std::scoped_lock entry_lock(entry->mutex);
entry->stopping = true;
entry->queue.clear();
has_writer = entry->writer.joinable();
Expand All @@ -275,12 +275,12 @@ class SessionRegistry {
std::shared_ptr<Entry> entry;
std::optional<Handle> old_handle; // a copy to close outside the locks
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
const auto it = sessions_.find(id);
if (it == sessions_.end()) return false;
entry = it->second;
{
const std::lock_guard<std::mutex> entry_lock(entry->mutex);
const std::scoped_lock entry_lock(entry->mutex);
if (entry->detached) return false;
entry->detached = true;
entry->deadline = std::chrono::steady_clock::now() + options_.grace_period;
Expand Down Expand Up @@ -313,7 +313,7 @@ class SessionRegistry {
std::shared_ptr<Entry> entry;
std::optional<Tx> claimed;
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
const auto it = sessions_.find(id);
if (it == sessions_.end()) return false;
entry = it->second;
Expand Down Expand Up @@ -404,7 +404,7 @@ class SessionRegistry {
bool SendTo(const Id& id, Tx event, DeliveryClass delivery = {}) {
std::shared_ptr<Entry> entry;
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
const auto it = sessions_.find(id);
if (it == sessions_.end()) return false;
entry = it->second;
Expand All @@ -422,7 +422,7 @@ class SessionRegistry {
std::vector<std::pair<const Id*, std::shared_ptr<Entry>>> targets;
targets.reserve(ids.size());
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
for (const Id& id : ids) {
if (const auto it = sessions_.find(id); it != sessions_.end()) {
targets.emplace_back(&id, it->second);
Expand All @@ -448,7 +448,7 @@ class SessionRegistry {
const DeliveryClass& delivery = {}) {
std::vector<std::pair<Id, std::shared_ptr<Entry>>> targets;
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
targets.reserve(sessions_.size());
for (const auto& [id, entry] : sessions_) targets.emplace_back(id, entry);
}
Expand Down Expand Up @@ -478,10 +478,10 @@ class SessionRegistry {
bool Close(const Id& id) {
std::optional<Handle> doomed;
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
const auto it = sessions_.find(id);
if (it == sessions_.end()) return false;
const std::lock_guard<std::mutex> entry_lock(it->second->mutex);
const std::scoped_lock entry_lock(it->second->mutex);
doomed.emplace(it->second->handle);
}
doomed->Close();
Expand All @@ -496,7 +496,7 @@ class SessionRegistry {
// Resume's handle swap. The closes still run outside every lock.
std::vector<Handle> handles;
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
handles.reserve(sessions_.size());
for (const auto& [id, entry] : sessions_) handles.push_back(entry->handle);
}
Expand All @@ -519,15 +519,15 @@ class SessionRegistry {
// A snapshot of the registered ids — the "everyone currently here" input
// to the Broadcast(ids, ...) overloads.
std::vector<Id> Ids() const {
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
std::vector<Id> ids;
ids.reserve(sessions_.size());
for (const auto& [id, entry] : sessions_) ids.push_back(id);
return ids;
}

std::size_t size() const {
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
return sessions_.size();
}

Expand Down Expand Up @@ -590,7 +590,7 @@ class SessionRegistry {
entry.queue.pop_front();
}
if (!entry.handle.Send(event).ok()) {
const std::lock_guard<std::mutex> lock(entry.mutex);
const std::scoped_lock lock(entry.mutex);
entry.stopping = true;
// A detached entry may be retaining its queue for the resume
// (the failed send is the dying old connection's, not the tail's).
Expand All @@ -599,7 +599,7 @@ class SessionRegistry {
}
}
{
const std::lock_guard<std::mutex> lock(entry.mutex);
const std::scoped_lock lock(entry.mutex);
entry.done = true;
}
entry.wake.notify_all(); // Resume waits out this exit before swapping
Expand All @@ -609,7 +609,7 @@ class SessionRegistry {
// own failure path sets the same state inline, under its held lock.)
static void RequestStop(Entry& entry) {
{
const std::lock_guard<std::mutex> lock(entry.mutex);
const std::scoped_lock lock(entry.mutex);
entry.stopping = true;
entry.queue.clear();
}
Expand Down Expand Up @@ -656,7 +656,7 @@ class SessionRegistry {
bool queued = false;
std::optional<Tx> claimed;
{
const std::lock_guard<std::mutex> lock(entry->mutex);
const std::scoped_lock lock(entry->mutex);
if (entry->detached) {
// Tested before stopping: detached implies stopping, and the
// retention branch must win over the refuse-on-stopping one.
Expand Down Expand Up @@ -699,7 +699,7 @@ class SessionRegistry {
// id has as the drop is charged; that is close-on-full's contract.
std::optional<Handle> doomed;
{
const std::lock_guard<std::mutex> lock(entry->mutex);
const std::scoped_lock lock(entry->mutex);
doomed.emplace(entry->handle);
}
doomed->Close();
Expand Down Expand Up @@ -743,7 +743,7 @@ class SessionRegistry {
entry->handle.SendAsync(event, [entry](const Outcome<Unit>& sent) {
std::optional<Tx> next;
{
const std::lock_guard<std::mutex> lock(entry->mutex);
const std::scoped_lock lock(entry->mutex);
if (sent.ok()) {
// Delivered: retire the event. (RequestStop may have cleared the
// queue mid-flight, so the pop is guarded.)
Expand Down Expand Up @@ -796,7 +796,7 @@ class SessionRegistry {
}
bool done = false;
{
const std::lock_guard<std::mutex> lock((*it)->mutex);
const std::scoped_lock lock((*it)->mutex);
done = (*it)->done;
}
if (done) {
Expand Down Expand Up @@ -825,7 +825,7 @@ class SessionRegistry {

void StopExpiry() {
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
expiry_stop_ = true;
}
expiry_wake_.notify_all();
Expand All @@ -837,7 +837,7 @@ class SessionRegistry {
while (!expiry_stop_) {
std::optional<std::chrono::steady_clock::time_point> next;
for (const auto& [id, entry] : sessions_) {
const std::lock_guard<std::mutex> entry_lock(entry->mutex);
const std::scoped_lock entry_lock(entry->mutex);
if (!entry->detached) continue;
if (!next || entry->deadline < *next) next = entry->deadline;
}
Expand Down Expand Up @@ -869,7 +869,7 @@ class SessionRegistry {
bool claim = false;
bool has_writer = false;
{
const std::lock_guard<std::mutex> entry_lock(it->second->mutex);
const std::scoped_lock entry_lock(it->second->mutex);
claim = it->second->detached && now >= it->second->deadline;
has_writer = claim && it->second->writer.joinable();
}
Expand Down Expand Up @@ -905,7 +905,7 @@ class SessionRegistry {
void ExpireDetachedNow() {
std::vector<std::pair<Id, std::shared_ptr<Entry>>> expired;
{
const std::lock_guard<std::mutex> lock(mutex_);
const std::scoped_lock lock(mutex_);
expired = TakeExpiredLocked(std::chrono::steady_clock::time_point::max());
}
FireExpiries(expired);
Expand Down
4 changes: 2 additions & 2 deletions runtime/src/cbor/cbor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,12 @@ class Decoder {
if (inner->is_int()) {
auto ts = Timestamp::FromEpochSecondsChecked(static_cast<double>(inner->as_int()));
if (!ts) return std::move(ts).error();
return Document(TimestampValue{*ts, TimestampFormat::kEpochSeconds});
return Document(TimestampValue{.value = *ts, .format = TimestampFormat::kEpochSeconds});
}
if (inner->is_double()) {
auto ts = Timestamp::FromEpochSecondsChecked(inner->as_double());
if (!ts) return std::move(ts).error();
return Document(TimestampValue{*ts, TimestampFormat::kEpochSeconds});
return Document(TimestampValue{.value = *ts, .format = TimestampFormat::kEpochSeconds});
}
return Fail("tag 1 content is not a number");
}
Expand Down
Loading
Loading