Actions
Bug #14660
closed
DM
RM
Possible FixedSqlConnectionPool deadlock
Bug #14660:
Possible FixedSqlConnectionPool deadlock
Start date:
07/10/2026
Due date:
% Done:
0%
Estimated time:
Description
If multiple connections are returned fast after each other while multiple threads are waiting for a connection, a deadlock may occur due to only notifying another thread when impl_->freeList.size() == 1.
Consider the following example:
std::shared<SqlConnection> connection = ...; // setup sql connection
auto pool = std::make_shared<Wt::Dbo::FixedSqlConnectionPool>(std::move(connection), 2);
auto con1 = pool->getConnection();
auto con2 = pool->getConnection();
// all connections of pool are now used.
auto thread1 = std::thread([pool](){
std::cout << "[thread1] Requesting connection ..." << std::endl;
pool->getConnection();
std::cout << "[thread1] Connection obtained" << std::endl;
});
auto thread2 = std::thread([pool](){
std::cout << "[thread2] Requesting connection ..." << std::endl;
pool->getConnection();
std::cout << "[thread2] Connection obtained" << std::endl;
});
// wait for 1 second to ensure both threads are waiting for a connection to become available
std::this_thread::sleep_for(std::chrono::seconds(1));
// release two connections immediately after each other
std::cout << "Returning con1" << std::endl;
pool->returnConnection(std::move(con1)); // will wake a single thread (e.g. thread1)
std::cout << "Returning con2" << std::endl;
pool->returnConnection(std::move(con2)); // will probably not wake another thread (e.g. thread2) as `impl_->freeList.size()` is probably 2 due to thread1 not having taken yet the freed connection.
std::cout << "Waiting for threads to finish" << std::endl;
thread1.join();
thread2.join();
std::cout << "OK. No deadlock occured." << std::endl; // probably never reached.
A typical output is:
[thread1] Requesting connection ...
[thread2] Requesting connection ...
Dbo.FixedSqlConnectionPool: no free connections, waiting for connection
Dbo.FixedSqlConnectionPool: no free connections, waiting for connection
Returning con1
Returning con2
Waiting for threads to finish
[thread1] Connection obtained
Eventually, this may result in all request handling threads being busy waiting for an available connection even though all connections are available, effectively deadlocking the full Wt application.
A possible solution is to always call impl_->connectionAvailable.notify_one();, even if impl_->freeList.size() != 1.
As a side note, it may be better to release the lock before calling notify_one (see Notes section of condition_variable::notify_one).
RM Updated by Romain Mardulyn about 1 month ago
- Target version set to 4.14.2
RM Updated by Romain Mardulyn about 1 month ago
- Status changed from New to InProgress
- Assignee set to Romain Mardulyn
RM Updated by Romain Mardulyn about 1 month ago
- Status changed from InProgress to New
- Assignee deleted (
Romain Mardulyn)
RM Updated by Romain Mardulyn about 1 month ago
- Status changed from New to InProgress
- Assignee set to Romain Mardulyn
RM Updated by Romain Mardulyn about 1 month ago
- Status changed from InProgress to Review
- Assignee deleted (
Romain Mardulyn)
ED Updated by emil de keyser about 1 month ago
- Assignee set to emil de keyser
ED Updated by emil de keyser about 1 month ago
- Status changed from Review to Resolved
- Assignee changed from emil de keyser to Romain Mardulyn
RM Updated by Romain Mardulyn about 1 month ago
- Status changed from Resolved to Implemented @Emweb
RM Updated by Romain Mardulyn 16 days ago
- Status changed from Implemented @Emweb to Closed
Actions