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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## LATEST Changes

* Fixed RPC server deadlock on shutdown, overly strict Vector3D assert, OpenDrive lane width for center lanes, busy-wait yield() calls, and strict RELEASE_ASSERTs in road Map (ported from ue4-dev)
* Fix typos in README.md
* Added actor description as Actor TAGs
* Create class with functions to import points and polylines from satellite segmentation (#8946, #8949 #8950)
Expand Down
3 changes: 2 additions & 1 deletion LibCarla/source/carla/client/detail/Simulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "carla/trafficmanager/TrafficManager.h"
#include "carla/sensor/Deserializer.h"

#include <chrono>
#include <exception>
#include <thread>

Expand Down Expand Up @@ -50,7 +51,7 @@ namespace detail {
bool result = true;
auto start = std::chrono::system_clock::now();
while (frame > episode.GetState()->GetTimestamp().frame) {
std::this_thread::yield();
std::this_thread::sleep_for(std::chrono::microseconds(100));
auto end = std::chrono::system_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end-start);
if(timeout.to_chrono() < diff) {
Expand Down
4 changes: 3 additions & 1 deletion LibCarla/source/carla/geom/Vector3D.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ namespace geom {

inline Vector3D MakeUnitVector() const {
const float length = Length();
DEVELOPMENT_ASSERT(length > 2.0f * std::numeric_limits<float>::epsilon());
if (length <= 0.0f) {
return Vector3D(0.0f, 0.0f, 0.0f);
}
const float k = 1.0f / length;
return Vector3D(x * k, y * k, z * k);
}
Expand Down
8 changes: 5 additions & 3 deletions LibCarla/source/carla/opendrive/parser/LaneParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ namespace parser {
map_builder.CreateLaneWidth(lane, s_offset + s, a, b, c, d);
width_count++;
}
if (width_count == 0 && lane->GetId() != 0) {
if (width_count == 0) {
map_builder.CreateLaneWidth(lane, s, 0.0, 0.0, 0.0, 0.0);
std::cout << "WARNING: In road " << lane->GetRoad()->GetId() << " lane " << lane->GetId() <<
" no \"<width>\" parameter found under \"<lane>\" tag. Using default values." << std::endl;
if (lane->GetId() != 0) {
std::cout << "WARNING: In road " << lane->GetRoad()->GetId() << " lane " << lane->GetId() <<
" no \"<width>\" parameter found under \"<lane>\" tag. Using default values." << std::endl;
}
}

// Lane Border
Expand Down
32 changes: 24 additions & 8 deletions LibCarla/source/carla/road/Map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,21 @@ namespace road {
std::vector<Waypoint> result;
result.reserve(next_lanes.size());
for (auto *next_lane : next_lanes) {
RELEASE_ASSERT(next_lane != nullptr);
if (next_lane == nullptr) {
continue;
}
const auto lane_id = next_lane->GetId();
RELEASE_ASSERT(lane_id != 0);
if (lane_id == 0) {
continue;
}
const auto *section = next_lane->GetLaneSection();
RELEASE_ASSERT(section != nullptr);
if (section == nullptr) {
continue;
}
const auto *road = next_lane->GetRoad();
RELEASE_ASSERT(road != nullptr);
if (road == nullptr) {
continue;
}
const auto distance = GetDistanceAtStartOfLane(*next_lane);
result.emplace_back(Waypoint{road->GetId(), section->GetId(), lane_id, distance});
}
Expand All @@ -539,13 +547,21 @@ namespace road {
std::vector<Waypoint> result;
result.reserve(prev_lanes.size());
for (auto *next_lane : prev_lanes) {
RELEASE_ASSERT(next_lane != nullptr);
if (next_lane == nullptr) {
continue;
}
const auto lane_id = next_lane->GetId();
RELEASE_ASSERT(lane_id != 0);
if (lane_id == 0) {
continue;
}
const auto *section = next_lane->GetLaneSection();
RELEASE_ASSERT(section != nullptr);
if (section == nullptr) {
continue;
}
const auto *road = next_lane->GetRoad();
RELEASE_ASSERT(road != nullptr);
if (road == nullptr) {
continue;
}
const auto distance = GetDistanceAtEndOfLane(*next_lane);
result.emplace_back(Waypoint{road->GetId(), section->GetId(), lane_id, distance});
}
Expand Down
21 changes: 17 additions & 4 deletions LibCarla/source/carla/rpc/Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

#include <rpc/server.h>

#include <chrono>
#include <atomic>
#include <future>
#include <stdexcept>

namespace carla {
namespace rpc {
Expand Down Expand Up @@ -62,6 +65,7 @@ namespace rpc {

/// @warning does not stop the game thread.
void Stop() {
_shutdown_in_progress = true;
_server.stop();
}

Expand All @@ -70,6 +74,7 @@ namespace rpc {
boost::asio::io_context _sync_io_context;

::rpc::server _server;
std::atomic_bool _shutdown_in_progress{false};
};

// ===========================================================================
Expand Down Expand Up @@ -106,8 +111,8 @@ namespace detail {
/// I.e., we can use the io_context to run tasks on a specific thread (e.g.
/// game thread).
template <typename FuncT>
static auto WrapSyncCall(boost::asio::io_context &io, FuncT &&functor) {
return [&io, functor=std::forward<FuncT>(functor)](Metadata metadata, Args... args) -> R {
static auto WrapSyncCall(std::atomic_bool &shutdown_in_progress, boost::asio::io_context &io, FuncT &&functor) {
return [&shutdown_in_progress, &io, functor=std::forward<FuncT>(functor)](Metadata metadata, Args... args) -> R {
auto task = std::packaged_task<R()>([functor=std::move(functor), args...]() {
return functor(args...);
});
Expand All @@ -119,7 +124,15 @@ namespace detail {
// Post task and wait for result.
auto result = task.get_future();
boost::asio::post(io, MoveHandler(task));
return result.get();
std::future_status status;
do {
status = result.wait_for(std::chrono::milliseconds(100));
} while (!shutdown_in_progress && (status != std::future_status::ready));
if (status == std::future_status::ready) {
return result.get();
} else {
throw std::runtime_error("RPC server is shutting down");
}
Comment on lines +127 to +135
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the server is shutting down and the posted sync task never runs, this wrapper returns a default-constructed R. For RPCs returning primitive types this can silently look like a valid result (e.g., 0), and for carla::rpc::Response<T> it will surface as an unhelpful "unknown error". Consider returning a deterministic shutdown-specific error (e.g., set a ResponseError message when R is a Response<...> / Response<void>, or throw an exception that rpclib can convert into an RPC error).

Copilot uses AI. Check for mistakes.
Comment on lines +127 to +135
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change introduces shutdown-aware waiting logic in WrapSyncCall, but there is no regression test covering the shutdown path (i.e., a client call blocked on SyncRunFor work that gets unblocked when Server::Stop() is called). Adding a unit/integration test in the existing test_rpc.cpp suite would help prevent deadlock regressions.

Copilot uses AI. Check for mistakes.
}
};
}
Expand Down Expand Up @@ -153,7 +166,7 @@ namespace detail {
using Wrapper = detail::FunctionWrapper<FunctorT>;
_server.bind(
name,
Wrapper::WrapSyncCall(_sync_io_context, std::forward<FunctorT>(functor)));
Wrapper::WrapSyncCall(_shutdown_in_progress, _sync_io_context, std::forward<FunctorT>(functor)));
}

template <typename FunctorT>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <boost/asio/post.hpp>

#include <atomic>
#include <chrono>
#include <thread>

namespace carla {
Expand Down Expand Up @@ -86,7 +87,7 @@ namespace tcp {
if (_server.IsSynchronousMode()) {
// wait until previous message has been sent
while (_is_writing) {
std::this_thread::yield();
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
} else {
// ignore this message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
#include <RHIGPUReadback.h>
#include <util/ue-header-guard-end.h>


#include <chrono>
#include <thread>

template <typename F>
class ScopedCallback
Expand Down Expand Up @@ -255,7 +256,7 @@ namespace ImageUtil
Self = std::move(Self)]() mutable
{
while (!Self.Readback->IsReady())
std::this_thread::yield();
std::this_thread::sleep_for(std::chrono::microseconds(100));
ReadImageDataEnd(Self);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
#include "RHIGPUReadback.h"
#include <util/ue-header-guard-end.h>

#include <chrono>
#include <thread>

// =============================================================================
// -- FPixelReader -------------------------------------------------------------
// =============================================================================
Expand Down Expand Up @@ -63,7 +66,7 @@ void FPixelReader::WritePixelsToBuffer(
TRACE_CPUPROFILER_EVENT_SCOPE_STR("Wait GPU transfer");
while (!Readback->IsReady())
{
std::this_thread::yield();
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}

Expand Down